Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/src/libgnomecanvas
diff options
context:
space:
mode:
authorBruno Coudoin <bcoudoin@src.gnome.org>2007-05-22 22:46:46 (GMT)
committer Bruno Coudoin <bcoudoin@src.gnome.org>2007-05-22 22:46:46 (GMT)
commit84b86797cb241dd2a8d0951bd2845619edba4014 (patch)
treef4b26fd97bbc098fc0a4899fd7e3a65c114ff485 /src/libgnomecanvas
parentc7f435b9d44eb6d9f860fabf1cb590535599aee2 (diff)
- major packaging change, imported libart_lgpl and libgnomecanvas
from gnome svn (trunk). We now build them as static library. Packager change, you no more need them in GCompris require's. svn path=/trunk/; revision=2651
Diffstat (limited to 'src/libgnomecanvas')
-rw-r--r--src/libgnomecanvas/Makefile649
-rw-r--r--src/libgnomecanvas/Makefile.am72
-rw-r--r--src/libgnomecanvas/Makefile.in649
-rw-r--r--src/libgnomecanvas/gnome-canvas-bpath.c175
-rw-r--r--src/libgnomecanvas/gnome-canvas-bpath.h61
-rw-r--r--src/libgnomecanvas/gnome-canvas-clipgroup.c451
-rw-r--r--src/libgnomecanvas/gnome-canvas-clipgroup.h58
-rw-r--r--src/libgnomecanvas/gnome-canvas-i18n.h68
-rw-r--r--src/libgnomecanvas/gnome-canvas-line.c1422
-rw-r--r--src/libgnomecanvas/gnome-canvas-line.h154
-rw-r--r--src/libgnomecanvas/gnome-canvas-marshal.list2
-rw-r--r--src/libgnomecanvas/gnome-canvas-path-def.c1287
-rw-r--r--src/libgnomecanvas/gnome-canvas-path-def.h96
-rw-r--r--src/libgnomecanvas/gnome-canvas-pixbuf.c1079
-rw-r--r--src/libgnomecanvas/gnome-canvas-pixbuf.h62
-rw-r--r--src/libgnomecanvas/gnome-canvas-polygon.c249
-rw-r--r--src/libgnomecanvas/gnome-canvas-polygon.h88
-rw-r--r--src/libgnomecanvas/gnome-canvas-rect-ellipse.c431
-rw-r--r--src/libgnomecanvas/gnome-canvas-rect-ellipse.h159
-rw-r--r--src/libgnomecanvas/gnome-canvas-rich-text.c2203
-rw-r--r--src/libgnomecanvas/gnome-canvas-rich-text.h79
-rw-r--r--src/libgnomecanvas/gnome-canvas-shape-private.h103
-rw-r--r--src/libgnomecanvas/gnome-canvas-shape.c1559
-rw-r--r--src/libgnomecanvas/gnome-canvas-shape.h81
-rw-r--r--src/libgnomecanvas/gnome-canvas-text.c1740
-rw-r--r--src/libgnomecanvas/gnome-canvas-text.h170
-rw-r--r--src/libgnomecanvas/gnome-canvas-util.c700
-rw-r--r--src/libgnomecanvas/gnome-canvas-util.h155
-rw-r--r--src/libgnomecanvas/gnome-canvas-widget.c599
-rw-r--r--src/libgnomecanvas/gnome-canvas-widget.h103
-rw-r--r--src/libgnomecanvas/gnome-canvas.c4081
-rw-r--r--src/libgnomecanvas/gnome-canvas.h635
-rw-r--r--src/libgnomecanvas/libgnomecanvas.h48
-rw-r--r--src/libgnomecanvas/libgnomecanvastypes.c43
34 files changed, 19511 insertions, 0 deletions
diff --git a/src/libgnomecanvas/Makefile b/src/libgnomecanvas/Makefile
new file mode 100644
index 0000000..2a52b4e
--- /dev/null
+++ b/src/libgnomecanvas/Makefile
@@ -0,0 +1,649 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# src/libgnomecanvas/Makefile. Generated from Makefile.in by configure.
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 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.
+
+
+
+srcdir = .
+top_srcdir = ../..
+
+pkgdatadir = $(datadir)/gcompris
+pkglibdir = $(libdir)/gcompris
+pkgincludedir = $(includedir)/gcompris
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = /usr/bin/install -c
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = i686-pc-linux-gnu
+host_triplet = i686-pc-linux-gnu
+target_triplet = i686-pc-linux-gnu
+subdir = src/libgnomecanvas
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+ARFLAGS = cru
+libgnomecanvas_2_a_AR = $(AR) $(ARFLAGS)
+libgnomecanvas_2_a_DEPENDENCIES =
+am__objects_1 =
+am_libgnomecanvas_2_a_OBJECTS = $(am__objects_1) \
+ gnome-canvas-shape.$(OBJEXT) gnome-canvas-bpath.$(OBJEXT) \
+ gnome-canvas-path-def.$(OBJEXT) \
+ gnome-canvas-clipgroup.$(OBJEXT) gnome-canvas-line.$(OBJEXT) \
+ gnome-canvas-pixbuf.$(OBJEXT) gnome-canvas-polygon.$(OBJEXT) \
+ gnome-canvas-rect-ellipse.$(OBJEXT) \
+ gnome-canvas-text.$(OBJEXT) gnome-canvas-rich-text.$(OBJEXT) \
+ gnome-canvas-util.$(OBJEXT) gnome-canvas-widget.$(OBJEXT) \
+ gnome-canvas.$(OBJEXT) libgnomecanvastypes.$(OBJEXT)
+libgnomecanvas_2_a_OBJECTS = $(am_libgnomecanvas_2_a_OBJECTS)
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libgnomecanvas_2_a_SOURCES)
+DIST_SOURCES = $(libgnomecanvas_2_a_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = ${SHELL} /home/bruno/Projets/gcompris/trunk/missing --run aclocal-1.9
+ALLOCA =
+ALL_LINGUAS = am ar ar_TN az bg ca cs da de dz el en_CA en_GB es et eu fi fr ga gl gu he hi hr hu id it ja ka ko lt mk ml mr ms nb ne nl nn oc pa pl pt pt_BR ro ru rw sk sl so sq sr sr@Latn sv ta th tr vi wa zh_CN zh_TW
+AMDEP_FALSE = #
+AMDEP_TRUE =
+AMTAR = ${SHELL} /home/bruno/Projets/gcompris/trunk/missing --run tar
+AR = ar
+AS = as
+AUTOCONF = ${SHELL} /home/bruno/Projets/gcompris/trunk/missing --run autoconf
+AUTOHEADER = ${SHELL} /home/bruno/Projets/gcompris/trunk/missing --run autoheader
+AUTOMAKE = ${SHELL} /home/bruno/Projets/gcompris/trunk/missing --run automake-1.9
+AWK = gawk
+BINRELOC_CFLAGS = -DENABLE_BINRELOC
+BINRELOC_LIBS =
+BUILD_DATE = 0705
+BUILD_MINGW32_FALSE =
+BUILD_MINGW32_TRUE = #
+BUNDLE_APPDIR = /home/bruno/Projets/gcompris/trunk/GCompris.app
+BUNDLE_NAME = GCompris
+CAIRO_CFLAGS =
+CAIRO_LIBS =
+CATALOGS = am.gmo ar.gmo ar_TN.gmo az.gmo bg.gmo ca.gmo cs.gmo da.gmo de.gmo dz.gmo el.gmo en_CA.gmo en_GB.gmo es.gmo et.gmo eu.gmo fi.gmo fr.gmo ga.gmo gl.gmo gu.gmo he.gmo hi.gmo hr.gmo hu.gmo id.gmo it.gmo ja.gmo ka.gmo ko.gmo lt.gmo mk.gmo ml.gmo mr.gmo ms.gmo nb.gmo ne.gmo nl.gmo nn.gmo oc.gmo pa.gmo pl.gmo pt.gmo pt_BR.gmo ro.gmo ru.gmo rw.gmo sk.gmo sl.gmo so.gmo sq.gmo sr.gmo sr@Latn.gmo sv.gmo ta.gmo th.gmo tr.gmo vi.gmo wa.gmo zh_CN.gmo zh_TW.gmo
+CATOBJEXT = .gmo
+CC = gcc
+CCDEPMODE = depmode=gcc3
+CFLAGS = -Wall -Werror
+CPP = gcc -E
+CPPFLAGS =
+CXX = g++
+CXXCPP = g++ -E
+CXXDEPMODE = depmode=gcc3
+CXXFLAGS = -g -O2
+CYGPATH_W = echo
+DATADIRNAME = share
+DEFS = -DHAVE_CONFIG_H
+DEPDIR = .deps
+DLLTOOL = dlltool
+ECHO = echo
+ECHO_C =
+ECHO_N = -n
+ECHO_T =
+EGREP = /bin/grep -E
+EXEEXT =
+F77 =
+FFLAGS =
+GCOMPRIS_CFLAGS = -pthread -I/usr/include/gtk-2.0 -I/usr/lib/gtk-2.0/include -I/usr/include/atk-1.0 -I/usr/include/cairo -I/usr/include/pango-1.0 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/freetype2 -I/usr/include/libpng12 -I/usr/include/gstreamer-0.10 -I/usr/include/libxml2
+GCOMPRIS_LIBS = -pthread -lgtk-x11-2.0 -lgdk-x11-2.0 -latk-1.0 -lpangocairo-1.0 -lfontconfig -lXext -lXrender -lXinerama -lXi -lXrandr -lXcursor -lXfixes -lpango-1.0 -lcairo -lX11 -lgdk_pixbuf-2.0 -lm -lgstreamer-0.10 -lgobject-2.0 -lgmodule-2.0 -ldl -lgthread-2.0 -lrt -lxml2 -lglib-2.0
+GETTEXT_PACKAGE = gcompris
+GLIB_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include
+GLIB_GENMARSHAL = /usr/bin/glib-genmarshal
+GLIB_LIBS = -lglib-2.0
+GLIB_MKENUMS = glib-mkenums
+GMOFILES = am.gmo ar.gmo ar_TN.gmo az.gmo bg.gmo ca.gmo cs.gmo da.gmo de.gmo dz.gmo el.gmo en_CA.gmo en_GB.gmo es.gmo et.gmo eu.gmo fi.gmo fr.gmo ga.gmo gl.gmo gu.gmo he.gmo hi.gmo hr.gmo hu.gmo id.gmo it.gmo ja.gmo ka.gmo ko.gmo lt.gmo mk.gmo ml.gmo mr.gmo ms.gmo nb.gmo ne.gmo nl.gmo nn.gmo oc.gmo pa.gmo pl.gmo pt.gmo pt_BR.gmo ro.gmo ru.gmo rw.gmo sk.gmo sl.gmo so.gmo sq.gmo sr.gmo sr@Latn.gmo sv.gmo ta.gmo th.gmo tr.gmo vi.gmo wa.gmo zh_CN.gmo zh_TW.gmo
+GMSGFMT = /usr/bin/msgfmt
+GNET_CFLAGS =
+GNET_LIBS =
+GNUCHESS = gnome-gnuchess
+GOBJECT_QUERY = gobject-query
+GREP = /bin/grep
+INSTALL_DATA = ${INSTALL} -m 644
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_SCRIPT = ${INSTALL}
+INSTALL_STRIP_PROGRAM = ${SHELL} $(install_sh) -c -s
+INSTOBJEXT = .mo
+INTLLIBS =
+INTLTOOL_CAVES_RULE = %.caves: %.caves.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< $@
+INTLTOOL_DESKTOP_RULE = %.desktop: %.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< $@
+INTLTOOL_DIRECTORY_RULE = %.directory: %.directory.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< $@
+INTLTOOL_EXTRACT = $(top_builddir)/intltool-extract
+INTLTOOL_ICONV = /usr/bin/iconv
+INTLTOOL_KBD_RULE = %.kbd: %.kbd.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -x -u -m -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< $@
+INTLTOOL_KEYS_RULE = %.keys: %.keys.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -k -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< $@
+INTLTOOL_MERGE = $(top_builddir)/intltool-merge
+INTLTOOL_MSGFMT = /usr/bin/msgfmt
+INTLTOOL_MSGMERGE = /usr/bin/msgmerge
+INTLTOOL_OAF_RULE = %.oaf: %.oaf.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -o -p $(top_srcdir)/po $< $@
+INTLTOOL_PERL = /usr/bin/perl
+INTLTOOL_PONG_RULE = %.pong: %.pong.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -x -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< $@
+INTLTOOL_PROP_RULE = %.prop: %.prop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< $@
+INTLTOOL_SCHEMAS_RULE = %.schemas: %.schemas.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -s -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< $@
+INTLTOOL_SERVER_RULE = %.server: %.server.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -o -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< $@
+INTLTOOL_SERVICE_RULE = %.service: %.service.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< $@
+INTLTOOL_SHEET_RULE = %.sheet: %.sheet.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -x -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< $@
+INTLTOOL_SOUNDLIST_RULE = %.soundlist: %.soundlist.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< $@
+INTLTOOL_THEME_RULE = %.theme: %.theme.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< $@
+INTLTOOL_UI_RULE = %.ui: %.ui.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -x -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< $@
+INTLTOOL_UPDATE = $(top_builddir)/intltool-update
+INTLTOOL_XAM_RULE = %.xam: %.xml.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -x -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< $@
+INTLTOOL_XGETTEXT = /usr/bin/xgettext
+INTLTOOL_XML_NOMERGE_RULE = %.xml: %.xml.in $(INTLTOOL_MERGE) ; LC_ALL=C $(INTLTOOL_MERGE) -x -u /tmp $< $@
+INTLTOOL_XML_RULE = %.xml: %.xml.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -x -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< $@
+LDFLAGS = -lXxf86vm
+LIBICONV =
+LIBOBJS =
+LIBS =
+LIBTOOL = $(SHELL) $(top_builddir)/libtool
+LN_S = ln -s
+LTLIBICONV =
+LTLIBOBJS =
+MAINT =
+MAINTAINER_MODE_FALSE = #
+MAINTAINER_MODE_TRUE =
+MAKEINFO = ${SHELL} /home/bruno/Projets/gcompris/trunk/missing --run makeinfo
+MKINSTALLDIRS = ./mkinstalldirs
+MSGFMT = /usr/bin/msgfmt
+MSGFMT_OPTS = -c
+NSBUNDLE_CPPFLAGS =
+NSBUNDLE_GTK_DIR =
+NSBUNDLE_LDFLAGS =
+OBJC = gcc
+OBJCDEPMODE = depmode=gcc3
+OBJCFLAGS =
+OBJCPP =
+OBJDUMP = objdump
+OBJEXT = o
+OS_MACOSX_FALSE =
+OS_MACOSX_TRUE = #
+OS_WIN32_FALSE =
+OS_WIN32_TRUE = #
+PACKAGE = gcompris
+PACKAGE_BUGREPORT =
+PACKAGE_DATA_DIR = boards
+PACKAGE_HELP_DIR = /usr/local/share/gcompris/help
+PACKAGE_NAME =
+PACKAGE_STRING =
+PACKAGE_TARNAME =
+PACKAGE_VERSION =
+PATH_SEPARATOR = :
+PKG_CONFIG = /usr/bin/pkg-config
+PLATFORM_WIN32_FALSE =
+PLATFORM_WIN32_TRUE = #
+POFILES = am.po ar.po ar_TN.po az.po bg.po ca.po cs.po da.po de.po dz.po el.po en_CA.po en_GB.po es.po et.po eu.po fi.po fr.po ga.po gl.po gu.po he.po hi.po hr.po hu.po id.po it.po ja.po ka.po ko.po lt.po mk.po ml.po mr.po ms.po nb.po ne.po nl.po nn.po oc.po pa.po pl.po pt.po pt_BR.po ro.po ru.po rw.po sk.po sl.po so.po sq.po sr.po sr@Latn.po sv.po ta.po th.po tr.po vi.po wa.po zh_CN.po zh_TW.po
+POSUB = po
+PO_IN_DATADIR_FALSE =
+PO_IN_DATADIR_TRUE =
+PYCAIRO_CFLAGS =
+PYCAIRO_LIBS =
+PYGTK_CFLAGS = -I/usr/include/pygtk-2.0 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include
+PYGTK_CODEGEN = /usr/bin/python /usr/share/pygtk/2.0/codegen/codegen.py
+PYGTK_DEFSDIR = /usr/share/pygtk/2.0/defs
+PYGTK_H2DEF = /usr/bin/python /usr/share/pygtk/2.0/codegen/h2def.py
+PYGTK_LIBS = -lgobject-2.0 -lglib-2.0
+PYTHON = /usr/bin/python
+PYTHON_CFLAGS = -I/usr/include/python2.5
+PYTHON_EXEC_PREFIX = ${exec_prefix}
+PYTHON_LIBS = -L/usr/lib -lpython2.5
+PYTHON_PLATFORM = linux2
+PYTHON_PLUGIN_DIR = /usr/local/share/gcompris/python
+PYTHON_PLUGIN_FALSE = #
+PYTHON_PLUGIN_TRUE =
+PYTHON_PREFIX = ${prefix}
+PYTHON_VERSION = 2.5
+RANLIB = ranlib
+REQUIRE_PYTHON = python pygtk2.0 python-sqlite2
+SET_MAKE =
+SHELL = /bin/bash
+SQLITE3_CFLAGS =
+SQLITE3_LIBS = -lsqlite3
+STRIP = strip
+TETEX = /usr/bin/texi2html
+TEXINFO = /usr/bin/makeinfo
+TEXINFO_FALSE = #
+TEXINFO_TRUE =
+USE_CAIRO_FALSE =
+USE_CAIRO_TRUE = #
+USE_NLS = yes
+USE_SQLITE_FALSE = #
+USE_SQLITE_TRUE =
+VERSION = 8.3.1
+WITH_NSBUNDLE_FALSE =
+WITH_NSBUNDLE_TRUE = #
+XGETTEXT = /usr/bin/xgettext
+XMKMF =
+XML_CFLAGS = -I/usr/include/libxml2
+XML_LIBS = -lxml2
+ac_ct_CC = gcc
+ac_ct_CXX = g++
+ac_ct_F77 =
+ac_ct_OBJC =
+am__fastdepCC_FALSE = #
+am__fastdepCC_TRUE =
+am__fastdepCXX_FALSE = #
+am__fastdepCXX_TRUE =
+am__fastdepOBJC_FALSE = #
+am__fastdepOBJC_TRUE =
+am__include = include
+am__leading_dot = .
+am__quote =
+am__tar = ${AMTAR} chof - "$$tardir"
+am__untar = ${AMTAR} xf -
+bindir = ${exec_prefix}/bin
+build = i686-pc-linux-gnu
+build_alias =
+build_cpu = i686
+build_os = linux-gnu
+build_vendor = pc
+datadir = ${datarootdir}
+datarootdir = ${prefix}/share
+docdir = ${datarootdir}/doc/${PACKAGE}
+dvidir = ${docdir}
+exec_prefix = /usr/local
+host = i686-pc-linux-gnu
+host_alias =
+host_cpu = i686
+host_os = linux-gnu
+host_vendor = pc
+htmldir = ${docdir}
+includedir = ${prefix}/include
+infodir = ${datarootdir}/info
+install_sh = /home/bruno/Projets/gcompris/trunk/install-sh
+libdir = ${exec_prefix}/lib
+libexecdir = ${exec_prefix}/libexec
+localedir = ${datarootdir}/locale
+localstatedir = ${prefix}/var
+mandir = ${datarootdir}/man
+mkdir_p = mkdir -p --
+oldincludedir = /usr/include
+pdfdir = ${docdir}
+pkgpyexecdir = ${pyexecdir}/gcompris
+pkgpythondir = ${pythondir}/gcompris
+plugindir = ${exec_prefix}/lib/gcompris
+prefix = /usr/local
+program_transform_name = s,x,x,
+psdir = ${docdir}
+pyexecdir = ${exec_prefix}/lib/python2.5/site-packages
+pythondir = ${prefix}/lib/python2.5/site-packages
+sbindir = ${exec_prefix}/sbin
+sharedstatedir = ${prefix}/com
+sysconfdir = ${prefix}/etc
+target = i686-pc-linux-gnu
+target_alias =
+target_cpu = i686
+target_os = linux-gnu
+target_vendor = pc
+INCLUDES = \
+ -I$(top_srcdir) \
+ -I$(top_builddir) \
+ -I$(top_srcdir)/src \
+ $(WARN_CFLAGS) \
+ $(GCOMPRIS_CFLAGS) \
+ -DGNOMECANVASLIBDIR=\""$(libdir)"\" \
+ -DGNOMECANVASDATADIR=\""$(datadir)"\" \
+ -DGNOMECANVASPIXMAPDIR=\""$(datadir)/pixmaps"\" \
+ -DGNOMECANVASBINDIR=\""$(bindir)"\" \
+ -DGNOMECANVASLOCALSTATEDIR=\""$(localstatedir)"\" \
+ -DG_LOG_DOMAIN=\"GnomeCanvas\"
+
+noinst_LIBRARIES = libgnomecanvas-2.a
+libgnomecanvas_2_a_LIBADD = \
+ $(LIBGNOMECANVAS_LIBS)
+
+libgnomecanvasinclude_headers = \
+ gnome-canvas-shape.h \
+ gnome-canvas-bpath.h \
+ gnome-canvas-clipgroup.h \
+ gnome-canvas-line.h \
+ gnome-canvas-pixbuf.h \
+ gnome-canvas-polygon.h \
+ gnome-canvas-rect-ellipse.h \
+ gnome-canvas-text.h \
+ gnome-canvas-rich-text.h \
+ gnome-canvas-util.h \
+ gnome-canvas-widget.h \
+ gnome-canvas-path-def.h \
+ gnome-canvas.h \
+ libgnomecanvas.h
+
+libgnomecanvas_2_a_SOURCES = \
+ $(libgnomecanvasinclude_headers) \
+ gnome-canvas-shape.c \
+ gnome-canvas-shape-private.h \
+ gnome-canvas-bpath.c \
+ gnome-canvas-path-def.c \
+ gnome-canvas-clipgroup.c \
+ gnome-canvas-i18n.h \
+ gnome-canvas-line.c \
+ gnome-canvas-pixbuf.c \
+ gnome-canvas-polygon.c \
+ gnome-canvas-rect-ellipse.c \
+ gnome-canvas-text.c \
+ gnome-canvas-rich-text.c \
+ gnome-canvas-util.c \
+ gnome-canvas-widget.c \
+ gnome-canvas.c \
+ libgnomecanvastypes.c
+
+marshal_sources = \
+ gnome-canvas-marshal.c \
+ gnome-canvas-marshal.h
+
+BUILT_SOURCES = \
+ $(marshal_sources)
+
+CLEANFILES = $(marshal_sources)
+DONT_DIST_SOURCE = $(marshal_sources)
+all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libgnomecanvas/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/libgnomecanvas/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+libgnomecanvas-2.a: $(libgnomecanvas_2_a_OBJECTS) $(libgnomecanvas_2_a_DEPENDENCIES)
+ -rm -f libgnomecanvas-2.a
+ $(libgnomecanvas_2_a_AR) libgnomecanvas-2.a $(libgnomecanvas_2_a_OBJECTS) $(libgnomecanvas_2_a_LIBADD)
+ $(RANLIB) libgnomecanvas-2.a
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+include ./$(DEPDIR)/gnome-canvas-bpath.Po
+include ./$(DEPDIR)/gnome-canvas-clipgroup.Po
+include ./$(DEPDIR)/gnome-canvas-line.Po
+include ./$(DEPDIR)/gnome-canvas-path-def.Po
+include ./$(DEPDIR)/gnome-canvas-pixbuf.Po
+include ./$(DEPDIR)/gnome-canvas-polygon.Po
+include ./$(DEPDIR)/gnome-canvas-rect-ellipse.Po
+include ./$(DEPDIR)/gnome-canvas-rich-text.Po
+include ./$(DEPDIR)/gnome-canvas-shape.Po
+include ./$(DEPDIR)/gnome-canvas-text.Po
+include ./$(DEPDIR)/gnome-canvas-util.Po
+include ./$(DEPDIR)/gnome-canvas-widget.Po
+include ./$(DEPDIR)/gnome-canvas.Po
+include ./$(DEPDIR)/libgnomecanvastypes.Po
+
+.c.o:
+ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+# source='$<' object='$@' libtool=no \
+# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \
+# $(COMPILE) -c $<
+
+.c.obj:
+ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+# source='$<' object='$@' libtool=no \
+# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \
+# $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+# source='$<' object='$@' libtool=yes \
+# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \
+# $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+uninstall-info-am:
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LIBRARIES)
+installdirs:
+install: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-exec \
+ install-exec-am install-info install-info-am install-man \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags uninstall uninstall-am \
+ uninstall-info-am
+
+
+$(libgnomecanvas_2_a_OBJECTS): $(marshal_sources)
+
+gnome-canvas-marshal.h: gnome-canvas-marshal.list $(GLIB_GENMARSHAL)
+ $(GLIB_GENMARSHAL) $< --header --prefix=gnome_canvas_marshal > $@
+gnome-canvas-marshal.c: gnome-canvas-marshal.list $(GLIB_GENMARSHAL)
+ $(GLIB_GENMARSHAL) $< --body --prefix=gnome_canvas_marshal > $@
+# 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/src/libgnomecanvas/Makefile.am b/src/libgnomecanvas/Makefile.am
new file mode 100644
index 0000000..e2bdb61
--- /dev/null
+++ b/src/libgnomecanvas/Makefile.am
@@ -0,0 +1,72 @@
+
+INCLUDES = \
+ -I$(top_srcdir) \
+ -I$(top_builddir) \
+ -I$(top_srcdir)/src \
+ $(WARN_CFLAGS) \
+ $(GCOMPRIS_CFLAGS) \
+ -DGNOMECANVASLIBDIR=\""$(libdir)"\" \
+ -DGNOMECANVASDATADIR=\""$(datadir)"\" \
+ -DGNOMECANVASPIXMAPDIR=\""$(datadir)/pixmaps"\" \
+ -DGNOMECANVASBINDIR=\""$(bindir)"\" \
+ -DGNOMECANVASLOCALSTATEDIR=\""$(localstatedir)"\" \
+ -DG_LOG_DOMAIN=\"GnomeCanvas\"
+
+noinst_LIBRARIES = libgnomecanvas-2.a
+
+libgnomecanvas_2_a_LIBADD = \
+ $(LIBGNOMECANVAS_LIBS)
+
+libgnomecanvasinclude_headers = \
+ gnome-canvas-shape.h \
+ gnome-canvas-bpath.h \
+ gnome-canvas-clipgroup.h \
+ gnome-canvas-line.h \
+ gnome-canvas-pixbuf.h \
+ gnome-canvas-polygon.h \
+ gnome-canvas-rect-ellipse.h \
+ gnome-canvas-text.h \
+ gnome-canvas-rich-text.h \
+ gnome-canvas-util.h \
+ gnome-canvas-widget.h \
+ gnome-canvas-path-def.h \
+ gnome-canvas.h \
+ libgnomecanvas.h
+
+libgnomecanvas_2_a_SOURCES = \
+ $(libgnomecanvasinclude_headers) \
+ gnome-canvas-shape.c \
+ gnome-canvas-shape-private.h \
+ gnome-canvas-bpath.c \
+ gnome-canvas-path-def.c \
+ gnome-canvas-clipgroup.c \
+ gnome-canvas-i18n.h \
+ gnome-canvas-line.c \
+ gnome-canvas-pixbuf.c \
+ gnome-canvas-polygon.c \
+ gnome-canvas-rect-ellipse.c \
+ gnome-canvas-text.c \
+ gnome-canvas-rich-text.c \
+ gnome-canvas-util.c \
+ gnome-canvas-widget.c \
+ gnome-canvas.c \
+ libgnomecanvastypes.c
+
+$(libgnomecanvas_2_a_OBJECTS): $(marshal_sources)
+
+marshal_sources = \
+ gnome-canvas-marshal.c \
+ gnome-canvas-marshal.h
+
+BUILT_SOURCES = \
+ $(marshal_sources)
+
+gnome-canvas-marshal.h: gnome-canvas-marshal.list $(GLIB_GENMARSHAL)
+ $(GLIB_GENMARSHAL) $< --header --prefix=gnome_canvas_marshal > $@
+gnome-canvas-marshal.c: gnome-canvas-marshal.list $(GLIB_GENMARSHAL)
+ $(GLIB_GENMARSHAL) $< --body --prefix=gnome_canvas_marshal > $@
+
+CLEANFILES = $(marshal_sources)
+
+DONT_DIST_SOURCE = $(marshal_sources)
+
diff --git a/src/libgnomecanvas/Makefile.in b/src/libgnomecanvas/Makefile.in
new file mode 100644
index 0000000..2fe8b87
--- /dev/null
+++ b/src/libgnomecanvas/Makefile.in
@@ -0,0 +1,649 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 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.
+
+@SET_MAKE@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = src/libgnomecanvas
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+ARFLAGS = cru
+libgnomecanvas_2_a_AR = $(AR) $(ARFLAGS)
+libgnomecanvas_2_a_DEPENDENCIES =
+am__objects_1 =
+am_libgnomecanvas_2_a_OBJECTS = $(am__objects_1) \
+ gnome-canvas-shape.$(OBJEXT) gnome-canvas-bpath.$(OBJEXT) \
+ gnome-canvas-path-def.$(OBJEXT) \
+ gnome-canvas-clipgroup.$(OBJEXT) gnome-canvas-line.$(OBJEXT) \
+ gnome-canvas-pixbuf.$(OBJEXT) gnome-canvas-polygon.$(OBJEXT) \
+ gnome-canvas-rect-ellipse.$(OBJEXT) \
+ gnome-canvas-text.$(OBJEXT) gnome-canvas-rich-text.$(OBJEXT) \
+ gnome-canvas-util.$(OBJEXT) gnome-canvas-widget.$(OBJEXT) \
+ gnome-canvas.$(OBJEXT) libgnomecanvastypes.$(OBJEXT)
+libgnomecanvas_2_a_OBJECTS = $(am_libgnomecanvas_2_a_OBJECTS)
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libgnomecanvas_2_a_SOURCES)
+DIST_SOURCES = $(libgnomecanvas_2_a_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+ALL_LINGUAS = @ALL_LINGUAS@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINRELOC_CFLAGS = @BINRELOC_CFLAGS@
+BINRELOC_LIBS = @BINRELOC_LIBS@
+BUILD_DATE = @BUILD_DATE@
+BUILD_MINGW32_FALSE = @BUILD_MINGW32_FALSE@
+BUILD_MINGW32_TRUE = @BUILD_MINGW32_TRUE@
+BUNDLE_APPDIR = @BUNDLE_APPDIR@
+BUNDLE_NAME = @BUNDLE_NAME@
+CAIRO_CFLAGS = @CAIRO_CFLAGS@
+CAIRO_LIBS = @CAIRO_LIBS@
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATADIRNAME = @DATADIRNAME@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+GCOMPRIS_CFLAGS = @GCOMPRIS_CFLAGS@
+GCOMPRIS_LIBS = @GCOMPRIS_LIBS@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GMOFILES = @GMOFILES@
+GMSGFMT = @GMSGFMT@
+GNET_CFLAGS = @GNET_CFLAGS@
+GNET_LIBS = @GNET_LIBS@
+GNUCHESS = @GNUCHESS@
+GOBJECT_QUERY = @GOBJECT_QUERY@
+GREP = @GREP@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INSTOBJEXT = @INSTOBJEXT@
+INTLLIBS = @INTLLIBS@
+INTLTOOL_CAVES_RULE = @INTLTOOL_CAVES_RULE@
+INTLTOOL_DESKTOP_RULE = @INTLTOOL_DESKTOP_RULE@
+INTLTOOL_DIRECTORY_RULE = @INTLTOOL_DIRECTORY_RULE@
+INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
+INTLTOOL_ICONV = @INTLTOOL_ICONV@
+INTLTOOL_KBD_RULE = @INTLTOOL_KBD_RULE@
+INTLTOOL_KEYS_RULE = @INTLTOOL_KEYS_RULE@
+INTLTOOL_MERGE = @INTLTOOL_MERGE@
+INTLTOOL_MSGFMT = @INTLTOOL_MSGFMT@
+INTLTOOL_MSGMERGE = @INTLTOOL_MSGMERGE@
+INTLTOOL_OAF_RULE = @INTLTOOL_OAF_RULE@
+INTLTOOL_PERL = @INTLTOOL_PERL@
+INTLTOOL_PONG_RULE = @INTLTOOL_PONG_RULE@
+INTLTOOL_PROP_RULE = @INTLTOOL_PROP_RULE@
+INTLTOOL_SCHEMAS_RULE = @INTLTOOL_SCHEMAS_RULE@
+INTLTOOL_SERVER_RULE = @INTLTOOL_SERVER_RULE@
+INTLTOOL_SERVICE_RULE = @INTLTOOL_SERVICE_RULE@
+INTLTOOL_SHEET_RULE = @INTLTOOL_SHEET_RULE@
+INTLTOOL_SOUNDLIST_RULE = @INTLTOOL_SOUNDLIST_RULE@
+INTLTOOL_THEME_RULE = @INTLTOOL_THEME_RULE@
+INTLTOOL_UI_RULE = @INTLTOOL_UI_RULE@
+INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_XAM_RULE = @INTLTOOL_XAM_RULE@
+INTLTOOL_XGETTEXT = @INTLTOOL_XGETTEXT@
+INTLTOOL_XML_NOMERGE_RULE = @INTLTOOL_XML_NOMERGE_RULE@
+INTLTOOL_XML_RULE = @INTLTOOL_XML_RULE@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MSGFMT = @MSGFMT@
+MSGFMT_OPTS = @MSGFMT_OPTS@
+NSBUNDLE_CPPFLAGS = @NSBUNDLE_CPPFLAGS@
+NSBUNDLE_GTK_DIR = @NSBUNDLE_GTK_DIR@
+NSBUNDLE_LDFLAGS = @NSBUNDLE_LDFLAGS@
+OBJC = @OBJC@
+OBJCDEPMODE = @OBJCDEPMODE@
+OBJCFLAGS = @OBJCFLAGS@
+OBJCPP = @OBJCPP@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OS_MACOSX_FALSE = @OS_MACOSX_FALSE@
+OS_MACOSX_TRUE = @OS_MACOSX_TRUE@
+OS_WIN32_FALSE = @OS_WIN32_FALSE@
+OS_WIN32_TRUE = @OS_WIN32_TRUE@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_DATA_DIR = @PACKAGE_DATA_DIR@
+PACKAGE_HELP_DIR = @PACKAGE_HELP_DIR@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PLATFORM_WIN32_FALSE = @PLATFORM_WIN32_FALSE@
+PLATFORM_WIN32_TRUE = @PLATFORM_WIN32_TRUE@
+POFILES = @POFILES@
+POSUB = @POSUB@
+PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@
+PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@
+PYCAIRO_CFLAGS = @PYCAIRO_CFLAGS@
+PYCAIRO_LIBS = @PYCAIRO_LIBS@
+PYGTK_CFLAGS = @PYGTK_CFLAGS@
+PYGTK_CODEGEN = @PYGTK_CODEGEN@
+PYGTK_DEFSDIR = @PYGTK_DEFSDIR@
+PYGTK_H2DEF = @PYGTK_H2DEF@
+PYGTK_LIBS = @PYGTK_LIBS@
+PYTHON = @PYTHON@
+PYTHON_CFLAGS = @PYTHON_CFLAGS@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_LIBS = @PYTHON_LIBS@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PLUGIN_DIR = @PYTHON_PLUGIN_DIR@
+PYTHON_PLUGIN_FALSE = @PYTHON_PLUGIN_FALSE@
+PYTHON_PLUGIN_TRUE = @PYTHON_PLUGIN_TRUE@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+REQUIRE_PYTHON = @REQUIRE_PYTHON@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SQLITE3_CFLAGS = @SQLITE3_CFLAGS@
+SQLITE3_LIBS = @SQLITE3_LIBS@
+STRIP = @STRIP@
+TETEX = @TETEX@
+TEXINFO = @TEXINFO@
+TEXINFO_FALSE = @TEXINFO_FALSE@
+TEXINFO_TRUE = @TEXINFO_TRUE@
+USE_CAIRO_FALSE = @USE_CAIRO_FALSE@
+USE_CAIRO_TRUE = @USE_CAIRO_TRUE@
+USE_NLS = @USE_NLS@
+USE_SQLITE_FALSE = @USE_SQLITE_FALSE@
+USE_SQLITE_TRUE = @USE_SQLITE_TRUE@
+VERSION = @VERSION@
+WITH_NSBUNDLE_FALSE = @WITH_NSBUNDLE_FALSE@
+WITH_NSBUNDLE_TRUE = @WITH_NSBUNDLE_TRUE@
+XGETTEXT = @XGETTEXT@
+XMKMF = @XMKMF@
+XML_CFLAGS = @XML_CFLAGS@
+XML_LIBS = @XML_LIBS@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+ac_ct_OBJC = @ac_ct_OBJC@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
+am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
+am__fastdepOBJC_FALSE = @am__fastdepOBJC_FALSE@
+am__fastdepOBJC_TRUE = @am__fastdepOBJC_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+plugindir = @plugindir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+INCLUDES = \
+ -I$(top_srcdir) \
+ -I$(top_builddir) \
+ -I$(top_srcdir)/src \
+ $(WARN_CFLAGS) \
+ $(GCOMPRIS_CFLAGS) \
+ -DGNOMECANVASLIBDIR=\""$(libdir)"\" \
+ -DGNOMECANVASDATADIR=\""$(datadir)"\" \
+ -DGNOMECANVASPIXMAPDIR=\""$(datadir)/pixmaps"\" \
+ -DGNOMECANVASBINDIR=\""$(bindir)"\" \
+ -DGNOMECANVASLOCALSTATEDIR=\""$(localstatedir)"\" \
+ -DG_LOG_DOMAIN=\"GnomeCanvas\"
+
+noinst_LIBRARIES = libgnomecanvas-2.a
+libgnomecanvas_2_a_LIBADD = \
+ $(LIBGNOMECANVAS_LIBS)
+
+libgnomecanvasinclude_headers = \
+ gnome-canvas-shape.h \
+ gnome-canvas-bpath.h \
+ gnome-canvas-clipgroup.h \
+ gnome-canvas-line.h \
+ gnome-canvas-pixbuf.h \
+ gnome-canvas-polygon.h \
+ gnome-canvas-rect-ellipse.h \
+ gnome-canvas-text.h \
+ gnome-canvas-rich-text.h \
+ gnome-canvas-util.h \
+ gnome-canvas-widget.h \
+ gnome-canvas-path-def.h \
+ gnome-canvas.h \
+ libgnomecanvas.h
+
+libgnomecanvas_2_a_SOURCES = \
+ $(libgnomecanvasinclude_headers) \
+ gnome-canvas-shape.c \
+ gnome-canvas-shape-private.h \
+ gnome-canvas-bpath.c \
+ gnome-canvas-path-def.c \
+ gnome-canvas-clipgroup.c \
+ gnome-canvas-i18n.h \
+ gnome-canvas-line.c \
+ gnome-canvas-pixbuf.c \
+ gnome-canvas-polygon.c \
+ gnome-canvas-rect-ellipse.c \
+ gnome-canvas-text.c \
+ gnome-canvas-rich-text.c \
+ gnome-canvas-util.c \
+ gnome-canvas-widget.c \
+ gnome-canvas.c \
+ libgnomecanvastypes.c
+
+marshal_sources = \
+ gnome-canvas-marshal.c \
+ gnome-canvas-marshal.h
+
+BUILT_SOURCES = \
+ $(marshal_sources)
+
+CLEANFILES = $(marshal_sources)
+DONT_DIST_SOURCE = $(marshal_sources)
+all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libgnomecanvas/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/libgnomecanvas/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+libgnomecanvas-2.a: $(libgnomecanvas_2_a_OBJECTS) $(libgnomecanvas_2_a_DEPENDENCIES)
+ -rm -f libgnomecanvas-2.a
+ $(libgnomecanvas_2_a_AR) libgnomecanvas-2.a $(libgnomecanvas_2_a_OBJECTS) $(libgnomecanvas_2_a_LIBADD)
+ $(RANLIB) libgnomecanvas-2.a
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome-canvas-bpath.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome-canvas-clipgroup.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome-canvas-line.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome-canvas-path-def.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome-canvas-pixbuf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome-canvas-polygon.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome-canvas-rect-ellipse.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome-canvas-rich-text.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome-canvas-shape.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome-canvas-text.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome-canvas-util.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome-canvas-widget.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome-canvas.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgnomecanvastypes.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+uninstall-info-am:
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LIBRARIES)
+installdirs:
+install: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-exec \
+ install-exec-am install-info install-info-am install-man \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags uninstall uninstall-am \
+ uninstall-info-am
+
+
+$(libgnomecanvas_2_a_OBJECTS): $(marshal_sources)
+
+gnome-canvas-marshal.h: gnome-canvas-marshal.list $(GLIB_GENMARSHAL)
+ $(GLIB_GENMARSHAL) $< --header --prefix=gnome_canvas_marshal > $@
+gnome-canvas-marshal.c: gnome-canvas-marshal.list $(GLIB_GENMARSHAL)
+ $(GLIB_GENMARSHAL) $< --body --prefix=gnome_canvas_marshal > $@
+# 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/src/libgnomecanvas/gnome-canvas-bpath.c b/src/libgnomecanvas/gnome-canvas-bpath.c
new file mode 100644
index 0000000..9c59aa3
--- /dev/null
+++ b/src/libgnomecanvas/gnome-canvas-bpath.c
@@ -0,0 +1,175 @@
+/* Bpath item type for GnomeCanvas widget
+ *
+ * GnomeCanvas is basically a port of the Tk toolkit's most excellent canvas widget. Tk is
+ * copyrighted by the Regents of the University of California, Sun Microsystems, and other parties.
+ *
+ * Copyright (C) 1998,1999 The Free Software Foundation
+ *
+ * Authors: Federico Mena <federico@nuclecu.unam.mx>
+ * Raph Levien <raph@acm.org>
+ * Lauris Kaplinski <lauris@ximian.com>
+ * Miguel de Icaza <miguel@kernel.org>
+ * Cody Russell <bratsche@gnome.org>
+ * Rusty Conover <rconover@bangtail.net>
+ */
+
+/* These includes are set up for standalone compile. If/when this codebase
+ is integrated into libgnomeui, the includes will need to change. */
+
+#include <math.h>
+#include <string.h>
+
+#include <gtk/gtkobject.h>
+#include "gnome-canvas.h"
+#include "gnome-canvas-util.h"
+
+#include "gnome-canvas-bpath.h"
+#include "gnome-canvas-shape.h"
+#include "gnome-canvas-shape-private.h"
+#include "gnome-canvas-path-def.h"
+
+enum {
+ PROP_0,
+ PROP_BPATH
+};
+
+static void gnome_canvas_bpath_class_init (GnomeCanvasBpathClass *class);
+static void gnome_canvas_bpath_init (GnomeCanvasBpath *bpath);
+static void gnome_canvas_bpath_destroy (GtkObject *object);
+static void gnome_canvas_bpath_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gnome_canvas_bpath_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+static void gnome_canvas_bpath_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags);
+
+
+static GnomeCanvasShapeClass *parent_class;
+
+GtkType
+gnome_canvas_bpath_get_type (void)
+{
+ static GType bpath_type;
+
+ if (!bpath_type) {
+ static const GTypeInfo object_info = {
+ sizeof (GnomeCanvasBpathClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gnome_canvas_bpath_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (GnomeCanvasBpath),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) gnome_canvas_bpath_init,
+ NULL /* value_table */
+ };
+
+ bpath_type = g_type_register_static (GNOME_TYPE_CANVAS_SHAPE, "GnomeCanvasBpath",
+ &object_info, 0);
+ }
+
+ return bpath_type;
+}
+
+static void
+gnome_canvas_bpath_class_init (GnomeCanvasBpathClass *class)
+{
+ GObjectClass *gobject_class;
+ GtkObjectClass *object_class;
+ GnomeCanvasItemClass *item_class;
+
+ gobject_class = (GObjectClass *) class;
+ object_class = (GtkObjectClass *) class;
+ item_class = (GnomeCanvasItemClass *) class;
+
+ parent_class = g_type_class_peek_parent (class);
+
+ /* when this gets checked into libgnomeui, change the
+ GTK_TYPE_POINTER to GTK_TYPE_GNOME_CANVAS_BPATH, and add an
+ entry to gnome-boxed.defs */
+
+ gobject_class->set_property = gnome_canvas_bpath_set_property;
+ gobject_class->get_property = gnome_canvas_bpath_get_property;
+
+ object_class->destroy = gnome_canvas_bpath_destroy;
+
+ g_object_class_install_property (gobject_class,
+ PROP_BPATH,
+ g_param_spec_boxed ("bpath", NULL, NULL,
+ GNOME_TYPE_CANVAS_PATH_DEF,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+
+ item_class->update = gnome_canvas_bpath_update;
+}
+
+static void
+gnome_canvas_bpath_init (GnomeCanvasBpath *bpath)
+{
+
+}
+
+static void
+gnome_canvas_bpath_destroy (GtkObject *object)
+{
+ if (GTK_OBJECT_CLASS (parent_class)->destroy)
+ (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+}
+
+static void
+gnome_canvas_bpath_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GnomeCanvasItem *item;
+ GnomeCanvasPathDef *gpp;
+
+ item = GNOME_CANVAS_ITEM (object);
+
+ switch (param_id) {
+ case PROP_BPATH:
+ gpp = (GnomeCanvasPathDef*) g_value_get_boxed (value);
+
+ gnome_canvas_shape_set_path_def (GNOME_CANVAS_SHAPE (object), gpp);
+
+ gnome_canvas_item_request_update (item);
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+static void
+gnome_canvas_bpath_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GnomeCanvasShape *shape;
+
+ shape = GNOME_CANVAS_SHAPE(object);
+
+ switch (param_id) {
+ case PROP_BPATH:
+ g_value_set_boxed (value, shape->priv->path);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+gnome_canvas_bpath_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
+{
+ if(GNOME_CANVAS_ITEM_CLASS(parent_class)->update) {
+ (* GNOME_CANVAS_ITEM_CLASS(parent_class)->update)(item, affine, clip_path, flags);
+ }
+}
diff --git a/src/libgnomecanvas/gnome-canvas-bpath.h b/src/libgnomecanvas/gnome-canvas-bpath.h
new file mode 100644
index 0000000..d7a9269
--- /dev/null
+++ b/src/libgnomecanvas/gnome-canvas-bpath.h
@@ -0,0 +1,61 @@
+/* Bpath item type for GnomeCanvas widget
+ *
+ * GnomeCanvas is basically a port of the Tk toolkit's most excellent canvas widget. Tk is
+ * copyrighted by the Regents of the University of California, Sun Microsystems, and other parties.
+ *
+ * Copyright (C) 1998,1999 The Free Software Foundation
+ *
+ * Authors: Federico Mena <federico@nuclecu.unam.mx>
+ * Raph Levien <raph@acm.org>
+ * Lauris Kaplinski <lauris@ximian.com>
+ * Rusty Conover <rconover@bangtail.net>
+ */
+
+#ifndef GNOME_CANVAS_BPATH_H
+#define GNOME_CANVAS_BPATH_H
+
+#include <libgnomecanvas/gnome-canvas.h>
+#include <libgnomecanvas/gnome-canvas-shape.h>
+#include <libgnomecanvas/gnome-canvas-path-def.h>
+
+G_BEGIN_DECLS
+
+
+/* Bpath item for the canvas.
+ *
+ * The following object arguments are available:
+ *
+ * name type read/write description
+ * ------------------------------------------------------------------------------------------
+ * bpath GnomeCanvasPathDef * RW Pointer to an GnomeCanvasPathDef structure.
+ * This can be created by a call to
+ * gp_path_new() in (gp-path.h).
+ */
+
+#define GNOME_TYPE_CANVAS_BPATH (gnome_canvas_bpath_get_type ())
+#define GNOME_CANVAS_BPATH(obj) (GTK_CHECK_CAST ((obj), GNOME_TYPE_CANVAS_BPATH, GnomeCanvasBpath))
+#define GNOME_CANVAS_BPATH_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GNOME_TYPE_CANVAS_BPATH, GnomeCanvasBpathClass))
+#define GNOME_IS_CANVAS_BPATH(obj) (GTK_CHECK_TYPE ((obj), GNOME_TYPE_CANVAS_BPATH))
+#define GNOME_IS_CANVAS_BPATH_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_CANVAS_BPATH))
+
+
+typedef struct _GnomeCanvasBpath GnomeCanvasBpath;
+typedef struct _GnomeCanvasBpathPriv GnomeCanvasBpathPriv;
+typedef struct _GnomeCanvasBpathClass GnomeCanvasBpathClass;
+
+struct _GnomeCanvasBpath {
+ GnomeCanvasShape item;
+
+};
+
+struct _GnomeCanvasBpathClass {
+ GnomeCanvasShapeClass parent_class;
+};
+
+
+/* Standard Gtk function */
+GType gnome_canvas_bpath_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif
diff --git a/src/libgnomecanvas/gnome-canvas-clipgroup.c b/src/libgnomecanvas/gnome-canvas-clipgroup.c
new file mode 100644
index 0000000..ce77f49
--- /dev/null
+++ b/src/libgnomecanvas/gnome-canvas-clipgroup.c
@@ -0,0 +1,451 @@
+#define GNOME_CANVAS_CLIPGROUP_C
+
+/* Clipping group for GnomeCanvas
+ *
+ * GnomeCanvas is basically a port of the Tk toolkit's most excellent canvas widget. Tk is
+ * copyrighted by the Regents of the University of California, Sun Microsystems, and other parties.
+ *
+ * Copyright (C) 1998,1999 The Free Software Foundation
+ *
+ * Author:
+ * Lauris Kaplinski <lauris@ximian.com>
+ */
+
+/* These includes are set up for standalone compile. If/when this codebase
+ is integrated into libgnomeui, the includes will need to change. */
+
+#include <math.h>
+#include <string.h>
+
+#include <gtk/gtkobject.h>
+#include <gtk/gtkwidget.h>
+
+#include <libart_lgpl/art_misc.h>
+#include <libart_lgpl/art_rect.h>
+#include <libart_lgpl/art_vpath.h>
+#include <libart_lgpl/art_bpath.h>
+#include <libart_lgpl/art_vpath.h>
+#include <libart_lgpl/art_vpath_bpath.h>
+#include <libart_lgpl/art_svp.h>
+#include <libart_lgpl/art_svp_vpath.h>
+#include <libart_lgpl/art_rect_svp.h>
+#include <libart_lgpl/art_gray_svp.h>
+#include <libart_lgpl/art_svp_intersect.h>
+#include <libart_lgpl/art_svp_ops.h>
+
+#include "gnome-canvas.h"
+#include "gnome-canvas-util.h"
+#include "gnome-canvas-clipgroup.h"
+
+enum {
+ PROP_0,
+ PROP_PATH,
+ PROP_WIND
+};
+
+static void gnome_canvas_clipgroup_class_init (GnomeCanvasClipgroupClass *klass);
+static void gnome_canvas_clipgroup_init (GnomeCanvasClipgroup *clipgroup);
+static void gnome_canvas_clipgroup_destroy (GtkObject *object);
+static void gnome_canvas_clipgroup_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gnome_canvas_clipgroup_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void gnome_canvas_clipgroup_update (GnomeCanvasItem *item,
+ double *affine,
+ ArtSVP *clip_path,
+ int flags);
+
+/*
+ * Generic clipping stuff
+ *
+ * This is somewhat slow and memory-hungry - we add extra
+ * composition, extra SVP render and allocate 65536
+ * bytes for each clip level. It could be done more
+ * efficently per-object basis - but to make clipping
+ * universal, there is no alternative to double
+ * buffering (although it should be done into RGBA
+ * buffer by other method than ::render to make global
+ * opacity possible).
+ * Using art-render could possibly optimize that a bit,
+ * although I am not sure.
+ */
+
+#define GCG_BUF_WIDTH 128
+#define GCG_BUF_HEIGHT 128
+#define GCG_BUF_PIXELS (GCG_BUF_WIDTH * GCG_BUF_HEIGHT)
+#define GCG_BUF_SIZE (GCG_BUF_WIDTH * GCG_BUF_HEIGHT * 3)
+
+#define noSHOW_SHADOW
+
+static guchar *gcg_buf_new (void);
+static void gcg_buf_free (guchar *buf);
+static guchar *gcg_mask_new (void);
+static void gcg_mask_free (guchar *mask);
+
+static void gnome_canvas_clipgroup_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf);
+
+static GnomeCanvasGroupClass *parent_class;
+
+GType
+gnome_canvas_clipgroup_get_type (void)
+{
+ static GType clipgroup_type;
+
+ if (!clipgroup_type) {
+ static const GTypeInfo object_info = {
+ sizeof (GnomeCanvasClipgroupClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gnome_canvas_clipgroup_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (GnomeCanvasClipgroup),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) gnome_canvas_clipgroup_init,
+ NULL /* value_table */
+ };
+
+ clipgroup_type = g_type_register_static (GNOME_TYPE_CANVAS_GROUP, "GnomeCanvasClipgroup",
+ &object_info, 0);
+ }
+
+ return clipgroup_type;
+}
+
+static void
+gnome_canvas_clipgroup_class_init (GnomeCanvasClipgroupClass *klass)
+{
+ GObjectClass *gobject_class;
+ GtkObjectClass *object_class;
+ GnomeCanvasItemClass *item_class;
+
+ gobject_class = (GObjectClass *) klass;
+ object_class = (GtkObjectClass *) klass;
+ item_class = (GnomeCanvasItemClass *) klass;
+ parent_class = g_type_class_ref (GNOME_TYPE_CANVAS_GROUP);
+
+ object_class->destroy = gnome_canvas_clipgroup_destroy;
+ gobject_class->set_property = gnome_canvas_clipgroup_set_property;
+ gobject_class->get_property = gnome_canvas_clipgroup_get_property;
+ item_class->update = gnome_canvas_clipgroup_update;
+ item_class->render = gnome_canvas_clipgroup_render;
+
+ g_object_class_install_property (gobject_class,
+ PROP_PATH,
+ g_param_spec_pointer ("path", NULL, NULL,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property (gobject_class,
+ PROP_WIND,
+ g_param_spec_uint ("wind", NULL, NULL,
+ 0, G_MAXUINT, 0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+}
+
+static void
+gnome_canvas_clipgroup_init (GnomeCanvasClipgroup *clipgroup)
+{
+ clipgroup->path = NULL;
+ clipgroup->wind = ART_WIND_RULE_NONZERO; /* default winding rule */
+ clipgroup->svp = NULL;
+}
+
+static void
+gnome_canvas_clipgroup_destroy (GtkObject *object)
+{
+ GnomeCanvasClipgroup *clipgroup;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GNOME_IS_CANVAS_CLIPGROUP (object));
+
+ clipgroup = GNOME_CANVAS_CLIPGROUP (object);
+
+ if (clipgroup->path) {
+ gnome_canvas_path_def_unref (clipgroup->path);
+ clipgroup->path = NULL;
+ }
+
+ if (clipgroup->svp) {
+ art_svp_free (clipgroup->svp);
+ clipgroup->svp = NULL;
+ }
+
+ if (GTK_OBJECT_CLASS (parent_class)->destroy)
+ (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+}
+
+
+static void
+gnome_canvas_clipgroup_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GnomeCanvasItem *item;
+ GnomeCanvasClipgroup *cgroup;
+ GnomeCanvasPathDef *gpp;
+
+ item = GNOME_CANVAS_ITEM (object);
+ cgroup = GNOME_CANVAS_CLIPGROUP (object);
+
+ switch (param_id) {
+ case PROP_PATH:
+ gpp = g_value_get_pointer (value);
+
+ if (cgroup->path) {
+ gnome_canvas_path_def_unref (cgroup->path);
+ cgroup->path = NULL;
+ }
+ if (gpp != NULL) {
+ cgroup->path = gnome_canvas_path_def_closed_parts (gpp);
+ }
+
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_WIND:
+ cgroup->wind = g_value_get_uint (value);
+ gnome_canvas_item_request_update (item);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void
+gnome_canvas_clipgroup_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GnomeCanvasClipgroup * cgroup;
+
+ cgroup = GNOME_CANVAS_CLIPGROUP (object);
+
+ switch (param_id) {
+ case PROP_PATH:
+ g_value_set_pointer (value, cgroup->path);
+ break;
+
+ case PROP_WIND:
+ g_value_set_uint (value, cgroup->wind);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+gnome_canvas_clipgroup_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
+{
+ GnomeCanvasClipgroup *clipgroup;
+ ArtSvpWriter *swr;
+ ArtBpath *bp;
+ ArtBpath *bpath;
+ ArtVpath *vpath;
+ ArtSVP *svp, *svp1, *svp2;
+
+ clipgroup = GNOME_CANVAS_CLIPGROUP (item);
+
+ if (clipgroup->svp) {
+ art_svp_free (clipgroup->svp);
+ clipgroup->svp = NULL;
+ }
+
+ if (clipgroup->path) {
+ bp = gnome_canvas_path_def_bpath (clipgroup->path);
+ bpath = art_bpath_affine_transform (bp, affine);
+
+ vpath = art_bez_path_to_vec (bpath, 0.25);
+ art_free (bpath);
+
+ svp1 = art_svp_from_vpath (vpath);
+ art_free (vpath);
+
+ swr = art_svp_writer_rewind_new (clipgroup->wind);
+ art_svp_intersector (svp1, swr);
+
+ svp2 = art_svp_writer_rewind_reap (swr);
+ art_svp_free (svp1);
+
+ if (clip_path != NULL) {
+ svp = art_svp_intersect (svp2, clip_path);
+ art_svp_free (svp2);
+ } else {
+ svp = svp2;
+ }
+
+ clipgroup->svp = svp;
+ }
+
+ if (GNOME_CANVAS_ITEM_CLASS (parent_class)->update)
+ (GNOME_CANVAS_ITEM_CLASS (parent_class)->update) (item, affine, NULL, flags);
+
+ if (clipgroup->svp) {
+ ArtDRect cbox;
+ art_drect_svp (&cbox, clipgroup->svp);
+ item->x1 = MAX (item->x1, cbox.x0 - 1.0);
+ item->y1 = MAX (item->y1, cbox.y0 - 1.0);
+ item->x2 = MIN (item->x2, cbox.x1 + 1.0);
+ item->y2 = MIN (item->y2, cbox.y1 + 1.0);
+ }
+}
+
+/* non-premultiplied composition into RGB */
+
+#define COMPOSEN11(fc,fa,bc) (((255 - (guint) (fa)) * (guint) (bc) + (guint) (fc) * (guint) (fa) + 127) / 255)
+
+static void
+gnome_canvas_clipgroup_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf)
+{
+ GnomeCanvasClipgroup *cg;
+ GnomeCanvasBuf lbuf;
+ guchar *mask;
+
+ cg = GNOME_CANVAS_CLIPGROUP (item);
+
+ if (cg->svp) {
+ gint bw, bh, sw, sh;
+ gint x, y;
+
+ /* fixme: We could optimize background handling (lauris) */
+
+ if (buf->is_bg) {
+ gnome_canvas_buf_ensure_buf (buf);
+ buf->is_bg = FALSE;
+ buf->is_buf = TRUE;
+ }
+
+ bw = buf->rect.x1 - buf->rect.x0;
+ bh = buf->rect.y1 - buf->rect.y0;
+ if ((bw < 1) || (bh < 1)) return;
+
+ if (bw * bh <= GCG_BUF_PIXELS) {
+ /* We can go with single buffer */
+ sw = bw;
+ sh = bh;
+ } else if (bw <= (GCG_BUF_PIXELS >> 3)) {
+ /* Go with row buffer */
+ sw = bw;
+ sh = GCG_BUF_PIXELS / bw;
+ } else if (bh <= (GCG_BUF_PIXELS >> 3)) {
+ /* Go with column buffer */
+ sw = GCG_BUF_PIXELS / bh;
+ sh = bh;
+ } else {
+ /* Tile buffer */
+ sw = GCG_BUF_WIDTH;
+ sh = GCG_BUF_HEIGHT;
+ }
+
+ /* Set up local buffer */
+ lbuf.buf = gcg_buf_new ();
+ lbuf.bg_color = buf->bg_color;
+ lbuf.is_bg = FALSE;
+ lbuf.is_buf = TRUE;
+ /* Allocate mask */
+ mask = gcg_mask_new ();
+
+ for (y = buf->rect.y0; y < buf->rect.y1; y += sh) {
+ for (x = buf->rect.x0; x < buf->rect.x1; x += sw) {
+ gint r, xx, yy;
+ /* Set up local buffer */
+ lbuf.rect.x0 = x;
+ lbuf.rect.y0 = y;
+ lbuf.rect.x1 = MIN (x + sw, buf->rect.x1);
+ lbuf.rect.y1 = MIN (y + sh, buf->rect.y1);
+ lbuf.buf_rowstride = 3 * (lbuf.rect.x1 - lbuf.rect.x0);
+ /* Copy background */
+ for (r = lbuf.rect.y0; r < lbuf.rect.y1; r++) {
+ memcpy (lbuf.buf + (r - lbuf.rect.y0) * lbuf.buf_rowstride,
+ buf->buf + (r - buf->rect.y0) * buf->buf_rowstride + (x - buf->rect.x0) * 3,
+ (lbuf.rect.x1 - lbuf.rect.x0) * 3);
+ }
+ /* Invoke render method */
+ if (((GnomeCanvasItemClass *) parent_class)->render)
+ ((GnomeCanvasItemClass *) parent_class)->render (item, &lbuf);
+ /* Render mask */
+ art_gray_svp_aa (cg->svp, lbuf.rect.x0, lbuf.rect.y0, lbuf.rect.x1, lbuf.rect.y1,
+ mask, lbuf.rect.x1 - lbuf.rect.x0);
+ /* Combine */
+ for (yy = lbuf.rect.y0; yy < lbuf.rect.y1; yy++) {
+ guchar *s, *m, *d;
+ s = lbuf.buf + (yy - lbuf.rect.y0) * lbuf.buf_rowstride;
+ m = mask + (yy - lbuf.rect.y0) * (lbuf.rect.x1 - lbuf.rect.x0);
+ d = buf->buf + (yy - buf->rect.y0) * buf->buf_rowstride + (x - buf->rect.x0) * 3;
+ for (xx = lbuf.rect.x0; xx < lbuf.rect.x1; xx++) {
+#ifndef SHOW_SHADOW
+ d[0] = COMPOSEN11 (s[0], m[0], d[0]);
+ d[1] = COMPOSEN11 (s[1], m[0], d[1]);
+ d[2] = COMPOSEN11 (s[2], m[0], d[2]);
+#else
+ d[0] = COMPOSEN11 (s[0], m[0] | 0x7f, d[0]);
+ d[1] = COMPOSEN11 (s[1], m[0] | 0x7f, d[1]);
+ d[2] = COMPOSEN11 (s[2], m[0] | 0x7f, d[2]);
+#endif
+ s += 3;
+ m += 1;
+ d += 3;
+ }
+ }
+ }
+ }
+ /* Free buffers */
+ gcg_mask_free (mask);
+ gcg_buf_free (lbuf.buf);
+ } else {
+ if (((GnomeCanvasItemClass *) parent_class)->render)
+ ((GnomeCanvasItemClass *) parent_class)->render (item, buf);
+ }
+}
+
+static GSList *gcg_buffers = NULL;
+static GSList *gcg_masks = NULL;
+
+static guchar *
+gcg_buf_new (void)
+{
+ guchar *buf;
+
+ if (!gcg_buffers) {
+ buf = g_new (guchar, GCG_BUF_SIZE);
+ } else {
+ buf = (guchar *) gcg_buffers->data;
+ gcg_buffers = g_slist_remove (gcg_buffers, buf);
+ }
+
+ return buf;
+}
+
+static void
+gcg_buf_free (guchar *buf)
+{
+ gcg_buffers = g_slist_prepend (gcg_buffers, buf);
+}
+
+static guchar *
+gcg_mask_new (void)
+{
+ guchar *mask;
+
+ if (!gcg_masks) {
+ mask = g_new (guchar, GCG_BUF_PIXELS);
+ } else {
+ mask = (guchar *) gcg_masks->data;
+ gcg_masks = g_slist_remove (gcg_masks, mask);
+ }
+
+ return mask;
+}
+
+static void
+gcg_mask_free (guchar *mask)
+{
+ gcg_masks = g_slist_prepend (gcg_masks, mask);
+}
diff --git a/src/libgnomecanvas/gnome-canvas-clipgroup.h b/src/libgnomecanvas/gnome-canvas-clipgroup.h
new file mode 100644
index 0000000..269ad3f
--- /dev/null
+++ b/src/libgnomecanvas/gnome-canvas-clipgroup.h
@@ -0,0 +1,58 @@
+#ifndef GNOME_CANVAS_CLIPGROUP_H
+#define GNOME_CANVAS_CLIPGROUP_H
+
+/* Clipping group implementation for GnomeCanvas
+ *
+ * GnomeCanvas is basically a port of the Tk toolkit's most excellent canvas widget. Tk is
+ * copyrighted by the Regents of the University of California, Sun Microsystems, and other parties.
+ *
+ * TODO: Implement this in libgnomeui, possibly merge with real group
+ *
+ * Copyright (C) 1998,1999 The Free Software Foundation
+ *
+ * Author:
+ * Lauris Kaplinski <lauris@ximian.com>
+ */
+
+#include <libgnomecanvas/gnome-canvas.h>
+#include <libgnomecanvas/gnome-canvas-util.h>
+
+#include <libart_lgpl/art_bpath.h>
+#include <libart_lgpl/art_svp_wind.h>
+#include <libart_lgpl/art_vpath_dash.h>
+#include <libgnomecanvas/gnome-canvas-path-def.h>
+
+G_BEGIN_DECLS
+
+
+#define GNOME_TYPE_CANVAS_CLIPGROUP (gnome_canvas_clipgroup_get_type ())
+#define GNOME_CANVAS_CLIPGROUP(obj) (GTK_CHECK_CAST ((obj), GNOME_TYPE_CANVAS_CLIPGROUP, GnomeCanvasClipgroup))
+#define GNOME_CANVAS_CLIPGROUP_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GNOME_TYPE_CANVAS_CLIPGROUP, GnomeCanvasClipgroupClass))
+#define GNOME_IS_CANVAS_CLIPGROUP(obj) (GTK_CHECK_TYPE ((obj), GNOME_TYPE_CANVAS_CLIPGROUP))
+#define GNOME_IS_CANVAS_CLIPGROUP_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_CANVAS_CLIPGROUP))
+
+
+typedef struct _GnomeCanvasClipgroup GnomeCanvasClipgroup;
+typedef struct _GnomeCanvasClipgroupClass GnomeCanvasClipgroupClass;
+
+struct _GnomeCanvasClipgroup {
+ GnomeCanvasGroup group;
+
+ GnomeCanvasPathDef * path;
+ ArtWindRule wind;
+
+ ArtSVP * svp;
+};
+
+struct _GnomeCanvasClipgroupClass {
+ GnomeCanvasGroupClass parent_class;
+};
+
+
+/* Standard Gtk function */
+GType gnome_canvas_clipgroup_get_type (void) G_GNUC_CONST;
+
+
+G_END_DECLS
+
+#endif
diff --git a/src/libgnomecanvas/gnome-canvas-i18n.h b/src/libgnomecanvas/gnome-canvas-i18n.h
new file mode 100644
index 0000000..a768438
--- /dev/null
+++ b/src/libgnomecanvas/gnome-canvas-i18n.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ @NOTATION@
+ */
+
+/*
+ * Handles all of the internationalization configuration options.
+ * Author: Tom Tromey <tromey@creche.cygnus.com>
+ */
+
+#ifndef __LIBGNOME_CANVAS_I18N_H__
+#define __LIBGNOME_CANVAS_I18N_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#if !defined(__LIBGNOME_CANVAS_I18NP_H__)
+
+#ifdef ENABLE_NLS
+# include <libintl.h>
+# ifdef GNOME_EXPLICIT_TRANSLATION_DOMAIN
+# undef _
+# define _(String) dgettext (GNOME_EXPLICIT_TRANSLATION_DOMAIN, String)
+# else
+# define _(String) gettext (String)
+# endif
+# ifdef gettext_noop
+# define N_(String) gettext_noop (String)
+# else
+# define N_(String) (String)
+# endif
+#else
+/* Stubs that do something close enough. */
+# define textdomain(String) (String)
+# define gettext(String) (String)
+# define dgettext(Domain,Message) (Message)
+# define dcgettext(Domain,Message,Type) (Message)
+# define bindtextdomain(Domain,Directory) (Domain)
+# define _(String) (String)
+# define N_(String) (String)
+#endif
+
+#endif
+
+G_END_DECLS
+
+#endif /* __LIBGNOME_CANVAS_I18N_H__ */
diff --git a/src/libgnomecanvas/gnome-canvas-line.c b/src/libgnomecanvas/gnome-canvas-line.c
new file mode 100644
index 0000000..8546c44
--- /dev/null
+++ b/src/libgnomecanvas/gnome-canvas-line.c
@@ -0,0 +1,1422 @@
+/*
+ * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ @NOTATION@
+ */
+
+/* Line/curve item type for GnomeCanvas widget
+ *
+ * GnomeCanvas is basically a port of the Tk toolkit's most excellent canvas widget. Tk is
+ * copyrighted by the Regents of the University of California, Sun Microsystems, and other parties.
+ *
+ *
+ * Author: Federico Mena <federico@nuclecu.unam.mx>
+ */
+
+#include <config.h>
+#include <math.h>
+#include <string.h>
+#include "libart_lgpl/art_vpath.h"
+#include "libart_lgpl/art_svp.h"
+#include "libart_lgpl/art_svp_vpath.h"
+#include "libart_lgpl/art_svp_vpath_stroke.h"
+#include "libgnomecanvas.h"
+
+#define noVERBOSE
+
+#define DEFAULT_SPLINE_STEPS 12 /* this is what Tk uses */
+#define NUM_ARROW_POINTS 6 /* number of points in an arrowhead */
+#define NUM_STATIC_POINTS 256 /* number of static points to use to avoid allocating arrays */
+
+
+#define GROW_BOUNDS(bx1, by1, bx2, by2, x, y) { \
+ if (x < bx1) \
+ bx1 = x; \
+ \
+ if (x > bx2) \
+ bx2 = x; \
+ \
+ if (y < by1) \
+ by1 = y; \
+ \
+ if (y > by2) \
+ by2 = y; \
+}
+
+
+enum {
+ PROP_0,
+ PROP_POINTS,
+ PROP_FILL_COLOR,
+ PROP_FILL_COLOR_GDK,
+ PROP_FILL_COLOR_RGBA,
+ PROP_FILL_STIPPLE,
+ PROP_WIDTH_PIXELS,
+ PROP_WIDTH_UNITS,
+ PROP_CAP_STYLE,
+ PROP_JOIN_STYLE,
+ PROP_LINE_STYLE,
+ PROP_FIRST_ARROWHEAD,
+ PROP_LAST_ARROWHEAD,
+ PROP_SMOOTH,
+ PROP_SPLINE_STEPS,
+ PROP_ARROW_SHAPE_A,
+ PROP_ARROW_SHAPE_B,
+ PROP_ARROW_SHAPE_C
+};
+
+
+static void gnome_canvas_line_class_init (GnomeCanvasLineClass *class);
+static void gnome_canvas_line_init (GnomeCanvasLine *line);
+static void gnome_canvas_line_destroy (GtkObject *object);
+static void gnome_canvas_line_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gnome_canvas_line_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+static void gnome_canvas_line_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags);
+static void gnome_canvas_line_realize (GnomeCanvasItem *item);
+static void gnome_canvas_line_unrealize (GnomeCanvasItem *item);
+static void gnome_canvas_line_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
+ int x, int y, int width, int height);
+static double gnome_canvas_line_point (GnomeCanvasItem *item, double x, double y,
+ int cx, int cy, GnomeCanvasItem **actual_item);
+static void gnome_canvas_line_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2);
+static void gnome_canvas_line_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf);
+
+
+static GnomeCanvasItemClass *parent_class;
+
+
+GType
+gnome_canvas_line_get_type (void)
+{
+ static GType line_type;
+
+ if (!line_type) {
+ static const GTypeInfo object_info = {
+ sizeof (GnomeCanvasLineClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gnome_canvas_line_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (GnomeCanvasLine),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) gnome_canvas_line_init,
+ NULL /* value_table */
+ };
+
+ line_type = g_type_register_static (GNOME_TYPE_CANVAS_ITEM, "GnomeCanvasLine",
+ &object_info, 0);
+ }
+
+ return line_type;
+}
+
+static void
+gnome_canvas_line_class_init (GnomeCanvasLineClass *class)
+{
+ GObjectClass *gobject_class;
+ GtkObjectClass *object_class;
+ GnomeCanvasItemClass *item_class;
+
+ gobject_class = (GObjectClass *) class;
+ object_class = (GtkObjectClass *) class;
+ item_class = (GnomeCanvasItemClass *) class;
+
+ parent_class = g_type_class_peek_parent (class);
+
+ gobject_class->set_property = gnome_canvas_line_set_property;
+ gobject_class->get_property = gnome_canvas_line_get_property;
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_POINTS,
+ g_param_spec_boxed ("points", NULL, NULL,
+ GNOME_TYPE_CANVAS_POINTS,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_FILL_COLOR,
+ g_param_spec_string ("fill_color", NULL, NULL,
+ NULL,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_FILL_COLOR_GDK,
+ g_param_spec_boxed ("fill_color_gdk", NULL, NULL,
+ GDK_TYPE_COLOR,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_FILL_COLOR_RGBA,
+ g_param_spec_uint ("fill_color_rgba", NULL, NULL,
+ 0, G_MAXUINT, 0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_FILL_STIPPLE,
+ g_param_spec_object ("fill_stipple", NULL, NULL,
+ GDK_TYPE_DRAWABLE,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_WIDTH_PIXELS,
+ g_param_spec_uint ("width_pixels", NULL, NULL,
+ 0, G_MAXUINT, 0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_WIDTH_UNITS,
+ g_param_spec_double ("width_units", NULL, NULL,
+ 0.0, G_MAXDOUBLE, 0.0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_CAP_STYLE,
+ g_param_spec_enum ("cap_style", NULL, NULL,
+ GDK_TYPE_CAP_STYLE,
+ GDK_CAP_BUTT,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_JOIN_STYLE,
+ g_param_spec_enum ("join_style", NULL, NULL,
+ GDK_TYPE_JOIN_STYLE,
+ GDK_JOIN_MITER,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_LINE_STYLE,
+ g_param_spec_enum ("line_style", NULL, NULL,
+ GDK_TYPE_LINE_STYLE,
+ GDK_LINE_SOLID,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_FIRST_ARROWHEAD,
+ g_param_spec_boolean ("first_arrowhead", NULL, NULL,
+ FALSE,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_LAST_ARROWHEAD,
+ g_param_spec_boolean ("last_arrowhead", NULL, NULL,
+ FALSE,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_SMOOTH,
+ g_param_spec_boolean ("smooth", NULL, NULL,
+ FALSE,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_SPLINE_STEPS,
+ g_param_spec_uint ("spline_steps", NULL, NULL,
+ 0, G_MAXUINT, DEFAULT_SPLINE_STEPS,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_ARROW_SHAPE_A,
+ g_param_spec_double ("arrow_shape_a", NULL, NULL,
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_ARROW_SHAPE_B,
+ g_param_spec_double ("arrow_shape_b", NULL, NULL,
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_ARROW_SHAPE_C,
+ g_param_spec_double ("arrow_shape_c", NULL, NULL,
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+
+ object_class->destroy = gnome_canvas_line_destroy;
+
+ item_class->update = gnome_canvas_line_update;
+ item_class->realize = gnome_canvas_line_realize;
+ item_class->unrealize = gnome_canvas_line_unrealize;
+ item_class->draw = gnome_canvas_line_draw;
+ item_class->point = gnome_canvas_line_point;
+ item_class->bounds = gnome_canvas_line_bounds;
+
+ item_class->render = gnome_canvas_line_render;
+}
+
+static void
+gnome_canvas_line_init (GnomeCanvasLine *line)
+{
+ line->width = 0.0;
+ line->cap = GDK_CAP_BUTT;
+ line->join = GDK_JOIN_MITER;
+ line->line_style = GDK_LINE_SOLID;
+ line->shape_a = 0.0;
+ line->shape_b = 0.0;
+ line->shape_c = 0.0;
+ line->spline_steps = DEFAULT_SPLINE_STEPS;
+}
+
+static void
+gnome_canvas_line_destroy (GtkObject *object)
+{
+ GnomeCanvasLine *line;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GNOME_IS_CANVAS_LINE (object));
+
+ line = GNOME_CANVAS_LINE (object);
+
+ /* remember, destroy can be run multiple times! */
+
+ if (line->coords)
+ g_free (line->coords);
+ line->coords = NULL;
+
+ if (line->first_coords)
+ g_free (line->first_coords);
+ line->first_coords = NULL;
+
+ if (line->last_coords)
+ g_free (line->last_coords);
+ line->last_coords = NULL;
+
+ if (line->stipple)
+ gdk_bitmap_unref (line->stipple);
+ line->stipple = NULL;
+
+ if (line->fill_svp)
+ art_svp_free (line->fill_svp);
+ line->fill_svp = NULL;
+
+ if (line->first_svp)
+ art_svp_free (line->first_svp);
+ line->first_svp = NULL;
+
+ if (line->last_svp)
+ art_svp_free (line->last_svp);
+ line->last_svp = NULL;
+
+ if (GTK_OBJECT_CLASS (parent_class)->destroy)
+ (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+}
+
+/* Computes the bounding box of the line, including its arrow points. Assumes that the number of
+ * points in the line is not zero.
+ */
+static void
+get_bounds (GnomeCanvasLine *line, double *bx1, double *by1, double *bx2, double *by2)
+{
+ double *coords;
+ double x1, y1, x2, y2;
+ double width;
+ int i;
+
+ if (!line->coords) {
+ *bx1 = *by1 = *bx2 = *by2 = 0.0;
+ return;
+ }
+
+ /* Find bounding box of line's points */
+
+ x1 = x2 = line->coords[0];
+ y1 = y2 = line->coords[1];
+
+ for (i = 1, coords = line->coords + 2; i < line->num_points; i++, coords += 2)
+ GROW_BOUNDS (x1, y1, x2, y2, coords[0], coords[1]);
+
+ /* Add possible over-estimate for wide lines */
+
+ if (line->width_pixels)
+ width = line->width / line->item.canvas->pixels_per_unit;
+ else
+ width = line->width;
+
+ x1 -= width;
+ y1 -= width;
+ x2 += width;
+ y2 += width;
+
+ /* For mitered lines, make a second pass through all the points. Compute the location of
+ * the two miter vertex points and add them to the bounding box.
+ */
+
+ if (line->join == GDK_JOIN_MITER)
+ for (i = line->num_points, coords = line->coords; i >= 3; i--, coords += 2) {
+ double mx1, my1, mx2, my2;
+
+ if (gnome_canvas_get_miter_points (coords[0], coords[1],
+ coords[2], coords[3],
+ coords[4], coords[5],
+ width,
+ &mx1, &my1, &mx2, &my2)) {
+ GROW_BOUNDS (x1, y1, x2, y2, mx1, my1);
+ GROW_BOUNDS (x1, y1, x2, y2, mx2, my2);
+ }
+ }
+
+ /* Add the arrow points, if any */
+
+ if (line->first_arrow && line->first_coords)
+ for (i = 0, coords = line->first_coords; i < NUM_ARROW_POINTS; i++, coords += 2)
+ GROW_BOUNDS (x1, y1, x2, y2, coords[0], coords[1]);
+
+ if (line->last_arrow && line->last_coords)
+ for (i = 0, coords = line->last_coords; i < NUM_ARROW_POINTS; i++, coords += 2)
+ GROW_BOUNDS (x1, y1, x2, y2, coords[0], coords[1]);
+
+ /* Done */
+
+ *bx1 = x1;
+ *by1 = y1;
+ *bx2 = x2;
+ *by2 = y2;
+}
+
+/* Computes the bounding box of the line, in canvas coordinates. Assumes that the number of points in the polygon is
+ * not zero. Affine is the i2c transformation.
+ */
+static void
+get_bounds_canvas (GnomeCanvasLine *line, double *bx1, double *by1, double *bx2, double *by2, double affine[6])
+{
+ /* It would be possible to tighten the bounds somewhat by transforming the individual points before
+ aggregating them into the bbox. But it hardly seems worth it. */
+ ArtDRect bbox_world;
+ ArtDRect bbox_canvas;
+
+ get_bounds (line, &bbox_world.x0, &bbox_world.y0, &bbox_world.x1, &bbox_world.y1);
+
+ art_drect_affine_transform (&bbox_canvas, &bbox_world, affine);
+ /* include 1 pixel of fudge */
+ *bx1 = bbox_canvas.x0 - 1;
+ *by1 = bbox_canvas.y0 - 1;
+ *bx2 = bbox_canvas.x1 + 1;
+ *by2 = bbox_canvas.y1 + 1;
+}
+
+/* Recalculates the arrow polygons for the line */
+static void
+reconfigure_arrows (GnomeCanvasLine *line)
+{
+ double *poly, *coords;
+ double dx, dy, length;
+ double sin_theta, cos_theta, tmp;
+ double frac_height; /* Line width as fraction of arrowhead width */
+ double backup; /* Distance to backup end points so the line ends in the middle of the arrowhead */
+ double vx, vy; /* Position of arrowhead vertex */
+ double shape_a, shape_b, shape_c;
+ double width;
+ int i;
+
+ if (line->num_points == 0)
+ return;
+
+ /* Set up things */
+
+ if (line->first_arrow) {
+ if (line->first_coords) {
+ line->coords[0] = line->first_coords[0];
+ line->coords[1] = line->first_coords[1];
+ } else
+ line->first_coords = g_new (double, 2 * NUM_ARROW_POINTS);
+ } else if (line->first_coords) {
+ line->coords[0] = line->first_coords[0];
+ line->coords[1] = line->first_coords[1];
+
+ g_free (line->first_coords);
+ line->first_coords = NULL;
+ }
+
+ i = 2 * (line->num_points - 1);
+
+ if (line->last_arrow) {
+ if (line->last_coords) {
+ line->coords[i] = line->last_coords[0];
+ line->coords[i + 1] = line->last_coords[1];
+ } else
+ line->last_coords = g_new (double, 2 * NUM_ARROW_POINTS);
+ } else if (line->last_coords) {
+ line->coords[i] = line->last_coords[0];
+ line->coords[i + 1] = line->last_coords[1];
+
+ g_free (line->last_coords);
+ line->last_coords = NULL;
+ }
+
+ if (!line->first_arrow && !line->last_arrow)
+ return;
+
+ if (line->width_pixels)
+ width = line->width / line->item.canvas->pixels_per_unit;
+ else
+ width = line->width;
+
+ /* Add fudge value for better-looking results */
+
+ shape_a = line->shape_a;
+ shape_b = line->shape_b;
+ shape_c = line->shape_c + width / 2.0;
+
+ if (line->width_pixels) {
+ shape_a /= line->item.canvas->pixels_per_unit;
+ shape_b /= line->item.canvas->pixels_per_unit;
+ shape_c /= line->item.canvas->pixels_per_unit;
+ }
+
+ shape_a += 0.001;
+ shape_b += 0.001;
+ shape_c += 0.001;
+
+ /* Compute the polygon for the first arrowhead and adjust the first point in the line so
+ * that the line does not stick out past the leading edge of the arrowhead.
+ */
+
+ frac_height = (line->width / 2.0) / shape_c;
+ backup = frac_height * shape_b + shape_a * (1.0 - frac_height) / 2.0;
+
+ if (line->first_arrow) {
+ poly = line->first_coords;
+ poly[0] = poly[10] = line->coords[0];
+ poly[1] = poly[11] = line->coords[1];
+
+ dx = poly[0] - line->coords[2];
+ dy = poly[1] - line->coords[3];
+ length = sqrt (dx * dx + dy * dy);
+ if (length < GNOME_CANVAS_EPSILON)
+ sin_theta = cos_theta = 0.0;
+ else {
+ sin_theta = dy / length;
+ cos_theta = dx / length;
+ }
+
+ vx = poly[0] - shape_a * cos_theta;
+ vy = poly[1] - shape_a * sin_theta;
+
+ tmp = shape_c * sin_theta;
+
+ poly[2] = poly[0] - shape_b * cos_theta + tmp;
+ poly[8] = poly[2] - 2.0 * tmp;
+
+ tmp = shape_c * cos_theta;
+
+ poly[3] = poly[1] - shape_b * sin_theta - tmp;
+ poly[9] = poly[3] + 2.0 * tmp;
+
+ poly[4] = poly[2] * frac_height + vx * (1.0 - frac_height);
+ poly[5] = poly[3] * frac_height + vy * (1.0 - frac_height);
+ poly[6] = poly[8] * frac_height + vx * (1.0 - frac_height);
+ poly[7] = poly[9] * frac_height + vy * (1.0 - frac_height);
+
+ /* Move the first point towards the second so that the corners at the end of the
+ * line are inside the arrowhead.
+ */
+
+ line->coords[0] = poly[0] - backup * cos_theta;
+ line->coords[1] = poly[1] - backup * sin_theta;
+ }
+
+ /* Same process for last arrowhead */
+
+ if (line->last_arrow) {
+ coords = line->coords + 2 * (line->num_points - 2);
+ poly = line->last_coords;
+ poly[0] = poly[10] = coords[2];
+ poly[1] = poly[11] = coords[3];
+
+ dx = poly[0] - coords[0];
+ dy = poly[1] - coords[1];
+ length = sqrt (dx * dx + dy * dy);
+ if (length < GNOME_CANVAS_EPSILON)
+ sin_theta = cos_theta = 0.0;
+ else {
+ sin_theta = dy / length;
+ cos_theta = dx / length;
+ }
+
+ vx = poly[0] - shape_a * cos_theta;
+ vy = poly[1] - shape_a * sin_theta;
+
+ tmp = shape_c * sin_theta;
+
+ poly[2] = poly[0] - shape_b * cos_theta + tmp;
+ poly[8] = poly[2] - 2.0 * tmp;
+
+ tmp = shape_c * cos_theta;
+
+ poly[3] = poly[1] - shape_b * sin_theta - tmp;
+ poly[9] = poly[3] + 2.0 * tmp;
+
+ poly[4] = poly[2] * frac_height + vx * (1.0 - frac_height);
+ poly[5] = poly[3] * frac_height + vy * (1.0 - frac_height);
+ poly[6] = poly[8] * frac_height + vx * (1.0 - frac_height);
+ poly[7] = poly[9] * frac_height + vy * (1.0 - frac_height);
+
+ coords[2] = poly[0] - backup * cos_theta;
+ coords[3] = poly[1] - backup * sin_theta;
+ }
+}
+
+/* Convenience function to set the line's GC's foreground color */
+static void
+set_line_gc_foreground (GnomeCanvasLine *line)
+{
+ GdkColor c;
+
+ if (!line->gc)
+ return;
+
+ c.pixel = line->fill_pixel;
+ gdk_gc_set_foreground (line->gc, &c);
+}
+
+/* Recalculate the line's width and set it in its GC */
+static void
+set_line_gc_width (GnomeCanvasLine *line)
+{
+ int width;
+
+ if (!line->gc)
+ return;
+
+ if (line->width_pixels)
+ width = (int) line->width;
+ else
+ width = (int) (line->width * line->item.canvas->pixels_per_unit + 0.5);
+
+ gdk_gc_set_line_attributes (line->gc,
+ width,
+ line->line_style,
+ (line->first_arrow || line->last_arrow) ? GDK_CAP_BUTT : line->cap,
+ line->join);
+}
+
+/* Sets the stipple pattern for the line */
+static void
+set_stipple (GnomeCanvasLine *line, GdkBitmap *stipple, int reconfigure)
+{
+ if (line->stipple && !reconfigure)
+ gdk_bitmap_unref (line->stipple);
+
+ line->stipple = stipple;
+ if (stipple && !reconfigure)
+ gdk_bitmap_ref (stipple);
+
+ if (line->gc) {
+ if (stipple) {
+ gdk_gc_set_stipple (line->gc, stipple);
+ gdk_gc_set_fill (line->gc, GDK_STIPPLED);
+ } else
+ gdk_gc_set_fill (line->gc, GDK_SOLID);
+ }
+}
+
+static void
+gnome_canvas_line_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GnomeCanvasItem *item;
+ GnomeCanvasLine *line;
+ GnomeCanvasPoints *points;
+ GdkColor color = { 0, 0, 0, 0, };
+ GdkColor *pcolor;
+ gboolean color_changed;
+ int have_pixel;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GNOME_IS_CANVAS_LINE (object));
+
+ item = GNOME_CANVAS_ITEM (object);
+ line = GNOME_CANVAS_LINE (object);
+
+ color_changed = FALSE;
+ have_pixel = FALSE;
+
+ switch (param_id) {
+ case PROP_POINTS:
+ points = g_value_get_boxed (value);
+
+ if (line->coords) {
+ g_free (line->coords);
+ line->coords = NULL;
+ }
+
+ if (!points)
+ line->num_points = 0;
+ else {
+ line->num_points = points->num_points;
+ line->coords = g_new (double, 2 * line->num_points);
+ memcpy (line->coords, points->coords, 2 * line->num_points * sizeof (double));
+ }
+
+ /* Drop the arrowhead polygons if they exist -- they will be regenerated */
+
+ if (line->first_coords) {
+ g_free (line->first_coords);
+ line->first_coords = NULL;
+ }
+
+ if (line->last_coords) {
+ g_free (line->last_coords);
+ line->last_coords = NULL;
+ }
+
+ /* Since the line's points have changed, we need to re-generate arrowheads in
+ * addition to recalculating the bounds.
+ */
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_FILL_COLOR:
+ if (g_value_get_string (value))
+ gdk_color_parse (g_value_get_string (value), &color);
+ line->fill_rgba = ((color.red & 0xff00) << 16 |
+ (color.green & 0xff00) << 8 |
+ (color.blue & 0xff00) |
+ 0xff);
+ color_changed = TRUE;
+ break;
+
+ case PROP_FILL_COLOR_GDK:
+ pcolor = g_value_get_boxed (value);
+ if (pcolor) {
+ GdkColormap *colormap;
+ color = *pcolor;
+
+ colormap = gtk_widget_get_colormap (GTK_WIDGET (item->canvas));
+ gdk_rgb_find_color (colormap, &color);
+
+ have_pixel = TRUE;
+ }
+
+ line->fill_rgba = ((color.red & 0xff00) << 16 |
+ (color.green & 0xff00) << 8 |
+ (color.blue & 0xff00) |
+ 0xff);
+ color_changed = TRUE;
+ break;
+
+ case PROP_FILL_COLOR_RGBA:
+ line->fill_rgba = g_value_get_uint (value);
+ color_changed = TRUE;
+ break;
+
+ case PROP_FILL_STIPPLE:
+ set_stipple (line, (GdkBitmap *) g_value_get_object (value), FALSE);
+ gnome_canvas_item_request_redraw_svp (item, line->fill_svp);
+ break;
+
+ case PROP_WIDTH_PIXELS:
+ line->width = g_value_get_uint (value);
+ line->width_pixels = TRUE;
+ set_line_gc_width (line);
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_WIDTH_UNITS:
+ line->width = fabs (g_value_get_double (value));
+ line->width_pixels = FALSE;
+ set_line_gc_width (line);
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_CAP_STYLE:
+ line->cap = g_value_get_enum (value);
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_JOIN_STYLE:
+ line->join = g_value_get_enum (value);
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_LINE_STYLE:
+ line->line_style = g_value_get_enum (value);
+ set_line_gc_width (line);
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_FIRST_ARROWHEAD:
+ line->first_arrow = g_value_get_boolean (value);
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_LAST_ARROWHEAD:
+ line->last_arrow = g_value_get_boolean (value);
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_SMOOTH:
+ /* FIXME */
+ break;
+
+ case PROP_SPLINE_STEPS:
+ /* FIXME */
+ break;
+
+ case PROP_ARROW_SHAPE_A:
+ line->shape_a = fabs (g_value_get_double (value));
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_ARROW_SHAPE_B:
+ line->shape_b = fabs (g_value_get_double (value));
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_ARROW_SHAPE_C:
+ line->shape_c = fabs (g_value_get_double (value));
+ gnome_canvas_item_request_update (item);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+
+ if (color_changed) {
+ if (have_pixel)
+ line->fill_pixel = color.pixel;
+ else
+ line->fill_pixel = gnome_canvas_get_color_pixel (item->canvas,
+ line->fill_rgba);
+
+ if (!item->canvas->aa)
+ set_line_gc_foreground (line);
+
+ gnome_canvas_item_request_redraw_svp (item, line->fill_svp);
+
+ if (line->first_svp)
+ gnome_canvas_item_request_redraw_svp (item, line->first_svp);
+
+ if (line->last_svp)
+ gnome_canvas_item_request_redraw_svp (item, line->last_svp);
+
+ }
+}
+
+/* Returns a copy of the line's points without the endpoint adjustments for
+ * arrowheads.
+ */
+static GnomeCanvasPoints *
+get_points (GnomeCanvasLine *line)
+{
+ GnomeCanvasPoints *points;
+ int start_ofs, end_ofs;
+
+ if (line->num_points == 0)
+ return NULL;
+
+ start_ofs = end_ofs = 0;
+
+ points = gnome_canvas_points_new (line->num_points);
+
+ /* Invariant: if first_coords or last_coords exist, then the line's
+ * endpoints have been adjusted.
+ */
+
+ if (line->first_coords) {
+ start_ofs = 1;
+
+ points->coords[0] = line->first_coords[0];
+ points->coords[1] = line->first_coords[1];
+ }
+
+ if (line->last_coords) {
+ end_ofs = 1;
+
+ points->coords[2 * (line->num_points - 1)] = line->last_coords[0];
+ points->coords[2 * (line->num_points - 1) + 1] = line->last_coords[1];
+ }
+
+ memcpy (points->coords + 2 * start_ofs,
+ line->coords + 2 * start_ofs,
+ 2 * (line->num_points - (start_ofs + end_ofs)) * sizeof (double));
+
+ return points;
+}
+
+static void
+gnome_canvas_line_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GnomeCanvasLine *line;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GNOME_IS_CANVAS_LINE (object));
+
+ line = GNOME_CANVAS_LINE (object);
+
+ switch (param_id) {
+ case PROP_POINTS:
+ g_value_set_boxed (value, get_points (line));
+ break;
+
+ case PROP_FILL_COLOR:
+ g_value_set_string_take_ownership (value,
+ g_strdup_printf ("#%02x%02x%02x",
+ line->fill_rgba >> 24,
+ (line->fill_rgba >> 16) & 0xff,
+ (line->fill_rgba >> 8) & 0xff));
+ break;
+
+ case PROP_FILL_COLOR_GDK: {
+ GnomeCanvas *canvas = GNOME_CANVAS_ITEM (line)->canvas;
+ GdkColormap *colormap = gtk_widget_get_colormap (GTK_WIDGET (canvas));
+ GdkColor color;
+
+ gdk_colormap_query_color (colormap, line->fill_pixel, &color);
+ g_value_set_boxed (value, &color);
+ break;
+ }
+
+ case PROP_FILL_COLOR_RGBA:
+ g_value_set_uint (value, line->fill_rgba);
+ break;
+
+ case PROP_FILL_STIPPLE:
+ g_value_set_object (value, line->stipple);
+ break;
+
+ case PROP_WIDTH_PIXELS:
+ g_value_set_uint (value, line->width);
+ break;
+
+ case PROP_WIDTH_UNITS:
+ g_value_set_double (value, line->width);
+ break;
+
+ case PROP_CAP_STYLE:
+ g_value_set_enum (value, line->cap);
+ break;
+
+ case PROP_JOIN_STYLE:
+ g_value_set_enum (value, line->join);
+ break;
+
+ case PROP_LINE_STYLE:
+ g_value_set_enum (value, line->line_style);
+ break;
+
+ case PROP_FIRST_ARROWHEAD:
+ g_value_set_boolean (value, line->first_arrow);
+ break;
+
+ case PROP_LAST_ARROWHEAD:
+ g_value_set_boolean (value, line->last_arrow);
+ break;
+
+ case PROP_SMOOTH:
+ g_value_set_boolean (value, line->smooth);
+ break;
+
+ case PROP_SPLINE_STEPS:
+ g_value_set_uint (value, line->spline_steps);
+ break;
+
+ case PROP_ARROW_SHAPE_A:
+ g_value_set_double (value, line->shape_a);
+ break;
+
+ case PROP_ARROW_SHAPE_B:
+ g_value_set_double (value, line->shape_b);
+ break;
+
+ case PROP_ARROW_SHAPE_C:
+ g_value_set_double (value, line->shape_c);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+gnome_canvas_line_render (GnomeCanvasItem *item,
+ GnomeCanvasBuf *buf)
+{
+ GnomeCanvasLine *line;
+
+ line = GNOME_CANVAS_LINE (item);
+
+ if (line->fill_svp != NULL)
+ gnome_canvas_render_svp (buf, line->fill_svp, line->fill_rgba);
+
+ if (line->first_svp != NULL)
+ gnome_canvas_render_svp (buf, line->first_svp, line->fill_rgba);
+
+ if (line->last_svp != NULL)
+ gnome_canvas_render_svp (buf, line->last_svp, line->fill_rgba);
+}
+
+
+static ArtSVP *
+svp_from_points (const double *item_coords, int num_points, const double affine[6])
+{
+ ArtVpath *vpath;
+ ArtSVP *svp;
+ double x, y;
+ int i;
+
+ vpath = art_new (ArtVpath, num_points + 2);
+
+ for (i = 0; i < num_points; i++) {
+ vpath[i].code = i == 0 ? ART_MOVETO : ART_LINETO;
+ x = item_coords[i * 2];
+ y = item_coords[i * 2 + 1];
+ vpath[i].x = x * affine[0] + y * affine[2] + affine[4];
+ vpath[i].y = x * affine[1] + y * affine[3] + affine[5];
+ }
+#if 0
+ vpath[i].code = ART_LINETO;
+ vpath[i].x = vpath[0].x;
+ vpath[i].y = vpath[0].y;
+ i++;
+#endif
+ vpath[i].code = ART_END;
+ vpath[i].x = 0;
+ vpath[i].y = 0;
+
+ svp = art_svp_from_vpath (vpath);
+
+ art_free (vpath);
+
+ return svp;
+}
+
+static void
+gnome_canvas_line_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
+{
+ GnomeCanvasLine *line;
+ int i;
+ ArtVpath *vpath;
+ ArtPoint pi, pc;
+ double width;
+ ArtSVP *svp;
+ double x1, y1, x2, y2;
+
+ line = GNOME_CANVAS_LINE (item);
+
+ if (parent_class->update)
+ (* parent_class->update) (item, affine, clip_path, flags);
+
+ reconfigure_arrows (line);
+
+ if (item->canvas->aa) {
+ gnome_canvas_item_reset_bounds (item);
+
+ vpath = art_new (ArtVpath, line->num_points + 2);
+
+ for (i = 0; i < line->num_points; i++) {
+ pi.x = line->coords[i * 2];
+ pi.y = line->coords[i * 2 + 1];
+ art_affine_point (&pc, &pi, affine);
+ vpath[i].code = i == 0 ? ART_MOVETO : ART_LINETO;
+ vpath[i].x = pc.x;
+ vpath[i].y = pc.y;
+ }
+ vpath[i].code = ART_END;
+ vpath[i].x = 0;
+ vpath[i].y = 0;
+
+ if (line->width_pixels)
+ width = line->width;
+ else
+ width = line->width * art_affine_expansion (affine);
+
+ if (width < 0.5)
+ width = 0.5;
+
+ svp = art_svp_vpath_stroke (vpath,
+ gnome_canvas_join_gdk_to_art (line->join),
+ gnome_canvas_cap_gdk_to_art (line->cap),
+ width,
+ 4,
+ 0.25);
+ art_free (vpath);
+
+ gnome_canvas_item_update_svp_clip (item, &line->fill_svp, svp, clip_path);
+
+ if (line->first_arrow && line->first_coords) {
+ svp = svp_from_points (line->first_coords, NUM_ARROW_POINTS, affine);
+ gnome_canvas_item_update_svp_clip (item,
+ &line->first_svp, svp, clip_path);
+ }
+
+
+ if (line->last_arrow && line->last_coords) {
+ svp = svp_from_points (line->last_coords, NUM_ARROW_POINTS, affine);
+ gnome_canvas_item_update_svp_clip (item,
+ &line->last_svp, svp, clip_path);
+ }
+
+
+ } else {
+ set_line_gc_foreground (line);
+ set_line_gc_width (line);
+ set_stipple (line, line->stipple, TRUE);
+
+ get_bounds_canvas (line, &x1, &y1, &x2, &y2, affine);
+ gnome_canvas_update_bbox (item, x1, y1, x2, y2);
+ }
+}
+
+static void
+gnome_canvas_line_realize (GnomeCanvasItem *item)
+{
+ GnomeCanvasLine *line;
+
+ line = GNOME_CANVAS_LINE (item);
+
+ if (parent_class->realize)
+ (* parent_class->realize) (item);
+
+ line->gc = gdk_gc_new (item->canvas->layout.bin_window);
+
+#if 0
+ (* GNOME_CANVAS_ITEM_CLASS (item->object.klass)->update) (item, NULL, NULL, 0);
+#endif
+}
+
+static void
+gnome_canvas_line_unrealize (GnomeCanvasItem *item)
+{
+ GnomeCanvasLine *line;
+
+ line = GNOME_CANVAS_LINE (item);
+
+ gdk_gc_unref (line->gc);
+ line->gc = NULL;
+
+ if (parent_class->unrealize)
+ (* parent_class->unrealize) (item);
+}
+
+static void
+item_to_canvas (GnomeCanvas *canvas, double *item_coords, GdkPoint *canvas_coords, int num_points,
+ int *num_drawn_points, double i2c[6], int x, int y)
+{
+ int i;
+ int old_cx, old_cy;
+ int cx, cy;
+ ArtPoint pi, pc;
+
+#ifdef VERBOSE
+ {
+ char str[128];
+ art_affine_to_string (str, i2c);
+ g_print ("line item_to_canvas %s\n", str);
+ }
+#endif
+
+ /* the first point is always drawn */
+
+ pi.x = item_coords[0];
+ pi.y = item_coords[1];
+ art_affine_point (&pc, &pi, i2c);
+ cx = floor (pc.x + 0.5);
+ cy = floor (pc.y + 0.5);
+ canvas_coords->x = cx - x;
+ canvas_coords->y = cy - y;
+ canvas_coords++;
+ old_cx = cx;
+ old_cy = cy;
+ *num_drawn_points = 1;
+
+ for (i = 1; i < num_points; i++) {
+ pi.x = item_coords[i * 2];
+ pi.y = item_coords[i * 2 + 1];
+ art_affine_point (&pc, &pi, i2c);
+ cx = floor (pc.x + 0.5);
+ cy = floor (pc.y + 0.5);
+ if (old_cx != cx || old_cy != cy) {
+ canvas_coords->x = cx - x;
+ canvas_coords->y = cy - y;
+ old_cx = cx;
+ old_cy = cy;
+ canvas_coords++;
+ (*num_drawn_points)++;
+ }
+ }
+}
+
+static void
+gnome_canvas_line_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
+ int x, int y, int width, int height)
+{
+ GnomeCanvasLine *line;
+ GdkPoint static_points[NUM_STATIC_POINTS];
+ GdkPoint *points;
+ int actual_num_points_drawn;
+ double i2c[6];
+
+ line = GNOME_CANVAS_LINE (item);
+
+ if (line->num_points == 0)
+ return;
+
+ /* Build array of canvas pixel coordinates */
+
+ if (line->num_points <= NUM_STATIC_POINTS)
+ points = static_points;
+ else
+ points = g_new (GdkPoint, line->num_points);
+
+
+ gnome_canvas_item_i2c_affine (item, i2c);
+
+ item_to_canvas (item->canvas, line->coords, points, line->num_points,
+ &actual_num_points_drawn, i2c, x, y);
+
+ if (line->stipple)
+ gnome_canvas_set_stipple_origin (item->canvas, line->gc);
+
+ gdk_draw_lines (drawable, line->gc, points, actual_num_points_drawn);
+
+ if (points != static_points)
+ g_free (points);
+
+ /* Draw arrowheads */
+
+ points = static_points;
+
+ if (line->first_arrow) {
+ item_to_canvas (item->canvas, line->first_coords, points, NUM_ARROW_POINTS,
+ &actual_num_points_drawn, i2c, x, y);
+ gdk_draw_polygon (drawable, line->gc, TRUE, points, actual_num_points_drawn );
+ }
+
+ if (line->last_arrow) {
+ item_to_canvas (item->canvas, line->last_coords, points, NUM_ARROW_POINTS,
+ &actual_num_points_drawn, i2c, x, y);
+ gdk_draw_polygon (drawable, line->gc, TRUE, points, actual_num_points_drawn );
+ }
+}
+
+static double
+gnome_canvas_line_point (GnomeCanvasItem *item, double x, double y,
+ int cx, int cy, GnomeCanvasItem **actual_item)
+{
+ GnomeCanvasLine *line;
+ double *line_points = NULL, *coords;
+ double static_points[2 * NUM_STATIC_POINTS];
+ double poly[10];
+ double best, dist;
+ double dx, dy;
+ double width;
+ int num_points = 0, i;
+ int changed_miter_to_bevel;
+
+#ifdef VERBOSE
+ g_print ("gnome_canvas_line_point x, y = (%g, %g); cx, cy = (%d, %d)\n", x, y, cx, cy);
+#endif
+
+ line = GNOME_CANVAS_LINE (item);
+
+ *actual_item = item;
+
+ best = 1.0e36;
+
+ /* Handle smoothed lines by generating an expanded set ot points */
+
+ if (line->smooth && (line->num_points > 2)) {
+ /* FIXME */
+ } else {
+ num_points = line->num_points;
+ line_points = line->coords;
+ }
+
+ /* Compute a polygon for each edge of the line and test the point against it. The effective
+ * width of the line is adjusted so that it will be at least one pixel thick (so that zero
+ * pixel-wide lines can be pickedup as well).
+ */
+
+ if (line->width_pixels)
+ width = line->width / item->canvas->pixels_per_unit;
+ else
+ width = line->width;
+
+ if (width < (1.0 / item->canvas->pixels_per_unit))
+ width = 1.0 / item->canvas->pixels_per_unit;
+
+ changed_miter_to_bevel = 0;
+
+ for (i = num_points, coords = line_points; i >= 2; i--, coords += 2) {
+ /* If rounding is done around the first point, then compute distance between the
+ * point and the first point.
+ */
+
+ if (((line->cap == GDK_CAP_ROUND) && (i == num_points))
+ || ((line->join == GDK_JOIN_ROUND) && (i != num_points))) {
+ dx = coords[0] - x;
+ dy = coords[1] - y;
+ dist = sqrt (dx * dx + dy * dy) - width / 2.0;
+ if (dist < GNOME_CANVAS_EPSILON) {
+ best = 0.0;
+ goto done;
+ } else if (dist < best)
+ best = dist;
+ }
+
+ /* Compute the polygonal shape corresponding to this edge, with two points for the
+ * first point of the edge and two points for the last point of the edge.
+ */
+
+ if (i == num_points)
+ gnome_canvas_get_butt_points (coords[2], coords[3], coords[0], coords[1],
+ width, (line->cap == GDK_CAP_PROJECTING),
+ poly, poly + 1, poly + 2, poly + 3);
+ else if ((line->join == GDK_JOIN_MITER) && !changed_miter_to_bevel) {
+ poly[0] = poly[6];
+ poly[1] = poly[7];
+ poly[2] = poly[4];
+ poly[3] = poly[5];
+ } else {
+ gnome_canvas_get_butt_points (coords[2], coords[3], coords[0], coords[1],
+ width, FALSE,
+ poly, poly + 1, poly + 2, poly + 3);
+
+ /* If this line uses beveled joints, then check the distance to a polygon
+ * comprising the last two points of the previous polygon and the first two
+ * from this polygon; this checks the wedges that fill the mitered point.
+ */
+
+ if ((line->join == GDK_JOIN_BEVEL) || changed_miter_to_bevel) {
+ poly[8] = poly[0];
+ poly[9] = poly[1];
+
+ dist = gnome_canvas_polygon_to_point (poly, 5, x, y);
+ if (dist < GNOME_CANVAS_EPSILON) {
+ best = 0.0;
+ goto done;
+ } else if (dist < best)
+ best = dist;
+
+ changed_miter_to_bevel = FALSE;
+ }
+ }
+
+ if (i == 2)
+ gnome_canvas_get_butt_points (coords[0], coords[1], coords[2], coords[3],
+ width, (line->cap == GDK_CAP_PROJECTING),
+ poly + 4, poly + 5, poly + 6, poly + 7);
+ else if (line->join == GDK_JOIN_MITER) {
+ if (!gnome_canvas_get_miter_points (coords[0], coords[1],
+ coords[2], coords[3],
+ coords[4], coords[5],
+ width,
+ poly + 4, poly + 5, poly + 6, poly + 7)) {
+ changed_miter_to_bevel = TRUE;
+ gnome_canvas_get_butt_points (coords[0], coords[1], coords[2], coords[3],
+ width, FALSE,
+ poly + 4, poly + 5, poly + 6, poly + 7);
+ }
+ } else
+ gnome_canvas_get_butt_points (coords[0], coords[1], coords[2], coords[3],
+ width, FALSE,
+ poly + 4, poly + 5, poly + 6, poly + 7);
+
+ poly[8] = poly[0];
+ poly[9] = poly[1];
+
+ dist = gnome_canvas_polygon_to_point (poly, 5, x, y);
+ if (dist < GNOME_CANVAS_EPSILON) {
+ best = 0.0;
+ goto done;
+ } else if (dist < best)
+ best = dist;
+ }
+
+ /* If caps are rounded, check the distance to the cap around the final end point of the line */
+
+ if (line->cap == GDK_CAP_ROUND) {
+ dx = coords[0] - x;
+ dy = coords[1] - y;
+ dist = sqrt (dx * dx + dy * dy) - width / 2.0;
+ if (dist < GNOME_CANVAS_EPSILON) {
+ best = 0.0;
+ goto done;
+ } else
+ best = dist;
+ }
+
+ /* sometimes the GnomeCanvasItem::update signal will not have
+ been processed between deleting the arrow points and a call
+ to this routine -- this can cause a segfault here */
+ if ((line->first_arrow && !line->first_coords) ||
+ (line->last_arrow && !line->last_coords))
+ reconfigure_arrows(line);
+
+ /* If there are arrowheads, check the distance to them */
+
+ if (line->first_arrow) {
+ dist = gnome_canvas_polygon_to_point (line->first_coords, NUM_ARROW_POINTS, x, y);
+ if (dist < GNOME_CANVAS_EPSILON) {
+ best = 0.0;
+ goto done;
+ } else
+ best = dist;
+ }
+
+ if (line->last_arrow) {
+ dist = gnome_canvas_polygon_to_point (line->last_coords, NUM_ARROW_POINTS, x, y);
+ if (dist < GNOME_CANVAS_EPSILON) {
+ best = 0.0;
+ goto done;
+ } else
+ best = dist;
+ }
+
+done:
+
+ if ((line_points != static_points) && (line_points != line->coords))
+ g_free (line_points);
+
+ return best;
+}
+
+static void
+gnome_canvas_line_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
+{
+ GnomeCanvasLine *line;
+
+ line = GNOME_CANVAS_LINE (item);
+
+ if (line->num_points == 0) {
+ *x1 = *y1 = *x2 = *y2 = 0.0;
+ return;
+ }
+
+ get_bounds (line, x1, y1, x2, y2);
+}
diff --git a/src/libgnomecanvas/gnome-canvas-line.h b/src/libgnomecanvas/gnome-canvas-line.h
new file mode 100644
index 0000000..29893ab
--- /dev/null
+++ b/src/libgnomecanvas/gnome-canvas-line.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ @NOTATION@
+ */
+
+/* Line/curve item type for GnomeCanvas widget
+ *
+ * GnomeCanvas is basically a port of the Tk toolkit's most excellent canvas widget. Tk is
+ * copyrighted by the Regents of the University of California, Sun Microsystems, and other parties.
+ *
+ *
+ * Author: Federico Mena <federico@nuclecu.unam.mx>
+ */
+
+#ifndef GNOME_CANVAS_LINE_H
+#define GNOME_CANVAS_LINE_H
+
+
+#include <libgnomecanvas/gnome-canvas.h>
+
+
+G_BEGIN_DECLS
+
+
+/* Line item for the canvas. This is a polyline with configurable width, cap/join styles, and arrowheads.
+ * If arrowheads are enabled, then three values are used to specify their shape:
+ *
+ * arrow_shape_a: Distance from tip of arrowhead to the center point.
+ * arrow_shape_b: Distance from tip of arrowhead to trailing point, measured along the shaft.
+ * arrow_shape_c: Distance of trailing point from outside edge of shaft.
+ *
+ * The following object arguments are available:
+ *
+ * name type read/write description
+ * ------------------------------------------------------------------------------------------
+ * points GnomeCanvasPoints* RW Pointer to a GnomeCanvasPoints structure.
+ * This can be created by a call to
+ * gnome_canvas_points_new() (in gnome-canvas-util.h).
+ * X coordinates are in the even indices of the
+ * points->coords array, Y coordinates are in
+ * the odd indices.
+ * fill_color string W X color specification for line
+ * fill_color_gdk GdkColor* RW Pointer to an allocated GdkColor
+ * fill_stipple GdkBitmap* RW Stipple pattern for the line
+ * width_pixels uint R Width of the line in pixels. The line width
+ * will not be scaled when the canvas zoom factor changes.
+ * width_units double R Width of the line in canvas units. The line width
+ * will be scaled when the canvas zoom factor changes.
+ * cap_style GdkCapStyle RW Cap ("endpoint") style for the line.
+ * join_style GdkJoinStyle RW Join ("vertex") style for the line.
+ * line_style GdkLineStyle RW Line dash style
+ * first_arrowhead boolean RW Specifies whether to draw an arrowhead on the
+ * first point of the line.
+ * last_arrowhead boolean RW Specifies whether to draw an arrowhead on the
+ * last point of the line.
+ * smooth boolean RW Specifies whether to smooth the line using
+ * parabolic splines.
+ * spline_steps uint RW Specifies the number of steps to use when rendering curves.
+ * arrow_shape_a double RW First arrow shape specifier.
+ * arrow_shape_b double RW Second arrow shape specifier.
+ * arrow_shape_c double RW Third arrow shape specifier.
+ */
+
+
+#define GNOME_TYPE_CANVAS_LINE (gnome_canvas_line_get_type ())
+#define GNOME_CANVAS_LINE(obj) (GTK_CHECK_CAST ((obj), GNOME_TYPE_CANVAS_LINE, GnomeCanvasLine))
+#define GNOME_CANVAS_LINE_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GNOME_TYPE_CANVAS_LINE, GnomeCanvasLineClass))
+#define GNOME_IS_CANVAS_LINE(obj) (GTK_CHECK_TYPE ((obj), GNOME_TYPE_CANVAS_LINE))
+#define GNOME_IS_CANVAS_LINE_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_CANVAS_LINE))
+#define GNOME_CANVAS_LINE_GET_CLASS(obj) (GTK_CHECK_GET_CLASS ((obj), GNOME_TYPE_CANVAS_LINE, GnomeCanvasLineClass))
+
+
+typedef struct _GnomeCanvasLine GnomeCanvasLine;
+typedef struct _GnomeCanvasLineClass GnomeCanvasLineClass;
+
+struct _GnomeCanvasLine {
+ GnomeCanvasItem item;
+
+ double *coords; /* Array of coordinates for the line's points. X coords are in the
+ * even indices, Y coords are in the odd indices. If the line has
+ * arrowheads then the first and last points have been adjusted to
+ * refer to the necks of the arrowheads rather than their tips. The
+ * actual endpoints are stored in the first_arrow and last_arrow
+ * arrays, if they exist.
+ */
+
+ double *first_coords; /* Array of points describing polygon for the first arrowhead */
+ double *last_coords; /* Array of points describing polygon for the last arrowhead */
+
+ GdkGC *gc; /* GC for drawing line */
+
+ GdkBitmap *stipple; /* Stipple pattern */
+
+ ArtSVP *fill_svp; /* The SVP for the outline shape */ /*AA*/
+ ArtSVP *first_svp; /* The SVP for the first arrow */ /*AA*/
+ ArtSVP *last_svp; /* The SVP for the last arrow */ /*AA*/
+
+ double width; /* Width of the line */
+
+ double shape_a; /* Distance from tip of arrowhead to center */
+ double shape_b; /* Distance from tip of arrowhead to trailing point, measured along shaft */
+ double shape_c; /* Distance of trailing points from outside edge of shaft */
+
+ GdkCapStyle cap; /* Cap style for line */
+ GdkJoinStyle join; /* Join style for line */
+ GdkLineStyle line_style;/* Style for the line */
+
+ gulong fill_pixel; /* Color for line */
+
+ guint32 fill_rgba; /* RGBA color for outline */ /*AA*/
+
+ int num_points; /* Number of points in the line */
+ guint fill_color; /* Fill color, RGBA */
+
+ int spline_steps; /* Number of steps in each spline segment */
+
+ guint width_pixels : 1; /* Is the width specified in pixels or units? */
+ guint first_arrow : 1; /* Draw first arrowhead? */
+ guint last_arrow : 1; /* Draw last arrowhead? */
+ guint smooth : 1; /* Smooth line (with parabolic splines)? */
+};
+
+struct _GnomeCanvasLineClass {
+ GnomeCanvasItemClass parent_class;
+};
+
+
+/* Standard Gtk function */
+GType gnome_canvas_line_get_type (void) G_GNUC_CONST;
+
+
+G_END_DECLS
+
+#endif
diff --git a/src/libgnomecanvas/gnome-canvas-marshal.list b/src/libgnomecanvas/gnome-canvas-marshal.list
new file mode 100644
index 0000000..5ad61bf
--- /dev/null
+++ b/src/libgnomecanvas/gnome-canvas-marshal.list
@@ -0,0 +1,2 @@
+VOID:OBJECT,INT,INT,INT,INT
+BOOLEAN:BOXED
diff --git a/src/libgnomecanvas/gnome-canvas-path-def.c b/src/libgnomecanvas/gnome-canvas-path-def.c
new file mode 100644
index 0000000..11b0924
--- /dev/null
+++ b/src/libgnomecanvas/gnome-canvas-path-def.c
@@ -0,0 +1,1287 @@
+#define GNOME_CANVAS_PATH_DEF_C
+
+/*
+ * GnomeCanvasPathDef
+ *
+ * (C) 1999-2000 Lauris Kaplinski <lauris@ximian.com>
+ * Released under LGPL
+ *
+ * Authors: Lauris Kaplinski <lauris@ximian.com>
+ * Rusty Conover <rconover@bangtail.net>
+ *
+ * Copyright 1999-2001 Ximian Inc. and authors.
+ */
+
+#include <string.h>
+#include <libart_lgpl/art_misc.h>
+#include "gnome-canvas-path-def.h"
+
+/* The number of points to allocate at once */
+#define GNOME_CANVAS_PATH_DEF_LENSTEP 32
+
+struct _GnomeCanvasPathDef {
+ gint refcount;
+ ArtBpath * bpath;
+ gint end; /* ART_END position */
+ gint length; /* Num allocated Bpaths */
+ gint substart; /* subpath start */
+ gdouble x, y; /* previous moveto position */
+ guint sbpath : 1; /* Bpath is static */
+ guint hascpt : 1; /* Currentpoint is defined */
+ guint posset : 1; /* Previous was moveto */
+ guint moving : 1; /* Bpath end is moving */
+ guint allclosed : 1; /* All subpaths are closed */
+ guint allopen : 1; /* All subpaths are open */
+};
+
+static gboolean sp_bpath_good (ArtBpath * bpath);
+static ArtBpath * sp_bpath_check_subpath (ArtBpath * bpath);
+static gint sp_bpath_length (const ArtBpath * bpath);
+static gboolean sp_bpath_all_closed (const ArtBpath * bpath);
+static gboolean sp_bpath_all_open (const ArtBpath * bpath);
+
+/* Boxed Type Support */
+
+static GnomeCanvasPathDef *
+path_def_boxed_copy (GnomeCanvasPathDef * path_def)
+{
+ if (path_def)
+ gnome_canvas_path_def_ref (path_def);
+ return path_def;
+}
+
+GType
+gnome_canvas_path_def_get_type (void)
+{
+ static GType t = 0;
+ if (t == 0)
+ t = g_boxed_type_register_static
+ ("GnomeCanvasPathDef",
+ (GBoxedCopyFunc)path_def_boxed_copy,
+ (GBoxedFreeFunc)gnome_canvas_path_def_unref);
+ return t;
+}
+
+/* Constructors */
+
+/**
+ * gnome_canvas_path_def_new:
+ *
+ * This function creates a new empty #gnome_canvas_path_def.
+ *
+ * Returns: the new canvas path definition.
+ */
+GnomeCanvasPathDef *
+gnome_canvas_path_def_new (void)
+{
+ GnomeCanvasPathDef * path;
+
+ path = gnome_canvas_path_def_new_sized (GNOME_CANVAS_PATH_DEF_LENSTEP);
+
+ return path;
+}
+
+/**
+ * gnome_canvas_path_def_new_sized:
+ * @length: number of points to allocate for the path
+ *
+ * This function creates a new #gnome_canvas_path_def with @length
+ * number of points allocated. It is useful, if you know the exact
+ * number of points in path, so you can avoid automatic point
+ * array reallocation.
+ *
+ * Returns: the new canvas path definition
+ */
+GnomeCanvasPathDef *
+gnome_canvas_path_def_new_sized (gint length)
+{
+ GnomeCanvasPathDef * path;
+
+ g_return_val_if_fail (length > 0, NULL);
+
+ path = g_new (GnomeCanvasPathDef, 1);
+
+ path->refcount = 1;
+ path->bpath = art_new (ArtBpath, length);
+ path->end = 0;
+ path->bpath[path->end].code = ART_END;
+ path->length = length;
+ path->sbpath = FALSE;
+ path->hascpt = FALSE;
+ path->posset = FALSE;
+ path->moving = FALSE;
+ path->allclosed = TRUE;
+ path->allopen = TRUE;
+
+ return path;
+}
+
+/**
+ * gnome_canvas_path_def_new_from_bpath:
+ * @bpath: libart bezier path
+ *
+ * This function constructs a new #gnome_canvas_path_def and uses the
+ * passed @bpath as the contents. The passed bpath should not be
+ * static as the path definition is editable when constructed with
+ * this function. Also, passed bpath will be freed with art_free, if
+ * path is destroyed, so use it with caution.
+ * For constructing a #gnome_canvas_path_def
+ * from (non-modifiable) bpath use
+ * #gnome_canvas_path_def_new_from_static_bpath.
+ *
+ * Returns: the new canvas path definition that is populated with the
+ * passed bezier path, if the @bpath is bad NULL is returned.
+ */
+GnomeCanvasPathDef *
+gnome_canvas_path_def_new_from_bpath (ArtBpath * bpath)
+{
+ GnomeCanvasPathDef * path;
+
+ g_return_val_if_fail (sp_bpath_good (bpath), NULL);
+
+ path = g_new (GnomeCanvasPathDef, 1);
+
+ path->refcount = 1;
+ path->bpath = bpath;
+ path->length = sp_bpath_length (bpath);
+ path->end = path->length - 1;
+ path->sbpath = FALSE;
+ path->hascpt = FALSE;
+ path->posset = FALSE;
+ path->moving = FALSE;
+ path->allclosed = sp_bpath_all_closed (bpath);
+ path->allopen = sp_bpath_all_open (bpath);
+
+ return path;
+}
+
+/**
+ * gnome_canvas_path_def_new_from_static_bpath:
+ * @bpath: libart bezier path
+ *
+ * This function constructs a new #gnome_canvas_path_def and
+ * references the passed @bpath as its contents. The
+ * #gnome_canvas_path_def returned from this function is to be
+ * considered static and non-editable (meaning you cannot change the
+ * path from what you passed in @bpath). The bpath will not be freed,
+ * if path will be destroyed, so use it with caution.
+ *
+ * Returns: the new canvas path definition that references the passed
+ * @bpath, or if the path is bad NULL is returned.
+ */
+GnomeCanvasPathDef *
+gnome_canvas_path_def_new_from_static_bpath (ArtBpath * bpath)
+{
+ GnomeCanvasPathDef * path;
+
+ g_return_val_if_fail (sp_bpath_good (bpath), NULL);
+
+ path = g_new (GnomeCanvasPathDef, 1);
+
+ path->refcount = 1;
+ path->bpath = bpath;
+ path->length = sp_bpath_length (bpath);
+ path->end = path->length - 1;
+ path->sbpath = TRUE;
+ path->hascpt = FALSE;
+ path->posset = FALSE;
+ path->moving = FALSE;
+ path->allclosed = sp_bpath_all_closed (bpath);
+ path->allopen = sp_bpath_all_open (bpath);
+
+ return path;
+}
+
+/**
+ * gnome_canvas_path_def_new_from_foreign_bpath:
+ * @bpath: libart bezier path
+ *
+ * This function constructs a new #gnome_canvas_path_def and
+ * duplicates the contents of the passed @bpath in the definition.
+ *
+ * Returns: the newly created #gnome_canvas_path_def or NULL if the
+ * path is invalid.
+ */
+GnomeCanvasPathDef *
+gnome_canvas_path_def_new_from_foreign_bpath (ArtBpath * bpath)
+{
+ GnomeCanvasPathDef * path;
+ gint length;
+
+ g_return_val_if_fail (sp_bpath_good (bpath), NULL);
+
+ length = sp_bpath_length (bpath);
+
+ path = gnome_canvas_path_def_new_sized (length);
+ memcpy (path->bpath, bpath, sizeof (ArtBpath) * length);
+ path->end = length - 1;
+ path->allclosed = sp_bpath_all_closed (bpath);
+ path->allopen = sp_bpath_all_open (bpath);
+
+ return path;
+}
+
+/**
+ * gnome_canvas_path_def_ref:
+ * @path: a GnomeCanvasPathDef
+ *
+ * Increment the reference count of the GnomeCanvasPathDef.
+ */
+void
+gnome_canvas_path_def_ref (GnomeCanvasPathDef * path)
+{
+ g_return_if_fail (path != NULL);
+
+ path->refcount++;
+}
+
+/**
+ * gnome_canvas_path_def_finish:
+ * @path: a GnomeCanvasPathDef
+ *
+ * Trims dynamic point array to exact length of path.
+ */
+void
+gnome_canvas_path_def_finish (GnomeCanvasPathDef * path)
+{
+ g_return_if_fail (path != NULL);
+ g_return_if_fail (path->sbpath);
+
+ if ((path->end + 1) < path->length) {
+ path->bpath = art_renew (path->bpath, ArtBpath, path->end + 1);
+ path->length = path->end + 1;
+ }
+
+ path->hascpt = FALSE;
+ path->posset = FALSE;
+ path->moving = FALSE;
+}
+/**
+ * gnome_canvas_path_def_ensure_space:
+ * @path: a GnomeCanvasPathDef
+ * @space: number of points to guarantee are allocated at the end of
+ * the path.
+ *
+ * This function ensures that enough space for @space points is
+ * allocated at the end of the path.
+ */
+void
+gnome_canvas_path_def_ensure_space (GnomeCanvasPathDef * path, gint space)
+{
+ g_return_if_fail (path != NULL);
+ g_return_if_fail (space > 0);
+
+ if (path->end + space < path->length) return;
+
+ if (space < GNOME_CANVAS_PATH_DEF_LENSTEP) space = GNOME_CANVAS_PATH_DEF_LENSTEP;
+
+ path->bpath = art_renew (path->bpath, ArtBpath, path->length + space);
+
+ path->length += space;
+}
+
+/**
+ * gnome_canvas_path_def_copy:
+ * @dst: a GnomeCanvasPathDef where the contents of @src will be stored.
+ * @src: a GnomeCanvasPathDef whose contents will be copied it @src.
+ *
+ * This function copies the contents @src to @dest. The old @dest path
+ * array is freed and @dest is marked as non-static (editable),
+ * regardless of the status of @src.
+ */
+void
+gnome_canvas_path_def_copy (GnomeCanvasPathDef * dst, const GnomeCanvasPathDef * src)
+{
+ g_return_if_fail (dst != NULL);
+ g_return_if_fail (src != NULL);
+
+ if (!dst->sbpath) g_free (dst->bpath);
+
+ memcpy (dst, src, sizeof (GnomeCanvasPathDef));
+
+ dst->bpath = g_new (ArtBpath, src->end + 1);
+ memcpy (dst->bpath, src->bpath, (src->end + 1) * sizeof (ArtBpath));
+
+ dst->sbpath = FALSE;
+}
+
+
+/**
+ * gnome_canvas_path_def_duplicate:
+ * @path: a GnomeCanvasPathDef to duplicate
+ *
+ * This function duplicates the passed @path. The new path is
+ * marked as non-static regardless of the state of original.
+ *
+ * Returns: a GnomeCanvasPathDef which is a duplicate of @path.
+ */
+GnomeCanvasPathDef *
+gnome_canvas_path_def_duplicate (const GnomeCanvasPathDef * path)
+{
+ GnomeCanvasPathDef * new;
+
+ g_return_val_if_fail (path != NULL, NULL);
+
+ new = gnome_canvas_path_def_new_from_foreign_bpath (path->bpath);
+ new->x = path->x;
+ new->y = path->y;
+ new->hascpt = path->hascpt;
+ new->posset = path->posset;
+ new->moving = path->moving;
+ new->allclosed = path->allclosed;
+ new->allopen = path->allopen;
+
+ return new;
+}
+
+/**
+ * gnome_canvas_path_def_concat:
+ * @list: a GSList of GnomeCanvasPathDefs to concatenate into one new
+ * path.
+ *
+ * This function concatenates a list of GnomeCanvasPathDefs into one
+ * newly created GnomeCanvasPathDef.
+ *
+ * Returns: a new GnomeCanvasPathDef
+ */
+GnomeCanvasPathDef *
+gnome_canvas_path_def_concat (const GSList * list)
+{
+ GnomeCanvasPathDef * c, * new;
+ ArtBpath * bp;
+ const GSList * l;
+ gint length;
+
+ g_return_val_if_fail (list != NULL, NULL);
+
+ length = 1;
+
+ for (l = list; l != NULL; l = l->next) {
+ c = (GnomeCanvasPathDef *) l->data;
+ length += c->end;
+ }
+
+ new = gnome_canvas_path_def_new_sized (length);
+
+ bp = new->bpath;
+
+ for (l = list; l != NULL; l = l->next) {
+ c = (GnomeCanvasPathDef *) l->data;
+ memcpy (bp, c->bpath, c->end * sizeof (ArtBpath));
+ bp += c->end;
+ }
+
+ bp->code = ART_END;
+
+ new->end = length - 1;
+
+ new->allclosed = sp_bpath_all_closed (new->bpath);
+ new->allopen = sp_bpath_all_open (new->bpath);
+
+ return new;
+}
+
+/**
+ * gnome_canvas_path_def_split:
+ * @path: a GnomeCanvasPathDef
+ *
+ * This function splits the passed @path into a list of
+ * GnomeCanvasPathDefs which represent each segment of the origional
+ * path. The path is split when ever an ART_MOVETO or ART_MOVETO_OPEN
+ * is encountered. The closedness of resulting paths is set accordingly
+ * to closedness of corresponding segment.
+ *
+ * Returns: a list of GnomeCanvasPathDef(s).
+ */
+GSList *
+gnome_canvas_path_def_split (const GnomeCanvasPathDef * path)
+{
+ GnomeCanvasPathDef * new;
+ GSList * l;
+ gint p, i;
+
+ g_return_val_if_fail (path != NULL, NULL);
+
+ p = 0;
+ l = NULL;
+
+ while (p < path->end) {
+ i = 1;
+ while ((path->bpath[p + i].code == ART_LINETO) || (path->bpath[p + i].code == ART_CURVETO)) i++;
+ new = gnome_canvas_path_def_new_sized (i + 1);
+ memcpy (new->bpath, path->bpath + p, i * sizeof (ArtBpath));
+ new->end = i;
+ new->bpath[i].code = ART_END;
+ new->allclosed = (new->bpath->code == ART_MOVETO);
+ new->allopen = (new->bpath->code == ART_MOVETO_OPEN);
+ l = g_slist_append (l, new);
+ p += i;
+ }
+
+ return l;
+}
+
+/**
+ * gnome_canvas_path_def_open_parts:
+ * @path: a GnomeCanvasPathDef
+ *
+ * This function creates a new GnomeCanvasPathDef that contains all of
+ * the open segments on the passed @path.
+ *
+ * Returns: a new GnomeCanvasPathDef that contains all of the open segemtns in @path.
+ */
+GnomeCanvasPathDef *
+gnome_canvas_path_def_open_parts (const GnomeCanvasPathDef * path)
+{
+ GnomeCanvasPathDef * new;
+ ArtBpath * p, * d;
+ gint len;
+ gboolean closed;
+
+ g_return_val_if_fail (path != NULL, NULL);
+
+ closed = TRUE;
+ len = 0;
+
+ for (p = path->bpath; p->code != ART_END; p++) {
+ switch (p->code) {
+ case ART_MOVETO_OPEN:
+ closed = FALSE;
+ len++;
+ break;
+ case ART_MOVETO:
+ closed = TRUE;
+ break;
+ case ART_LINETO:
+ case ART_CURVETO:
+ if (!closed) len++;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ }
+
+ new = gnome_canvas_path_def_new_sized (len + 1);
+
+ closed = TRUE;
+ d = new->bpath;
+
+ for (p = path->bpath; p->code != ART_END; p++) {
+ switch (p->code) {
+ case ART_MOVETO_OPEN:
+ closed = FALSE;
+ *d++ = *p;
+ break;
+ case ART_MOVETO:
+ closed = TRUE;
+ break;
+ case ART_LINETO:
+ case ART_CURVETO:
+ if (!closed) *d++ = *p;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ }
+
+ d->code = ART_END;
+
+ new->end = len;
+ new->allclosed = FALSE;
+ new->allopen = TRUE;
+
+ return new;
+}
+
+/**
+ * gnome_canvas_path_def_closed_parts:
+ * @path: a GnomeCanvasPathDef
+ *
+ * This function returns a new GnomeCanvasPathDef that contains the
+ * all of close parts of passed @path.
+ *
+ * Returns: a new GnomeCanvasPathDef that contains all of the closed
+ * parts of passed @path.
+ */
+GnomeCanvasPathDef *
+gnome_canvas_path_def_closed_parts (const GnomeCanvasPathDef * path)
+{
+ GnomeCanvasPathDef * new;
+ ArtBpath * p, * d;
+ gint len;
+ gboolean closed;
+
+ g_return_val_if_fail (path != NULL, NULL);
+
+ closed = FALSE;
+ len = 0;
+
+ for (p = path->bpath; p->code != ART_END; p++) {
+ switch (p->code) {
+ case ART_MOVETO_OPEN:
+ closed = FALSE;
+ break;
+ case ART_MOVETO:
+ closed = TRUE;
+ len++;
+ break;
+ case ART_LINETO:
+ case ART_CURVETO:
+ if (closed) len++;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ }
+
+ new = gnome_canvas_path_def_new_sized (len + 1);
+
+ closed = FALSE;
+ d = new->bpath;
+
+ for (p = path->bpath; p->code != ART_END; p++) {
+ switch (p->code) {
+ case ART_MOVETO_OPEN:
+ closed = FALSE;
+ break;
+ case ART_MOVETO:
+ closed = TRUE;
+ *d++ = *p;
+ break;
+ case ART_LINETO:
+ case ART_CURVETO:
+ if (closed) *d++ = *p;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ }
+
+ d->code = ART_END;
+
+ new->end = len;
+ new->allclosed = TRUE;
+ new->allopen = FALSE;
+
+ return new;
+}
+
+/**
+ * gnome_canvas_path_def_close_all:
+ * @path: a GnomeCanvasPathDef
+ *
+ * This function closes all of the open segments in the passed path
+ * and returns a new GnomeCanvasPathDef.
+ *
+ * Returns: a GnomeCanvasPathDef that contains the contents of @path
+ * but has modified the path is fully closed
+ */
+GnomeCanvasPathDef *
+gnome_canvas_path_def_close_all (const GnomeCanvasPathDef * path)
+{
+ GnomeCanvasPathDef * new;
+ ArtBpath * p, * d, * start;
+ gint len;
+ gboolean closed;
+
+ g_return_val_if_fail (path != NULL, NULL);
+
+ if (path->allclosed) {
+ new = gnome_canvas_path_def_duplicate (path);
+ return new;
+ }
+
+ len = 1;
+
+ /* Count MOVETO_OPEN */
+
+ for (p = path->bpath; p->code != ART_END; p++) {
+ len += 1;
+ if (p->code == ART_MOVETO_OPEN) len += 2;
+ }
+
+ new = gnome_canvas_path_def_new_sized (len);
+
+ d = start = new->bpath;
+ closed = TRUE;
+
+ for (p = path->bpath; p->code != ART_END; p++) {
+ switch (p->code) {
+ case ART_MOVETO_OPEN:
+ start = p;
+ closed = FALSE;
+ case ART_MOVETO:
+ if ((!closed) && ((start->x3 != p->x3) || (start->y3 != p->y3))) {
+ d->code = ART_LINETO;
+ d->x3 = start->x3;
+ d->y3 = start->y3;
+ d++;
+ }
+ if (p->code == ART_MOVETO) closed = TRUE;
+ d->code = ART_MOVETO;
+ d->x3 = p->x3;
+ d->y3 = p->y3;
+ d++;
+ break;
+ case ART_LINETO:
+ case ART_CURVETO:
+ *d++ = *p;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ }
+
+ if ((!closed) && ((start->x3 != p->x3) || (start->y3 != p->y3))) {
+ d->code = ART_LINETO;
+ d->x3 = start->x3;
+ d->y3 = start->y3;
+ d++;
+ }
+
+ d->code = ART_END;
+
+ new->end = d - new->bpath;
+ new->allclosed = TRUE;
+ new->allopen = FALSE;
+
+ return new;
+}
+
+/* Destructor */
+
+/**
+ * gnome_canvas_path_def_unref:
+ * @path: a GnomeCanvasPathDef
+ *
+ * Decrease the reference count of the passed @path. If the reference
+ * count is < 1 the path is deallocated.
+ */
+void
+gnome_canvas_path_def_unref (GnomeCanvasPathDef * path)
+{
+ g_return_if_fail (path != NULL);
+
+ if (--path->refcount < 1) {
+ if ((!path->sbpath) && (path->bpath)) art_free (path->bpath);
+ g_free (path);
+ }
+}
+
+
+/* Methods */
+/**
+ * gnome_canvas_path_def_reset:
+ * @path: a GnomeCanvasPathDef
+ *
+ * This function clears the contents of the passed @path.
+ */
+void
+gnome_canvas_path_def_reset (GnomeCanvasPathDef * path)
+{
+ g_return_if_fail (path != NULL);
+ g_return_if_fail (!path->sbpath);
+
+ path->bpath->code = ART_END;
+ path->end = 0;
+ path->hascpt = FALSE;
+ path->posset = FALSE;
+ path->moving = FALSE;
+ path->allclosed = TRUE;
+ path->allopen = TRUE;
+}
+
+/* Several consequtive movetos are ALLOWED */
+
+/**
+ * gnome_canvas_path_def_moveto:
+ * @path: a GnomeCanvasPathDef
+ * @x: x coordinate
+ * @y: y coordinate
+ *
+ * This function adds starts new subpath on @path, and sets its
+ * starting point to @x and @y. If current subpath is empty, it
+ * simply changes its starting coordinates to new values.
+ */
+void
+gnome_canvas_path_def_moveto (GnomeCanvasPathDef * path, gdouble x, gdouble y)
+{
+ g_return_if_fail (path != NULL);
+ g_return_if_fail (!path->sbpath);
+ g_return_if_fail (!path->moving);
+
+ path->substart = path->end;
+ path->hascpt = TRUE;
+ path->posset = TRUE;
+ path->x = x;
+ path->y = y;
+
+ path->allclosed = FALSE;
+}
+
+/**
+ * gnome_canvas_path_def_lineto:
+ * @path: a GnomeCanvasPathDef
+ * @x: x coordinate
+ * @y: y coordinate
+ *
+ * This function add a line segment to the passed @path with the
+ * specified @x and @y coordinates.
+ */
+void
+gnome_canvas_path_def_lineto (GnomeCanvasPathDef * path, gdouble x, gdouble y)
+{
+ ArtBpath * bp;
+
+ g_return_if_fail (path != NULL);
+ g_return_if_fail (!path->sbpath);
+ g_return_if_fail (path->hascpt);
+
+ if (path->moving) {
+ /* simply fix endpoint */
+ g_return_if_fail (!path->posset);
+ g_return_if_fail (path->end > 1);
+ bp = path->bpath + path->end - 1;
+ g_return_if_fail (bp->code == ART_LINETO);
+ bp->x3 = x;
+ bp->y3 = y;
+ path->moving = FALSE;
+ return;
+ }
+
+ if (path->posset) {
+ /* start a new segment */
+ gnome_canvas_path_def_ensure_space (path, 2);
+ bp = path->bpath + path->end;
+ bp->code = ART_MOVETO_OPEN;
+ bp->x3 = path->x;
+ bp->y3 = path->y;
+ bp++;
+ bp->code = ART_LINETO;
+ bp->x3 = x;
+ bp->y3 = y;
+ bp++;
+ bp->code = ART_END;
+ path->end += 2;
+ path->posset = FALSE;
+ path->allclosed = FALSE;
+ return;
+ }
+
+ /* Simply add line */
+
+ g_return_if_fail (path->end > 1);
+ gnome_canvas_path_def_ensure_space (path, 1);
+ bp = path->bpath + path->end;
+ bp->code = ART_LINETO;
+ bp->x3 = x;
+ bp->y3 = y;
+ bp++;
+ bp->code = ART_END;
+ path->end++;
+}
+
+
+/**
+ * gnome_canvas_path_def_lineto_moving:
+ * @path: a GnomeCanvasPathDef
+ * @x: x coordinate
+ * @y: y coordinate
+ *
+ * This functions adds a new line segment with loose endpoint to the path, or
+ * if endpoint is already loose, changes its coordinates to @x, @y. You
+ * can change the coordinates of loose endpoint as many times as you want,
+ * the last ones set will be fixed, if you continue line. This is useful
+ * for handling drawing with mouse.
+ */
+void
+gnome_canvas_path_def_lineto_moving (GnomeCanvasPathDef * path, gdouble x, gdouble y)
+{
+ ArtBpath * bp;
+
+ g_return_if_fail (path != NULL);
+ g_return_if_fail (!path->sbpath);
+ g_return_if_fail (path->hascpt);
+
+ if (path->moving) {
+ /* simply change endpoint */
+ g_return_if_fail (!path->posset);
+ g_return_if_fail (path->end > 1);
+ bp = path->bpath + path->end - 1;
+ g_return_if_fail (bp->code == ART_LINETO);
+ bp->x3 = x;
+ bp->y3 = y;
+ return;
+ }
+
+ if (path->posset) {
+ /* start a new segment */
+ gnome_canvas_path_def_ensure_space (path, 2);
+ bp = path->bpath + path->end;
+ bp->code = ART_MOVETO_OPEN;
+ bp->x3 = path->x;
+ bp->y3 = path->y;
+ bp++;
+ bp->code = ART_LINETO;
+ bp->x3 = x;
+ bp->y3 = y;
+ bp++;
+ bp->code = ART_END;
+ path->end += 2;
+ path->posset = FALSE;
+ path->moving = TRUE;
+ path->allclosed = FALSE;
+ return;
+ }
+
+ /* Simply add line */
+
+ g_return_if_fail (path->end > 1);
+ gnome_canvas_path_def_ensure_space (path, 1);
+ bp = path->bpath + path->end;
+ bp->code = ART_LINETO;
+ bp->x3 = x;
+ bp->y3 = y;
+ bp++;
+ bp->code = ART_END;
+ path->end++;
+ path->moving = TRUE;
+}
+
+/**
+ * gnome_canvas_path_def_curveto:
+ * @path: a GnomeCanvasPathDef
+ * @x0: first control point x coordinate
+ * @y0: first control point y coordinate
+ * @x1: second control point x coordinate
+ * @y1: second control point y coordinate
+ * @x2: end of curve x coordinate
+ * @y2: end of curve y coordinate
+ *
+ * This function adds a bezier curve segment to the path definition.
+ */
+
+void
+gnome_canvas_path_def_curveto (GnomeCanvasPathDef * path, gdouble x0, gdouble y0, gdouble x1, gdouble y1, gdouble x2, gdouble y2)
+{
+ ArtBpath * bp;
+
+ g_return_if_fail (path != NULL);
+ g_return_if_fail (!path->sbpath);
+ g_return_if_fail (path->hascpt);
+ g_return_if_fail (!path->moving);
+
+ if (path->posset) {
+ /* start a new segment */
+ gnome_canvas_path_def_ensure_space (path, 2);
+ bp = path->bpath + path->end;
+ bp->code = ART_MOVETO_OPEN;
+ bp->x3 = path->x;
+ bp->y3 = path->y;
+ bp++;
+ bp->code = ART_CURVETO;
+ bp->x1 = x0;
+ bp->y1 = y0;
+ bp->x2 = x1;
+ bp->y2 = y1;
+ bp->x3 = x2;
+ bp->y3 = y2;
+ bp++;
+ bp->code = ART_END;
+ path->end += 2;
+ path->posset = FALSE;
+ path->allclosed = FALSE;
+ return;
+ }
+
+ /* Simply add path */
+
+ g_return_if_fail (path->end > 1);
+ gnome_canvas_path_def_ensure_space (path, 1);
+ bp = path->bpath + path->end;
+ bp->code = ART_CURVETO;
+ bp->x1 = x0;
+ bp->y1 = y0;
+ bp->x2 = x1;
+ bp->y2 = y1;
+ bp->x3 = x2;
+ bp->y3 = y2;
+ bp++;
+ bp->code = ART_END;
+ path->end++;
+}
+
+/**
+ * gnome_canvas_path_def_closepath:
+ * @path: a GnomeCanvasPathDef
+ *
+ * This function closes the last subpath of @path, adding a ART_LINETO to
+ * subpath starting point, if needed and changing starting pathcode to
+ * ART_MOVETO
+ */
+void
+gnome_canvas_path_def_closepath (GnomeCanvasPathDef * path)
+{
+ ArtBpath * bs, * be;
+
+ g_return_if_fail (path != NULL);
+ g_return_if_fail (!path->sbpath);
+ g_return_if_fail (path->hascpt);
+ g_return_if_fail (!path->posset);
+ g_return_if_fail (!path->moving);
+ g_return_if_fail (!path->allclosed);
+ /* We need at last M + L + L + E */
+ g_return_if_fail (path->end - path->substart > 2);
+
+ bs = path->bpath + path->substart;
+ be = path->bpath + path->end - 1;
+
+ if ((bs->x3 != be->x3) || (bs->y3 != be->y3)) {
+ gnome_canvas_path_def_lineto (path, bs->x3, bs->y3);
+ }
+
+ bs = path->bpath + path->substart; /* NB. def_lineto can
+ realloc bpath */
+ bs->code = ART_MOVETO;
+
+ path->allclosed = sp_bpath_all_closed (path->bpath);
+ path->allopen = sp_bpath_all_open (path->bpath);
+
+ path->hascpt = FALSE;
+}
+
+/**
+ * gnome_canvas_path_def_closepath_current:
+ * @path: a GnomeCanvasPathDef
+ *
+ * This function closes the last subpath by setting the coordinates of
+ * the endpoint of the last segment (line or curve) to starting point.
+ */
+void
+gnome_canvas_path_def_closepath_current (GnomeCanvasPathDef * path)
+{
+ ArtBpath * bs, * be;
+
+ g_return_if_fail (path != NULL);
+ g_return_if_fail (!path->sbpath);
+ g_return_if_fail (path->hascpt);
+ g_return_if_fail (!path->posset);
+ g_return_if_fail (!path->allclosed);
+ /* We need at last M + L + L + E */
+ g_return_if_fail (path->end - path->substart > 2);
+
+ bs = path->bpath + path->substart;
+ be = path->bpath + path->end - 1;
+
+ be->x3 = bs->x3;
+ be->y3 = bs->y3;
+
+ bs->code = ART_MOVETO;
+
+ path->allclosed = sp_bpath_all_closed (path->bpath);
+ path->allopen = sp_bpath_all_open (path->bpath);
+
+ path->hascpt = FALSE;
+ path->moving = FALSE;
+}
+
+/**
+ * gnome_canvas_path_def_bpath:
+ * @path: a GnomeCanvasPathDef
+ *
+ * This function returns a ArtBpath that consists of the path
+ * definition.
+ *
+ * Returns: ArtBpath
+ */
+ArtBpath * gnome_canvas_path_def_bpath (const GnomeCanvasPathDef * path)
+{
+ g_return_val_if_fail (path != NULL, NULL);
+
+ return path->bpath;
+}
+
+/**
+ * gnome_canvas_path_def_length:
+ * @path: a GnomeCanvasPathDef
+ *
+ * This function returns the length of the path definition. Not
+ * Euclidian length of the path but rather the number of points on the
+ * path.
+ *
+ * Returns: integer, number of points on the path.
+ */
+gint gnome_canvas_path_def_length (const GnomeCanvasPathDef * path)
+{
+ g_return_val_if_fail (path != NULL, -1);
+
+ return path->end + 1;
+}
+
+/**
+ * gnome_canvas_path_def_is_empty:
+ * @path: a GnomeCanvasPathDef
+ *
+ * This function is a boolean test to see if the path is empty,
+ * meaning containing no line segments.
+ *
+ * Returns: boolean, indicating if the path is empty.
+ */
+gboolean
+gnome_canvas_path_def_is_empty (const GnomeCanvasPathDef * path)
+{
+ g_return_val_if_fail (path != NULL, TRUE);
+
+ return (path->bpath->code == ART_END);
+}
+
+/**
+ * gnome_canvas_path_def_has_currentpoint:
+ * @path: a GnomeCanvasPathdef
+ *
+ * This function is a boolean test checking to see if the path has a
+ * current point defined. Current point will be set by line operators,
+ * and cleared by closing subpath.
+ *
+ * Returns: boolean, indicating if the path has a current point defined.
+ */
+gboolean
+gnome_canvas_path_def_has_currentpoint (const GnomeCanvasPathDef * path)
+{
+ g_return_val_if_fail (path != NULL, FALSE);
+
+ return (path->hascpt);
+}
+
+/**
+ * gnome_canvas_path_def_currentpoint:
+ * @path: a GnomeCanvasPathDef
+ * @p: a ArtPoint where to store the current point
+ *
+ * Stores the current point of the path definition in the passed ArtPoint @p.
+ */
+void
+gnome_canvas_path_def_currentpoint (const GnomeCanvasPathDef * path, ArtPoint * p)
+{
+ g_return_if_fail (path != NULL);
+ g_return_if_fail (p != NULL);
+ g_return_if_fail (path->hascpt);
+
+ if (path->posset) {
+ p->x = path->x;
+ p->y = path->y;
+ } else {
+ p->x = (path->bpath + path->end - 1)->x3;
+ p->y = (path->bpath + path->end - 1)->y3;
+ }
+}
+
+/**
+ * gnome_canvas_path_def_last_bpath:
+ * @path: a GnomeCanvasPathDef
+ *
+ * This function returns pointer to the last ArtBpath segment in the path
+ * definition.
+ *
+ * Returns: ArtBpath, being the last segment in the path definition or
+ * null if no line segments have been defined.
+ */
+ArtBpath *
+gnome_canvas_path_def_last_bpath (const GnomeCanvasPathDef * path)
+{
+ g_return_val_if_fail (path != NULL, NULL);
+
+ if (path->end == 0) return NULL;
+
+ return path->bpath + path->end - 1;
+}
+
+/**
+ * gnome_canvas_path_def_first_bpath:
+ * @path: a GnomeCanvasPathDef
+ *
+ * This function returns the first ArtBpath point in the definition.
+ *
+ * Returns: ArtBpath being the first point in the path definition or
+ * null if no points are defined
+*/
+ArtBpath *
+gnome_canvas_path_def_first_bpath (const GnomeCanvasPathDef * path)
+{
+ g_return_val_if_fail (path != NULL, NULL);
+
+ if (path->end == 0) return NULL;
+
+ return path->bpath;
+}
+
+/**
+ * gnome_canvas_path_def_any_open:
+ * @path: a GnomeCanvasPathDef
+ *
+ * This function returns a boolean value indicating if the path has
+ * any open segments.
+ *
+ * Returns: boolean, indicating if the path has any open segments.
+ */
+gboolean
+gnome_canvas_path_def_any_open (const GnomeCanvasPathDef * path)
+{
+ g_return_val_if_fail (path != NULL, FALSE);
+
+ return (!path->allclosed);
+}
+
+/**
+ * gnome_canvas_path_def_all_open:
+ * @path: a GnomeCanvasPathDef
+ *
+ * This function returns a boolean value indicating if the path only
+ * contains open segments.
+ *
+ * Returns: boolean, indicating if the path has all open segments.
+ */
+gboolean
+gnome_canvas_path_def_all_open (const GnomeCanvasPathDef * path)
+{
+ g_return_val_if_fail (path != NULL, FALSE);
+
+ return (path->allopen);
+}
+
+/**
+ * gnome_canvas_path_def_any_closed:
+ * @path: a GnomeCanvasPathDef
+ *
+ * This function returns a boolean valid indicating if the path has
+ * any closed segements.
+ *
+ * Returns: boolean, indicating if the path has any closed segments.
+ */
+gboolean
+gnome_canvas_path_def_any_closed (const GnomeCanvasPathDef * path)
+{
+ g_return_val_if_fail (path != NULL, FALSE);
+
+ return (!path->allopen);
+}
+
+/**
+ * gnome_canvas_path_def_all_closed:
+ * @path: a GnomeCanvasPathDef
+ *
+ * This function returns a boolean value indicating if the path only
+ * contains closed segments.
+ *
+ * Returns: boolean, indicating if the path has all closed segments.
+ */
+gboolean
+gnome_canvas_path_def_all_closed (const GnomeCanvasPathDef * path)
+{
+ g_return_val_if_fail (path != NULL, FALSE);
+
+ return (path->allclosed);
+}
+
+/* Private methods */
+
+static
+gboolean sp_bpath_good (ArtBpath * bpath)
+{
+ ArtBpath * bp;
+
+ g_return_val_if_fail (bpath != NULL, FALSE);
+
+ if (bpath->code == ART_END)
+ return TRUE;
+
+ bp = bpath;
+
+ while (bp->code != ART_END) {
+ bp = sp_bpath_check_subpath (bp);
+ if (bp == NULL) return FALSE;
+ }
+
+ return TRUE;
+}
+
+static ArtBpath *
+sp_bpath_check_subpath (ArtBpath * bpath)
+{
+ gint i, len;
+ gboolean closed;
+
+ g_return_val_if_fail (bpath != NULL, NULL);
+
+ if (bpath->code == ART_MOVETO) {
+ closed = TRUE;
+ } else if (bpath->code == ART_MOVETO_OPEN) {
+ closed = FALSE;
+ } else {
+ return NULL;
+ }
+
+ len = 0;
+
+ for (i = 1; (bpath[i].code != ART_END) && (bpath[i].code != ART_MOVETO) && (bpath[i].code != ART_MOVETO_OPEN); i++) {
+ switch (bpath[i].code) {
+ case ART_LINETO:
+ case ART_CURVETO:
+ len++;
+ break;
+ default:
+ return NULL;
+ }
+ }
+
+ if (closed) {
+ if (len < 2) return NULL;
+ if ((bpath->x3 != bpath[i-1].x3) || (bpath->y3 != bpath[i-1].y3)) return NULL;
+ } else {
+ if (len < 1) return NULL;
+ }
+
+ return bpath + i;
+}
+
+static gint
+sp_bpath_length (const ArtBpath * bpath)
+{
+ gint l;
+
+ g_return_val_if_fail (bpath != NULL, FALSE);
+
+ for (l = 0; bpath[l].code != ART_END; l++) ;
+
+ l++;
+
+ return l;
+}
+
+static gboolean
+sp_bpath_all_closed (const ArtBpath * bpath)
+{
+ const ArtBpath * bp;
+
+ g_return_val_if_fail (bpath != NULL, FALSE);
+
+ for (bp = bpath; bp->code != ART_END; bp++)
+ if (bp->code == ART_MOVETO_OPEN) return FALSE;
+
+ return TRUE;
+}
+
+static gboolean
+sp_bpath_all_open (const ArtBpath * bpath)
+{
+ const ArtBpath * bp;
+
+ g_return_val_if_fail (bpath != NULL, FALSE);
+
+ for (bp = bpath; bp->code != ART_END; bp++)
+ if (bp->code == ART_MOVETO) return FALSE;
+
+ return TRUE;
+}
+
+
diff --git a/src/libgnomecanvas/gnome-canvas-path-def.h b/src/libgnomecanvas/gnome-canvas-path-def.h
new file mode 100644
index 0000000..c3f6b25
--- /dev/null
+++ b/src/libgnomecanvas/gnome-canvas-path-def.h
@@ -0,0 +1,96 @@
+#ifndef GNOME_CANVAS_PATH_DEF_H
+#define GNOME_CANVAS_PATH_DEF_H
+
+/*
+ * GnomeCanvasPathDef
+ *
+ * (C) 1999-2000 Lauris Kaplinski <lauris@ximian.com>
+ * Released under LGPL
+ *
+ * This is mostly like GnomeCanvasBpathDef, but with added functionality:
+ * - can be constructed from scratch, from existing bpath of from static bpath
+ * - Path is always terminated with ART_END
+ * - Has closed flag
+ * - has concat, split and copy methods
+ *
+ */
+
+#include <glib-object.h>
+#include <libart_lgpl/art_bpath.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GnomeCanvasPathDef GnomeCanvasPathDef;
+
+#define GNOME_TYPE_CANVAS_PATH_DEF (gnome_canvas_path_def_get_type ())
+GType gnome_canvas_path_def_get_type (void) G_GNUC_CONST;
+
+/* Constructors */
+
+GnomeCanvasPathDef * gnome_canvas_path_def_new (void);
+GnomeCanvasPathDef * gnome_canvas_path_def_new_sized (gint length);
+GnomeCanvasPathDef * gnome_canvas_path_def_new_from_bpath (ArtBpath * bpath);
+GnomeCanvasPathDef * gnome_canvas_path_def_new_from_static_bpath (ArtBpath * bpath);
+GnomeCanvasPathDef * gnome_canvas_path_def_new_from_foreign_bpath (ArtBpath * bpath);
+
+void gnome_canvas_path_def_ref (GnomeCanvasPathDef * path);
+void gnome_canvas_path_def_finish (GnomeCanvasPathDef * path);
+void gnome_canvas_path_def_ensure_space (GnomeCanvasPathDef * path, gint space);
+
+/*
+ * Misc constructors
+ * All these return NEW path, not unrefing old
+ * Also copy and duplicate force bpath to be private (otherwise you
+ * would use ref :)
+ */
+
+void gnome_canvas_path_def_copy (GnomeCanvasPathDef * dst, const GnomeCanvasPathDef * src);
+GnomeCanvasPathDef * gnome_canvas_path_def_duplicate (const GnomeCanvasPathDef * path);
+GnomeCanvasPathDef * gnome_canvas_path_def_concat (const GSList * list);
+GSList * gnome_canvas_path_def_split (const GnomeCanvasPathDef * path);
+GnomeCanvasPathDef * gnome_canvas_path_def_open_parts (const GnomeCanvasPathDef * path);
+GnomeCanvasPathDef * gnome_canvas_path_def_closed_parts (const GnomeCanvasPathDef * path);
+GnomeCanvasPathDef * gnome_canvas_path_def_close_all (const GnomeCanvasPathDef * path);
+
+/* Destructor */
+
+void gnome_canvas_path_def_unref (GnomeCanvasPathDef * path);
+
+/* Methods */
+
+/* Sets GnomeCanvasPathDef to zero length */
+
+void gnome_canvas_path_def_reset (GnomeCanvasPathDef * path);
+
+/* Drawing methods */
+
+void gnome_canvas_path_def_moveto (GnomeCanvasPathDef * path, gdouble x, gdouble y);
+void gnome_canvas_path_def_lineto (GnomeCanvasPathDef * path, gdouble x, gdouble y);
+
+/* Does not create new ArtBpath, but simply changes last lineto position */
+
+void gnome_canvas_path_def_lineto_moving (GnomeCanvasPathDef * path, gdouble x, gdouble y);
+void gnome_canvas_path_def_curveto (GnomeCanvasPathDef * path, gdouble x0, gdouble y0,gdouble x1, gdouble y1, gdouble x2, gdouble y2);
+void gnome_canvas_path_def_closepath (GnomeCanvasPathDef * path);
+
+/* Does not draw new line to startpoint, but moves last lineto */
+
+void gnome_canvas_path_def_closepath_current (GnomeCanvasPathDef * path);
+
+/* Various methods */
+
+ArtBpath * gnome_canvas_path_def_bpath (const GnomeCanvasPathDef * path);
+gint gnome_canvas_path_def_length (const GnomeCanvasPathDef * path);
+gboolean gnome_canvas_path_def_is_empty (const GnomeCanvasPathDef * path);
+gboolean gnome_canvas_path_def_has_currentpoint (const GnomeCanvasPathDef * path);
+void gnome_canvas_path_def_currentpoint (const GnomeCanvasPathDef * path, ArtPoint * p);
+ArtBpath * gnome_canvas_path_def_last_bpath (const GnomeCanvasPathDef * path);
+ArtBpath * gnome_canvas_path_def_first_bpath (const GnomeCanvasPathDef * path);
+gboolean gnome_canvas_path_def_any_open (const GnomeCanvasPathDef * path);
+gboolean gnome_canvas_path_def_all_open (const GnomeCanvasPathDef * path);
+gboolean gnome_canvas_path_def_any_closed (const GnomeCanvasPathDef * path);
+gboolean gnome_canvas_path_def_all_closed (const GnomeCanvasPathDef * path);
+
+G_END_DECLS
+
+#endif
diff --git a/src/libgnomecanvas/gnome-canvas-pixbuf.c b/src/libgnomecanvas/gnome-canvas-pixbuf.c
new file mode 100644
index 0000000..84452cd
--- /dev/null
+++ b/src/libgnomecanvas/gnome-canvas-pixbuf.c
@@ -0,0 +1,1079 @@
+/* GNOME libraries - GdkPixbuf item for the GNOME canvas
+ *
+ * Copyright (C) 1999 The Free Software Foundation
+ *
+ * Author: Federico Mena-Quintero <federico@gimp.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+#include <math.h>
+#include <libgnomecanvas/gnome-canvas.h>
+#include <libgnomecanvas/gnome-canvas-util.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <libart_lgpl/art_rgb_affine.h>
+#include <libart_lgpl/art_rgb_rgba_affine.h>
+#include "gnome-canvas-pixbuf.h"
+
+/* Private part of the GnomeCanvasPixbuf structure */
+typedef struct {
+ /* Our gdk-pixbuf */
+ GdkPixbuf *pixbuf;
+
+ /* Width value */
+ double width;
+
+ /* Height value */
+ double height;
+
+ /* X translation */
+ double x;
+
+ /* Y translation */
+ double y;
+
+ /* Whether dimensions are set and whether they are in pixels or units */
+ guint width_set : 1;
+ guint width_in_pixels : 1;
+ guint height_set : 1;
+ guint height_in_pixels : 1;
+ guint x_in_pixels : 1;
+ guint y_in_pixels : 1;
+
+ /* Whether the pixbuf has changed */
+ guint need_pixbuf_update : 1;
+
+ /* Whether the transformation or size have changed */
+ guint need_xform_update : 1;
+
+ /* Anchor */
+ GtkAnchorType anchor;
+} PixbufPrivate;
+
+/* Object argument IDs */
+enum {
+ PROP_0,
+ PROP_PIXBUF,
+ PROP_WIDTH,
+ PROP_WIDTH_SET,
+ PROP_WIDTH_IN_PIXELS,
+ PROP_HEIGHT,
+ PROP_HEIGHT_SET,
+ PROP_HEIGHT_IN_PIXELS,
+ PROP_X,
+ PROP_X_IN_PIXELS,
+ PROP_Y,
+ PROP_Y_IN_PIXELS,
+ PROP_ANCHOR
+};
+
+static void gnome_canvas_pixbuf_class_init (GnomeCanvasPixbufClass *class);
+static void gnome_canvas_pixbuf_init (GnomeCanvasPixbuf *cpb);
+static void gnome_canvas_pixbuf_destroy (GtkObject *object);
+static void gnome_canvas_pixbuf_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gnome_canvas_pixbuf_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+static void gnome_canvas_pixbuf_update (GnomeCanvasItem *item, double *affine,
+ ArtSVP *clip_path, int flags);
+static void gnome_canvas_pixbuf_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
+ int x, int y, int width, int height);
+static void gnome_canvas_pixbuf_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf);
+static double gnome_canvas_pixbuf_point (GnomeCanvasItem *item, double x, double y, int cx, int cy,
+ GnomeCanvasItem **actual_item);
+static void gnome_canvas_pixbuf_bounds (GnomeCanvasItem *item,
+ double *x1, double *y1, double *x2, double *y2);
+
+static GnomeCanvasItemClass *parent_class;
+
+
+
+/**
+ * gnome_canvas_pixbuf_get_type:
+ * @void:
+ *
+ * Registers the #GnomeCanvasPixbuf class if necessary, and returns the type ID
+ * associated to it.
+ *
+ * Return value: The type ID of the #GnomeCanvasPixbuf class.
+ **/
+GtkType
+gnome_canvas_pixbuf_get_type (void)
+{
+ static GType pixbuf_type;
+
+ if (!pixbuf_type) {
+ static const GTypeInfo object_info = {
+ sizeof (GnomeCanvasPixbufClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gnome_canvas_pixbuf_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (GnomeCanvasPixbuf),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) gnome_canvas_pixbuf_init,
+ NULL /* value_table */
+ };
+
+ pixbuf_type = g_type_register_static (GNOME_TYPE_CANVAS_ITEM, "GnomeCanvasPixbuf",
+ &object_info, 0);
+ }
+
+ return pixbuf_type;
+}
+
+/* Class initialization function for the pixbuf canvas item */
+static void
+gnome_canvas_pixbuf_class_init (GnomeCanvasPixbufClass *class)
+{
+ GObjectClass *gobject_class;
+ GtkObjectClass *object_class;
+ GnomeCanvasItemClass *item_class;
+
+ gobject_class = (GObjectClass *) class;
+ object_class = (GtkObjectClass *) class;
+ item_class = (GnomeCanvasItemClass *) class;
+
+ parent_class = g_type_class_peek_parent (class);
+
+ gobject_class->set_property = gnome_canvas_pixbuf_set_property;
+ gobject_class->get_property = gnome_canvas_pixbuf_get_property;
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_PIXBUF,
+ g_param_spec_object ("pixbuf", NULL, NULL,
+ GDK_TYPE_PIXBUF,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_WIDTH,
+ g_param_spec_double ("width", NULL, NULL,
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_WIDTH_SET,
+ g_param_spec_boolean ("width_set", NULL, NULL,
+ FALSE,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_WIDTH_IN_PIXELS,
+ g_param_spec_boolean ("width_in_pixels", NULL, NULL,
+ FALSE,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_HEIGHT,
+ g_param_spec_double ("height", NULL, NULL,
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_HEIGHT_SET,
+ g_param_spec_boolean ("height_set", NULL, NULL,
+ FALSE,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_HEIGHT_IN_PIXELS,
+ g_param_spec_boolean ("height_in_pixels", NULL, NULL,
+ FALSE,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_X,
+ g_param_spec_double ("x", NULL, NULL,
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_X_IN_PIXELS,
+ g_param_spec_boolean ("x_in_pixels", NULL, NULL,
+ FALSE,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_Y,
+ g_param_spec_double ("y", NULL, NULL,
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_Y_IN_PIXELS,
+ g_param_spec_boolean ("y_in_pixels", NULL, NULL,
+ FALSE,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_ANCHOR,
+ g_param_spec_enum ("anchor", NULL, NULL,
+ GTK_TYPE_ANCHOR_TYPE,
+ GTK_ANCHOR_NW,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+
+ object_class->destroy = gnome_canvas_pixbuf_destroy;
+
+ item_class->update = gnome_canvas_pixbuf_update;
+ item_class->draw = gnome_canvas_pixbuf_draw;
+ item_class->render = gnome_canvas_pixbuf_render;
+ item_class->point = gnome_canvas_pixbuf_point;
+ item_class->bounds = gnome_canvas_pixbuf_bounds;
+}
+
+/* Object initialization function for the pixbuf canvas item */
+static void
+gnome_canvas_pixbuf_init (GnomeCanvasPixbuf *gcp)
+{
+ PixbufPrivate *priv;
+
+ priv = g_new0 (PixbufPrivate, 1);
+ gcp->priv = priv;
+
+ priv->width = 0.0;
+ priv->height = 0.0;
+ priv->x = 0.0;
+ priv->y = 0.0;
+ priv->anchor = GTK_ANCHOR_NW;
+}
+
+/* Destroy handler for the pixbuf canvas item */
+static void
+gnome_canvas_pixbuf_destroy (GtkObject *object)
+{
+ GnomeCanvasItem *item;
+ GnomeCanvasPixbuf *gcp;
+ PixbufPrivate *priv;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GNOME_IS_CANVAS_PIXBUF (object));
+
+ item = GNOME_CANVAS_ITEM (object);
+ gcp = (GNOME_CANVAS_PIXBUF (object));
+ priv = gcp->priv;
+
+ /* remember, destroy can be run multiple times! */
+
+ if (priv) {
+ gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2);
+
+ if (priv->pixbuf)
+ gdk_pixbuf_unref (priv->pixbuf);
+
+ g_free (priv);
+ gcp->priv = NULL;
+ }
+
+ if (GTK_OBJECT_CLASS (parent_class)->destroy)
+ (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+}
+
+
+
+/* Set_property handler for the pixbuf canvas item */
+static void
+gnome_canvas_pixbuf_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GnomeCanvasItem *item;
+ GnomeCanvasPixbuf *gcp;
+ PixbufPrivate *priv;
+ GdkPixbuf *pixbuf;
+ double val;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GNOME_IS_CANVAS_PIXBUF (object));
+
+ item = GNOME_CANVAS_ITEM (object);
+ gcp = GNOME_CANVAS_PIXBUF (object);
+ priv = gcp->priv;
+
+ switch (param_id) {
+ case PROP_PIXBUF:
+ if (g_value_get_object (value))
+ pixbuf = GDK_PIXBUF (g_value_get_object (value));
+ else
+ pixbuf = NULL;
+ if (pixbuf != priv->pixbuf) {
+ if (pixbuf) {
+ g_return_if_fail
+ (gdk_pixbuf_get_colorspace (pixbuf) == GDK_COLORSPACE_RGB);
+ g_return_if_fail
+ (gdk_pixbuf_get_n_channels (pixbuf) == 3
+ || gdk_pixbuf_get_n_channels (pixbuf) == 4);
+ g_return_if_fail
+ (gdk_pixbuf_get_bits_per_sample (pixbuf) == 8);
+
+ gdk_pixbuf_ref (pixbuf);
+ }
+
+ if (priv->pixbuf)
+ gdk_pixbuf_unref (priv->pixbuf);
+
+ priv->pixbuf = pixbuf;
+ }
+
+ priv->need_pixbuf_update = TRUE;
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_WIDTH:
+ val = g_value_get_double (value);
+ g_return_if_fail (val >= 0.0);
+ priv->width = val;
+ priv->need_xform_update = TRUE;
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_WIDTH_SET:
+ priv->width_set = g_value_get_boolean (value);
+ priv->need_xform_update = TRUE;
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_WIDTH_IN_PIXELS:
+ priv->width_in_pixels = g_value_get_boolean (value);
+ priv->need_xform_update = TRUE;
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_HEIGHT:
+ val = g_value_get_double (value);
+ g_return_if_fail (val >= 0.0);
+ priv->height = val;
+ priv->need_xform_update = TRUE;
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_HEIGHT_SET:
+ priv->height_set = g_value_get_boolean (value);
+ priv->need_xform_update = TRUE;
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_HEIGHT_IN_PIXELS:
+ priv->height_in_pixels = g_value_get_boolean (value);
+ priv->need_xform_update = TRUE;
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_X:
+ priv->x = g_value_get_double (value);
+ priv->need_xform_update = TRUE;
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_X_IN_PIXELS:
+ priv->x_in_pixels = g_value_get_boolean (value);
+ priv->need_xform_update = TRUE;
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_Y:
+ priv->y = g_value_get_double (value);
+ priv->need_xform_update = TRUE;
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_Y_IN_PIXELS:
+ priv->y_in_pixels = g_value_get_boolean (value);
+ priv->need_xform_update = TRUE;
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_ANCHOR:
+ priv->anchor = g_value_get_enum (value);
+ priv->need_xform_update = TRUE;
+ gnome_canvas_item_request_update (item);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+/* Get_property handler for the pixbuf canvasi item */
+static void
+gnome_canvas_pixbuf_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GnomeCanvasPixbuf *gcp;
+ PixbufPrivate *priv;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GNOME_IS_CANVAS_PIXBUF (object));
+
+ gcp = GNOME_CANVAS_PIXBUF (object);
+ priv = gcp->priv;
+
+ switch (param_id) {
+ case PROP_PIXBUF:
+ g_value_set_object (value, G_OBJECT (priv->pixbuf));
+ break;
+
+ case PROP_WIDTH:
+ g_value_set_double (value, priv->width);
+ break;
+
+ case PROP_WIDTH_SET:
+ g_value_set_boolean (value, priv->width_set);
+ break;
+
+ case PROP_WIDTH_IN_PIXELS:
+ g_value_set_boolean (value, priv->width_in_pixels);
+ break;
+
+ case PROP_HEIGHT:
+ g_value_set_double (value, priv->height);
+ break;
+
+ case PROP_HEIGHT_SET:
+ g_value_set_boolean (value, priv->height_set);
+ break;
+
+ case PROP_HEIGHT_IN_PIXELS:
+ g_value_set_boolean (value, priv->height_in_pixels);
+ break;
+
+ case PROP_X:
+ g_value_set_double (value, priv->x);
+ break;
+
+ case PROP_X_IN_PIXELS:
+ g_value_set_boolean (value, priv->x_in_pixels);
+ break;
+
+ case PROP_Y:
+ g_value_set_double (value, priv->y);
+ break;
+
+ case PROP_Y_IN_PIXELS:
+ g_value_set_boolean (value, priv->y_in_pixels);
+ break;
+
+ case PROP_ANCHOR:
+ g_value_set_enum (value, priv->anchor);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+
+
+/* Bounds and utilities */
+
+/* Computes the amount by which the unit horizontal and vertical vectors will be
+ * scaled by an affine transformation.
+ */
+static void
+compute_xform_scaling (double *affine, ArtPoint *i_c, ArtPoint *j_c)
+{
+ ArtPoint orig, orig_c;
+ ArtPoint i, j;
+
+ /* Origin */
+
+ orig.x = 0.0;
+ orig.y = 0.0;
+ art_affine_point (&orig_c, &orig, affine);
+
+ /* Horizontal and vertical vectors */
+
+ i.x = 1.0;
+ i.y = 0.0;
+ art_affine_point (i_c, &i, affine);
+ i_c->x -= orig_c.x;
+ i_c->y -= orig_c.y;
+
+ j.x = 0.0;
+ j.y = 1.0;
+ art_affine_point (j_c, &j, affine);
+ j_c->x -= orig_c.x;
+ j_c->y -= orig_c.y;
+}
+
+/* computes the addtional resolution dependent affine needed to
+ * fit the image within its viewport defined by x,y,width and height
+ * args
+ */
+static void
+compute_viewport_affine (GnomeCanvasPixbuf *gcp, double *viewport_affine, double *i2c)
+{
+ PixbufPrivate *priv;
+ ArtPoint i_c, j_c;
+ double i_len, j_len;
+ double si_len, sj_len;
+ double ti_len, tj_len;
+ double scale[6], translate[6];
+ double w, h;
+ double x, y;
+
+ priv = gcp->priv;
+
+ /* Compute scaling vectors and required width/height */
+
+ compute_xform_scaling (i2c, &i_c, &j_c);
+
+ i_len = sqrt (i_c.x * i_c.x + i_c.y * i_c.y);
+ j_len = sqrt (j_c.x * j_c.x + j_c.y * j_c.y);
+
+ if (priv->width_set)
+ w = priv->width;
+ else
+ w = gdk_pixbuf_get_width (priv->pixbuf);
+
+ if (priv->height_set)
+ h = priv->height;
+ else
+ h = gdk_pixbuf_get_height (priv->pixbuf);
+
+ x = priv->x;
+ y = priv->y;
+
+ /* Convert i_len and j_len into scaling factors */
+
+ if (priv->width_in_pixels) {
+ if (i_len > GNOME_CANVAS_EPSILON)
+ si_len = 1.0 / i_len;
+ else
+ si_len = 0.0;
+ } else
+ si_len = 1.0;
+
+ si_len *= w / gdk_pixbuf_get_width (priv->pixbuf);
+
+ if (priv->height_in_pixels) {
+ if (j_len > GNOME_CANVAS_EPSILON)
+ sj_len = 1.0 / j_len;
+ else
+ sj_len = 0.0;
+ } else
+ sj_len = 1.0;
+
+ sj_len *= h / gdk_pixbuf_get_height (priv->pixbuf);
+
+ /* Calculate translation offsets */
+
+ if (priv->x_in_pixels) {
+ if (i_len > GNOME_CANVAS_EPSILON)
+ ti_len = 1.0 / i_len;
+ else
+ ti_len = 0.0;
+ } else
+ ti_len = 1.0;
+
+ switch (priv->anchor) {
+ case GTK_ANCHOR_NW:
+ case GTK_ANCHOR_W:
+ case GTK_ANCHOR_SW:
+ ti_len *= x;
+ break;
+
+ case GTK_ANCHOR_N:
+ case GTK_ANCHOR_CENTER:
+ case GTK_ANCHOR_S:
+ ti_len *= x - w * si_len / 2;
+ break;
+
+ case GTK_ANCHOR_NE:
+ case GTK_ANCHOR_E:
+ case GTK_ANCHOR_SE:
+ ti_len *= x - w * si_len;
+ break;
+
+ default:
+ break;
+ }
+
+ if (priv->y_in_pixels) {
+ if (j_len > GNOME_CANVAS_EPSILON)
+ tj_len = 1.0 / j_len;
+ else
+ tj_len = 0.0;
+ } else
+ tj_len = 1.0;
+
+ switch (priv->anchor) {
+ case GTK_ANCHOR_NW:
+ case GTK_ANCHOR_N:
+ case GTK_ANCHOR_NE:
+ tj_len *= y;
+ break;
+
+ case GTK_ANCHOR_W:
+ case GTK_ANCHOR_CENTER:
+ case GTK_ANCHOR_E:
+ tj_len *= y - h * sj_len / 2;
+ break;
+
+ case GTK_ANCHOR_SW:
+ case GTK_ANCHOR_S:
+ case GTK_ANCHOR_SE:
+ tj_len *= y - h * sj_len;
+ break;
+
+ default:
+ break;
+ }
+
+ /* Compute the final affine */
+
+ art_affine_scale (scale, si_len, sj_len);
+ art_affine_translate (translate, ti_len, tj_len);
+ art_affine_multiply (viewport_affine, scale, translate);
+}
+
+/* Computes the affine transformation with which the pixbuf needs to be
+ * transformed to render it on the canvas. This is not the same as the
+ * item_to_canvas transformation because we may need to scale the pixbuf
+ * by some other amount.
+ */
+static void
+compute_render_affine (GnomeCanvasPixbuf *gcp, double *ra, double *i2c)
+{
+ double va[6];
+
+ compute_viewport_affine (gcp, va, i2c);
+#ifdef GNOME_CANVAS_PIXBUF_VERBOSE
+ g_print ("va %g %g %g %g %g %g\n", va[0], va[1], va[2], va[3], va[4], va[5]);
+#endif
+ art_affine_multiply (ra, va, i2c);
+#ifdef GNOME_CANVAS_PIXBUF_VERBOSE
+ g_print ("ra %g %g %g %g %g %g\n", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5]);
+#endif
+}
+
+/* Recomputes the bounding box of a pixbuf canvas item. The horizontal and
+ * vertical dimensions may be specified in units or pixels, separately, so we
+ * have to compute the components individually for each dimension.
+ */
+static void
+recompute_bounding_box (GnomeCanvasPixbuf *gcp, gdouble *i2c)
+{
+ GnomeCanvasItem *item;
+ PixbufPrivate *priv;
+ double ra[6];
+ ArtDRect rect;
+
+ item = GNOME_CANVAS_ITEM (gcp);
+ priv = gcp->priv;
+
+ if (!priv->pixbuf) {
+ item->x1 = item->y1 = item->x2 = item->y2 = 0.0;
+ return;
+ }
+
+ rect.x0 = 0.0;
+ rect.x1 = gdk_pixbuf_get_width (priv->pixbuf);
+
+ rect.y0 = 0.0;
+ rect.y1 = gdk_pixbuf_get_height (priv->pixbuf);
+
+#ifdef GNOME_CANVAS_PIXBUF_VERBOSE
+ g_print ("i2c %g %g %g %g %g %g\n", i2c[0], i2c[1], i2c[2], i2c[3], i2c[4], i2c[5]);
+#endif
+ gnome_canvas_item_i2c_affine (item, i2c);
+#ifdef GNOME_CANVAS_PIXBUF_VERBOSE
+ g_print ("i2c %g %g %g %g %g %g\n", i2c[0], i2c[1], i2c[2], i2c[3], i2c[4], i2c[5]);
+#endif
+ compute_render_affine (gcp, ra, i2c);
+#ifdef GNOME_CANVAS_PIXBUF_VERBOSE
+ g_print ("ra %g %g %g %g %g %g\n", ra[0], ra[1], ra[2], ra[3], ra[4], ra[5]);
+#endif
+ art_drect_affine_transform (&rect, &rect, ra);
+
+ item->x1 = floor (rect.x0);
+ item->y1 = floor (rect.y0);
+ item->x2 = ceil (rect.x1);
+ item->y2 = ceil (rect.y1);
+}
+
+
+
+/* Update sequence */
+
+/* Update handler for the pixbuf canvas item */
+static void
+gnome_canvas_pixbuf_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
+{
+ GnomeCanvasPixbuf *gcp;
+ PixbufPrivate *priv;
+
+ gcp = GNOME_CANVAS_PIXBUF (item);
+ priv = gcp->priv;
+
+ if (parent_class->update)
+ (* parent_class->update) (item, affine, clip_path, flags);
+
+ /* the optimzations below cause rarely triggered redrawing bugs and
+ * don't seem to actually save much performance. so it's probably
+ * better to turn them off, than to chase subtle optimization bugs
+ * throughgout all of gnome-canvas-pixbuf.c - TIMJ
+ */
+#ifdef USE_BROKEN_OPTIMIZATIONS
+ if (((flags & GNOME_CANVAS_UPDATE_VISIBILITY)
+ && !(GTK_OBJECT_FLAGS (item) & GNOME_CANVAS_ITEM_VISIBLE))
+ || (flags & GNOME_CANVAS_UPDATE_AFFINE)
+ || priv->need_pixbuf_update
+ || priv->need_xform_update) {
+ gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2);
+ }
+
+ /* If we need a pixbuf update, or if the item changed visibility to
+ * shown, recompute the bounding box.
+ */
+ if (priv->need_pixbuf_update
+ || priv->need_xform_update
+ || ((flags & GNOME_CANVAS_UPDATE_VISIBILITY)
+ && (GTK_OBJECT_FLAGS (gcp) & GNOME_CANVAS_ITEM_VISIBLE))
+ || (flags & GNOME_CANVAS_UPDATE_AFFINE)) {
+ recompute_bounding_box (gcp, affine);
+#ifdef GNOME_CANVAS_PIXBUF_VERBOSE
+ g_print ("BBox is %g %g %g %g\n", item->x1, item->y1, item->x2, item->y2);
+#endif
+ gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2);
+ priv->need_pixbuf_update = FALSE;
+ priv->need_xform_update = FALSE;
+ }
+#else /* ordinary update logic */
+ gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2);
+ recompute_bounding_box (gcp, affine);
+ gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2);
+ priv->need_pixbuf_update = FALSE;
+ priv->need_xform_update = FALSE;
+#endif
+}
+
+
+
+/* Rendering */
+
+/* This is private to libart, but we need it. Sigh. */
+extern void art_rgb_affine_run (int *p_x0, int *p_x1, int y, int src_width, int src_height,
+ const double affine[6]);
+
+/* Fills the specified buffer with the transformed version of a pixbuf */
+static void
+transform_pixbuf (guchar *dest, int x, int y, int width, int height, int rowstride,
+ GdkPixbuf *pixbuf, double *affine)
+{
+ int xx, yy;
+ double inv[6];
+ guchar *src, *d;
+ ArtPoint src_p, dest_p;
+ int run_x1, run_x2;
+ int src_x, src_y;
+ int i;
+
+ art_affine_invert (inv, affine);
+
+ for (yy = 0; yy < height; yy++) {
+ dest_p.y = y + yy + 0.5;
+
+ run_x1 = x;
+ run_x2 = x + width;
+ art_rgb_affine_run (&run_x1, &run_x2, yy + y,
+ gdk_pixbuf_get_width (pixbuf),
+ gdk_pixbuf_get_height (pixbuf),
+ inv);
+
+ d = dest + yy * rowstride + (run_x1 - x) * 4;
+
+ for (xx = run_x1; xx < run_x2; xx++) {
+ dest_p.x = xx + 0.5;
+ art_affine_point (&src_p, &dest_p, inv);
+ src_x = floor (src_p.x);
+ src_y = floor (src_p.y);
+
+ src =
+ gdk_pixbuf_get_pixels (pixbuf) + src_y *
+ gdk_pixbuf_get_rowstride (pixbuf) + src_x *
+ gdk_pixbuf_get_n_channels (pixbuf);
+
+ for (i = 0; i < gdk_pixbuf_get_n_channels (pixbuf); i++)
+ *d++ = *src++;
+
+ if (!gdk_pixbuf_get_has_alpha(pixbuf))
+ *d++ = 255; /* opaque */
+ }
+ }
+}
+
+/* Draw handler for the pixbuf canvas item */
+static void
+gnome_canvas_pixbuf_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
+ int x, int y, int width, int height)
+{
+ GnomeCanvasPixbuf *gcp;
+ PixbufPrivate *priv;
+ double i2c[6], render_affine[6];
+ guchar *buf;
+ GdkPixbuf *pixbuf;
+ ArtIRect p_rect, a_rect, d_rect;
+ int w, h;
+
+ gcp = GNOME_CANVAS_PIXBUF (item);
+ priv = gcp->priv;
+
+ if (!priv->pixbuf)
+ return;
+
+ gnome_canvas_item_i2c_affine (item, i2c);
+ compute_render_affine (gcp, render_affine, i2c);
+
+ /* Compute the area we need to repaint */
+
+ p_rect.x0 = item->x1;
+ p_rect.y0 = item->y1;
+ p_rect.x1 = item->x2;
+ p_rect.y1 = item->y2;
+
+ a_rect.x0 = x;
+ a_rect.y0 = y;
+ a_rect.x1 = x + width;
+ a_rect.y1 = y + height;
+
+ art_irect_intersect (&d_rect, &p_rect, &a_rect);
+ if (art_irect_empty (&d_rect))
+ return;
+
+ /* Create a temporary buffer and transform the pixbuf there */
+
+ w = d_rect.x1 - d_rect.x0;
+ h = d_rect.y1 - d_rect.y0;
+
+ buf = g_new0 (guchar, w * h * 4);
+ transform_pixbuf (buf,
+ d_rect.x0, d_rect.y0,
+ w, h,
+ w * 4,
+ priv->pixbuf, render_affine);
+
+ pixbuf = gdk_pixbuf_new_from_data (buf, GDK_COLORSPACE_RGB,
+ TRUE,
+ 8, w, h,
+ w * 4,
+ NULL, NULL);
+
+ gdk_pixbuf_render_to_drawable_alpha (pixbuf, drawable,
+ 0, 0,
+ d_rect.x0 - x, d_rect.y0 - y,
+ w, h,
+ GDK_PIXBUF_ALPHA_FULL,
+ 0,
+ GDK_RGB_DITHER_MAX,
+ d_rect.x0, d_rect.y0);
+
+ gdk_pixbuf_unref (pixbuf);
+ g_free (buf);
+}
+
+/* Render handler for the pixbuf canvas item */
+static void
+gnome_canvas_pixbuf_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf)
+{
+ GnomeCanvasPixbuf *gcp;
+ PixbufPrivate *priv;
+ double i2c[6], render_affine[6];
+
+ gcp = GNOME_CANVAS_PIXBUF (item);
+ priv = gcp->priv;
+
+ if (!priv->pixbuf)
+ return;
+
+ gnome_canvas_item_i2c_affine (item, i2c);
+ compute_render_affine (gcp, render_affine, i2c);
+ gnome_canvas_buf_ensure_buf (buf);
+
+
+ if ((fabs (render_affine[1]) < GNOME_CANVAS_EPSILON) &&
+ (fabs (render_affine[2]) < GNOME_CANVAS_EPSILON) &&
+ render_affine[0] > 0.0 &&
+ render_affine[3] > 0.0)
+ {
+ GdkPixbuf *dest_pixbuf;
+ int x0, y0, x1, y1;
+
+ dest_pixbuf = gdk_pixbuf_new_from_data (buf->buf,
+ GDK_COLORSPACE_RGB,
+ FALSE,
+ 8,
+ buf->rect.x1 - buf->rect.x0,
+ buf->rect.y1 - buf->rect.y0,
+ buf->buf_rowstride,
+ NULL, NULL);
+
+
+ x0 = floor (render_affine[4] - buf->rect.x0 + 0.5);
+ y0 = floor (render_affine[5] - buf->rect.y0 + 0.5);
+
+ x1 = x0 + floor (gdk_pixbuf_get_width (priv->pixbuf) * render_affine[0] + 0.5);
+ y1 = y0 + floor (gdk_pixbuf_get_height (priv->pixbuf) * render_affine[3] + 0.5);
+
+ x0 = MAX (x0, 0);
+ x0 = MIN (x0, buf->rect.x1 - buf->rect.x0);
+ y0 = MAX (y0, 0);
+ y0 = MIN (y0, buf->rect.y1 - buf->rect.y0);
+
+ x1 = MAX (x1, 0);
+ x1 = MIN (x1, buf->rect.x1 - buf->rect.x0);
+ y1 = MAX (y1, 0);
+ y1 = MIN (y1, buf->rect.y1 - buf->rect.y0);
+
+ gdk_pixbuf_composite (priv->pixbuf,
+ dest_pixbuf,
+ x0, y0,
+ x1 - x0, y1 - y0,
+ render_affine[4] - buf->rect.x0,
+ render_affine[5] - buf->rect.y0,
+ render_affine[0],
+ render_affine[3],
+ GDK_INTERP_BILINEAR,
+ 255);
+
+ gdk_pixbuf_unref (dest_pixbuf);
+ }
+ else if (gdk_pixbuf_get_has_alpha(priv->pixbuf))
+ art_rgb_rgba_affine (buf->buf,
+ buf->rect.x0, buf->rect.y0, buf->rect.x1, buf->rect.y1,
+ buf->buf_rowstride,
+ gdk_pixbuf_get_pixels(priv->pixbuf),
+ gdk_pixbuf_get_width(priv->pixbuf),
+ gdk_pixbuf_get_height(priv->pixbuf),
+ gdk_pixbuf_get_rowstride(priv->pixbuf),
+ render_affine,
+ ART_FILTER_NEAREST,
+ NULL);
+ else
+ art_rgb_affine (buf->buf,
+ buf->rect.x0, buf->rect.y0, buf->rect.x1, buf->rect.y1,
+ buf->buf_rowstride,
+ gdk_pixbuf_get_pixels(priv->pixbuf),
+ gdk_pixbuf_get_width(priv->pixbuf),
+ gdk_pixbuf_get_height(priv->pixbuf),
+ gdk_pixbuf_get_rowstride(priv->pixbuf),
+ render_affine,
+ ART_FILTER_NEAREST,
+ NULL);
+
+ buf->is_bg = 0;
+}
+
+
+
+/* Point handler for the pixbuf canvas item */
+static double
+gnome_canvas_pixbuf_point (GnomeCanvasItem *item, double x, double y, int cx, int cy,
+ GnomeCanvasItem **actual_item)
+{
+ GnomeCanvasPixbuf *gcp;
+ PixbufPrivate *priv;
+ double i2c[6], render_affine[6], inv[6];
+ ArtPoint c, p;
+ int px, py;
+ double no_hit;
+ guchar *src;
+ GdkPixbuf *pixbuf;
+
+ gcp = GNOME_CANVAS_PIXBUF (item);
+ priv = gcp->priv;
+ pixbuf = priv->pixbuf;
+
+ *actual_item = item;
+
+ no_hit = item->canvas->pixels_per_unit * 2 + 10;
+
+ if (!priv->pixbuf)
+ return no_hit;
+
+ gnome_canvas_item_i2c_affine (item, i2c);
+ compute_render_affine (gcp, render_affine, i2c);
+ art_affine_invert (inv, render_affine);
+
+ c.x = cx;
+ c.y = cy;
+ art_affine_point (&p, &c, inv);
+ px = p.x;
+ py = p.y;
+
+ if (px < 0 || px >= gdk_pixbuf_get_width (pixbuf) ||
+ py < 0 || py >= gdk_pixbuf_get_height (pixbuf))
+ return no_hit;
+
+ if (!gdk_pixbuf_get_has_alpha (pixbuf))
+ return 0.0;
+
+ src = gdk_pixbuf_get_pixels (pixbuf) +
+ py * gdk_pixbuf_get_rowstride (pixbuf) +
+ px * gdk_pixbuf_get_n_channels (pixbuf);
+
+ if (src[3] < 128)
+ return no_hit;
+ else
+ return 0.0;
+}
+
+
+
+/* Bounds handler for the pixbuf canvas item */
+static void
+gnome_canvas_pixbuf_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
+{
+ GnomeCanvasPixbuf *gcp;
+ PixbufPrivate *priv;
+ double i2c[6], viewport_affine[6];
+ ArtDRect rect;
+
+ gcp = GNOME_CANVAS_PIXBUF (item);
+ priv = gcp->priv;
+
+ if (!priv->pixbuf) {
+ *x1 = *y1 = *x2 = *y2 = 0.0;
+ return;
+ }
+
+ rect.x0 = 0.0;
+ rect.x1 = gdk_pixbuf_get_width (priv->pixbuf);
+
+ rect.y0 = 0.0;
+ rect.y1 = gdk_pixbuf_get_height (priv->pixbuf);
+
+ gnome_canvas_item_i2c_affine (item, i2c);
+ compute_viewport_affine (gcp, viewport_affine, i2c);
+ art_drect_affine_transform (&rect, &rect, viewport_affine);
+
+ *x1 = rect.x0;
+ *y1 = rect.y0;
+ *x2 = rect.x1;
+ *y2 = rect.y1;
+}
diff --git a/src/libgnomecanvas/gnome-canvas-pixbuf.h b/src/libgnomecanvas/gnome-canvas-pixbuf.h
new file mode 100644
index 0000000..ee97ec9
--- /dev/null
+++ b/src/libgnomecanvas/gnome-canvas-pixbuf.h
@@ -0,0 +1,62 @@
+/* GNOME libraries - GdkPixbuf item for the GNOME canvas
+ *
+ * Copyright (C) 1999 The Free Software Foundation
+ *
+ * Author: Federico Mena-Quintero <federico@gimp.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GNOME_CANVAS_PIXBUF_H
+#define GNOME_CANVAS_PIXBUF_H
+
+
+#include <libgnomecanvas/gnome-canvas.h>
+
+G_BEGIN_DECLS
+
+
+
+#define GNOME_TYPE_CANVAS_PIXBUF (gnome_canvas_pixbuf_get_type ())
+#define GNOME_CANVAS_PIXBUF(obj) (GTK_CHECK_CAST ((obj), GNOME_TYPE_CANVAS_PIXBUF, GnomeCanvasPixbuf))
+#define GNOME_CANVAS_PIXBUF_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GNOME_TYPE_CANVAS_PIXBUF, GnomeCanvasPixbufClass))
+#define GNOME_IS_CANVAS_PIXBUF(obj) (GTK_CHECK_TYPE ((obj), GNOME_TYPE_CANVAS_PIXBUF))
+#define GNOME_IS_CANVAS_PIXBUF_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_CANVAS_PIXBUF))
+#define GNOME_CANVAS_PIXBUF_GET_CLASS(obj) (GTK_CHECK_GET_CLASS ((obj), GNOME_TYPE_CANVAS_PIXBUF, GnomeCanvasPixbufClass))
+
+
+typedef struct _GnomeCanvasPixbuf GnomeCanvasPixbuf;
+typedef struct _GnomeCanvasPixbufClass GnomeCanvasPixbufClass;
+
+struct _GnomeCanvasPixbuf {
+ GnomeCanvasItem item;
+
+ /* Private data */
+ gpointer priv;
+};
+
+struct _GnomeCanvasPixbufClass {
+ GnomeCanvasItemClass parent_class;
+};
+
+
+GType gnome_canvas_pixbuf_get_type (void) G_GNUC_CONST;
+
+
+
+G_END_DECLS
+
+#endif
diff --git a/src/libgnomecanvas/gnome-canvas-polygon.c b/src/libgnomecanvas/gnome-canvas-polygon.c
new file mode 100644
index 0000000..20c6c0f
--- /dev/null
+++ b/src/libgnomecanvas/gnome-canvas-polygon.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ @NOTATION@
+ */
+/* Polygon item type for GnomeCanvas widget
+ *
+ * GnomeCanvas is basically a port of the Tk toolkit's most excellent canvas widget. Tk is
+ * copyrighted by the Regents of the University of California, Sun Microsystems, and other parties.
+ *
+ * Author: Federico Mena <federico@nuclecu.unam.mx>
+ * Rusty Conover <rconover@bangtail.net>
+ */
+
+#include <config.h>
+#include <math.h>
+#include <string.h>
+#include "libart_lgpl/art_vpath.h"
+#include "libart_lgpl/art_svp.h"
+#include "libart_lgpl/art_svp_vpath.h"
+#include "libart_lgpl/art_svp_vpath_stroke.h"
+#include "libgnomecanvas.h"
+
+#include "gnome-canvas-shape.h"
+
+
+#define NUM_STATIC_POINTS 256 /* Number of static points to use to avoid allocating arrays */
+
+
+enum {
+ PROP_0,
+ PROP_POINTS
+};
+
+
+static void gnome_canvas_polygon_class_init (GnomeCanvasPolygonClass *class);
+static void gnome_canvas_polygon_init (GnomeCanvasPolygon *poly);
+static void gnome_canvas_polygon_destroy (GtkObject *object);
+static void gnome_canvas_polygon_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gnome_canvas_polygon_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+static void gnome_canvas_polygon_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags);
+
+static GnomeCanvasItemClass *parent_class;
+
+GType
+gnome_canvas_polygon_get_type (void)
+{
+ static GType polygon_type;
+
+ if (!polygon_type) {
+ static const GTypeInfo object_info = {
+ sizeof (GnomeCanvasPolygonClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gnome_canvas_polygon_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (GnomeCanvasPolygon),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) gnome_canvas_polygon_init,
+ NULL /* value_table */
+ };
+
+ polygon_type = g_type_register_static (GNOME_TYPE_CANVAS_SHAPE, "GnomeCanvasPolygon",
+ &object_info, 0);
+ }
+
+ return polygon_type;
+}
+
+static void
+gnome_canvas_polygon_class_init (GnomeCanvasPolygonClass *class)
+{
+ GObjectClass *gobject_class;
+ GtkObjectClass *object_class;
+ GnomeCanvasItemClass *item_class;
+
+ gobject_class = (GObjectClass *) class;
+ object_class = (GtkObjectClass *) class;
+ item_class = (GnomeCanvasItemClass *) class;
+
+ parent_class = g_type_class_peek_parent (class);
+
+ gobject_class->set_property = gnome_canvas_polygon_set_property;
+ gobject_class->get_property = gnome_canvas_polygon_get_property;
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_POINTS,
+ g_param_spec_boxed ("points", NULL, NULL,
+ GNOME_TYPE_CANVAS_POINTS,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+
+ object_class->destroy = gnome_canvas_polygon_destroy;
+
+ item_class->update = gnome_canvas_polygon_update;
+}
+
+static void
+gnome_canvas_polygon_init (GnomeCanvasPolygon *poly)
+{
+ poly->path_def = NULL;
+}
+
+static void
+gnome_canvas_polygon_destroy (GtkObject *object)
+{
+ GnomeCanvasPolygon *poly;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GNOME_IS_CANVAS_POLYGON (object));
+
+ poly = GNOME_CANVAS_POLYGON (object);
+
+ /* remember, destroy can be run multiple times! */
+
+ if(poly->path_def)
+ gnome_canvas_path_def_unref(poly->path_def);
+
+ poly->path_def = NULL;
+
+
+ if (GTK_OBJECT_CLASS (parent_class)->destroy)
+ (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+}
+
+static void
+set_points (GnomeCanvasPolygon *poly, GnomeCanvasPoints *points)
+{
+ int i;
+
+
+ if (poly->path_def)
+ gnome_canvas_path_def_unref(poly->path_def);
+
+ if (!points) {
+ poly->path_def = gnome_canvas_path_def_new();
+ gnome_canvas_shape_set_path_def (GNOME_CANVAS_SHAPE (poly), poly->path_def);
+ return;
+ }
+
+
+ /* Optomize the path def to the number of points */
+ poly->path_def = gnome_canvas_path_def_new_sized(points->num_points+1);
+
+#if 0
+ /* No need for explicit duplicate, as closepaths does it for us (Lauris) */
+ /* See if we need to duplicate the first point */
+ duplicate = ((points->coords[0] != points->coords[2 * points->num_points - 2])
+ || (points->coords[1] != points->coords[2 * points->num_points - 1]));
+#endif
+
+
+ gnome_canvas_path_def_moveto (poly->path_def, points->coords[0], points->coords[1]);
+
+ for (i = 1; i < points->num_points; i++) {
+ gnome_canvas_path_def_lineto(poly->path_def, points->coords[i * 2], points->coords[(i * 2) + 1]);
+ }
+
+ gnome_canvas_path_def_closepath (poly->path_def);
+
+ gnome_canvas_shape_set_path_def (GNOME_CANVAS_SHAPE (poly), poly->path_def);
+}
+
+
+static void
+gnome_canvas_polygon_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GnomeCanvasItem *item;
+ GnomeCanvasPolygon *poly;
+ GnomeCanvasPoints *points;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GNOME_IS_CANVAS_POLYGON (object));
+
+ item = GNOME_CANVAS_ITEM (object);
+ poly = GNOME_CANVAS_POLYGON (object);
+
+ switch (param_id) {
+ case PROP_POINTS:
+ points = g_value_get_boxed (value);
+
+ set_points (poly, points);
+
+ gnome_canvas_item_request_update (item);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+
+static void
+gnome_canvas_polygon_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GNOME_IS_CANVAS_POLYGON (object));
+
+ switch (param_id) {
+ case PROP_POINTS:
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+
+static void
+gnome_canvas_polygon_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
+{
+ /* Since the path has already been defined just pass the update up. */
+
+ if (parent_class->update)
+ (* parent_class->update) (item, affine, clip_path, flags);
+}
diff --git a/src/libgnomecanvas/gnome-canvas-polygon.h b/src/libgnomecanvas/gnome-canvas-polygon.h
new file mode 100644
index 0000000..3fb8267
--- /dev/null
+++ b/src/libgnomecanvas/gnome-canvas-polygon.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ @NOTATION@
+ */
+/* Polygon item type for GnomeCanvas widget
+ *
+ * GnomeCanvas is basically a port of the Tk toolkit's most excellent canvas widget. Tk is
+ * copyrighted by the Regents of the University of California, Sun Microsystems, and other parties.
+ *
+ *
+ * Author: Federico Mena <federico@nuclecu.unam.mx>
+ * Rusty Conover <rconover@bangtail.net>
+ */
+
+#ifndef GNOME_CANVAS_POLYGON_H
+#define GNOME_CANVAS_POLYGON_H
+
+
+#include <libgnomecanvas/gnome-canvas.h>
+#include <libgnomecanvas/gnome-canvas-shape.h>
+#include <libgnomecanvas/gnome-canvas-path-def.h>
+
+G_BEGIN_DECLS
+
+
+/* Polygon item for the canvas. A polygon is a bit different from rectangles and ellipses in that
+ * points inside it will always be considered "inside", even if the fill color is not set. If you
+ * want to have a hollow polygon, use a line item instead.
+ *
+ * The following object arguments are available:
+ *
+ * name type read/write description
+ * ------------------------------------------------------------------------------------------
+ * points GnomeCanvasPoints* RW Pointer to a GnomeCanvasPoints structure.
+ * This can be created by a call to
+ * gnome_canvas_points_new() (in gnome-canvas-util.h).
+ * X coordinates are in the even indices of the
+ * points->coords array, Y coordinates are in
+ * the odd indices.
+ */
+
+#define GNOME_TYPE_CANVAS_POLYGON (gnome_canvas_polygon_get_type ())
+#define GNOME_CANVAS_POLYGON(obj) (GTK_CHECK_CAST ((obj), GNOME_TYPE_CANVAS_POLYGON, GnomeCanvasPolygon))
+#define GNOME_CANVAS_POLYGON_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GNOME_TYPE_CANVAS_POLYGON, GnomeCanvasPolygonClass))
+#define GNOME_IS_CANVAS_POLYGON(obj) (GTK_CHECK_TYPE ((obj), GNOME_TYPE_CANVAS_POLYGON))
+#define GNOME_IS_CANVAS_POLYGON_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_CANVAS_POLYGON))
+#define GNOME_CANVAS_POLYGON_GET_CLASS(obj) (GTK_CHECK_GET_CLASS ((obj), GNOME_TYPE_CANVAS_POLYGON, GnomeCanvasPolygonClass))
+
+
+typedef struct _GnomeCanvasPolygon GnomeCanvasPolygon;
+typedef struct _GnomeCanvasPolygonClass GnomeCanvasPolygonClass;
+
+struct _GnomeCanvasPolygon {
+ GnomeCanvasShape item;
+
+ GnomeCanvasPathDef *path_def;
+};
+
+struct _GnomeCanvasPolygonClass {
+ GnomeCanvasShapeClass parent_class;
+};
+
+
+/* Standard Gtk function */
+GType gnome_canvas_polygon_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+#endif
diff --git a/src/libgnomecanvas/gnome-canvas-rect-ellipse.c b/src/libgnomecanvas/gnome-canvas-rect-ellipse.c
new file mode 100644
index 0000000..0513e83
--- /dev/null
+++ b/src/libgnomecanvas/gnome-canvas-rect-ellipse.c
@@ -0,0 +1,431 @@
+/*
+ * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ @NOTATION@
+ */
+/* Rectangle and ellipse item types for GnomeCanvas widget
+ *
+ * GnomeCanvas is basically a port of the Tk toolkit's most excellent canvas widget. Tk is
+ * copyrighted by the Regents of the University of California, Sun Microsystems, and other parties.
+ *
+ *
+ * Authors: Federico Mena <federico@nuclecu.unam.mx>
+ * Rusty Conover <rconover@bangtail.net>
+ */
+
+#include <config.h>
+#include <math.h>
+#include "gnome-canvas-rect-ellipse.h"
+#include "gnome-canvas-util.h"
+#include "gnome-canvas-shape.h"
+
+
+#include "libart_lgpl/art_vpath.h"
+#include "libart_lgpl/art_svp.h"
+#include "libart_lgpl/art_svp_vpath.h"
+#include "libart_lgpl/art_rgb_svp.h"
+
+/* Base class for rectangle and ellipse item types */
+
+#define noVERBOSE
+
+enum {
+ PROP_0,
+ PROP_X1,
+ PROP_Y1,
+ PROP_X2,
+ PROP_Y2
+};
+
+
+static void gnome_canvas_re_class_init (GnomeCanvasREClass *class);
+static void gnome_canvas_re_init (GnomeCanvasRE *re);
+static void gnome_canvas_re_destroy (GtkObject *object);
+static void gnome_canvas_re_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gnome_canvas_re_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+static void gnome_canvas_rect_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags);
+static void gnome_canvas_ellipse_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags);
+
+static GnomeCanvasItemClass *re_parent_class;
+
+
+GType
+gnome_canvas_re_get_type (void)
+{
+ static GType re_type;
+
+ if (!re_type) {
+ static const GTypeInfo object_info = {
+ sizeof (GnomeCanvasREClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gnome_canvas_re_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (GnomeCanvasRE),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) gnome_canvas_re_init,
+ NULL /* value_table */
+ };
+
+ re_type = g_type_register_static (GNOME_TYPE_CANVAS_SHAPE, "GnomeCanvasRE",
+ &object_info, 0);
+ }
+
+ return re_type;
+}
+
+static void
+gnome_canvas_re_class_init (GnomeCanvasREClass *class)
+{
+ GObjectClass *gobject_class;
+ GtkObjectClass *object_class;
+
+ gobject_class = (GObjectClass *) class;
+ object_class = (GtkObjectClass *) class;
+
+ re_parent_class = g_type_class_peek_parent (class);
+
+ gobject_class->set_property = gnome_canvas_re_set_property;
+ gobject_class->get_property = gnome_canvas_re_get_property;
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_X1,
+ g_param_spec_double ("x1", NULL, NULL,
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_Y1,
+ g_param_spec_double ("y1", NULL, NULL,
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_X2,
+ g_param_spec_double ("x2", NULL, NULL,
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_Y2,
+ g_param_spec_double ("y2", NULL, NULL,
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+
+ object_class->destroy = gnome_canvas_re_destroy;
+}
+
+static void
+gnome_canvas_re_init (GnomeCanvasRE *re)
+{
+ re->x1 = 0.0;
+ re->y1 = 0.0;
+ re->x2 = 0.0;
+ re->y2 = 0.0;
+ re->path_dirty = 0;
+}
+
+static void
+gnome_canvas_re_destroy (GtkObject *object)
+{
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GNOME_IS_CANVAS_RE (object));
+
+ if (GTK_OBJECT_CLASS (re_parent_class)->destroy)
+ (* GTK_OBJECT_CLASS (re_parent_class)->destroy) (object);
+}
+
+static void
+gnome_canvas_re_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GnomeCanvasItem *item;
+ GnomeCanvasRE *re;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GNOME_IS_CANVAS_RE (object));
+
+ item = GNOME_CANVAS_ITEM (object);
+ re = GNOME_CANVAS_RE (object);
+
+ switch (param_id) {
+ case PROP_X1:
+ re->x1 = g_value_get_double (value);
+ re->path_dirty = 1;
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_Y1:
+ re->y1 = g_value_get_double (value);
+ re->path_dirty = 1;
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_X2:
+ re->x2 = g_value_get_double (value);
+ re->path_dirty = 1;
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_Y2:
+ re->y2 = g_value_get_double (value);
+ re->path_dirty = 1;
+ gnome_canvas_item_request_update (item);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+gnome_canvas_re_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GnomeCanvasRE *re;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GNOME_IS_CANVAS_RE (object));
+
+ re = GNOME_CANVAS_RE (object);
+
+ switch (param_id) {
+ case PROP_X1:
+ g_value_set_double (value, re->x1);
+ break;
+
+ case PROP_Y1:
+ g_value_set_double (value, re->y1);
+ break;
+
+ case PROP_X2:
+ g_value_set_double (value, re->x2);
+ break;
+
+ case PROP_Y2:
+ g_value_set_double (value, re->y2);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+/* Rectangle item */
+static void gnome_canvas_rect_class_init (GnomeCanvasRectClass *class);
+
+
+
+GType
+gnome_canvas_rect_get_type (void)
+{
+ static GType rect_type;
+
+ if (!rect_type) {
+ static const GTypeInfo object_info = {
+ sizeof (GnomeCanvasRectClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gnome_canvas_rect_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (GnomeCanvasRect),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) NULL,
+ NULL /* value_table */
+ };
+
+ rect_type = g_type_register_static (GNOME_TYPE_CANVAS_RE, "GnomeCanvasRect",
+ &object_info, 0);
+ }
+
+ return rect_type;
+}
+
+static void
+gnome_canvas_rect_class_init (GnomeCanvasRectClass *class)
+{
+ GnomeCanvasItemClass *item_class;
+
+ item_class = (GnomeCanvasItemClass *) class;
+
+ item_class->update = gnome_canvas_rect_update;
+}
+
+static void
+gnome_canvas_rect_update (GnomeCanvasItem *item, double affine[6], ArtSVP *clip_path, gint flags)
+{ GnomeCanvasRE *re;
+
+ GnomeCanvasPathDef *path_def;
+
+ re = GNOME_CANVAS_RE(item);
+
+ if (re->path_dirty) {
+ path_def = gnome_canvas_path_def_new ();
+
+ gnome_canvas_path_def_moveto(path_def, re->x1, re->y1);
+ gnome_canvas_path_def_lineto(path_def, re->x2, re->y1);
+ gnome_canvas_path_def_lineto(path_def, re->x2, re->y2);
+ gnome_canvas_path_def_lineto(path_def, re->x1, re->y2);
+ gnome_canvas_path_def_lineto(path_def, re->x1, re->y1);
+ gnome_canvas_path_def_closepath_current(path_def);
+ gnome_canvas_shape_set_path_def (GNOME_CANVAS_SHAPE (item), path_def);
+ gnome_canvas_path_def_unref(path_def);
+ re->path_dirty = 0;
+ }
+
+ if (re_parent_class->update)
+ (* re_parent_class->update) (item, affine, clip_path, flags);
+}
+
+/* Ellipse item */
+
+
+static void gnome_canvas_ellipse_class_init (GnomeCanvasEllipseClass *class);
+
+
+GType
+gnome_canvas_ellipse_get_type (void)
+{
+ static GType ellipse_type;
+
+ if (!ellipse_type) {
+ static const GTypeInfo object_info = {
+ sizeof (GnomeCanvasEllipseClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gnome_canvas_ellipse_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (GnomeCanvasEllipse),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) NULL,
+ NULL /* value_table */
+ };
+
+ ellipse_type = g_type_register_static (GNOME_TYPE_CANVAS_RE, "GnomeCanvasEllipse",
+ &object_info, 0);
+ }
+
+ return ellipse_type;
+}
+
+static void
+gnome_canvas_ellipse_class_init (GnomeCanvasEllipseClass *class)
+{
+ GnomeCanvasItemClass *item_class;
+
+ item_class = (GnomeCanvasItemClass *) class;
+
+ item_class->update = gnome_canvas_ellipse_update;
+}
+
+#define N_PTS 90
+
+static void
+gnome_canvas_ellipse_update (GnomeCanvasItem *item, double affine[6], ArtSVP *clip_path, gint flags) {
+ GnomeCanvasPathDef *path_def;
+ GnomeCanvasRE *re;
+
+ re = GNOME_CANVAS_RE(item);
+
+ if (re->path_dirty) {
+ gdouble cx, cy, rx, ry;
+ gdouble beta = 0.26521648983954400922; /* 4*(1-cos(pi/8))/(3*sin(pi/8)) */
+ gdouble sincosA = 0.70710678118654752440; /* sin (pi/4), cos (pi/4) */
+ gdouble dx1, dy1, dx2, dy2;
+ gdouble mx, my;
+
+ path_def = gnome_canvas_path_def_new();
+
+ cx = (re->x2 + re->x1) * 0.5;
+ cy = (re->y2 + re->y1) * 0.5;
+ rx = re->x2 - cx;
+ ry = re->y2 - cy;
+
+ dx1 = beta * rx;
+ dy1 = beta * ry;
+ dx2 = beta * rx * sincosA;
+ dy2 = beta * ry * sincosA;
+ mx = rx * sincosA;
+ my = ry * sincosA;
+
+ gnome_canvas_path_def_moveto (path_def, cx + rx, cy);
+ gnome_canvas_path_def_curveto (path_def,
+ cx + rx, cy - dy1,
+ cx + mx + dx2, cy - my + dy2,
+ cx + mx, cy - my);
+ gnome_canvas_path_def_curveto (path_def,
+ cx + mx - dx2, cy - my - dy2,
+ cx + dx1, cy - ry,
+ cx, cy - ry);
+ gnome_canvas_path_def_curveto (path_def,
+ cx - dx1, cy - ry,
+ cx - mx + dx2, cy - my - dy2,
+ cx - mx, cy - my);
+ gnome_canvas_path_def_curveto (path_def,
+ cx - mx - dx2, cy - my + dy2,
+ cx - rx, cy - dy1,
+ cx - rx, cy);
+
+ gnome_canvas_path_def_curveto (path_def,
+ cx - rx, cy + dy1,
+ cx - mx - dx2, cy + my - dy2,
+ cx - mx, cy + my);
+ gnome_canvas_path_def_curveto (path_def,
+ cx - mx + dx2, cy + my + dy2,
+ cx - dx1, cy + ry,
+ cx, cy + ry);
+ gnome_canvas_path_def_curveto (path_def,
+ cx + dx1, cy + ry,
+ cx + mx - dx2, cy + my + dy2,
+ cx + mx, cy + my);
+ gnome_canvas_path_def_curveto (path_def,
+ cx + mx + dx2, cy + my - dy2,
+ cx + rx, cy + dy1,
+ cx + rx, cy);
+
+ gnome_canvas_path_def_closepath_current(path_def);
+
+ gnome_canvas_shape_set_path_def (GNOME_CANVAS_SHAPE (item), path_def);
+ gnome_canvas_path_def_unref(path_def);
+ re->path_dirty = 0;
+ }
+
+ if (re_parent_class->update)
+ (* re_parent_class->update) (item, affine, clip_path, flags);
+}
diff --git a/src/libgnomecanvas/gnome-canvas-rect-ellipse.h b/src/libgnomecanvas/gnome-canvas-rect-ellipse.h
new file mode 100644
index 0000000..a3a98dd
--- /dev/null
+++ b/src/libgnomecanvas/gnome-canvas-rect-ellipse.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ @NOTATION@
+ */
+/* Rectangle and ellipse item types for GnomeCanvas widget
+ *
+ * GnomeCanvas is basically a port of the Tk toolkit's most excellent canvas widget. Tk is
+ * copyrighted by the Regents of the University of California, Sun Microsystems, and other parties.
+ *
+ *
+ * Author: Federico Mena <federico@nuclecu.unam.mx>
+ */
+
+#ifndef GNOME_CANVAS_RECT_ELLIPSE_H
+#define GNOME_CANVAS_RECT_ELLIPSE_H
+
+
+#include <libgnomecanvas/gnome-canvas.h>
+
+#include <libgnomecanvas/gnome-canvas-shape.h>
+
+#include <libart_lgpl/art_svp.h>
+
+G_BEGIN_DECLS
+
+
+/* Base class for rectangle and ellipse item types. These are defined by their top-left and
+ * bottom-right corners. Rectangles and ellipses share the following arguments:
+ *
+ * name type read/write description
+ * ------------------------------------------------------------------------------------------
+ * x1 double RW Leftmost coordinate of rectangle or ellipse
+ * y1 double RW Topmost coordinate of rectangle or ellipse
+ * x2 double RW Rightmost coordinate of rectangle or ellipse
+ * y2 double RW Bottommost coordinate of rectangle or ellipse
+ * fill_color string W X color specification for fill color,
+ * or NULL pointer for no color (transparent)
+ * fill_color_gdk GdkColor* RW Allocated GdkColor for fill
+ * outline_color string W X color specification for outline color,
+ * or NULL pointer for no color (transparent)
+ * outline_color_gdk GdkColor* RW Allocated GdkColor for outline
+ * fill_stipple GdkBitmap* RW Stipple pattern for fill
+ * outline_stipple GdkBitmap* RW Stipple pattern for outline
+ * width_pixels uint RW Width of the outline in pixels. The outline will
+ * not be scaled when the canvas zoom factor is changed.
+ * width_units double RW Width of the outline in canvas units. The outline
+ * will be scaled when the canvas zoom factor is changed.
+ */
+
+
+#define GNOME_TYPE_CANVAS_RE (gnome_canvas_re_get_type ())
+#define GNOME_CANVAS_RE(obj) (GTK_CHECK_CAST ((obj), GNOME_TYPE_CANVAS_RE, GnomeCanvasRE))
+#define GNOME_CANVAS_RE_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GNOME_TYPE_CANVAS_RE, GnomeCanvasREClass))
+#define GNOME_IS_CANVAS_RE(obj) (GTK_CHECK_TYPE ((obj), GNOME_TYPE_CANVAS_RE))
+#define GNOME_IS_CANVAS_RE_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_CANVAS_RE))
+#define GNOME_CANVAS_RE_GET_CLASS(obj) (GTK_CHECK_GET_CLASS ((obj), GNOME_TYPE_CANVAS_RE, GnomeCanvasREClass))
+
+
+typedef struct _GnomeCanvasRE GnomeCanvasRE;
+typedef struct _GnomeCanvasREClass GnomeCanvasREClass;
+
+struct _GnomeCanvasRE {
+ GnomeCanvasShape item;
+
+ double x1, y1, x2, y2; /* Corners of item */
+
+ unsigned int path_dirty : 1;
+};
+
+struct _GnomeCanvasREClass {
+ GnomeCanvasShapeClass parent_class;
+};
+
+
+/* Standard Gtk function */
+GType gnome_canvas_re_get_type (void) G_GNUC_CONST;
+
+
+/* Rectangle item. No configurable or queryable arguments are available (use those in
+ * GnomeCanvasRE).
+ */
+
+
+#define GNOME_TYPE_CANVAS_RECT (gnome_canvas_rect_get_type ())
+#define GNOME_CANVAS_RECT(obj) (GTK_CHECK_CAST ((obj), GNOME_TYPE_CANVAS_RECT, GnomeCanvasRect))
+#define GNOME_CANVAS_RECT_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GNOME_TYPE_CANVAS_RECT, GnomeCanvasRectClass))
+#define GNOME_IS_CANVAS_RECT(obj) (GTK_CHECK_TYPE ((obj), GNOME_TYPE_CANVAS_RECT))
+#define GNOME_IS_CANVAS_RECT_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_CANVAS_RECT))
+#define GNOME_CANVAS_RECT_GET_CLASS(obj) (GTK_CHECK_GET_CLASS ((obj), GNOME_TYPE_CANVAS_RECT, GnomeCanvasRectClass))
+
+
+typedef struct _GnomeCanvasRect GnomeCanvasRect;
+typedef struct _GnomeCanvasRectClass GnomeCanvasRectClass;
+
+struct _GnomeCanvasRect {
+ GnomeCanvasRE re;
+};
+
+struct _GnomeCanvasRectClass {
+ GnomeCanvasREClass parent_class;
+};
+
+
+/* Standard Gtk function */
+GType gnome_canvas_rect_get_type (void) G_GNUC_CONST;
+
+
+/* Ellipse item. No configurable or queryable arguments are available (use those in
+ * GnomeCanvasRE).
+ */
+
+
+#define GNOME_TYPE_CANVAS_ELLIPSE (gnome_canvas_ellipse_get_type ())
+#define GNOME_CANVAS_ELLIPSE(obj) (GTK_CHECK_CAST ((obj), GNOME_TYPE_CANVAS_ELLIPSE, GnomeCanvasEllipse))
+#define GNOME_CANVAS_ELLIPSE_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GNOME_TYPE_CANVAS_ELLIPSE, GnomeCanvasEllipseClass))
+#define GNOME_IS_CANVAS_ELLIPSE(obj) (GTK_CHECK_TYPE ((obj), GNOME_TYPE_CANVAS_ELLIPSE))
+#define GNOME_IS_CANVAS_ELLIPSE_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_CANVAS_ELLIPSE))
+#define GNOME_CANVAS_ELLIPSE_GET_CLASS(obj) (GTK_CHECK_GET_CLASS ((obj), GNOME_TYPE_CANVAS_ELLIPSE, GnomeCanvasEllipseClass))
+
+
+typedef struct _GnomeCanvasEllipse GnomeCanvasEllipse;
+typedef struct _GnomeCanvasEllipseClass GnomeCanvasEllipseClass;
+
+struct _GnomeCanvasEllipse {
+ GnomeCanvasRE re;
+};
+
+struct _GnomeCanvasEllipseClass {
+ GnomeCanvasREClass parent_class;
+};
+
+
+/* Standard Gtk function */
+GType gnome_canvas_ellipse_get_type (void) G_GNUC_CONST;
+
+
+G_END_DECLS
+
+#endif
diff --git a/src/libgnomecanvas/gnome-canvas-rich-text.c b/src/libgnomecanvas/gnome-canvas-rich-text.c
new file mode 100644
index 0000000..043b54f
--- /dev/null
+++ b/src/libgnomecanvas/gnome-canvas-rich-text.c
@@ -0,0 +1,2203 @@
+/* Editable GnomeCanvas text item based on GtkTextLayout, borrowed heavily
+ * from GtkTextView.
+ *
+ * Copyright (c) 2000 Red Hat, Inc.
+ * Copyright (c) 2001 Joe Shaw
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+#define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtksignal.h>
+#include <gtk/gtktextdisplay.h>
+#include <gtk/gtkmain.h>
+
+#include "gnome-canvas.h"
+#include "gnome-canvas-util.h"
+#include "gnome-canvas-rich-text.h"
+#include "gnome-canvas-i18n.h"
+
+struct _GnomeCanvasRichTextPrivate {
+ GtkTextLayout *layout;
+ GtkTextBuffer *buffer;
+
+ char *text;
+
+ /* Position at anchor */
+ double x, y;
+ /* Dimensions */
+ double width, height;
+ /* Top-left canvas coordinates for text */
+ int cx, cy;
+
+ gboolean cursor_visible;
+ gboolean cursor_blink;
+ gboolean editable;
+ gboolean visible;
+ gboolean grow_height;
+ GtkWrapMode wrap_mode;
+ GtkJustification justification;
+ GtkTextDirection direction;
+ GtkAnchorType anchor;
+ int pixels_above_lines;
+ int pixels_below_lines;
+ int pixels_inside_wrap;
+ int left_margin;
+ int right_margin;
+ int indent;
+
+ guint preblink_timeout;
+ guint blink_timeout;
+
+ guint selection_drag_handler;
+
+ gint drag_start_x;
+ gint drag_start_y;
+
+ gboolean just_selected_element;
+
+ int clicks;
+ guint click_timeout;
+};
+
+enum {
+ PROP_0,
+ PROP_TEXT,
+ PROP_X,
+ PROP_Y,
+ PROP_WIDTH,
+ PROP_HEIGHT,
+ PROP_EDITABLE,
+ PROP_VISIBLE,
+ PROP_CURSOR_VISIBLE,
+ PROP_CURSOR_BLINK,
+ PROP_GROW_HEIGHT,
+ PROP_WRAP_MODE,
+ PROP_JUSTIFICATION,
+ PROP_DIRECTION,
+ PROP_ANCHOR,
+ PROP_PIXELS_ABOVE_LINES,
+ PROP_PIXELS_BELOW_LINES,
+ PROP_PIXELS_INSIDE_WRAP,
+ PROP_LEFT_MARGIN,
+ PROP_RIGHT_MARGIN,
+ PROP_INDENT
+};
+
+enum {
+ TAG_CHANGED,
+ LAST_SIGNAL
+};
+
+static GnomeCanvasItemClass *parent_class;
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static void gnome_canvas_rich_text_class_init(GnomeCanvasRichTextClass *klass);
+static void gnome_canvas_rich_text_init(GnomeCanvasRichText *text);
+static void gnome_canvas_rich_text_set_property(GObject *object, guint property_id,
+ const GValue *value, GParamSpec *pspec);
+static void gnome_canvas_rich_text_get_property(GObject *object, guint property_id,
+ GValue *value, GParamSpec *pspec);
+static void gnome_canvas_rich_text_update(GnomeCanvasItem *item, double *affine,
+ ArtSVP *clip_path, int flags);
+static void gnome_canvas_rich_text_realize(GnomeCanvasItem *item);
+static void gnome_canvas_rich_text_unrealize(GnomeCanvasItem *item);
+static double gnome_canvas_rich_text_point(GnomeCanvasItem *item,
+ double x, double y,
+ int cx, int cy,
+ GnomeCanvasItem **actual_item);
+static void gnome_canvas_rich_text_draw(GnomeCanvasItem *item,
+ GdkDrawable *drawable,
+ int x, int y, int width, int height);
+static void gnome_canvas_rich_text_render(GnomeCanvasItem *item,
+ GnomeCanvasBuf *buf);
+static gint gnome_canvas_rich_text_event(GnomeCanvasItem *item,
+ GdkEvent *event);
+static void gnome_canvas_rich_text_get_bounds(GnomeCanvasItem *text, double *px1, double *py1,
+ double *px2, double *py2);
+
+static void gnome_canvas_rich_text_ensure_layout(GnomeCanvasRichText *text);
+static void gnome_canvas_rich_text_destroy_layout(GnomeCanvasRichText *text);
+static void gnome_canvas_rich_text_start_cursor_blink(GnomeCanvasRichText *text, gboolean delay);
+static void gnome_canvas_rich_text_stop_cursor_blink(GnomeCanvasRichText *text);
+static void gnome_canvas_rich_text_move_cursor(GnomeCanvasRichText *text,
+ GtkMovementStep step,
+ gint count,
+ gboolean extend_selection);
+
+
+
+static GtkTextBuffer *get_buffer(GnomeCanvasRichText *text);
+static gint blink_cb(gpointer data);
+
+#define PREBLINK_TIME 300
+#define CURSOR_ON_TIME 800
+#define CURSOR_OFF_TIME 400
+
+GType
+gnome_canvas_rich_text_get_type(void)
+{
+ static GType rich_text_type;
+
+ if (!rich_text_type) {
+ static const GTypeInfo object_info = {
+ sizeof (GnomeCanvasRichTextClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gnome_canvas_rich_text_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (GnomeCanvasRichText),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) gnome_canvas_rich_text_init,
+ NULL /* value_table */
+ };
+
+ rich_text_type = g_type_register_static (GNOME_TYPE_CANVAS_ITEM, "GnomeCanvasRichText",
+ &object_info, 0);
+ }
+
+ return rich_text_type;
+}
+
+static void
+gnome_canvas_rich_text_finalize(GObject *object)
+{
+ GnomeCanvasRichText *text;
+
+ text = GNOME_CANVAS_RICH_TEXT(object);
+
+ g_free (text->_priv);
+ text->_priv = NULL;
+
+ if (G_OBJECT_CLASS (parent_class)->finalize)
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gnome_canvas_rich_text_class_init(GnomeCanvasRichTextClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
+ GtkObjectClass *object_class = GTK_OBJECT_CLASS(klass);
+ GnomeCanvasItemClass *item_class = GNOME_CANVAS_ITEM_CLASS(klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ gobject_class->set_property = gnome_canvas_rich_text_set_property;
+ gobject_class->get_property = gnome_canvas_rich_text_get_property;
+
+ g_object_class_install_property (
+ gobject_class,
+ PROP_TEXT,
+ g_param_spec_string ("text",
+ _("Text"),
+ _("Text to display"),
+ NULL,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (
+ gobject_class,
+ PROP_X,
+ g_param_spec_double ("x",
+ _("X"),
+ _("X position"),
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (
+ gobject_class,
+ PROP_Y,
+ g_param_spec_double ("y",
+ _("Y"),
+ _("Y position"),
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (
+ gobject_class,
+ PROP_WIDTH,
+ g_param_spec_double ("width",
+ _("Width"),
+ _("Width for text box"),
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (
+ gobject_class,
+ PROP_HEIGHT,
+ g_param_spec_double ("height",
+ _("Height"),
+ _("Height for text box"),
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (
+ gobject_class,
+ PROP_EDITABLE,
+ g_param_spec_boolean ("editable",
+ _("Editable"),
+ _("Is this rich text item editable?"),
+ TRUE,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (
+ gobject_class,
+ PROP_VISIBLE,
+ g_param_spec_boolean ("visible",
+ _("Visible"),
+ _("Is this rich text item visible?"),
+ TRUE,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (
+ gobject_class,
+ PROP_CURSOR_VISIBLE,
+ g_param_spec_boolean ("cursor_visible",
+ _("Cursor Visible"),
+ _("Is the cursor visible in this rich text item?"),
+ TRUE,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (
+ gobject_class,
+ PROP_CURSOR_BLINK,
+ g_param_spec_boolean ("cursor_blink",
+ _("Cursor Blink"),
+ _("Does the cursor blink in this rich text item?"),
+ TRUE,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (
+ gobject_class,
+ PROP_GROW_HEIGHT,
+ g_param_spec_boolean ("grow_height",
+ _("Grow Height"),
+ _("Should the text box height grow if the text does not fit?"),
+ FALSE,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (
+ gobject_class,
+ PROP_WRAP_MODE,
+ g_param_spec_enum ("wrap_mode",
+ _("Wrap Mode"),
+ _("Wrap mode for multiline text"),
+ GTK_TYPE_WRAP_MODE,
+ GTK_WRAP_WORD,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (
+ gobject_class,
+ PROP_JUSTIFICATION,
+ g_param_spec_enum ("justification",
+ _("Justification"),
+ _("Justification mode"),
+ GTK_TYPE_JUSTIFICATION,
+ GTK_JUSTIFY_LEFT,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (
+ gobject_class,
+ PROP_DIRECTION,
+ g_param_spec_enum ("direction",
+ _("Direction"),
+ _("Text direction"),
+ GTK_TYPE_DIRECTION_TYPE,
+ gtk_widget_get_default_direction (),
+ G_PARAM_READWRITE));
+ g_object_class_install_property (
+ gobject_class,
+ PROP_ANCHOR,
+ g_param_spec_enum ("anchor",
+ _("Anchor"),
+ _("Anchor point for text"),
+ GTK_TYPE_ANCHOR_TYPE,
+ GTK_ANCHOR_NW,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (
+ gobject_class,
+ PROP_PIXELS_ABOVE_LINES,
+ g_param_spec_int ("pixels_above_lines",
+ _("Pixels Above Lines"),
+ _("Number of pixels to put above lines"),
+ G_MININT, G_MAXINT,
+ 0,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (
+ gobject_class,
+ PROP_PIXELS_BELOW_LINES,
+ g_param_spec_int ("pixels_below_lines",
+ _("Pixels Below Lines"),
+ _("Number of pixels to put below lines"),
+ G_MININT, G_MAXINT,
+ 0,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (
+ gobject_class,
+ PROP_PIXELS_INSIDE_WRAP,
+ g_param_spec_int ("pixels_inside_wrap",
+ _("Pixels Inside Wrap"),
+ _("Number of pixels to put inside the wrap"),
+ G_MININT, G_MAXINT,
+ 0,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (
+ gobject_class,
+ PROP_LEFT_MARGIN,
+ g_param_spec_int ("left_margin",
+ _("Left Margin"),
+ _("Number of pixels in the left margin"),
+ G_MININT, G_MAXINT,
+ 0,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (
+ gobject_class,
+ PROP_RIGHT_MARGIN,
+ g_param_spec_int ("right_margin",
+ _("Right Margin"),
+ _("Number of pixels in the right margin"),
+ G_MININT, G_MAXINT,
+ 0,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (
+ gobject_class,
+ PROP_INDENT,
+ g_param_spec_int ("indent",
+ _("Indentation"),
+ _("Number of pixels for indentation"),
+ G_MININT, G_MAXINT,
+ 0,
+ G_PARAM_READWRITE));
+
+ /* Signals */
+ signals[TAG_CHANGED] = g_signal_new(
+ "tag_changed",
+ G_TYPE_FROM_CLASS(object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(GnomeCanvasRichTextClass, tag_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ G_TYPE_OBJECT);
+
+ gobject_class->finalize = gnome_canvas_rich_text_finalize;
+
+ item_class->update = gnome_canvas_rich_text_update;
+ item_class->realize = gnome_canvas_rich_text_realize;
+ item_class->unrealize = gnome_canvas_rich_text_unrealize;
+ item_class->draw = gnome_canvas_rich_text_draw;
+ item_class->point = gnome_canvas_rich_text_point;
+ item_class->render = gnome_canvas_rich_text_render;
+ item_class->event = gnome_canvas_rich_text_event;
+ item_class->bounds = gnome_canvas_rich_text_get_bounds;
+} /* gnome_canvas_rich_text_class_init */
+
+static void
+gnome_canvas_rich_text_init(GnomeCanvasRichText *text)
+{
+#if 0
+ GtkObject *object = GTK_OBJECT(text);
+
+ object->flags |= GNOME_CANVAS_ITEM_ALWAYS_REDRAW;
+#endif
+ text->_priv = g_new0(GnomeCanvasRichTextPrivate, 1);
+
+ /* Try to set some sane defaults */
+ text->_priv->cursor_visible = TRUE;
+ text->_priv->cursor_blink = TRUE;
+ text->_priv->editable = TRUE;
+ text->_priv->visible = TRUE;
+ text->_priv->grow_height = FALSE;
+ text->_priv->wrap_mode = GTK_WRAP_WORD;
+ text->_priv->justification = GTK_JUSTIFY_LEFT;
+ text->_priv->direction = gtk_widget_get_default_direction();
+ text->_priv->anchor = GTK_ANCHOR_NW;
+
+ text->_priv->blink_timeout = 0;
+ text->_priv->preblink_timeout = 0;
+
+ text->_priv->clicks = 0;
+ text->_priv->click_timeout = 0;
+} /* gnome_canvas_rich_text_init */
+
+static void
+gnome_canvas_rich_text_set_property (GObject *object, guint property_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ GnomeCanvasRichText *text = GNOME_CANVAS_RICH_TEXT(object);
+
+ switch (property_id) {
+ case PROP_TEXT:
+ if (text->_priv->text)
+ g_free(text->_priv->text);
+
+ text->_priv->text = g_value_dup_string (value);
+
+ gtk_text_buffer_set_text(
+ get_buffer(text), text->_priv->text, strlen(text->_priv->text));
+
+ break;
+ case PROP_X:
+ text->_priv->x = g_value_get_double (value);
+ break;
+ case PROP_Y:
+ text->_priv->y = g_value_get_double (value);
+ break;
+ case PROP_WIDTH:
+ text->_priv->width = g_value_get_double (value);
+ break;
+ case PROP_HEIGHT:
+ text->_priv->height = g_value_get_double (value);
+ break;
+ case PROP_EDITABLE:
+ text->_priv->editable = g_value_get_boolean (value);
+ if (text->_priv->layout) {
+ text->_priv->layout->default_style->editable =
+ text->_priv->editable;
+ gtk_text_layout_default_style_changed(text->_priv->layout);
+ }
+ break;
+ case PROP_VISIBLE:
+ text->_priv->visible = g_value_get_boolean (value);
+ if (text->_priv->layout) {
+ text->_priv->layout->default_style->invisible =
+ !text->_priv->visible;
+ gtk_text_layout_default_style_changed(text->_priv->layout);
+ }
+ break;
+ case PROP_CURSOR_VISIBLE:
+ text->_priv->cursor_visible = g_value_get_boolean (value);
+ if (text->_priv->layout) {
+ gtk_text_layout_set_cursor_visible(
+ text->_priv->layout, text->_priv->cursor_visible);
+
+ if (text->_priv->cursor_visible && text->_priv->cursor_blink) {
+ gnome_canvas_rich_text_start_cursor_blink(
+ text, FALSE);
+ }
+ else
+ gnome_canvas_rich_text_stop_cursor_blink(text);
+ }
+ break;
+ case PROP_CURSOR_BLINK:
+ text->_priv->cursor_blink = g_value_get_boolean (value);
+ if (text->_priv->layout && text->_priv->cursor_visible) {
+ if (text->_priv->cursor_blink && !text->_priv->blink_timeout) {
+ gnome_canvas_rich_text_start_cursor_blink(
+ text, FALSE);
+ }
+ else if (!text->_priv->cursor_blink && text->_priv->blink_timeout) {
+ gnome_canvas_rich_text_stop_cursor_blink(text);
+ gtk_text_layout_set_cursor_visible(
+ text->_priv->layout, TRUE);
+ }
+ }
+ break;
+ case PROP_GROW_HEIGHT:
+ text->_priv->grow_height = g_value_get_boolean (value);
+ /* FIXME: Recalc here */
+ break;
+ case PROP_WRAP_MODE:
+ text->_priv->wrap_mode = g_value_get_enum (value);
+
+ if (text->_priv->layout) {
+ text->_priv->layout->default_style->wrap_mode =
+ text->_priv->wrap_mode;
+ gtk_text_layout_default_style_changed(text->_priv->layout);
+ }
+ break;
+ case PROP_JUSTIFICATION:
+ text->_priv->justification = g_value_get_enum (value);
+
+ if (text->_priv->layout) {
+ text->_priv->layout->default_style->justification =
+ text->_priv->justification;
+ gtk_text_layout_default_style_changed(text->_priv->layout);
+ }
+ break;
+ case PROP_DIRECTION:
+ text->_priv->direction = g_value_get_enum (value);
+
+ if (text->_priv->layout) {
+ text->_priv->layout->default_style->direction =
+ text->_priv->direction;
+ gtk_text_layout_default_style_changed(text->_priv->layout);
+ }
+ break;
+ case PROP_ANCHOR:
+ text->_priv->anchor = g_value_get_enum (value);
+ break;
+ case PROP_PIXELS_ABOVE_LINES:
+ text->_priv->pixels_above_lines = g_value_get_int (value);
+
+ if (text->_priv->layout) {
+ text->_priv->layout->default_style->pixels_above_lines =
+ text->_priv->pixels_above_lines;
+ gtk_text_layout_default_style_changed(text->_priv->layout);
+ }
+ break;
+ case PROP_PIXELS_BELOW_LINES:
+ text->_priv->pixels_below_lines = g_value_get_int (value);
+
+ if (text->_priv->layout) {
+ text->_priv->layout->default_style->pixels_below_lines =
+ text->_priv->pixels_below_lines;
+ gtk_text_layout_default_style_changed(text->_priv->layout);
+ }
+ break;
+ case PROP_PIXELS_INSIDE_WRAP:
+ text->_priv->pixels_inside_wrap = g_value_get_int (value);
+
+ if (text->_priv->layout) {
+ text->_priv->layout->default_style->pixels_inside_wrap =
+ text->_priv->pixels_inside_wrap;
+ gtk_text_layout_default_style_changed(text->_priv->layout);
+ }
+ break;
+ case PROP_LEFT_MARGIN:
+ text->_priv->left_margin = g_value_get_int (value);
+
+ if (text->_priv->layout) {
+ text->_priv->layout->default_style->left_margin =
+ text->_priv->left_margin;
+ gtk_text_layout_default_style_changed(text->_priv->layout);
+ }
+ break;
+ case PROP_RIGHT_MARGIN:
+ text->_priv->right_margin = g_value_get_int (value);
+
+ if (text->_priv->layout) {
+ text->_priv->layout->default_style->right_margin =
+ text->_priv->right_margin;
+ gtk_text_layout_default_style_changed(text->_priv->layout);
+ }
+ break;
+ case PROP_INDENT:
+ text->_priv->pixels_above_lines = g_value_get_int (value);
+
+ if (text->_priv->layout) {
+ text->_priv->layout->default_style->indent = text->_priv->indent;
+ gtk_text_layout_default_style_changed(text->_priv->layout);
+ }
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+
+ gnome_canvas_item_request_update(GNOME_CANVAS_ITEM(text));
+}
+
+static void
+gnome_canvas_rich_text_get_property (GObject *object, guint property_id,
+ GValue *value, GParamSpec *pspec)
+{
+ GnomeCanvasRichText *text = GNOME_CANVAS_RICH_TEXT(object);
+
+ switch (property_id) {
+ case PROP_TEXT:
+ g_value_set_string (value, text->_priv->text);
+ break;
+ case PROP_X:
+ g_value_set_double (value, text->_priv->x);
+ break;
+ case PROP_Y:
+ g_value_set_double (value, text->_priv->y);
+ break;
+ case PROP_HEIGHT:
+ g_value_set_double (value, text->_priv->height);
+ break;
+ case PROP_WIDTH:
+ g_value_set_double (value, text->_priv->width);
+ break;
+ case PROP_EDITABLE:
+ g_value_set_boolean (value, text->_priv->editable);
+ break;
+ case PROP_CURSOR_VISIBLE:
+ g_value_set_boolean (value, text->_priv->cursor_visible);
+ break;
+ case PROP_CURSOR_BLINK:
+ g_value_set_boolean (value, text->_priv->cursor_blink);
+ break;
+ case PROP_GROW_HEIGHT:
+ g_value_set_boolean (value, text->_priv->grow_height);
+ break;
+ case PROP_WRAP_MODE:
+ g_value_set_enum (value, text->_priv->wrap_mode);
+ break;
+ case PROP_JUSTIFICATION:
+ g_value_set_enum (value, text->_priv->justification);
+ break;
+ case PROP_DIRECTION:
+ g_value_set_enum (value, text->_priv->direction);
+ break;
+ case PROP_ANCHOR:
+ g_value_set_enum (value, text->_priv->anchor);
+ break;
+ case PROP_PIXELS_ABOVE_LINES:
+ g_value_set_enum (value, text->_priv->pixels_above_lines);
+ break;
+ case PROP_PIXELS_BELOW_LINES:
+ g_value_set_int (value, text->_priv->pixels_below_lines);
+ break;
+ case PROP_PIXELS_INSIDE_WRAP:
+ g_value_set_int (value, text->_priv->pixels_inside_wrap);
+ break;
+ case PROP_LEFT_MARGIN:
+ g_value_set_int (value, text->_priv->left_margin);
+ break;
+ case PROP_RIGHT_MARGIN:
+ g_value_set_int (value, text->_priv->right_margin);
+ break;
+ case PROP_INDENT:
+ g_value_set_int (value, text->_priv->indent);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gnome_canvas_rich_text_realize(GnomeCanvasItem *item)
+{
+ GnomeCanvasRichText *text = GNOME_CANVAS_RICH_TEXT(item);
+
+ (* GNOME_CANVAS_ITEM_CLASS(parent_class)->realize)(item);
+
+ gnome_canvas_rich_text_ensure_layout(text);
+} /* gnome_canvas_rich_text_realize */
+
+static void
+gnome_canvas_rich_text_unrealize(GnomeCanvasItem *item)
+{
+ GnomeCanvasRichText *text = GNOME_CANVAS_RICH_TEXT(item);
+
+ gnome_canvas_rich_text_destroy_layout(text);
+
+ (* GNOME_CANVAS_ITEM_CLASS(parent_class)->unrealize)(item);
+} /* gnome_canvas_rich_text_unrealize */
+
+static void
+gnome_canvas_rich_text_move_iter_by_lines(GnomeCanvasRichText *text,
+ GtkTextIter *newplace, gint count)
+{
+ while (count < 0) {
+ gtk_text_layout_move_iter_to_previous_line(
+ text->_priv->layout, newplace);
+ count++;
+ }
+
+ while (count > 0) {
+ gtk_text_layout_move_iter_to_next_line(
+ text->_priv->layout, newplace);
+ count--;
+ }
+} /* gnome_canvas_rich_text_move_iter_by_lines */
+
+static gint
+gnome_canvas_rich_text_get_cursor_x_position(GnomeCanvasRichText *text)
+{
+ GtkTextIter insert;
+ GdkRectangle rect;
+
+ gtk_text_buffer_get_iter_at_mark(
+ get_buffer(text), &insert,
+ gtk_text_buffer_get_mark(get_buffer(text), "insert"));
+ gtk_text_layout_get_cursor_locations(
+ text->_priv->layout, &insert, &rect, NULL);
+
+ return rect.x;
+} /* gnome_canvas_rich_text_get_cursor_x_position */
+
+static void
+gnome_canvas_rich_text_move_cursor(GnomeCanvasRichText *text,
+ GtkMovementStep step,
+ gint count, gboolean extend_selection)
+{
+ GtkTextIter insert, newplace;
+
+ gtk_text_buffer_get_iter_at_mark(
+ get_buffer(text), &insert,
+ gtk_text_buffer_get_mark(get_buffer(text), "insert"));
+
+ newplace = insert;
+
+ switch (step) {
+ case GTK_MOVEMENT_LOGICAL_POSITIONS:
+ gtk_text_iter_forward_cursor_positions(&newplace, count);
+ break;
+ case GTK_MOVEMENT_VISUAL_POSITIONS:
+ gtk_text_layout_move_iter_visually(
+ text->_priv->layout, &newplace, count);
+ break;
+ case GTK_MOVEMENT_WORDS:
+ if (count < 0)
+ gtk_text_iter_backward_word_starts(&newplace, -count);
+ else if (count > 0)
+ gtk_text_iter_forward_word_ends(&newplace, count);
+ break;
+ case GTK_MOVEMENT_DISPLAY_LINES:
+ gnome_canvas_rich_text_move_iter_by_lines(
+ text, &newplace, count);
+ gtk_text_layout_move_iter_to_x(
+ text->_priv->layout, &newplace,
+ gnome_canvas_rich_text_get_cursor_x_position(text));
+ break;
+ case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
+ if (count > 1) {
+ gnome_canvas_rich_text_move_iter_by_lines(
+ text, &newplace, --count);
+ }
+ else if (count < -1) {
+ gnome_canvas_rich_text_move_iter_by_lines(
+ text, &newplace, ++count);
+ }
+
+ if (count != 0) {
+ gtk_text_layout_move_iter_to_line_end(
+ text->_priv->layout, &newplace, count);
+ }
+ break;
+ case GTK_MOVEMENT_PARAGRAPHS:
+ /* FIXME: Busted in gtktextview.c too */
+ break;
+ case GTK_MOVEMENT_PARAGRAPH_ENDS:
+ if (count > 0)
+ gtk_text_iter_forward_to_line_end(&newplace);
+ else if (count < 0)
+ gtk_text_iter_set_line_offset(&newplace, 0);
+ break;
+ case GTK_MOVEMENT_BUFFER_ENDS:
+ if (count > 0) {
+ gtk_text_buffer_get_end_iter(
+ get_buffer(text), &newplace);
+ }
+ else if (count < 0) {
+ gtk_text_buffer_get_iter_at_offset(
+ get_buffer(text), &newplace, 0);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (!gtk_text_iter_equal(&insert, &newplace)) {
+ if (extend_selection) {
+ gtk_text_buffer_move_mark(
+ get_buffer(text),
+ gtk_text_buffer_get_mark(
+ get_buffer(text), "insert"),
+ &newplace);
+ }
+ else {
+ gtk_text_buffer_place_cursor(
+ get_buffer(text), &newplace);
+ }
+ }
+
+ gnome_canvas_rich_text_start_cursor_blink(text, TRUE);
+} /* gnome_canvas_rich_text_move_cursor */
+
+static gboolean
+whitespace(gunichar ch, gpointer user_data)
+{
+ return (ch == ' ' || ch == '\t');
+} /* whitespace */
+
+static gboolean
+not_whitespace(gunichar ch, gpointer user_data)
+{
+ return !whitespace(ch, user_data);
+} /* not_whitespace */
+
+static gboolean
+find_whitespace_region(const GtkTextIter *center,
+ GtkTextIter *start, GtkTextIter *end)
+{
+ *start = *center;
+ *end = *center;
+
+ if (gtk_text_iter_backward_find_char(start, not_whitespace, NULL, NULL))
+ gtk_text_iter_forward_char(start);
+ if (whitespace(gtk_text_iter_get_char(end), NULL))
+ gtk_text_iter_forward_find_char(end, not_whitespace, NULL, NULL);
+
+ return !gtk_text_iter_equal(start, end);
+} /* find_whitespace_region */
+
+static void
+gnome_canvas_rich_text_delete_from_cursor(GnomeCanvasRichText *text,
+ GtkDeleteType type,
+ gint count)
+{
+ GtkTextIter insert, start, end;
+
+ /* Special case: If the user wants to delete a character and there is
+ a selection, then delete the selection and return */
+ if (type == GTK_DELETE_CHARS) {
+ if (gtk_text_buffer_delete_selection(get_buffer(text), TRUE,
+ text->_priv->editable))
+ return;
+ }
+
+ gtk_text_buffer_get_iter_at_mark(
+ get_buffer(text), &insert,
+ gtk_text_buffer_get_mark(get_buffer(text), "insert"));
+
+ start = insert;
+ end = insert;
+
+ switch (type) {
+ case GTK_DELETE_CHARS:
+ gtk_text_iter_forward_cursor_positions(&end, count);
+ break;
+ case GTK_DELETE_WORD_ENDS:
+ if (count > 0)
+ gtk_text_iter_forward_word_ends(&end, count);
+ else if (count < 0)
+ gtk_text_iter_backward_word_starts(&start, -count);
+ break;
+ case GTK_DELETE_WORDS:
+ break;
+ case GTK_DELETE_DISPLAY_LINE_ENDS:
+ break;
+ case GTK_DELETE_PARAGRAPH_ENDS:
+ if (gtk_text_iter_ends_line(&end)) {
+ gtk_text_iter_forward_line(&end);
+ --count;
+ }
+
+ while (count > 0) {
+ if (!gtk_text_iter_forward_to_line_end(&end))
+ break;
+
+ --count;
+ }
+ break;
+ case GTK_DELETE_PARAGRAPHS:
+ if (count > 0) {
+ gtk_text_iter_set_line_offset(&start, 0);
+ gtk_text_iter_forward_to_line_end(&end);
+
+ /* Do the lines beyond the first. */
+ while (count > 1) {
+ gtk_text_iter_forward_to_line_end(&end);
+ --count;
+ }
+ }
+ break;
+ case GTK_DELETE_WHITESPACE:
+ find_whitespace_region(&insert, &start, &end);
+ break;
+
+ default:
+ break;
+ }
+
+ if (!gtk_text_iter_equal(&start, &end)) {
+ gtk_text_buffer_begin_user_action(get_buffer(text));
+ gtk_text_buffer_delete_interactive(
+ get_buffer(text), &start, &end, text->_priv->editable);
+ gtk_text_buffer_end_user_action(get_buffer(text));
+ }
+} /* gnome_canvas_rich_text_delete_from_cursor */
+
+static gint
+selection_motion_event_handler(GnomeCanvasRichText *text, GdkEvent *event,
+ gpointer data)
+{
+ GtkTextIter newplace;
+ GtkTextMark *mark;
+ double newx, newy;
+
+ /* We only want to handle motion events... */
+ if (event->type != GDK_MOTION_NOTIFY)
+ return FALSE;
+
+ newx = (event->motion.x - text->_priv->x) *
+ GNOME_CANVAS_ITEM(text)->canvas->pixels_per_unit;
+ newy = (event->motion.y - text->_priv->y) *
+ GNOME_CANVAS_ITEM(text)->canvas->pixels_per_unit;
+
+ gtk_text_layout_get_iter_at_pixel(text->_priv->layout, &newplace, newx, newy);
+ mark = gtk_text_buffer_get_mark(get_buffer(text), "insert");
+ gtk_text_buffer_move_mark(get_buffer(text), mark, &newplace);
+
+ return TRUE;
+} /* selection_motion_event_handler */
+
+static void
+gnome_canvas_rich_text_start_selection_drag(GnomeCanvasRichText *text,
+ const GtkTextIter *iter,
+ GdkEventButton *button)
+{
+ GtkTextIter newplace;
+
+ g_return_if_fail(text->_priv->selection_drag_handler == 0);
+
+#if 0
+ gnome_canvas_item_grab_focus(GNOME_CANVAS_ITEM(text));
+#endif
+
+ newplace = *iter;
+
+ gtk_text_buffer_place_cursor(get_buffer(text), &newplace);
+
+ text->_priv->selection_drag_handler = g_signal_connect(
+ text, "event",
+ G_CALLBACK (selection_motion_event_handler),
+ NULL);
+} /* gnome_canvas_rich_text_start_selection_drag */
+
+static gboolean
+gnome_canvas_rich_text_end_selection_drag(GnomeCanvasRichText *text,
+ GdkEventButton *event)
+{
+ if (text->_priv->selection_drag_handler == 0)
+ return FALSE;
+
+ g_signal_handler_disconnect (text, text->_priv->selection_drag_handler);
+ text->_priv->selection_drag_handler = 0;
+
+#if 0
+ gnome_canvas_item_grab(NULL);
+#endif
+
+ return TRUE;
+} /* gnome_canvas_rich_text_end_selection_drag */
+
+static void
+gnome_canvas_rich_text_emit_tag_changed(GnomeCanvasRichText *text,
+ GtkTextTag *tag)
+{
+ g_signal_emit(G_OBJECT(text), signals[TAG_CHANGED], 0, tag);
+} /* gnome_canvas_rich_text_emit_tag_changed */
+
+static gint
+gnome_canvas_rich_text_key_press_event(GnomeCanvasItem *item,
+ GdkEventKey *event)
+{
+ GnomeCanvasRichText *text = GNOME_CANVAS_RICH_TEXT(item);
+ gboolean extend_selection = FALSE;
+ gboolean handled = FALSE;
+
+#if 0
+ printf("Key press event\n");
+#endif
+
+ if (!text->_priv->layout || !text->_priv->buffer)
+ return FALSE;
+
+ if (event->state & GDK_SHIFT_MASK)
+ extend_selection = TRUE;
+
+ switch (event->keyval) {
+ case GDK_Return:
+ case GDK_KP_Enter:
+ gtk_text_buffer_delete_selection(
+ get_buffer(text), TRUE, text->_priv->editable);
+ gtk_text_buffer_insert_interactive_at_cursor(
+ get_buffer(text), "\n", 1, text->_priv->editable);
+ handled = TRUE;
+ break;
+
+ case GDK_Tab:
+ gtk_text_buffer_insert_interactive_at_cursor(
+ get_buffer(text), "\t", 1, text->_priv->editable);
+ handled = TRUE;
+ break;
+
+ /* MOVEMENT */
+ case GDK_Right:
+ if (event->state & GDK_CONTROL_MASK) {
+ gnome_canvas_rich_text_move_cursor(
+ text, GTK_MOVEMENT_WORDS, 1,
+ extend_selection);
+ handled = TRUE;
+ }
+ else {
+ gnome_canvas_rich_text_move_cursor(
+ text, GTK_MOVEMENT_VISUAL_POSITIONS, 1,
+ extend_selection);
+ handled = TRUE;
+ }
+ break;
+ case GDK_Left:
+ if (event->state & GDK_CONTROL_MASK) {
+ gnome_canvas_rich_text_move_cursor(
+ text, GTK_MOVEMENT_WORDS, -1,
+ extend_selection);
+ handled = TRUE;
+ }
+ else {
+ gnome_canvas_rich_text_move_cursor(
+ text, GTK_MOVEMENT_VISUAL_POSITIONS, -1,
+ extend_selection);
+ handled = TRUE;
+ }
+ break;
+ case GDK_f:
+ if (event->state & GDK_CONTROL_MASK) {
+ gnome_canvas_rich_text_move_cursor(
+ text, GTK_MOVEMENT_LOGICAL_POSITIONS, 1,
+ extend_selection);
+ handled = TRUE;
+ }
+ else if (event->state & GDK_MOD1_MASK) {
+ gnome_canvas_rich_text_move_cursor(
+ text, GTK_MOVEMENT_WORDS, 1,
+ extend_selection);
+ handled = TRUE;
+ }
+ break;
+ case GDK_b:
+ if (event->state & GDK_CONTROL_MASK) {
+ gnome_canvas_rich_text_move_cursor(
+ text, GTK_MOVEMENT_LOGICAL_POSITIONS, -1,
+ extend_selection);
+ handled = TRUE;
+ }
+ else if (event->state & GDK_MOD1_MASK) {
+ gnome_canvas_rich_text_move_cursor(
+ text, GTK_MOVEMENT_WORDS, -1,
+ extend_selection);
+ handled = TRUE;
+ }
+ break;
+ case GDK_Up:
+ gnome_canvas_rich_text_move_cursor(
+ text, GTK_MOVEMENT_DISPLAY_LINES, -1,
+ extend_selection);
+ handled = TRUE;
+ break;
+ case GDK_Down:
+ gnome_canvas_rich_text_move_cursor(
+ text, GTK_MOVEMENT_DISPLAY_LINES, 1,
+ extend_selection);
+ handled = TRUE;
+ break;
+ case GDK_p:
+ if (event->state & GDK_CONTROL_MASK) {
+ gnome_canvas_rich_text_move_cursor(
+ text, GTK_MOVEMENT_DISPLAY_LINES, -1,
+ extend_selection);
+ handled = TRUE;
+ }
+ break;
+ case GDK_n:
+ if (event->state & GDK_CONTROL_MASK) {
+ gnome_canvas_rich_text_move_cursor(
+ text, GTK_MOVEMENT_DISPLAY_LINES, 1,
+ extend_selection);
+ handled = TRUE;
+ }
+ break;
+ case GDK_Home:
+ gnome_canvas_rich_text_move_cursor(
+ text, GTK_MOVEMENT_PARAGRAPH_ENDS, -1,
+ extend_selection);
+ handled = TRUE;
+ break;
+ case GDK_End:
+ gnome_canvas_rich_text_move_cursor(
+ text, GTK_MOVEMENT_PARAGRAPH_ENDS, 1,
+ extend_selection);
+ handled = TRUE;
+ break;
+ case GDK_a:
+ if (event->state & GDK_CONTROL_MASK) {
+ gnome_canvas_rich_text_move_cursor(
+ text, GTK_MOVEMENT_PARAGRAPH_ENDS, -1,
+ extend_selection);
+ handled = TRUE;
+ }
+ break;
+ case GDK_e:
+ if (event->state & GDK_CONTROL_MASK) {
+ gnome_canvas_rich_text_move_cursor(
+ text, GTK_MOVEMENT_PARAGRAPH_ENDS, 1,
+ extend_selection);
+ handled = TRUE;
+ }
+ break;
+
+ /* DELETING TEXT */
+ case GDK_Delete:
+ case GDK_KP_Delete:
+ if (event->state & GDK_CONTROL_MASK) {
+ gnome_canvas_rich_text_delete_from_cursor(
+ text, GTK_DELETE_WORD_ENDS, 1);
+ handled = TRUE;
+ }
+ else {
+ gnome_canvas_rich_text_delete_from_cursor(
+ text, GTK_DELETE_CHARS, 1);
+ handled = TRUE;
+ }
+ break;
+ case GDK_d:
+ if (event->state & GDK_CONTROL_MASK) {
+ gnome_canvas_rich_text_delete_from_cursor(
+ text, GTK_DELETE_CHARS, 1);
+ handled = TRUE;
+ }
+ else if (event->state & GDK_MOD1_MASK) {
+ gnome_canvas_rich_text_delete_from_cursor(
+ text, GTK_DELETE_WORD_ENDS, 1);
+ handled = TRUE;
+ }
+ break;
+ case GDK_BackSpace:
+ if (event->state & GDK_CONTROL_MASK) {
+ gnome_canvas_rich_text_delete_from_cursor(
+ text, GTK_DELETE_WORD_ENDS, -1);
+ handled = TRUE;
+ }
+ else {
+ gnome_canvas_rich_text_delete_from_cursor(
+ text, GTK_DELETE_CHARS, -1);
+ }
+ handled = TRUE;
+ break;
+ case GDK_k:
+ if (event->state & GDK_CONTROL_MASK) {
+ gnome_canvas_rich_text_delete_from_cursor(
+ text, GTK_DELETE_PARAGRAPH_ENDS, 1);
+ handled = TRUE;
+ }
+ break;
+ case GDK_u:
+ if (event->state & GDK_CONTROL_MASK) {
+ gnome_canvas_rich_text_delete_from_cursor(
+ text, GTK_DELETE_PARAGRAPHS, 1);
+ handled = TRUE;
+ }
+ break;
+ case GDK_space:
+ if (event->state & GDK_MOD1_MASK) {
+ gnome_canvas_rich_text_delete_from_cursor(
+ text, GTK_DELETE_WHITESPACE, 1);
+ handled = TRUE;
+ }
+ break;
+ case GDK_backslash:
+ if (event->state & GDK_MOD1_MASK) {
+ gnome_canvas_rich_text_delete_from_cursor(
+ text, GTK_DELETE_WHITESPACE, 1);
+ handled = TRUE;
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* An empty string, click just pressing "Alt" by itself or whatever. */
+ if (!event->length)
+ return FALSE;
+
+ if (!handled) {
+ gtk_text_buffer_delete_selection(
+ get_buffer(text), TRUE, text->_priv->editable);
+ gtk_text_buffer_insert_interactive_at_cursor(
+ get_buffer(text), event->string, event->length,
+ text->_priv->editable);
+ }
+
+ gnome_canvas_rich_text_start_cursor_blink(text, TRUE);
+
+ return TRUE;
+} /* gnome_canvas_rich_text_key_press_event */
+
+static gint
+gnome_canvas_rich_text_key_release_event(GnomeCanvasItem *item,
+ GdkEventKey *event)
+{
+ return FALSE;
+} /* gnome_canvas_rich_text_key_release_event */
+
+static gboolean
+_click(gpointer data)
+{
+ GnomeCanvasRichText *text = GNOME_CANVAS_RICH_TEXT(data);
+
+ text->_priv->clicks = 0;
+ text->_priv->click_timeout = 0;
+
+ return FALSE;
+} /* _click */
+
+static gint
+gnome_canvas_rich_text_button_press_event(GnomeCanvasItem *item,
+ GdkEventButton *event)
+{
+ GnomeCanvasRichText *text = GNOME_CANVAS_RICH_TEXT(item);
+ GtkTextIter iter;
+ GdkEventType event_type;
+ double newx, newy;
+
+ newx = (event->x - text->_priv->x) * item->canvas->pixels_per_unit;
+ newy = (event->y - text->_priv->y) * item->canvas->pixels_per_unit;
+
+ gtk_text_layout_get_iter_at_pixel(text->_priv->layout, &iter, newx, newy);
+
+ /* The canvas doesn't give us double- or triple-click events, so
+ we have to synthesize them ourselves. Yay. */
+ event_type = event->type;
+ if (event_type == GDK_BUTTON_PRESS) {
+ text->_priv->clicks++;
+ text->_priv->click_timeout = gtk_timeout_add(400, _click, text);
+
+ if (text->_priv->clicks > 3)
+ text->_priv->clicks = text->_priv->clicks % 3;
+
+ if (text->_priv->clicks == 1)
+ event_type = GDK_BUTTON_PRESS;
+ else if (text->_priv->clicks == 2)
+ event_type = GDK_2BUTTON_PRESS;
+ else if (text->_priv->clicks == 3)
+ event_type = GDK_3BUTTON_PRESS;
+ else
+ printf("ZERO CLICKS!\n");
+ }
+
+ if (event->button == 1 && event_type == GDK_BUTTON_PRESS) {
+ GtkTextIter start, end;
+
+ if (gtk_text_buffer_get_selection_bounds(
+ get_buffer(text), &start, &end) &&
+ gtk_text_iter_in_range(&iter, &start, &end)) {
+ text->_priv->drag_start_x = event->x;
+ text->_priv->drag_start_y = event->y;
+ }
+ else {
+ gnome_canvas_rich_text_start_selection_drag(
+ text, &iter, event);
+ }
+
+ return TRUE;
+ }
+ else if (event->button == 1 && event_type == GDK_2BUTTON_PRESS) {
+ GtkTextIter start, end;
+
+#if 0
+ printf("double-click\n");
+#endif
+
+ gnome_canvas_rich_text_end_selection_drag(text, event);
+
+ start = iter;
+ end = start;
+
+ if (gtk_text_iter_inside_word(&start)) {
+ if (!gtk_text_iter_starts_word(&start))
+ gtk_text_iter_backward_word_start(&start);
+
+ if (!gtk_text_iter_ends_word(&end))
+ gtk_text_iter_forward_word_end(&end);
+ }
+
+ gtk_text_buffer_move_mark(
+ get_buffer(text),
+ gtk_text_buffer_get_selection_bound(get_buffer(text)),
+ &start);
+ gtk_text_buffer_move_mark(
+ get_buffer(text),
+ gtk_text_buffer_get_insert(get_buffer(text)), &end);
+
+ text->_priv->just_selected_element = TRUE;
+
+ return TRUE;
+ }
+ else if (event->button == 1 && event_type == GDK_3BUTTON_PRESS) {
+ GtkTextIter start, end;
+
+#if 0
+ printf("triple-click\n");
+#endif
+
+ gnome_canvas_rich_text_end_selection_drag(text, event);
+
+ start = iter;
+ end = start;
+
+ if (gtk_text_layout_iter_starts_line(text->_priv->layout, &start)) {
+ gtk_text_layout_move_iter_to_line_end(
+ text->_priv->layout, &start, -1);
+ }
+ else {
+ gtk_text_layout_move_iter_to_line_end(
+ text->_priv->layout, &start, -1);
+
+ if (!gtk_text_layout_iter_starts_line(
+ text->_priv->layout, &end)) {
+ gtk_text_layout_move_iter_to_line_end(
+ text->_priv->layout, &end, 1);
+ }
+ }
+
+ gtk_text_buffer_move_mark(
+ get_buffer(text),
+ gtk_text_buffer_get_selection_bound(get_buffer(text)),
+ &start);
+ gtk_text_buffer_move_mark(
+ get_buffer(text),
+ gtk_text_buffer_get_insert(get_buffer(text)), &end);
+
+ text->_priv->just_selected_element = TRUE;
+
+ return TRUE;
+ }
+ else if (event->button == 2 && event_type == GDK_BUTTON_PRESS) {
+ gtk_text_buffer_paste_clipboard(
+ get_buffer(text),
+ gtk_clipboard_get (GDK_SELECTION_PRIMARY),
+ &iter, text->_priv->editable);
+ }
+
+ return FALSE;
+} /* gnome_canvas_rich_text_button_press_event */
+
+static gint
+gnome_canvas_rich_text_button_release_event(GnomeCanvasItem *item,
+ GdkEventButton *event)
+{
+ GnomeCanvasRichText *text = GNOME_CANVAS_RICH_TEXT(item);
+ double newx, newy;
+
+ newx = (event->x - text->_priv->x) * item->canvas->pixels_per_unit;
+ newy = (event->y - text->_priv->y) * item->canvas->pixels_per_unit;
+
+ if (event->button == 1) {
+ if (text->_priv->drag_start_x >= 0) {
+ text->_priv->drag_start_x = -1;
+ text->_priv->drag_start_y = -1;
+ }
+
+ if (gnome_canvas_rich_text_end_selection_drag(text, event))
+ return TRUE;
+ else if (text->_priv->just_selected_element) {
+ text->_priv->just_selected_element = FALSE;
+ return FALSE;
+ }
+ else {
+ GtkTextIter iter;
+
+ gtk_text_layout_get_iter_at_pixel(
+ text->_priv->layout, &iter, newx, newy);
+
+ gtk_text_buffer_place_cursor(get_buffer(text), &iter);
+
+ return FALSE;
+ }
+ }
+
+ return FALSE;
+} /* gnome_canvas_rich_text_button_release_event */
+
+static gint
+gnome_canvas_rich_text_focus_in_event(GnomeCanvasItem *item,
+ GdkEventFocus *event)
+{
+ GnomeCanvasRichText *text = GNOME_CANVAS_RICH_TEXT(item);
+
+ if (text->_priv->cursor_visible && text->_priv->layout) {
+ gtk_text_layout_set_cursor_visible(text->_priv->layout, TRUE);
+ gnome_canvas_rich_text_start_cursor_blink(text, FALSE);
+ }
+
+ return FALSE;
+} /* gnome_canvas_rich_text_focus_in_event */
+
+static gint
+gnome_canvas_rich_text_focus_out_event(GnomeCanvasItem *item,
+ GdkEventFocus *event)
+{
+ GnomeCanvasRichText *text = GNOME_CANVAS_RICH_TEXT(item);
+
+ if (text->_priv->cursor_visible && text->_priv->layout) {
+ gtk_text_layout_set_cursor_visible(text->_priv->layout, FALSE);
+ gnome_canvas_rich_text_stop_cursor_blink(text);
+ }
+
+ return FALSE;
+} /* gnome_canvas_rich_text_focus_out_event */
+
+static gboolean
+get_event_coordinates(GdkEvent *event, gint *x, gint *y)
+{
+ g_return_val_if_fail(event, FALSE);
+
+ switch (event->type) {
+ case GDK_MOTION_NOTIFY:
+ *x = event->motion.x;
+ *y = event->motion.y;
+ return TRUE;
+ case GDK_BUTTON_PRESS:
+ case GDK_2BUTTON_PRESS:
+ case GDK_3BUTTON_PRESS:
+ case GDK_BUTTON_RELEASE:
+ *x = event->button.x;
+ *y = event->button.y;
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
+} /* get_event_coordinates */
+
+static void
+emit_event_on_tags(GnomeCanvasRichText *text, GdkEvent *event,
+ GtkTextIter *iter)
+{
+ GSList *tags;
+ GSList *i;
+
+ tags = gtk_text_iter_get_tags(iter);
+
+ i = tags;
+ while (i) {
+ GtkTextTag *tag = i->data;
+
+ gtk_text_tag_event(tag, G_OBJECT(text), event, iter);
+
+ /* The cursor has been moved to within this tag. Emit the
+ tag_changed signal */
+ if (event->type == GDK_BUTTON_RELEASE ||
+ event->type == GDK_KEY_PRESS ||
+ event->type == GDK_KEY_RELEASE) {
+ gnome_canvas_rich_text_emit_tag_changed(
+ text, tag);
+ }
+
+ i = g_slist_next(i);
+ }
+
+ g_slist_free(tags);
+} /* emit_event_on_tags */
+
+static gint
+gnome_canvas_rich_text_event(GnomeCanvasItem *item, GdkEvent *event)
+{
+ GnomeCanvasRichText *text = GNOME_CANVAS_RICH_TEXT(item);
+ int x, y;
+
+ if (get_event_coordinates(event, &x, &y)) {
+ GtkTextIter iter;
+
+ x -= text->_priv->x;
+ y -= text->_priv->y;
+
+ gtk_text_layout_get_iter_at_pixel(text->_priv->layout, &iter, x, y);
+ emit_event_on_tags(text, event, &iter);
+ }
+ else if (event->type == GDK_KEY_PRESS ||
+ event->type == GDK_KEY_RELEASE) {
+ GtkTextMark *insert;
+ GtkTextIter iter;
+
+ insert = gtk_text_buffer_get_mark(get_buffer(text), "insert");
+ gtk_text_buffer_get_iter_at_mark(
+ get_buffer(text), &iter, insert);
+ emit_event_on_tags(text, event, &iter);
+ }
+
+ switch (event->type) {
+ case GDK_KEY_PRESS:
+ return gnome_canvas_rich_text_key_press_event(
+ item, (GdkEventKey *) event);
+ case GDK_KEY_RELEASE:
+ return gnome_canvas_rich_text_key_release_event(
+ item, (GdkEventKey *) event);
+ case GDK_BUTTON_PRESS:
+ return gnome_canvas_rich_text_button_press_event(
+ item, (GdkEventButton *) event);
+ case GDK_BUTTON_RELEASE:
+ return gnome_canvas_rich_text_button_release_event(
+ item, (GdkEventButton *) event);
+ case GDK_FOCUS_CHANGE:
+ if (((GdkEventFocus *) event)->window !=
+ item->canvas->layout.bin_window)
+ return FALSE;
+
+ if (((GdkEventFocus *) event)->in)
+ return gnome_canvas_rich_text_focus_in_event(
+ item, (GdkEventFocus *) event);
+ else
+ return gnome_canvas_rich_text_focus_out_event(
+ item, (GdkEventFocus *) event);
+ default:
+ return FALSE;
+ }
+} /* gnome_canvas_rich_text_event */
+
+/* Cut/Copy/Paste */
+
+/**
+ * gnome_canvas_rich_text_cut_clipboard:
+ * @text: a #GnomeCanvasRichText.
+ *
+ * Copies the currently selected @text to clipboard, then deletes said text
+ * if it's editable.
+ **/
+void
+gnome_canvas_rich_text_cut_clipboard(GnomeCanvasRichText *text)
+{
+ g_return_if_fail(text);
+ g_return_if_fail(get_buffer(text));
+
+ gtk_text_buffer_cut_clipboard(get_buffer(text),
+ gtk_clipboard_get (GDK_SELECTION_PRIMARY),
+ text->_priv->editable);
+} /* gnome_canvas_rich_text_cut_clipboard */
+
+
+/**
+ * gnome_canvas_rich_text_copy_clipboard:
+ * @text: a #GnomeCanvasRichText.
+ *
+ * Copies the currently selected @text to clipboard.
+ **/
+void
+gnome_canvas_rich_text_copy_clipboard(GnomeCanvasRichText *text)
+{
+ g_return_if_fail(text);
+ g_return_if_fail(get_buffer(text));
+
+ gtk_text_buffer_copy_clipboard(get_buffer(text),
+ gtk_clipboard_get (GDK_SELECTION_PRIMARY));
+} /* gnome_canvas_rich_text_cut_clipboard */
+
+
+/**
+ * gnome_canvas_rich_text_paste_clipboard:
+ * @text: a #GnomeCanvasRichText.
+ *
+ * Pastes the contents of the clipboard at the insertion point.
+ **/
+void
+gnome_canvas_rich_text_paste_clipboard(GnomeCanvasRichText *text)
+{
+ g_return_if_fail(text);
+ g_return_if_fail(get_buffer(text));
+
+ gtk_text_buffer_paste_clipboard(get_buffer(text),
+ gtk_clipboard_get (GDK_SELECTION_PRIMARY),
+ NULL,
+ text->_priv->editable);
+} /* gnome_canvas_rich_text_cut_clipboard */
+
+static gint
+preblink_cb(gpointer data)
+{
+ GnomeCanvasRichText *text = GNOME_CANVAS_RICH_TEXT(data);
+
+ text->_priv->preblink_timeout = 0;
+ gnome_canvas_rich_text_start_cursor_blink(text, FALSE);
+
+ /* Remove ourselves */
+ return FALSE;
+} /* preblink_cb */
+
+static gint
+blink_cb(gpointer data)
+{
+ GnomeCanvasRichText *text = GNOME_CANVAS_RICH_TEXT(data);
+ gboolean visible;
+
+ g_assert(text->_priv->layout);
+ g_assert(text->_priv->cursor_visible);
+
+ visible = gtk_text_layout_get_cursor_visible(text->_priv->layout);
+ if (visible)
+ text->_priv->blink_timeout = gtk_timeout_add(
+ CURSOR_OFF_TIME, blink_cb, text);
+ else
+ text->_priv->blink_timeout = gtk_timeout_add(
+ CURSOR_ON_TIME, blink_cb, text);
+
+ gtk_text_layout_set_cursor_visible(text->_priv->layout, !visible);
+
+ /* Remove ourself */
+ return FALSE;
+} /* blink_cb */
+
+static void
+gnome_canvas_rich_text_start_cursor_blink(GnomeCanvasRichText *text,
+ gboolean with_delay)
+{
+ if (!text->_priv->layout)
+ return;
+
+ if (!text->_priv->cursor_visible || !text->_priv->cursor_blink)
+ return;
+
+ if (text->_priv->preblink_timeout != 0) {
+ gtk_timeout_remove(text->_priv->preblink_timeout);
+ text->_priv->preblink_timeout = 0;
+ }
+
+ if (with_delay) {
+ if (text->_priv->blink_timeout != 0) {
+ gtk_timeout_remove(text->_priv->blink_timeout);
+ text->_priv->blink_timeout = 0;
+ }
+
+ gtk_text_layout_set_cursor_visible(text->_priv->layout, TRUE);
+
+ text->_priv->preblink_timeout = gtk_timeout_add(
+ PREBLINK_TIME, preblink_cb, text);
+ }
+ else {
+ if (text->_priv->blink_timeout == 0) {
+ gtk_text_layout_set_cursor_visible(text->_priv->layout, TRUE);
+ text->_priv->blink_timeout = gtk_timeout_add(
+ CURSOR_ON_TIME, blink_cb, text);
+ }
+ }
+} /* gnome_canvas_rich_text_start_cursor_blink */
+
+static void
+gnome_canvas_rich_text_stop_cursor_blink(GnomeCanvasRichText *text)
+{
+ if (text->_priv->blink_timeout) {
+ gtk_timeout_remove(text->_priv->blink_timeout);
+ text->_priv->blink_timeout = 0;
+ }
+} /* gnome_canvas_rich_text_stop_cursor_blink */
+
+/* We have to request updates this way because the update cycle is not
+ re-entrant. This will fire off a request in an idle loop. */
+static gboolean
+request_update(gpointer data)
+{
+ GnomeCanvasRichText *text = GNOME_CANVAS_RICH_TEXT(data);
+
+ gnome_canvas_item_request_update(GNOME_CANVAS_ITEM(text));
+
+ return FALSE;
+} /* request_update */
+
+static void
+invalidated_handler(GtkTextLayout *layout, gpointer data)
+{
+ GnomeCanvasRichText *text = GNOME_CANVAS_RICH_TEXT(data);
+
+#if 0
+ printf("Text is being invalidated.\n");
+#endif
+
+ gtk_text_layout_validate(text->_priv->layout, 2000);
+
+ /* We are called from the update cycle; gotta put this in an idle
+ loop. */
+ gtk_idle_add(request_update, text);
+} /* invalidated_handler */
+
+static void
+scale_fonts(GtkTextTag *tag, gpointer data)
+{
+ GnomeCanvasRichText *text = GNOME_CANVAS_RICH_TEXT(data);
+
+ if (!tag->values)
+ return;
+
+ g_object_set(
+ G_OBJECT(tag), "scale",
+ text->_priv->layout->default_style->font_scale, NULL);
+} /* scale_fonts */
+
+static void
+changed_handler(GtkTextLayout *layout, gint start_y,
+ gint old_height, gint new_height, gpointer data)
+{
+ GnomeCanvasRichText *text = GNOME_CANVAS_RICH_TEXT(data);
+
+#if 0
+ printf("Layout %p is being changed.\n", text->_priv->layout);
+#endif
+
+ if (text->_priv->layout->default_style->font_scale !=
+ GNOME_CANVAS_ITEM(text)->canvas->pixels_per_unit) {
+ GtkTextTagTable *tag_table;
+
+ text->_priv->layout->default_style->font_scale =
+ GNOME_CANVAS_ITEM(text)->canvas->pixels_per_unit;
+
+ tag_table = gtk_text_buffer_get_tag_table(get_buffer(text));
+ gtk_text_tag_table_foreach(tag_table, scale_fonts, text);
+
+ gtk_text_layout_default_style_changed(text->_priv->layout);
+ }
+
+ if (text->_priv->grow_height) {
+ int width, height;
+
+ gtk_text_layout_get_size(text->_priv->layout, &width, &height);
+
+ if (height > text->_priv->height)
+ text->_priv->height = height;
+ }
+
+ /* We are called from the update cycle; gotta put this in an idle
+ loop. */
+ gtk_idle_add(request_update, text);
+} /* changed_handler */
+
+
+/**
+ * gnome_canvas_rich_text_set_buffer:
+ * @text: a #GnomeCanvasRichText.
+ * @buffer: a #GtkTextBuffer.
+ *
+ * Sets the buffer field of the @text to @buffer.
+ **/
+void
+gnome_canvas_rich_text_set_buffer(GnomeCanvasRichText *text,
+ GtkTextBuffer *buffer)
+{
+ g_return_if_fail(GNOME_IS_CANVAS_RICH_TEXT(text));
+ g_return_if_fail(buffer == NULL || GTK_IS_TEXT_BUFFER(buffer));
+
+ if (text->_priv->buffer == buffer)
+ return;
+
+ if (text->_priv->buffer != NULL) {
+ g_object_unref(G_OBJECT(text->_priv->buffer));
+ }
+
+ text->_priv->buffer = buffer;
+
+ if (buffer) {
+ g_object_ref(G_OBJECT(buffer));
+
+ if (text->_priv->layout)
+ gtk_text_layout_set_buffer(text->_priv->layout, buffer);
+ }
+
+ gnome_canvas_item_request_update(GNOME_CANVAS_ITEM(text));
+} /* gnome_canvas_rich_text_set_buffer */
+
+static GtkTextBuffer *
+get_buffer(GnomeCanvasRichText *text)
+{
+ if (!text->_priv->buffer) {
+ GtkTextBuffer *b;
+
+ b = gtk_text_buffer_new(NULL);
+ gnome_canvas_rich_text_set_buffer(text, b);
+ g_object_unref(G_OBJECT(b));
+ }
+
+ return text->_priv->buffer;
+} /* get_buffer */
+
+
+/**
+ * gnome_canvas_rich_text_get_buffer:
+ * @text: a #GnomeCanvasRichText.
+ *
+ * Returns a #GtkTextBuffer associated with the #GnomeCanvasRichText.
+ * This function creates a new #GtkTextBuffer if the text buffer is NULL.
+ *
+ * Return value: the #GtkTextBuffer.
+ **/
+GtkTextBuffer *
+gnome_canvas_rich_text_get_buffer(GnomeCanvasRichText *text)
+{
+ g_return_val_if_fail(GNOME_IS_CANVAS_RICH_TEXT(text), NULL);
+
+ return get_buffer(text);
+} /* gnome_canvas_rich_text_get_buffer */
+
+
+/**
+ * gnome_canvas_rich_text_get_iter_location:
+ * @text: a #GnomeCanvasRichText.
+ * @iter: a #GtkTextIter.
+ * @location: a #GdkRectangle containing the bounds of the character at @iter.
+ *
+ * Gets a rectangle which roughly contains the character at @iter.
+ **/
+void
+gnome_canvas_rich_text_get_iter_location (GnomeCanvasRichText *text,
+ const GtkTextIter *iter,
+ GdkRectangle *location)
+{
+ g_return_if_fail (GNOME_IS_CANVAS_RICH_TEXT (text));
+ g_return_if_fail (gtk_text_iter_get_buffer (iter) == text->_priv->buffer);
+
+ gtk_text_layout_get_iter_location (text->_priv->layout, iter, location);
+}
+
+
+/**
+ * gnome_canvas_rich_text_get_iter_at_location:
+ * @text: a #GnomeCanvasRichText.
+ * @iter: a #GtkTextIter.
+ * @x: x position, in buffer coordinates.
+ * @y: y position, in buffer coordinates.
+ *
+ * Retrieves the iterator at the buffer coordinates x and y.
+ **/
+void
+gnome_canvas_rich_text_get_iter_at_location (GnomeCanvasRichText *text,
+ GtkTextIter *iter,
+ gint x,
+ gint y)
+{
+ g_return_if_fail (GNOME_IS_CANVAS_RICH_TEXT (text));
+ g_return_if_fail (iter != NULL);
+ g_return_if_fail (text->_priv->layout != NULL);
+
+ gtk_text_layout_get_iter_at_pixel (text->_priv->layout,
+ iter,
+ x,
+ y);
+}
+
+
+static void
+gnome_canvas_rich_text_set_attributes_from_style(GnomeCanvasRichText *text,
+ GtkTextAttributes *values,
+ GtkStyle *style)
+{
+ values->appearance.bg_color = style->base[GTK_STATE_NORMAL];
+ values->appearance.fg_color = style->fg[GTK_STATE_NORMAL];
+
+ if (values->font)
+ pango_font_description_free (values->font);
+
+ values->font = pango_font_description_copy (style->font_desc);
+
+} /* gnome_canvas_rich_text_set_attributes_from_style */
+
+static void
+gnome_canvas_rich_text_ensure_layout(GnomeCanvasRichText *text)
+{
+ if (!text->_priv->layout) {
+ GtkWidget *canvas;
+ GtkTextAttributes *style;
+ PangoContext *ltr_context, *rtl_context;
+
+ text->_priv->layout = gtk_text_layout_new();
+
+ gtk_text_layout_set_screen_width(text->_priv->layout, text->_priv->width);
+
+ if (get_buffer(text)) {
+ gtk_text_layout_set_buffer(
+ text->_priv->layout, get_buffer(text));
+ }
+
+ /* Setup the cursor stuff */
+ gtk_text_layout_set_cursor_visible(
+ text->_priv->layout, text->_priv->cursor_visible);
+ if (text->_priv->cursor_visible && text->_priv->cursor_blink)
+ gnome_canvas_rich_text_start_cursor_blink(text, FALSE);
+ else
+ gnome_canvas_rich_text_stop_cursor_blink(text);
+
+ canvas = GTK_WIDGET(GNOME_CANVAS_ITEM(text)->canvas);
+
+ ltr_context = gtk_widget_create_pango_context(canvas);
+ pango_context_set_base_dir(ltr_context, PANGO_DIRECTION_LTR);
+ rtl_context = gtk_widget_create_pango_context(canvas);
+ pango_context_set_base_dir(rtl_context, PANGO_DIRECTION_RTL);
+
+ gtk_text_layout_set_contexts(
+ text->_priv->layout, ltr_context, rtl_context);
+
+ g_object_unref(G_OBJECT(ltr_context));
+ g_object_unref(G_OBJECT(rtl_context));
+
+ style = gtk_text_attributes_new();
+
+ gnome_canvas_rich_text_set_attributes_from_style(
+ text, style, canvas->style);
+
+ style->pixels_above_lines = text->_priv->pixels_above_lines;
+ style->pixels_below_lines = text->_priv->pixels_below_lines;
+ style->pixels_inside_wrap = text->_priv->pixels_inside_wrap;
+ style->left_margin = text->_priv->left_margin;
+ style->right_margin = text->_priv->right_margin;
+ style->indent = text->_priv->indent;
+ style->tabs = NULL;
+ style->wrap_mode = text->_priv->wrap_mode;
+ style->justification = text->_priv->justification;
+ style->direction = text->_priv->direction;
+ style->editable = text->_priv->editable;
+ style->invisible = !text->_priv->visible;
+
+ gtk_text_layout_set_default_style(text->_priv->layout, style);
+
+ gtk_text_attributes_unref(style);
+
+ g_signal_connect(
+ G_OBJECT(text->_priv->layout), "invalidated",
+ G_CALLBACK (invalidated_handler), text);
+
+ g_signal_connect(
+ G_OBJECT(text->_priv->layout), "changed",
+ G_CALLBACK (changed_handler), text);
+ }
+} /* gnome_canvas_rich_text_ensure_layout */
+
+static void
+gnome_canvas_rich_text_destroy_layout(GnomeCanvasRichText *text)
+{
+ if (text->_priv->layout) {
+ g_signal_handlers_disconnect_by_func(
+ G_OBJECT(text->_priv->layout), invalidated_handler, text);
+ g_signal_handlers_disconnect_by_func(
+ G_OBJECT(text->_priv->layout), changed_handler, text);
+ g_object_unref(G_OBJECT(text->_priv->layout));
+ text->_priv->layout = NULL;
+ }
+} /* gnome_canvas_rich_text_destroy_layout */
+
+static void
+adjust_for_anchors(GnomeCanvasRichText *text, double *ax, double *ay)
+{
+ double x, y;
+
+ x = text->_priv->x;
+ y = text->_priv->y;
+
+ /* Anchor text */
+ /* X coordinates */
+ switch (text->_priv->anchor) {
+ case GTK_ANCHOR_NW:
+ case GTK_ANCHOR_W:
+ case GTK_ANCHOR_SW:
+ break;
+
+ case GTK_ANCHOR_N:
+ case GTK_ANCHOR_CENTER:
+ case GTK_ANCHOR_S:
+ x -= text->_priv->width / 2;
+ break;
+
+ case GTK_ANCHOR_NE:
+ case GTK_ANCHOR_E:
+ case GTK_ANCHOR_SE:
+ x -= text->_priv->width;
+ break;
+ default:
+ break;
+ }
+
+ /* Y coordinates */
+ switch (text->_priv->anchor) {
+ case GTK_ANCHOR_NW:
+ case GTK_ANCHOR_N:
+ case GTK_ANCHOR_NE:
+ break;
+
+ case GTK_ANCHOR_W:
+ case GTK_ANCHOR_CENTER:
+ case GTK_ANCHOR_E:
+ y -= text->_priv->height / 2;
+ break;
+
+ case GTK_ANCHOR_SW:
+ case GTK_ANCHOR_S:
+ case GTK_ANCHOR_SE:
+ y -= text->_priv->height;
+ break;
+ default:
+ break;
+ }
+
+ if (ax)
+ *ax = x;
+ if (ay)
+ *ay = y;
+} /* adjust_for_anchors */
+
+static void
+get_bounds(GnomeCanvasRichText *text, double *px1, double *py1,
+ double *px2, double *py2)
+{
+ GnomeCanvasItem *item = GNOME_CANVAS_ITEM(text);
+ double x, y;
+ double x1, x2, y1, y2;
+ int cx1, cx2, cy1, cy2;
+
+ adjust_for_anchors(text, &x, &y);
+
+ x1 = x;
+ y1 = y;
+ x2 = x + text->_priv->width;
+ y2 = y + text->_priv->height;
+
+ gnome_canvas_item_i2w(item, &x1, &y1);
+ gnome_canvas_item_i2w(item, &x2, &y2);
+ gnome_canvas_w2c(item->canvas, x1, y1, &cx1, &cy1);
+ gnome_canvas_w2c(item->canvas, x2, y2, &cx2, &cy2);
+
+ *px1 = cx1;
+ *py1 = cy1;
+ *px2 = cx2;
+ *py2 = cy2;
+} /* get_bounds */
+
+static void gnome_canvas_rich_text_get_bounds(GnomeCanvasItem *item, double *px1, double *py1,
+ double *px2, double *py2)
+{
+ GnomeCanvasRichText *text = GNOME_CANVAS_RICH_TEXT(item);
+ get_bounds (text, px1, py1, px2, py2);
+}
+
+static void
+gnome_canvas_rich_text_update(GnomeCanvasItem *item, double *affine,
+ ArtSVP *clip_path, int flags)
+{
+ GnomeCanvasRichText *text = GNOME_CANVAS_RICH_TEXT(item);
+ double x1, y1, x2, y2;
+ GtkTextIter start;
+
+ (* GNOME_CANVAS_ITEM_CLASS(parent_class)->update)(
+ item, affine, clip_path, flags);
+
+ get_bounds(text, &x1, &y1, &x2, &y2);
+
+ gtk_text_buffer_get_iter_at_offset(text->_priv->buffer, &start, 0);
+ if (text->_priv->layout)
+ gtk_text_layout_validate_yrange(
+ text->_priv->layout, &start, 0, y2 - y1);
+
+ gnome_canvas_update_bbox(item, x1, y1, x2, y2);
+} /* gnome_canvas_rich_text_update */
+
+static double
+gnome_canvas_rich_text_point(GnomeCanvasItem *item, double x, double y,
+ int cx, int cy, GnomeCanvasItem **actual_item)
+{
+ GnomeCanvasRichText *text = GNOME_CANVAS_RICH_TEXT(item);
+ double ax, ay;
+ double x1, x2, y1, y2;
+ double dx, dy;
+
+ *actual_item = item;
+
+ /* This is a lame cop-out. Anywhere inside of the bounding box. */
+
+ adjust_for_anchors(text, &ax, &ay);
+
+ x1 = ax;
+ y1 = ay;
+ x2 = ax + text->_priv->width;
+ y2 = ay + text->_priv->height;
+
+ if ((x > x1) && (y > y1) && (x < x2) && (y < y2))
+ return 0.0;
+
+ if (x < x1)
+ dx = x1 - x;
+ else if (x > x2)
+ dx = x - x2;
+ else
+ dx = 0.0;
+
+ if (y < y1)
+ dy = y1 - y;
+ else if (y > y2)
+ dy = y - y2;
+ else
+ dy = 0.0;
+
+ return sqrt(dx * dx + dy * dy);
+} /* gnome_canvas_rich_text_point */
+
+static void
+gnome_canvas_rich_text_draw(GnomeCanvasItem *item, GdkDrawable *drawable,
+ int x, int y, int width, int height)
+{
+ GnomeCanvasRichText *text = GNOME_CANVAS_RICH_TEXT(item);
+ double i2w[6], w2c[6], i2c[6];
+ double ax, ay;
+ int x1, y1, x2, y2;
+ ArtPoint i1, i2;
+ ArtPoint c1, c2;
+
+ gnome_canvas_item_i2w_affine(item, i2w);
+ gnome_canvas_w2c_affine(item->canvas, w2c);
+ art_affine_multiply(i2c, i2w, w2c);
+
+ adjust_for_anchors(text, &ax, &ay);
+
+ i1.x = ax;
+ i1.y = ay;
+ i2.x = ax + text->_priv->width;
+ i2.y = ay + text->_priv->height;
+ art_affine_point(&c1, &i1, i2c);
+ art_affine_point(&c2, &i2, i2c);
+
+ x1 = c1.x;
+ y1 = c1.y;
+ x2 = c2.x;
+ y2 = c2.y;
+
+ gtk_text_layout_set_screen_width(text->_priv->layout, x2 - x1);
+
+ /* FIXME: should last arg be NULL? */
+ gtk_text_layout_draw(
+ text->_priv->layout,
+ GTK_WIDGET(item->canvas),
+ drawable,
+ GTK_WIDGET (item->canvas)->style->text_gc[GTK_STATE_NORMAL],
+ x - x1, y - y1,
+ 0, 0, (x2 - x1) - (x - x1), (y2 - y1) - (y - y1),
+ NULL);
+} /* gnome_canvas_rich_text_draw */
+
+static void
+gnome_canvas_rich_text_render(GnomeCanvasItem *item, GnomeCanvasBuf *buf)
+{
+ g_warning ("rich text item not implemented for anti-aliased canvas");
+} /* gnome_canvas_rich_text_render */
+
+#if 0
+static GtkTextTag *
+gnome_canvas_rich_text_add_tag(GnomeCanvasRichText *text, char *tag_name,
+ int start_offset, int end_offset,
+ const char *first_property_name, ...)
+{
+ GtkTextTag *tag;
+ GtkTextIter start, end;
+ va_list var_args;
+
+ g_return_val_if_fail(text, NULL);
+ g_return_val_if_fail(start_offset >= 0, NULL);
+ g_return_val_if_fail(end_offset >= 0, NULL);
+
+ if (tag_name) {
+ GtkTextTagTable *tag_table;
+
+ tag_table = gtk_text_buffer_get_tag_table(get_buffer(text));
+ g_return_val_if_fail(gtk_text_tag_table_lookup(tag_table, tag_name) == NULL, NULL);
+ }
+
+ tag = gtk_text_buffer_create_tag(
+ get_buffer(text), tag_name, NULL);
+
+ va_start(var_args, first_property_name);
+ g_object_set_valist(G_OBJECT(tag), first_property_name, var_args);
+ va_end(var_args);
+
+ gtk_text_buffer_get_iter_at_offset(
+ get_buffer(text), &start, start_offset);
+ gtk_text_buffer_get_iter_at_offset(
+ get_buffer(text), &end, end_offset);
+ gtk_text_buffer_apply_tag(get_buffer(text), tag, &start, &end);
+
+ return tag;
+} /* gnome_canvas_rich_text_add_tag */
+#endif
diff --git a/src/libgnomecanvas/gnome-canvas-rich-text.h b/src/libgnomecanvas/gnome-canvas-rich-text.h
new file mode 100644
index 0000000..a662021
--- /dev/null
+++ b/src/libgnomecanvas/gnome-canvas-rich-text.h
@@ -0,0 +1,79 @@
+/* Editable GnomeCanvas text item based on GtkTextLayout, borrowed heavily
+ * from GtkTextView.
+ *
+ * Copyright (c) 2000 Red Hat, Inc.
+ * Copyright (c) 2001 Joe Shaw
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GNOME_CANVAS_RICH_TEXT_H
+#define GNOME_CANVAS_RICH_TEXT_H
+
+#include <libgnomecanvas/gnome-canvas.h>
+#include <gtk/gtktextbuffer.h>
+
+G_BEGIN_DECLS
+
+#define GNOME_TYPE_CANVAS_RICH_TEXT (gnome_canvas_rich_text_get_type ())
+#define GNOME_CANVAS_RICH_TEXT(obj) (GTK_CHECK_CAST ((obj), GNOME_TYPE_CANVAS_RICH_TEXT, GnomeCanvasRichText))
+#define GNOME_CANVAS_RICH_TEXT_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GNOME_TYPE_CANVAS_RICH_TEXT, GnomeCanvasRichTextClass))
+#define GNOME_IS_CANVAS_RICH_TEXT(obj) (GTK_CHECK_TYPE ((obj), GNOME_TYPE_CANVAS_RICH_TEXT))
+#define GNOME_IS_CANVAS_RICH_TEXT_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_CANVAS_RICH_TEXT))
+#define GNOME_CANVAS_RICH_TEXT_GET_CLASS(obj) (GTK_CHECK_GET_CLASS ((obj), GNOME_TYPE_CANVAS_RICH_TEXT, GnomeCanvasRichTextClass))
+
+typedef struct _GnomeCanvasRichText GnomeCanvasRichText;
+typedef struct _GnomeCanvasRichTextPrivate GnomeCanvasRichTextPrivate;
+typedef struct _GnomeCanvasRichTextClass GnomeCanvasRichTextClass;
+
+struct _GnomeCanvasRichText {
+ GnomeCanvasItem item;
+
+ GnomeCanvasRichTextPrivate *_priv;
+};
+
+struct _GnomeCanvasRichTextClass {
+ GnomeCanvasItemClass parent_class;
+
+ void (* tag_changed)(GnomeCanvasRichText *text,
+ GtkTextTag *tag);
+};
+
+GType gnome_canvas_rich_text_get_type(void) G_GNUC_CONST;
+
+void gnome_canvas_rich_text_cut_clipboard(GnomeCanvasRichText *text);
+
+void gnome_canvas_rich_text_copy_clipboard(GnomeCanvasRichText *text);
+
+void gnome_canvas_rich_text_paste_clipboard(GnomeCanvasRichText *text);
+
+void gnome_canvas_rich_text_set_buffer(GnomeCanvasRichText *text,
+ GtkTextBuffer *buffer);
+
+GtkTextBuffer *gnome_canvas_rich_text_get_buffer(GnomeCanvasRichText *text);
+void
+gnome_canvas_rich_text_get_iter_location (GnomeCanvasRichText *text,
+ const GtkTextIter *iter,
+ GdkRectangle *location);
+void
+gnome_canvas_rich_text_get_iter_at_location (GnomeCanvasRichText *text,
+ GtkTextIter *iter,
+ gint x,
+ gint y);
+
+G_END_DECLS
+
+#endif /* GNOME_CANVAS_RICH_TEXT_H */
diff --git a/src/libgnomecanvas/gnome-canvas-shape-private.h b/src/libgnomecanvas/gnome-canvas-shape-private.h
new file mode 100644
index 0000000..ffdd3ce
--- /dev/null
+++ b/src/libgnomecanvas/gnome-canvas-shape-private.h
@@ -0,0 +1,103 @@
+#ifndef GNOME_CANVAS_SHAPE_PRIVATE_H
+#define GNOME_CANVAS_SHAPE_PRIVATE_H
+
+/* Bpath item type for GnomeCanvas widget
+ *
+ * GnomeCanvas is basically a port of the Tk toolkit's most excellent canvas widget. Tk is
+ * copyrighted by the Regents of the University of California, Sun Microsystems, and other parties.
+ *
+ * Copyright (C) 1998,1999 The Free Software Foundation
+ *
+ * Authors: Federico Mena <federico@nuclecu.unam.mx>
+ * Raph Levien <raph@acm.org>
+ * Lauris Kaplinski <lauris@ariman.ee>
+ */
+
+#include <gdk/gdk.h>
+#include <libart_lgpl/art_vpath.h>
+#include <libart_lgpl/art_svp.h>
+#include <libart_lgpl/art_vpath_dash.h>
+#include <libart_lgpl/art_svp_wind.h>
+#include <libgnomecanvas/gnome-canvas.h>
+
+#include <libgnomecanvas/gnome-canvas-path-def.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GnomeCanvasShapePrivGdk GnomeCanvasShapePrivGdk;
+typedef struct _GCBPDrawCtx GCBPDrawCtx;
+
+/* Per canvas private structure, holding necessary data for rendering
+ * temporary masks, which are needed for drawing multipart bpaths.
+ * As canvas cannot multithread, we can be sure, that masks are used
+ * serially, also one set of masks per canvas is sufficent to guarantee,
+ * that masks are created on needed X server. Masks grow as needed.
+ * Full structure is refcounted in Bpath implementation
+ */
+
+struct _GCBPDrawCtx {
+ gint refcount;
+
+ GnomeCanvas * canvas;
+
+ gint width;
+ gint height;
+
+ GdkBitmap * mask;
+ GdkBitmap * clip;
+
+ GdkGC * clear_gc;
+ GdkGC * xor_gc;
+};
+
+/* Per Bpath private structure, holding Gdk specific data */
+
+struct _GnomeCanvasShapePrivGdk {
+ gulong fill_pixel; /* Color for fill */
+ gulong outline_pixel; /* Color for outline */
+
+ GdkBitmap *fill_stipple; /* Stipple for fill */
+ GdkBitmap *outline_stipple; /* Stipple for outline */
+
+ GdkGC * fill_gc; /* GC for filling */
+ GdkGC * outline_gc; /* GC for outline */
+
+ gint len_points; /* Size of allocated points array */
+ gint num_points; /* Gdk points in canvas coords */
+ GdkPoint * points; /* Ivariant: closed paths are before open ones */
+ GSList * closed_paths; /* List of lengths */
+ GSList * open_paths; /* List of lengths */
+
+ GCBPDrawCtx * ctx; /* Pointer to per-canvas drawing context */
+};
+
+struct _GnomeCanvasShapePriv {
+ GnomeCanvasPathDef * path; /* Our bezier path representation */
+
+ gdouble scale; /* CTM scaling (for pen) */
+
+ guint fill_set : 1; /* Is fill color set? */
+ guint outline_set : 1; /* Is outline color set? */
+ guint width_pixels : 1; /* Is outline width specified in pixels or units? */
+
+ double width; /* Width of outline, in user coords */
+
+ guint32 fill_rgba; /* Fill color, RGBA */
+ guint32 outline_rgba; /* Outline color, RGBA */
+
+ GdkCapStyle cap; /* Cap style for line */
+ GdkJoinStyle join; /* Join style for line */
+ ArtWindRule wind; /* Winding rule */
+ double miterlimit; /* Miter limit */
+
+ ArtVpathDash dash; /* Dashing pattern */
+
+ ArtSVP * fill_svp; /* The SVP for the filled shape */
+ ArtSVP * outline_svp; /* The SVP for the outline shape */
+
+ GnomeCanvasShapePrivGdk * gdk; /* Gdk specific things */
+};
+
+G_END_DECLS
+
+#endif
diff --git a/src/libgnomecanvas/gnome-canvas-shape.c b/src/libgnomecanvas/gnome-canvas-shape.c
new file mode 100644
index 0000000..f32ea29
--- /dev/null
+++ b/src/libgnomecanvas/gnome-canvas-shape.c
@@ -0,0 +1,1559 @@
+/* Generic bezier shape item for GnomeCanvasWidget. Most code taken
+ * from gnome-canvas-bpath but made into a shape item.
+ *
+ * GnomeCanvas is basically a port of the Tk toolkit's most excellent
+ * canvas widget. Tk is copyrighted by the Regents of the University
+ * of California, Sun Microsystems, and other parties.
+ *
+ * Copyright (C) 1998,1999 The Free Software Foundation
+ *
+ * Authors: Federico Mena <federico@nuclecu.unam.mx>
+ * Raph Levien <raph@acm.org>
+ * Lauris Kaplinski <lauris@ximian.com>
+ * Miguel de Icaza <miguel@kernel.org>
+ * Cody Russell <bratsche@gnome.org>
+ * Rusty Conover <rconover@bangtail.net>
+ */
+
+/* These includes are set up for standalone compile. If/when this codebase
+ is integrated into libgnomeui, the includes will need to change. */
+
+#include <math.h>
+#include <string.h>
+
+#include <gtk/gtkobject.h>
+#include <gtk/gtkwidget.h>
+#include "gnome-canvas.h"
+#include "gnome-canvas-util.h"
+
+#include "gnome-canvas-shape.h"
+#include "gnome-canvas-shape-private.h"
+#include "gnome-canvas-path-def.h"
+
+#include <libart_lgpl/art_rect.h>
+#include <libart_lgpl/art_vpath.h>
+#include <libart_lgpl/art_bpath.h>
+#include <libart_lgpl/art_vpath_bpath.h>
+#include <libart_lgpl/art_svp.h>
+#include <libart_lgpl/art_svp_point.h>
+#include <libart_lgpl/art_svp_vpath.h>
+#include <libart_lgpl/art_vpath_dash.h>
+#include <libart_lgpl/art_svp_wind.h>
+#include <libart_lgpl/art_svp_intersect.h>
+#include <libart_lgpl/art_rect_svp.h>
+
+enum {
+ PROP_0,
+ PROP_FILL_COLOR,
+ PROP_FILL_COLOR_GDK,
+ PROP_FILL_COLOR_RGBA,
+ PROP_OUTLINE_COLOR,
+ PROP_OUTLINE_COLOR_GDK,
+ PROP_OUTLINE_COLOR_RGBA,
+ PROP_FILL_STIPPLE,
+ PROP_OUTLINE_STIPPLE,
+ PROP_WIDTH_PIXELS,
+ PROP_WIDTH_UNITS,
+ PROP_CAP_STYLE,
+ PROP_JOIN_STYLE,
+ PROP_WIND,
+ PROP_MITERLIMIT,
+ PROP_DASH
+};
+
+static void gnome_canvas_shape_class_init (GnomeCanvasShapeClass *class);
+static void gnome_canvas_shape_init (GnomeCanvasShape *bpath);
+static void gnome_canvas_shape_destroy (GtkObject *object);
+static void gnome_canvas_shape_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gnome_canvas_shape_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+static void gnome_canvas_shape_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags);
+static void gnome_canvas_shape_realize (GnomeCanvasItem *item);
+static void gnome_canvas_shape_unrealize (GnomeCanvasItem *item);
+static void gnome_canvas_shape_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
+ int x, int y, int width, int height);
+static double gnome_canvas_shape_point (GnomeCanvasItem *item, double x, double y,
+ int cx, int cy, GnomeCanvasItem **actual_item);
+static void gnome_canvas_shape_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf);
+static void gnome_canvas_shape_bounds (GnomeCanvasItem *item,
+ double *x1, double *y1, double *x2, double *y2);
+
+static gulong get_pixel_from_rgba (GnomeCanvasItem *item, guint32 rgba_color);
+static guint32 get_rgba_from_color (GdkColor * color);
+static void set_gc_foreground (GdkGC *gc, gulong pixel);
+static void gcbp_ensure_gdk (GnomeCanvasShape * bpath);
+static void gcbp_destroy_gdk (GnomeCanvasShape * bpath);
+static void set_stipple (GdkGC *gc, GdkBitmap **internal_stipple, GdkBitmap *stipple, int reconfigure);
+static void gcbp_ensure_mask (GnomeCanvasShape * bpath, gint width, gint height);
+static void gcbp_draw_ctx_unref (GCBPDrawCtx * ctx);
+
+static GnomeCanvasItemClass *parent_class;
+
+GType
+gnome_canvas_shape_get_type (void)
+{
+ static GType shape_type;
+
+ if (!shape_type) {
+ static const GTypeInfo object_info = {
+ sizeof (GnomeCanvasShapeClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gnome_canvas_shape_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (GnomeCanvasShape),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) gnome_canvas_shape_init,
+ NULL /* value_table */
+ };
+
+ shape_type = g_type_register_static (GNOME_TYPE_CANVAS_ITEM, "GnomeCanvasShape",
+ &object_info, 0);
+ }
+
+ return shape_type;
+}
+
+static void
+gnome_canvas_shape_class_init (GnomeCanvasShapeClass *class)
+{
+ GObjectClass *gobject_class;
+ GtkObjectClass *object_class;
+ GnomeCanvasItemClass *item_class;
+
+ gobject_class = (GObjectClass *) class;
+ object_class = (GtkObjectClass *) class;
+ item_class = (GnomeCanvasItemClass *) class;
+
+ parent_class = g_type_class_peek_parent (class);
+
+ /* when this gets checked into libgnomeui, change the
+ GTK_TYPE_POINTER to GTK_TYPE_GNOME_CANVAS_SHAPE, and add an
+ entry to gnome-boxed.defs */
+
+ gobject_class->set_property = gnome_canvas_shape_set_property;
+ gobject_class->get_property = gnome_canvas_shape_get_property;
+
+
+
+ g_object_class_install_property (gobject_class,
+ PROP_FILL_COLOR,
+ g_param_spec_string ("fill_color", NULL, NULL,
+ NULL,
+ (G_PARAM_WRITABLE)));
+ g_object_class_install_property (gobject_class,
+ PROP_FILL_COLOR_GDK,
+ g_param_spec_boxed ("fill_color_gdk", NULL, NULL,
+ GDK_TYPE_COLOR,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property (gobject_class,
+ PROP_FILL_COLOR_RGBA,
+ g_param_spec_uint ("fill_color_rgba", NULL, NULL,
+ 0, G_MAXUINT, 0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property (gobject_class,
+ PROP_OUTLINE_COLOR,
+ g_param_spec_string ("outline_color", NULL, NULL,
+ NULL,
+ (G_PARAM_WRITABLE)));
+ g_object_class_install_property (gobject_class,
+ PROP_OUTLINE_COLOR_GDK,
+ g_param_spec_boxed ("outline_color_gdk", NULL, NULL,
+ GDK_TYPE_COLOR,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property (gobject_class,
+ PROP_OUTLINE_COLOR_RGBA,
+ g_param_spec_uint ("outline_color_rgba", NULL, NULL,
+ 0, G_MAXUINT, 0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property (gobject_class,
+ PROP_FILL_STIPPLE,
+ g_param_spec_object ("fill_stipple", NULL, NULL,
+ GDK_TYPE_DRAWABLE,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property (gobject_class,
+ PROP_OUTLINE_STIPPLE,
+ g_param_spec_object ("outline_stipple", NULL, NULL,
+ GDK_TYPE_DRAWABLE,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property (gobject_class,
+ PROP_WIDTH_PIXELS,
+ g_param_spec_uint ("width_pixels", NULL, NULL,
+ 0, G_MAXUINT, 0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property (gobject_class,
+ PROP_WIDTH_UNITS,
+ g_param_spec_double ("width_units", NULL, NULL,
+ 0.0, G_MAXDOUBLE, 0.0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property (gobject_class,
+ PROP_CAP_STYLE,
+ g_param_spec_enum ("cap_style", NULL, NULL,
+ GDK_TYPE_CAP_STYLE,
+ GDK_CAP_BUTT,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property (gobject_class,
+ PROP_JOIN_STYLE,
+ g_param_spec_enum ("join_style", NULL, NULL,
+ GDK_TYPE_JOIN_STYLE,
+ GDK_JOIN_MITER,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property (gobject_class,
+ PROP_WIND,
+ g_param_spec_uint ("wind", NULL, NULL,
+ 0, G_MAXUINT, 0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property (gobject_class,
+ PROP_MITERLIMIT,
+ g_param_spec_double ("miterlimit", NULL, NULL,
+ 0.0, G_MAXDOUBLE, 0.0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property (gobject_class,
+ PROP_DASH,
+ g_param_spec_pointer ("dash", NULL, NULL,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+
+ object_class->destroy = gnome_canvas_shape_destroy;
+
+ item_class->update = gnome_canvas_shape_update;
+ item_class->realize = gnome_canvas_shape_realize;
+ item_class->unrealize = gnome_canvas_shape_unrealize;
+ item_class->draw = gnome_canvas_shape_draw;
+ item_class->point = gnome_canvas_shape_point;
+ item_class->render = gnome_canvas_shape_render;
+ item_class->bounds = gnome_canvas_shape_bounds;
+}
+
+static void
+gnome_canvas_shape_init (GnomeCanvasShape *shape)
+{
+ shape->priv = g_new (GnomeCanvasShapePriv, 1);
+
+ shape->priv->path = NULL;
+
+ shape->priv->scale = 1.0;
+
+ shape->priv->fill_set = FALSE;
+ shape->priv->outline_set = FALSE;
+ shape->priv->width_pixels = FALSE;
+
+ shape->priv->width = 1.0;
+
+ shape->priv->fill_rgba = 0x0000003f;
+ shape->priv->outline_rgba = 0x0000007f;
+
+ shape->priv->cap = GDK_CAP_BUTT;
+ shape->priv->join = GDK_JOIN_MITER;
+ shape->priv->wind = ART_WIND_RULE_ODDEVEN;
+ shape->priv->miterlimit = 10.43; /* X11 default */
+
+ shape->priv->dash.n_dash = 0;
+ shape->priv->dash.dash = NULL;
+
+ shape->priv->fill_svp = NULL;
+ shape->priv->outline_svp = NULL;
+
+ shape->priv->gdk = NULL;
+}
+
+static void
+gnome_canvas_shape_destroy (GtkObject *object)
+{
+ GnomeCanvasShape *shape;
+ GnomeCanvasShapePriv *priv;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GNOME_IS_CANVAS_SHAPE (object));
+
+ shape = GNOME_CANVAS_SHAPE (object);
+
+ if (shape->priv) {
+ priv = shape->priv;
+ if (priv->gdk) gcbp_destroy_gdk (shape);
+
+ if (priv->path) gnome_canvas_path_def_unref (priv->path);
+
+ if (priv->dash.dash) g_free (priv->dash.dash);
+ if (priv->fill_svp) art_svp_free (priv->fill_svp);
+ if (priv->outline_svp) art_svp_free (priv->outline_svp);
+
+ g_free (shape->priv);
+ shape->priv = NULL;
+ }
+
+ if (GTK_OBJECT_CLASS (parent_class)->destroy)
+ (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+}
+
+/**
+ * gnome_canvas_shape_set_path_def:
+ * @shape: a GnomeCanvasShape
+ * @def: a GnomeCanvasPathDef
+ *
+ * This function sets the the GnomeCanvasPathDef used by the
+ * GnomeCanvasShape. Notice, that it does not request updates, as
+ * it is meant to be used from item implementations, from inside
+ * update queue.
+ */
+
+void
+gnome_canvas_shape_set_path_def (GnomeCanvasShape *shape, GnomeCanvasPathDef *def)
+{
+ GnomeCanvasShapePriv *priv;
+
+ g_return_if_fail (shape != NULL);
+ g_return_if_fail (GNOME_IS_CANVAS_SHAPE (shape));
+
+ priv = shape->priv;
+
+ if (priv->path) {
+ gnome_canvas_path_def_unref (priv->path);
+ priv->path = NULL;
+ }
+
+ if (def) {
+ priv->path = gnome_canvas_path_def_duplicate (def);
+ }
+}
+
+static void
+gnome_canvas_shape_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GnomeCanvasItem *item;
+ GnomeCanvasShape *shape;
+ GnomeCanvasShapePriv *priv;
+ GnomeCanvasShapePrivGdk *gdk;
+ GdkColor color;
+ GdkColor *colorptr;
+ ArtVpathDash *dash;
+
+ item = GNOME_CANVAS_ITEM (object);
+ shape = GNOME_CANVAS_SHAPE (object);
+ priv = shape->priv;
+
+ if (!item->canvas->aa) {
+ gcbp_ensure_gdk (shape);
+ gdk = priv->gdk;
+ } else {
+ gdk = NULL;
+ }
+
+ switch (param_id) {
+ case PROP_FILL_COLOR:
+ if (gnome_canvas_get_color (item->canvas, g_value_get_string (value), &color)) {
+ priv->fill_set = TRUE;
+ priv->fill_rgba = get_rgba_from_color (&color);
+ if (gdk) gdk->fill_pixel = color.pixel;
+ } else if (priv->fill_set)
+ priv->fill_set = FALSE;
+ else
+ break;
+
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_FILL_COLOR_GDK:
+ colorptr = g_value_get_boxed (value);
+ if (colorptr != NULL) {
+ priv->fill_set = TRUE;
+ priv->fill_rgba = get_rgba_from_color (colorptr);
+ if (gdk) {
+ GdkColormap *colormap = gtk_widget_get_colormap (GTK_WIDGET (item->canvas));
+ GdkColor tmp = *colorptr;
+ gdk_rgb_find_color (colormap, &tmp);
+ gdk->fill_pixel = tmp.pixel;
+ }
+ } else if (priv->fill_set)
+ priv->fill_set = FALSE;
+ else
+ break;
+
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_FILL_COLOR_RGBA:
+ priv->fill_set = TRUE;
+ priv->fill_rgba = g_value_get_uint (value);
+ if (gdk) gdk->fill_pixel = get_pixel_from_rgba (item, priv->fill_rgba);
+
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_OUTLINE_COLOR:
+ if (gnome_canvas_get_color (item->canvas, g_value_get_string (value), &color)) {
+ priv->outline_set = TRUE;
+ priv->outline_rgba = get_rgba_from_color (&color);
+ if (gdk) gdk->outline_pixel = color.pixel;
+ } else if (priv->outline_set)
+ priv->outline_set = FALSE;
+ else
+ break;
+
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_OUTLINE_COLOR_GDK:
+ colorptr = g_value_get_boxed (value);
+ if (colorptr != NULL) {
+ priv->outline_set = TRUE;
+ priv->outline_rgba = get_rgba_from_color (colorptr);
+ if (gdk) {
+ GdkColormap *colormap = gtk_widget_get_colormap (GTK_WIDGET (item->canvas));
+ GdkColor tmp = *colorptr;
+ gdk_rgb_find_color (colormap, &tmp);
+ gdk->outline_pixel = tmp.pixel;
+ }
+ } else if (priv->outline_set)
+ priv->outline_set = FALSE;
+ else
+ break;
+
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_OUTLINE_COLOR_RGBA:
+ priv->outline_set = TRUE;
+ priv->outline_rgba = g_value_get_uint (value);
+ if (gdk) gdk->outline_pixel = get_pixel_from_rgba (item, priv->outline_rgba);
+
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_FILL_STIPPLE:
+ if (gdk) {
+ set_stipple (gdk->fill_gc, &gdk->fill_stipple, (GdkBitmap*) g_value_get_object (value), FALSE);
+ gnome_canvas_item_request_update (item);
+ }
+ break;
+
+ case PROP_OUTLINE_STIPPLE:
+ if (gdk) {
+ set_stipple (gdk->outline_gc, &gdk->outline_stipple, (GdkBitmap*) g_value_get_object (value), FALSE);
+ gnome_canvas_item_request_update (item);
+ }
+ break;
+
+ case PROP_WIDTH_PIXELS:
+ priv->width = g_value_get_uint (value);
+ priv->width_pixels = TRUE;
+
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_WIDTH_UNITS:
+ priv->width = fabs (g_value_get_double (value));
+ priv->width_pixels = FALSE;
+
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_WIND:
+ priv->wind = g_value_get_uint (value);
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_CAP_STYLE:
+ priv->cap = g_value_get_enum (value);
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_JOIN_STYLE:
+ priv->join = g_value_get_enum (value);
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_MITERLIMIT:
+ priv->miterlimit = g_value_get_double (value);
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case PROP_DASH:
+ dash = g_value_get_pointer (value);
+ if (priv->dash.dash) g_free (priv->dash.dash);
+ priv->dash.dash = NULL;
+
+ if (dash) {
+ priv->dash.offset = dash->offset;
+ priv->dash.n_dash = dash->n_dash;
+ if (dash->dash != NULL) {
+ priv->dash.dash = g_new (double, dash->n_dash);
+ memcpy (priv->dash.dash, dash->dash, dash->n_dash * sizeof (double));
+ }
+ }
+ gnome_canvas_item_request_update (item);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+/* Allocates a GdkColor structure filled with the specified pixel, and
+ * puts it into the specified value for returning it in the get_property
+ * method.
+ */
+
+static void
+get_color_value (GnomeCanvasShape *shape, gulong pixel, GValue *value)
+{
+ GnomeCanvas *canvas = GNOME_CANVAS_ITEM (shape)->canvas;
+ GdkColormap *colormap = gtk_widget_get_colormap (GTK_WIDGET (canvas));
+ GdkColor color;
+
+ gdk_colormap_query_color (colormap, pixel, &color);
+ g_value_set_boxed (value, &color);
+}
+
+/**
+ * gnome_canvas_shape_get_path_def:
+ * @shape: a GnomeCanvasShape
+ *
+ * This function returns the #GnomeCanvasPathDef that the shape
+ * currently uses. It adds a reference to the #GnomeCanvasPathDef and
+ * returns it, if there is not a #GnomeCanvasPathDef set for the shape
+ * it returns NULL.
+ *
+ * Returns: a #GnomeCanvasPathDef or NULL if none is set for the shape.
+ */
+
+GnomeCanvasPathDef *
+gnome_canvas_shape_get_path_def (GnomeCanvasShape *shape)
+{
+ GnomeCanvasShapePriv *priv;
+
+ g_return_val_if_fail (shape != NULL, NULL);
+ g_return_val_if_fail (GNOME_IS_CANVAS_SHAPE (shape), NULL);
+
+ priv = shape->priv;
+
+ if (priv->path) {
+ gnome_canvas_path_def_ref (priv->path);
+ return priv->path;
+ }
+
+ return NULL;
+}
+
+static void
+gnome_canvas_shape_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GnomeCanvasItem *item = GNOME_CANVAS_ITEM (object);
+ GnomeCanvasShape *shape = GNOME_CANVAS_SHAPE (object);
+ GnomeCanvasShapePriv *priv = shape->priv;
+ GnomeCanvasShapePrivGdk *gdk;
+
+ if (!item->canvas->aa) {
+ gcbp_ensure_gdk (shape);
+ gdk = priv->gdk;
+ }
+ else {
+ gdk = NULL;
+ }
+
+ switch (param_id) {
+ case PROP_FILL_COLOR_GDK:
+ if (gdk) {
+ get_color_value (shape, gdk->fill_pixel, value);
+ } else {
+ get_color_value (shape, 0, value);
+ }
+ break;
+
+ case PROP_OUTLINE_COLOR_GDK:
+ if (gdk) {
+ get_color_value (shape, gdk->outline_pixel, value);
+ } else {
+ get_color_value (shape, 0, value);
+ }
+ break;
+
+ case PROP_FILL_COLOR_RGBA:
+ g_value_set_uint (value, priv->fill_rgba);
+ break;
+
+ case PROP_OUTLINE_COLOR_RGBA:
+ g_value_set_uint (value, priv->outline_rgba);
+ break;
+
+ case PROP_FILL_STIPPLE:
+ if (gdk) {
+ g_value_set_object (value, gdk->fill_stipple);
+ } else {
+ g_value_set_object (value, NULL);
+ }
+ break;
+
+ case PROP_OUTLINE_STIPPLE:
+ if (gdk) {
+ g_value_set_object (value, gdk->outline_stipple);
+ } else {
+ g_value_set_object (value, NULL);
+ }
+ break;
+
+ case PROP_WIND:
+ g_value_set_uint (value, priv->wind);
+ break;
+
+ case PROP_CAP_STYLE:
+ g_value_set_enum (value, priv->cap);
+ break;
+
+ case PROP_JOIN_STYLE:
+ g_value_set_enum (value, priv->join);
+ break;
+
+ case PROP_WIDTH_PIXELS:
+ g_value_set_uint (value, priv->width);
+ break;
+
+ case PROP_WIDTH_UNITS:
+ g_value_set_double (value, priv->width);
+ break;
+
+ case PROP_MITERLIMIT:
+ g_value_set_double (value, priv->miterlimit);
+ break;
+
+ case PROP_DASH:
+ g_value_set_pointer (value, &priv->dash);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+gnome_canvas_shape_realize (GnomeCanvasItem *item)
+{
+ GnomeCanvasShape *shape;
+
+ shape = GNOME_CANVAS_SHAPE (item);
+
+ if (parent_class->realize)
+ (* parent_class->realize) (item);
+
+ if (!item->canvas->aa) {
+ gcbp_ensure_gdk (shape);
+
+ g_assert(item->canvas->layout.bin_window != NULL);
+
+ shape->priv->gdk->fill_gc = gdk_gc_new (item->canvas->layout.bin_window);
+ shape->priv->gdk->outline_gc = gdk_gc_new (item->canvas->layout.bin_window);
+ }
+}
+
+static void
+gnome_canvas_shape_unrealize (GnomeCanvasItem *item)
+{
+ GnomeCanvasShape *shape;
+
+ shape = GNOME_CANVAS_SHAPE (item);
+
+ if (!item->canvas->aa) {
+ g_assert (shape->priv->gdk != NULL);
+
+ gdk_gc_unref (shape->priv->gdk->fill_gc);
+ shape->priv->gdk->fill_gc = NULL;
+
+ gdk_gc_unref (shape->priv->gdk->outline_gc);
+ shape->priv->gdk->outline_gc = NULL;
+ }
+
+ if (parent_class->unrealize)
+ (* parent_class->unrealize) (item);
+}
+
+static void
+gnome_canvas_shape_render (GnomeCanvasItem *item,
+ GnomeCanvasBuf *buf)
+{
+ GnomeCanvasShape *shape;
+
+ shape = GNOME_CANVAS_SHAPE (item);
+
+ if (shape->priv->fill_svp != NULL)
+ gnome_canvas_render_svp (buf,
+ shape->priv->fill_svp,
+ shape->priv->fill_rgba);
+
+ if (shape->priv->outline_svp != NULL)
+ gnome_canvas_render_svp (buf,
+ shape->priv->outline_svp,
+ shape->priv->outline_rgba);
+}
+
+static void
+gnome_canvas_shape_draw (GnomeCanvasItem *item,
+ GdkDrawable *drawable,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ static GdkPoint * dpoints = NULL;
+ static gint num_dpoints = 0;
+
+ GnomeCanvasShape * shape;
+ GnomeCanvasShapePriv * priv;
+ GnomeCanvasShapePrivGdk * gdk;
+ gint i, pos, len;
+ GSList * l;
+
+ shape = GNOME_CANVAS_SHAPE (item);
+ priv = shape->priv;
+
+ /* We have to be realized, so gdk struct should exist! */
+
+ gdk = shape->priv->gdk;
+ g_assert (gdk != NULL);
+
+ /* Build temporary point list, translated by -x, -y */
+
+ if (dpoints == NULL) {
+ dpoints = g_new (GdkPoint, gdk->num_points);
+ num_dpoints = gdk->num_points;
+ } else if (num_dpoints < gdk->num_points) {
+ dpoints = g_renew (GdkPoint, dpoints, gdk->num_points);
+ num_dpoints = gdk->num_points;
+ }
+
+ for (i = 0; i < gdk->num_points; i++) {
+ dpoints[i].x = gdk->points[i].x - x;
+ dpoints[i].y = gdk->points[i].y - y;
+ }
+
+ if (priv->fill_set) {
+
+ /* Ensure, that we have mask and it is big enough */
+
+ gcbp_ensure_mask (shape, width, height);
+
+ /* Clear mask */
+
+ gdk_draw_rectangle (gdk->ctx->mask,
+ gdk->ctx->clear_gc,
+ TRUE,
+ 0, 0,
+ width, height);
+
+ /* Draw subpaths, using XOR gc */
+
+ pos = 0;
+
+ for (l = gdk->closed_paths; l != NULL; l = l->next) {
+ len = GPOINTER_TO_INT (l->data);
+
+ gdk_draw_polygon (gdk->ctx->mask,
+ gdk->ctx->xor_gc,
+ TRUE,
+ &dpoints[pos],
+ len);
+
+ pos += len;
+ }
+
+ /* Set bitmap to clipping mask */
+
+ gdk_gc_set_clip_mask (gdk->fill_gc, gdk->ctx->mask);
+
+ /* Stipple offset */
+
+ if (gdk->fill_stipple) gnome_canvas_set_stipple_origin (item->canvas, gdk->fill_gc);
+
+ /* Draw clipped rect to drawable */
+
+ gdk_draw_rectangle (drawable,
+ gdk->fill_gc,
+ TRUE,
+ 0, 0,
+ width, height);
+ }
+
+ if (priv->outline_set) {
+
+ /* Stipple offset */
+
+ if (gdk->outline_stipple) gnome_canvas_set_stipple_origin (item->canvas, gdk->outline_gc);
+ /* Draw subpaths */
+
+ pos = 0;
+
+ for (l = gdk->closed_paths; l != NULL; l = l->next) {
+ len = GPOINTER_TO_INT (l->data);
+
+ gdk_draw_polygon (drawable,
+ gdk->outline_gc,
+ FALSE,
+ &dpoints[pos],
+ len);
+
+ pos += len;
+ }
+
+ for (l = gdk->open_paths; l != NULL; l = l->next) {
+ len = GPOINTER_TO_INT (l->data);
+
+ gdk_draw_lines (drawable,
+ gdk->outline_gc,
+ &dpoints[pos],
+ len);
+
+ pos += len;
+ }
+ }
+}
+
+#define GDK_POINTS_BLOCK 32
+
+static void
+gnome_canvas_shape_ensure_gdk_points (GnomeCanvasShapePrivGdk *gdk, gint num)
+{
+ if (gdk->len_points < gdk->num_points + num) {
+ gdk->len_points = MAX (gdk->len_points + GDK_POINTS_BLOCK, gdk->len_points + num);
+ gdk->points = g_renew (GdkPoint, gdk->points, gdk->len_points);
+ }
+}
+
+static void
+gnome_canvas_shape_update_gdk (GnomeCanvasShape * shape, double * affine, ArtSVP * clip, int flags)
+{
+ GnomeCanvasShapePriv * priv;
+ GnomeCanvasShapePrivGdk * gdk;
+ int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
+ gboolean bbox_set = FALSE;
+ gint width = 0; /* silence gcc */
+
+ g_assert (!((GnomeCanvasItem *) shape)->canvas->aa);
+
+ priv = shape->priv;
+ gdk = priv->gdk;
+ g_assert (gdk != NULL);
+
+ if (priv->outline_set) {
+ GdkLineStyle style;
+
+ if (priv->width_pixels) {
+ width = (int) floor (priv->width + 0.5);
+ /* Never select 0 pixels unless the user asked for it,
+ * since that is the X11 zero width lines are non-specified */
+ if (priv->width_pixels != 0 && width == 0) {
+ width = 1;
+ }
+ } else {
+ width = (int) floor ((priv->width * priv->scale) + 0.5);
+ /* Never select 0 pixels unless the user asked for it,
+ * since that is the X11 zero width lines are non-speciifed */
+ if (priv->width != 0 && width == 0) {
+ width = 1;
+ }
+ }
+
+ /* If dashed, set it in GdkGC */
+
+ if ((shape->priv->dash.dash != NULL) && (shape->priv->dash.n_dash > 0)) {
+ gint8 * dash_list;
+ gint i;
+
+ dash_list = g_new (gint8, shape->priv->dash.n_dash);
+
+ for (i = 0; i < priv->dash.n_dash; i++) {
+ dash_list[i] = (gint8) shape->priv->dash.dash[i];
+ }
+
+ gdk_gc_set_dashes (gdk->outline_gc,
+ (gint) priv->dash.offset,
+ dash_list,
+ priv->dash.n_dash);
+
+ g_free (dash_list);
+
+ style = GDK_LINE_ON_OFF_DASH;
+ } else {
+ style = GDK_LINE_SOLID;
+ }
+
+ /* Set line width, cap, join */
+ if(gdk->outline_gc) {
+
+ gdk_gc_set_line_attributes (gdk->outline_gc,
+ width,
+ style,
+ priv->cap,
+ priv->join);
+
+ /* Colors and stipples */
+ set_gc_foreground (gdk->outline_gc, gdk->outline_pixel);
+ set_stipple (gdk->outline_gc, &gdk->outline_stipple, gdk->outline_stipple, TRUE);
+ }
+ }
+
+ if (priv->fill_set) {
+
+ /* Colors and stipples */
+ if(gdk->fill_gc) {
+ set_gc_foreground (gdk->fill_gc, gdk->fill_pixel);
+ set_stipple (gdk->fill_gc, &gdk->fill_stipple, gdk->fill_stipple, TRUE);
+ }
+ }
+
+ /* Now the crazy part */
+
+ /* Free existing GdkPoint array */
+
+ if (gdk->points) {
+ g_free (gdk->points);
+ gdk->points = NULL;
+ gdk->len_points = 0;
+ gdk->num_points = 0;
+ }
+
+ /* Free subpath lists */
+
+ while (gdk->closed_paths) gdk->closed_paths = g_slist_remove (gdk->closed_paths, gdk->closed_paths->data);
+ while (gdk->open_paths) gdk->open_paths = g_slist_remove (gdk->open_paths, gdk->open_paths->data);
+
+ /* Calcualte new GdkPoints array and subpath lists */
+
+ if (priv->path) {
+ GnomeCanvasPathDef * apath, * cpath, * opath;
+ ArtBpath * abpath;
+ GSList * clist, * olist;
+ gint pos;
+
+#if 0
+ /* Allocate array */
+ gdk->num_points = gnome_canvas_path_def_length (priv->path) * 1000 - 1;
+ gdk->points = g_new (GdkPoint, gdk->num_points);
+ g_print ("Points %d\n", gdk->num_points);
+ /* Transform path */
+#endif
+
+ abpath = art_bpath_affine_transform (gnome_canvas_path_def_bpath (priv->path), affine);
+ apath = gnome_canvas_path_def_new_from_bpath (abpath);
+
+ /* Split path into open and closed parts */
+
+ cpath = gnome_canvas_path_def_closed_parts (apath);
+ opath = gnome_canvas_path_def_open_parts (apath);
+ gnome_canvas_path_def_unref (apath);
+
+ /* Split partial paths into subpaths */
+
+ clist = gnome_canvas_path_def_split (cpath);
+ gnome_canvas_path_def_unref (cpath);
+ olist = gnome_canvas_path_def_split (opath);
+ gnome_canvas_path_def_unref (opath);
+
+ pos = 0;
+
+ /* Fill GdkPoints and add subpaths to list: closed subpaths */
+
+ while (clist) {
+ GnomeCanvasPathDef * path;
+ ArtBpath * bpath;
+ ArtVpath * vpath;
+ gint len, i;
+
+ path = (GnomeCanvasPathDef *) clist->data;
+ bpath = gnome_canvas_path_def_bpath (path);
+ vpath = art_bez_path_to_vec (bpath, 0.1);
+ for (len = 0; vpath[len].code != ART_END; len++) ;
+
+ gnome_canvas_shape_ensure_gdk_points (gdk, len);
+ for (i = 0; i < len; i++) {
+ gdk->points[pos + i].x = (gint) floor (vpath[i].x + 0.5);
+ gdk->points[pos + i].y = (gint) floor (vpath[i].y + 0.5);
+
+ if (bbox_set) {
+ x1 = MIN (x1, gdk->points[pos + i].x);
+ x2 = MAX (x2, gdk->points[pos + i].x);
+ y1 = MIN (y1, gdk->points[pos + i].y);
+ y2 = MAX (y2, gdk->points[pos + i].y);
+ } else {
+ bbox_set = TRUE;
+ x1 = x2 = gdk->points[pos + i].x;
+ y1 = y2 = gdk->points[pos + i].y;
+ }
+ }
+ gdk->num_points += len;
+
+ art_free (vpath);
+
+ if (len > 0) {
+ pos += len;
+ gdk->closed_paths = g_slist_append (gdk->closed_paths, GINT_TO_POINTER (len));
+ }
+
+ gnome_canvas_path_def_unref (path);
+ clist = g_slist_remove (clist, clist->data);
+ }
+
+ /* Fill GdkPoints and add subpaths to list: open subpaths */
+
+ while (olist) {
+ GnomeCanvasPathDef * path;
+ ArtBpath * bpath;
+ ArtVpath * vpath;
+ gint len, i;
+
+ path = (GnomeCanvasPathDef *) olist->data;
+ bpath = gnome_canvas_path_def_bpath (path);
+ vpath = art_bez_path_to_vec (bpath, 0.1);
+ for (len = 0; vpath[len].code != ART_END; len++) ;
+
+ gnome_canvas_shape_ensure_gdk_points (gdk, len);
+ for (i = 0; i < len; i++) {
+ gdk->points[pos + i].x = (gint) floor (vpath[i].x + 0.5);
+ gdk->points[pos + i].y = (gint) floor (vpath[i].y + 0.5);
+
+ if (bbox_set) {
+ x1 = MIN (x1, gdk->points[pos + i].x);
+ x2 = MAX (x2, gdk->points[pos + i].x);
+ y1 = MIN (y1, gdk->points[pos + i].y);
+ y2 = MAX (y2, gdk->points[pos + i].y);
+ } else {
+ bbox_set = TRUE;
+ x1 = x2 = gdk->points[pos + i].x;
+ y1 = y2 = gdk->points[pos + i].y;
+ }
+ }
+ gdk->num_points += len;
+
+ art_free (vpath);
+
+ if (len > 0) {
+ pos += len;
+ gdk->open_paths = g_slist_append (gdk->open_paths, GINT_TO_POINTER (len));
+ }
+
+ gnome_canvas_path_def_unref (path);
+ olist = g_slist_remove (olist, olist->data);
+ }
+
+ }
+
+ if (bbox_set) {
+ if (priv->outline_set) {
+ int stroke_border = (priv->join == GDK_JOIN_MITER)
+ ? ceil (10.43*width/2) /* 10.43 is the miter limit for X11 */
+ : ceil (width/2);
+ x1 -= stroke_border;
+ x2 += stroke_border;
+ y1 -= stroke_border;
+ y2 += stroke_border;
+ }
+
+ gnome_canvas_update_bbox (GNOME_CANVAS_ITEM (shape),
+ x1, y1,
+ x2 + 1, y2 + 1);
+ }
+
+}
+
+static void
+gnome_canvas_shape_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
+{
+ GnomeCanvasShape * shape;
+ GnomeCanvasShapePriv * priv;
+ ArtSVP * svp;
+
+ shape = GNOME_CANVAS_SHAPE (item);
+
+ priv = shape->priv;
+
+ /* Common part */
+ if (parent_class->update) {
+ (* parent_class->update) (item, affine, clip_path, flags);
+ }
+
+ /* Outline width */
+ shape->priv->scale = art_affine_expansion (affine);
+
+ /* Reset bbox */
+ if (item->canvas->aa) {
+ gnome_canvas_item_reset_bounds (item);
+ }
+
+ /* Clipped fill SVP */
+
+ if ((priv->fill_set) && (priv->path) && (gnome_canvas_path_def_any_closed (priv->path))) {
+ GnomeCanvasPathDef * cpath;
+ ArtSvpWriter *swr;
+ ArtVpath *vpath;
+ ArtBpath *abp;
+ ArtSVP *svp2;
+
+ /* Get closed part of path */
+
+ cpath = gnome_canvas_path_def_closed_parts (shape->priv->path);
+ abp = art_bpath_affine_transform (gnome_canvas_path_def_bpath (cpath), affine);
+ gnome_canvas_path_def_unref (cpath);
+
+ /* Render, until SVP */
+
+ vpath = art_bez_path_to_vec (abp, 0.1);
+ art_free (abp);
+
+ svp = art_svp_from_vpath (vpath);
+ art_free (vpath);
+
+ swr = art_svp_writer_rewind_new (shape->priv->wind);
+ art_svp_intersector (svp, swr);
+
+ svp2 = art_svp_writer_rewind_reap (swr);
+ art_svp_free (svp);
+
+ if (item->canvas->aa) {
+ /* Update clipped path */
+ gnome_canvas_item_update_svp_clip (item,
+ &shape->priv->fill_svp,
+ svp2,
+ clip_path);
+ } else {
+ if (priv->fill_svp) {
+ art_svp_free (priv->fill_svp);
+ priv->fill_svp = NULL;
+ }
+ /* No clipping */
+ shape->priv->fill_svp = svp2;
+ }
+ }
+
+ if (priv->outline_set && priv->path && !gnome_canvas_path_def_is_empty (priv->path)) {
+ gdouble width;
+ ArtBpath * abp;
+ ArtVpath * vpath;
+
+ /* Set linewidth */
+
+ if (priv->width_pixels) {
+ width = priv->width;
+ } else {
+ width = priv->width * priv->scale;
+ }
+
+ if (width < 0.5) width = 0.5;
+
+ /* Render full path until vpath */
+
+ abp = art_bpath_affine_transform (gnome_canvas_path_def_bpath (priv->path), affine);
+
+ vpath = art_bez_path_to_vec (abp, 0.1);
+ art_free (abp);
+
+ /* If dashed, apply dash */
+
+ if (priv->dash.dash != NULL)
+ {
+ ArtVpath *old = vpath;
+
+ vpath = art_vpath_dash (old, &priv->dash);
+ art_free (old);
+ }
+
+ /* Stroke vpath to SVP */
+
+ svp = art_svp_vpath_stroke (vpath,
+ gnome_canvas_join_gdk_to_art (priv->join),
+ gnome_canvas_cap_gdk_to_art (priv->cap),
+ width,
+ priv->miterlimit,
+ 0.25);
+ art_free (vpath);
+
+ if (item->canvas->aa) {
+ /* Update clipped */
+ gnome_canvas_item_update_svp_clip (item, &priv->outline_svp, svp, clip_path);
+ } else {
+ if (priv->outline_svp) {
+ art_svp_free (priv->outline_svp);
+ priv->outline_svp = NULL;
+ }
+ /* No clipping (yet) */
+ shape->priv->outline_svp = svp;
+ }
+ }
+
+ /* Gdk requires additional handling */
+
+ if (!item->canvas->aa) {
+ gnome_canvas_shape_update_gdk (shape, affine, clip_path, flags);
+ }
+}
+
+static double
+gnome_canvas_shape_point (GnomeCanvasItem *item, double x, double y,
+ int cx, int cy, GnomeCanvasItem **actual_item)
+{
+ GnomeCanvasShape *shape;
+ double dist;
+ int wind;
+
+#if 0
+ /* fixme: This is just for debugging, canvas should ensure that */
+ /* fixme: IF YOU ARE SURE THAT IT IS CORRECT BEHAVIOUR, you can remove warning */
+ /* fixme: and make it to return silently */
+ g_return_val_if_fail (!item->canvas->need_update, 1e18);
+#endif
+
+ shape = GNOME_CANVAS_SHAPE (item);
+
+ /* todo: update? */
+ if (shape->priv->fill_set && shape->priv->fill_svp) {
+ wind = art_svp_point_wind (shape->priv->fill_svp, cx, cy);
+ if ((shape->priv->wind == ART_WIND_RULE_NONZERO) && (wind != 0)) {
+ *actual_item = item;
+ return 0.0;
+ }
+ if ((shape->priv->wind == ART_WIND_RULE_ODDEVEN) && ((wind & 0x1) != 0)) {
+ *actual_item = item;
+ return 0.0;
+ }
+ }
+
+ if (shape->priv->outline_set && shape->priv->outline_svp) {
+ wind = art_svp_point_wind (shape->priv->outline_svp, cx, cy);
+ if (wind) {
+ *actual_item = item;
+ return 0.0;
+ }
+ }
+
+ if (shape->priv->outline_set && shape->priv->outline_svp) {
+ dist = art_svp_point_dist (shape->priv->outline_svp, cx, cy);
+ } else if (shape->priv->fill_set && shape->priv->outline_svp) {
+ dist = art_svp_point_dist (shape->priv->fill_svp, cx, cy);
+ } else {
+ return 1e12;
+ }
+
+ *actual_item = item;
+
+ return dist;
+}
+
+/* Helpers */
+
+/* Get 32bit rgba color from GdkColor */
+
+static guint32
+get_rgba_from_color (GdkColor * color)
+{
+ return ((color->red & 0xff00) << 16) | ((color->green & 0xff00) << 8) | (color->blue & 0xff00) | 0xff;
+}
+
+/* Get Gdk pixel value from 32bit rgba color */
+
+static gulong
+get_pixel_from_rgba (GnomeCanvasItem *item, guint32 rgba_color)
+{
+ return gnome_canvas_get_color_pixel (item->canvas, rgba_color);
+}
+
+/* Convenience function to set a GC's foreground color to the specified pixel value */
+
+static void
+set_gc_foreground (GdkGC *gc, gulong pixel)
+{
+ GdkColor c;
+
+ g_assert (gc != NULL);
+
+ c.pixel = pixel;
+
+ gdk_gc_set_foreground (gc, &c);
+}
+
+/* Sets the stipple pattern for the specified gc */
+
+static void
+set_stipple (GdkGC *gc, GdkBitmap **internal_stipple, GdkBitmap *stipple, int reconfigure)
+{
+ if (*internal_stipple && !reconfigure)
+ gdk_bitmap_unref (*internal_stipple);
+
+ *internal_stipple = stipple;
+ if (stipple && !reconfigure)
+ gdk_bitmap_ref (stipple);
+
+ if (gc) {
+ if (stipple) {
+ gdk_gc_set_stipple (gc, stipple);
+ gdk_gc_set_fill (gc, GDK_STIPPLED);
+ } else
+ gdk_gc_set_fill (gc, GDK_SOLID);
+ }
+}
+
+/* Creates private Gdk struct, if not present */
+/* We cannot do it during ::init, as we have to know canvas */
+
+static void
+gcbp_ensure_gdk (GnomeCanvasShape * shape)
+{
+ g_assert (!((GnomeCanvasItem *) shape)->canvas->aa);
+
+ if (!shape->priv->gdk) {
+ GnomeCanvasShapePrivGdk * gdk;
+
+ gdk = g_new (GnomeCanvasShapePrivGdk, 1);
+
+ gdk->fill_pixel = get_pixel_from_rgba ((GnomeCanvasItem *) shape, shape->priv->fill_rgba);
+ gdk->outline_pixel = get_pixel_from_rgba ((GnomeCanvasItem *) shape, shape->priv->outline_rgba);
+
+ gdk->fill_stipple = NULL;
+ gdk->outline_stipple = NULL;
+
+ gdk->fill_gc = NULL;
+ gdk->outline_gc = NULL;
+
+ gdk->len_points = 0;
+ gdk->num_points = 0;
+ gdk->points = NULL;
+ gdk->closed_paths = NULL;
+ gdk->open_paths = NULL;
+
+ gdk->ctx = NULL;
+
+ shape->priv->gdk = gdk;
+ }
+}
+
+/* Destroy private Gdk struct */
+/* It is here, to make ::destroy implementation shorter :) */
+
+static void
+gcbp_destroy_gdk (GnomeCanvasShape * shape)
+{
+ GnomeCanvasShapePrivGdk * gdk;
+
+ g_assert (!((GnomeCanvasItem *)shape)->canvas->aa);
+
+ gdk = shape->priv->gdk;
+
+ if (gdk) {
+ g_assert (!gdk->fill_gc);
+ g_assert (!gdk->outline_gc);
+
+ if (gdk->fill_stipple)
+ gdk_bitmap_unref (gdk->fill_stipple);
+
+ if (gdk->outline_stipple)
+ gdk_bitmap_unref (gdk->outline_stipple);
+
+ if (gdk->points)
+ g_free (gdk->points);
+
+ while (gdk->closed_paths)
+ gdk->closed_paths = g_slist_remove (gdk->closed_paths, gdk->closed_paths->data);
+ while (gdk->open_paths)
+ gdk->open_paths = g_slist_remove (gdk->open_paths, gdk->open_paths->data);
+
+ if (gdk->ctx)
+ gcbp_draw_ctx_unref (gdk->ctx);
+
+ g_free (gdk);
+
+ shape->priv->gdk = NULL;
+ }
+}
+
+/*
+ * Ensure, that per-canvas Ctx struct is present and bitmaps are
+ * big enough, to mask full redraw area. Ctx is refcounted and
+ * defined as "BpathDrawCtx" data member on parent canvas
+ */
+
+static void
+gcbp_ensure_mask (GnomeCanvasShape * shape, gint width, gint height)
+{
+ GnomeCanvasShapePrivGdk * gdk;
+ GCBPDrawCtx * ctx;
+
+ gdk = shape->priv->gdk;
+ g_assert (gdk != NULL);
+ ctx = gdk->ctx;
+
+ if (!ctx) {
+ /* Ctx is not yet defined for us */
+
+ GnomeCanvas * canvas;
+
+ canvas = GNOME_CANVAS_ITEM (shape)->canvas;
+
+ ctx = g_object_get_data (G_OBJECT (canvas), "BpathDrawCtx");
+
+ if (!ctx) {
+ /* Ctx is not defined for parent canvas yet */
+
+ ctx = g_new (GCBPDrawCtx, 1);
+
+ ctx->refcount = 1;
+ ctx->canvas = canvas;
+ ctx->width = 0;
+ ctx->height = 0;
+
+ ctx->mask = NULL;
+ ctx->clip = NULL;
+
+ ctx->clear_gc = NULL;
+ ctx->xor_gc = NULL;
+
+ g_object_set_data (G_OBJECT (canvas), "BpathDrawCtx", ctx);
+
+ } else {
+ ctx->refcount++;
+ }
+
+ gdk->ctx = ctx;
+
+ }
+
+ /* Now we are sure, that ctx is present and properly refcounted */
+
+ if ((width > ctx->width) || (height > ctx->height)) {
+ /* Ctx is too small */
+
+ GdkWindow * window;
+
+ window = ((GtkWidget *) (((GnomeCanvasItem *) shape)->canvas))->window;
+
+ if (ctx->clear_gc) gdk_gc_unref (ctx->clear_gc);
+ if (ctx->xor_gc) gdk_gc_unref (ctx->xor_gc);
+ if (ctx->mask) gdk_bitmap_unref (ctx->mask);
+ if (ctx->clip) gdk_bitmap_unref (ctx->clip);
+
+ ctx->mask = gdk_pixmap_new (window, width, height, 1);
+ ctx->clip = NULL;
+
+ ctx->clear_gc = gdk_gc_new (ctx->mask);
+ gdk_gc_set_function (ctx->clear_gc, GDK_CLEAR);
+
+ ctx->xor_gc = gdk_gc_new (ctx->mask);
+ gdk_gc_set_function (ctx->xor_gc, GDK_INVERT);
+ }
+}
+
+/* It is cleaner to have it here, not in parent function */
+
+static void
+gcbp_draw_ctx_unref (GCBPDrawCtx * ctx)
+{
+ if (--ctx->refcount < 1) {
+ if (ctx->clear_gc)
+ gdk_gc_unref (ctx->clear_gc);
+ if (ctx->xor_gc)
+ gdk_gc_unref (ctx->xor_gc);
+
+ if (ctx->mask)
+ gdk_bitmap_unref (ctx->mask);
+ if (ctx->clip)
+ gdk_bitmap_unref (ctx->clip);
+
+ g_object_set_data (G_OBJECT (ctx->canvas), "BpathDrawCtx", NULL);
+ g_free (ctx);
+ }
+}
+
+static void
+gnome_canvas_shape_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
+{
+ GnomeCanvasShape * shape;
+ GnomeCanvasShapePriv * priv;
+ ArtDRect bbox;
+ ArtSVP * svp;
+
+ shape = GNOME_CANVAS_SHAPE (item);
+
+ priv = shape->priv;
+
+ bbox.x0 = *x1;
+ bbox.y0 = *y1;
+ bbox.x1 = *x2;
+ bbox.y1 = *y2;
+
+ if (priv->outline_set && priv->path && !gnome_canvas_path_def_is_empty (priv->path)) {
+ gdouble width;
+ ArtVpath * vpath;
+
+ /* Set linewidth */
+
+ if (priv->width_pixels) {
+ width = priv->width;
+ } else {
+ width = priv->width * priv->scale;
+ }
+
+ if (width < 0.5) width = 0.5;
+
+ /* Render full path until vpath */
+
+ vpath = art_bez_path_to_vec (gnome_canvas_path_def_bpath (priv->path), 0.1);
+
+ /* If dashed, apply dash */
+
+ if (priv->dash.dash != NULL)
+ {
+ ArtVpath *old = vpath;
+
+ vpath = art_vpath_dash (old, &priv->dash);
+ art_free (old);
+ }
+
+ /* Stroke vpath to SVP */
+
+ svp = art_svp_vpath_stroke (vpath,
+ gnome_canvas_join_gdk_to_art (priv->join),
+ gnome_canvas_cap_gdk_to_art (priv->cap),
+ width,
+ priv->miterlimit,
+ 0.25);
+ art_free (vpath);
+ art_drect_svp (&bbox, svp);
+ art_svp_free (svp);
+ } else if ((priv->fill_set) && (priv->path) && (gnome_canvas_path_def_any_closed (priv->path))) {
+ GnomeCanvasPathDef *cpath;
+ ArtSvpWriter *swr;
+ ArtVpath *vpath;
+ ArtSVP *svp2;
+
+ /* Get closed part of path */
+ cpath = gnome_canvas_path_def_closed_parts (shape->priv->path);
+ /* Render, until SVP */
+ vpath = art_bez_path_to_vec (gnome_canvas_path_def_bpath (cpath), 0.1);
+ gnome_canvas_path_def_unref (cpath);
+
+ svp = art_svp_from_vpath (vpath);
+ art_free (vpath);
+
+ swr = art_svp_writer_rewind_new (shape->priv->wind);
+ art_svp_intersector (svp, swr);
+
+ svp2 = art_svp_writer_rewind_reap (swr);
+ art_svp_free (svp);
+
+ art_drect_svp (&bbox, svp2);
+ art_svp_free (svp2);
+ }
+
+ *x1 = bbox.x0;
+ *y1 = bbox.y0;
+ *x2 = bbox.x1;
+ *y2 = bbox.y1;
+}
diff --git a/src/libgnomecanvas/gnome-canvas-shape.h b/src/libgnomecanvas/gnome-canvas-shape.h
new file mode 100644
index 0000000..d645465
--- /dev/null
+++ b/src/libgnomecanvas/gnome-canvas-shape.h
@@ -0,0 +1,81 @@
+/* Generic bezier shape item for GnomeCanvas
+ *
+ * GnomeCanvas is basically a port of the Tk toolkit's most excellent canvas widget. Tk is
+ * copyrighted by the Regents of the University of California, Sun Microsystems, and other parties.
+ *
+ * Copyright (C) 1998,1999 The Free Software Foundation
+ *
+ * Authors: Federico Mena <federico@nuclecu.unam.mx>
+ * Raph Levien <raph@acm.org>
+ * Lauris Kaplinski <lauris@ximian.com>
+ * Rusty Conover <rconover@bangtail.net>
+ */
+
+#ifndef GNOME_CANVAS_SHAPE_H
+#define GNOME_CANVAS_SHAPE_H
+
+#include <libgnomecanvas/gnome-canvas.h>
+#include <libgnomecanvas/gnome-canvas-path-def.h>
+
+G_BEGIN_DECLS
+
+
+/* Shape item for the canvas.
+ *
+ * The following object arguments are available:
+ *
+ * name type read/write description
+ * ------------------------------------------------------------------------------------------
+ * fill_color string W X color specification for fill color,
+ * or NULL pointer for no color (transparent).
+ * fill_color_gdk GdkColor* RW Allocated GdkColor for fill.
+ * outline_color string W X color specification for outline color,
+ * or NULL pointer for no color (transparent).
+ * outline_color_gdk GdkColor* RW Allocated GdkColor for outline.
+ * fill_stipple GdkBitmap* RW Stipple pattern for fill
+ * outline_stipple GdkBitmap* RW Stipple pattern for outline
+ * width_pixels uint RW Width of the outline in pixels. The outline will
+ * not be scaled when the canvas zoom factor is changed.
+ * width_units double RW Width of the outline in canvas units. The outline
+ * will be scaled when the canvas zoom factor is changed.
+ * cap_style GdkCapStyle RW Cap ("endpoint") style for the bpath.
+ * join_style GdkJoinStyle RW Join ("vertex") style for the bpath.
+ * wind ArtWindRule RW Winding rule for the bpath.
+ * dash ArtVpathDash RW Dashing pattern
+ * miterlimit double RW Minimum angle between segments, where miter join
+ * rule is applied.
+ */
+
+#define GNOME_TYPE_CANVAS_SHAPE (gnome_canvas_shape_get_type ())
+#define GNOME_CANVAS_SHAPE(obj) (GTK_CHECK_CAST ((obj), GNOME_TYPE_CANVAS_SHAPE, GnomeCanvasShape))
+#define GNOME_CANVAS_SHAPE_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GNOME_TYPE_CANVAS_SHAPE, GnomeCanvasShapeClass))
+#define GNOME_IS_CANVAS_SHAPE(obj) (GTK_CHECK_TYPE ((obj), GNOME_TYPE_CANVAS_SHAPE))
+#define GNOME_IS_CANVAS_SHAPE_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_CANVAS_SHAPE))
+
+
+typedef struct _GnomeCanvasShape GnomeCanvasShape;
+typedef struct _GnomeCanvasShapePriv GnomeCanvasShapePriv;
+typedef struct _GnomeCanvasShapeClass GnomeCanvasShapeClass;
+
+struct _GnomeCanvasShape {
+ GnomeCanvasItem item;
+
+ GnomeCanvasShapePriv *priv; /* Private data */
+};
+
+struct _GnomeCanvasShapeClass {
+ GnomeCanvasItemClass parent_class;
+};
+
+
+/* WARNING! These are not usable from modifying shapes from user programs */
+/* These are meant, to set master shape from subclass ::update method */
+void gnome_canvas_shape_set_path_def (GnomeCanvasShape *shape, GnomeCanvasPathDef *def);
+GnomeCanvasPathDef *gnome_canvas_shape_get_path_def (GnomeCanvasShape *shape);
+
+/* Standard Gtk function */
+GType gnome_canvas_shape_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif
diff --git a/src/libgnomecanvas/gnome-canvas-text.c b/src/libgnomecanvas/gnome-canvas-text.c
new file mode 100644
index 0000000..1213e9c
--- /dev/null
+++ b/src/libgnomecanvas/gnome-canvas-text.c
@@ -0,0 +1,1740 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * $Id: gnome-canvas-text.c 1192 2006-11-22 12:28:00Z herzi $
+ * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ @NOTATION@
+ */
+/* Text item type for GnomeCanvas widget
+ *
+ * GnomeCanvas is basically a port of the Tk toolkit's most excellent canvas
+ * widget. Tk is copyrighted by the Regents of the University of California,
+ * Sun Microsystems, and other parties.
+ *
+ *
+ * Author: Federico Mena <federico@nuclecu.unam.mx>
+ * Port to Pango co-done by Gergõ Érdi <cactus@cactus.rulez.org>
+ */
+
+#include <config.h>
+#include <math.h>
+#include <string.h>
+#include "gnome-canvas-text.h"
+#include <pango/pangoft2.h>
+
+#include "libart_lgpl/art_affine.h"
+#include "libart_lgpl/art_rgb_a_affine.h"
+#include "libart_lgpl/art_rgb.h"
+#include "libart_lgpl/art_rgb_bitmap_affine.h"
+#include "gnome-canvas-util.h"
+#include "gnome-canvas-i18n.h"
+
+
+
+/* Object argument IDs */
+enum {
+ PROP_0,
+
+ /* Text contents */
+ PROP_TEXT,
+ PROP_MARKUP,
+
+ /* Position */
+ PROP_X,
+ PROP_Y,
+
+ /* Font */
+ PROP_FONT,
+ PROP_FONT_DESC,
+ PROP_FAMILY, PROP_FAMILY_SET,
+
+ /* Style */
+ PROP_ATTRIBUTES,
+ PROP_STYLE, PROP_STYLE_SET,
+ PROP_VARIANT, PROP_VARIANT_SET,
+ PROP_WEIGHT, PROP_WEIGHT_SET,
+ PROP_STRETCH, PROP_STRETCH_SET,
+ PROP_SIZE, PROP_SIZE_SET,
+ PROP_SIZE_POINTS,
+ PROP_STRIKETHROUGH, PROP_STRIKETHROUGH_SET,
+ PROP_UNDERLINE, PROP_UNDERLINE_SET,
+ PROP_RISE, PROP_RISE_SET,
+ PROP_SCALE, PROP_SCALE_SET,
+
+ /* Clipping */
+ PROP_ANCHOR,
+ PROP_JUSTIFICATION,
+ PROP_CLIP_WIDTH,
+ PROP_CLIP_HEIGHT,
+ PROP_CLIP,
+ PROP_X_OFFSET,
+ PROP_Y_OFFSET,
+
+ /* Coloring */
+ PROP_FILL_COLOR,
+ PROP_FILL_COLOR_GDK,
+ PROP_FILL_COLOR_RGBA,
+ PROP_FILL_STIPPLE,
+
+ /* Rendered size accessors */
+ PROP_TEXT_WIDTH,
+ PROP_TEXT_HEIGHT
+};
+
+struct _GnomeCanvasTextPrivate {
+ guint render_dirty : 1;
+ FT_Bitmap bitmap;
+};
+
+
+static void gnome_canvas_text_class_init (GnomeCanvasTextClass *class);
+static void gnome_canvas_text_init (GnomeCanvasText *text);
+static void gnome_canvas_text_destroy (GtkObject *object);
+static void gnome_canvas_text_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gnome_canvas_text_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+static void gnome_canvas_text_update (GnomeCanvasItem *item, double *affine,
+ ArtSVP *clip_path, int flags);
+static void gnome_canvas_text_realize (GnomeCanvasItem *item);
+static void gnome_canvas_text_unrealize (GnomeCanvasItem *item);
+static void gnome_canvas_text_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
+ int x, int y, int width, int height);
+static double gnome_canvas_text_point (GnomeCanvasItem *item, double x, double y, int cx, int cy,
+ GnomeCanvasItem **actual_item);
+static void gnome_canvas_text_bounds (GnomeCanvasItem *item,
+ double *x1, double *y1, double *x2, double *y2);
+static void gnome_canvas_text_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf);
+
+static void gnome_canvas_text_set_markup (GnomeCanvasText *textitem,
+ const gchar *markup);
+
+static void gnome_canvas_text_set_font_desc (GnomeCanvasText *textitem,
+ PangoFontDescription *font_desc);
+
+static void gnome_canvas_text_apply_font_desc (GnomeCanvasText *textitem);
+static void gnome_canvas_text_apply_attributes (GnomeCanvasText *textitem);
+
+static void add_attr (PangoAttrList *attr_list,
+ PangoAttribute *attr);
+
+static GnomeCanvasItemClass *parent_class;
+
+
+
+/**
+ * gnome_canvas_text_get_type:
+ * @void:
+ *
+ * Registers the &GnomeCanvasText class if necessary, and returns the type ID
+ * associated to it.
+ *
+ * Return value: The type ID of the &GnomeCanvasText class.
+ **/
+GType
+gnome_canvas_text_get_type (void)
+{
+ static GType text_type;
+
+ if (!text_type) {
+ static const GTypeInfo object_info = {
+ sizeof (GnomeCanvasTextClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gnome_canvas_text_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (GnomeCanvasText),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) gnome_canvas_text_init,
+ NULL /* value_table */
+ };
+
+ text_type = g_type_register_static (GNOME_TYPE_CANVAS_ITEM, "GnomeCanvasText",
+ &object_info, 0);
+ }
+
+ return text_type;
+}
+
+/* Class initialization function for the text item */
+static void
+gnome_canvas_text_class_init (GnomeCanvasTextClass *class)
+{
+ GObjectClass *gobject_class;
+ GtkObjectClass *object_class;
+ GnomeCanvasItemClass *item_class;
+
+ gobject_class = (GObjectClass *) class;
+ object_class = (GtkObjectClass *) class;
+ item_class = (GnomeCanvasItemClass *) class;
+
+ parent_class = g_type_class_peek_parent (class);
+
+ gobject_class->set_property = gnome_canvas_text_set_property;
+ gobject_class->get_property = gnome_canvas_text_get_property;
+
+ /* Text */
+ g_object_class_install_property
+ (gobject_class,
+ PROP_TEXT,
+ g_param_spec_string ("text",
+ _("Text"),
+ _("Text to render"),
+ NULL,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_MARKUP,
+ g_param_spec_string ("markup",
+ _("Markup"),
+ _("Marked up text to render"),
+ NULL,
+ (G_PARAM_WRITABLE)));
+
+ /* Position */
+ g_object_class_install_property
+ (gobject_class,
+ PROP_X,
+ g_param_spec_double ("x", NULL, NULL,
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_Y,
+ g_param_spec_double ("y", NULL, NULL,
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+
+
+ /* Font */
+ g_object_class_install_property
+ (gobject_class,
+ PROP_FONT,
+ g_param_spec_string ("font",
+ _("Font"),
+ _("Font description as a string"),
+ NULL,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_FONT_DESC,
+ g_param_spec_boxed ("font_desc",
+ _("Font description"),
+ _("Font description as a PangoFontDescription struct"),
+ PANGO_TYPE_FONT_DESCRIPTION,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_FAMILY,
+ g_param_spec_string ("family",
+ _("Font family"),
+ _("Name of the font family, e.g. Sans, Helvetica, Times, Monospace"),
+ NULL,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+
+ /* Style */
+ g_object_class_install_property
+ (gobject_class,
+ PROP_ATTRIBUTES,
+ g_param_spec_boxed ("attributes", NULL, NULL,
+ PANGO_TYPE_ATTR_LIST,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_STYLE,
+ g_param_spec_enum ("style",
+ _("Font style"),
+ _("Font style"),
+ PANGO_TYPE_STYLE,
+ PANGO_STYLE_NORMAL,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_VARIANT,
+ g_param_spec_enum ("variant",
+ _("Font variant"),
+ _("Font variant"),
+ PANGO_TYPE_VARIANT,
+ PANGO_VARIANT_NORMAL,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_WEIGHT,
+ g_param_spec_int ("weight",
+ _("Font weight"),
+ _("Font weight"),
+ 0,
+ G_MAXINT,
+ PANGO_WEIGHT_NORMAL,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_STRETCH,
+ g_param_spec_enum ("stretch",
+ _("Font stretch"),
+ _("Font stretch"),
+ PANGO_TYPE_STRETCH,
+ PANGO_STRETCH_NORMAL,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_SIZE,
+ g_param_spec_int ("size",
+ _("Font size"),
+ _("Font size (as a multiple of PANGO_SCALE, eg. 12*PANGO_SCALE for a 12pt font size)"),
+ 0,
+ G_MAXINT,
+ 0,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_SIZE_POINTS,
+ g_param_spec_double ("size_points",
+ _("Font points"),
+ _("Font size in points (eg. 12 for a 12pt font size)"),
+ 0.0,
+ G_MAXDOUBLE,
+ 0.0,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_RISE,
+ g_param_spec_int ("rise",
+ _("Rise"),
+ _("Offset of text above the baseline (below the baseline if rise is negative)"),
+ -G_MAXINT,
+ G_MAXINT,
+ 0,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_STRIKETHROUGH,
+ g_param_spec_boolean ("strikethrough",
+ _("Strikethrough"),
+ _("Whether to strike through the text"),
+ FALSE,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_UNDERLINE,
+ g_param_spec_enum ("underline",
+ _("Underline"),
+ _("Style of underline for this text"),
+ PANGO_TYPE_UNDERLINE,
+ PANGO_UNDERLINE_NONE,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_SCALE,
+ g_param_spec_double ("scale",
+ _("Scale"),
+ _("Size of font, relative to default size"),
+ 0.0,
+ G_MAXDOUBLE,
+ 1.0,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_ANCHOR,
+ g_param_spec_enum ("anchor", NULL, NULL,
+ GTK_TYPE_ANCHOR_TYPE,
+ GTK_ANCHOR_CENTER,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_JUSTIFICATION,
+ g_param_spec_enum ("justification", NULL, NULL,
+ GTK_TYPE_JUSTIFICATION,
+ GTK_JUSTIFY_LEFT,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_CLIP_WIDTH,
+ g_param_spec_double ("clip_width", NULL, NULL,
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_CLIP_HEIGHT,
+ g_param_spec_double ("clip_height", NULL, NULL,
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_CLIP,
+ g_param_spec_boolean ("clip", NULL, NULL,
+ FALSE,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_X_OFFSET,
+ g_param_spec_double ("x_offset", NULL, NULL,
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_Y_OFFSET,
+ g_param_spec_double ("y_offset", NULL, NULL,
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_FILL_COLOR,
+ g_param_spec_string ("fill_color",
+ _("Color"),
+ _("Text color, as string"),
+ NULL,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_FILL_COLOR_GDK,
+ g_param_spec_boxed ("fill_color_gdk",
+ _("Color"),
+ _("Text color, as a GdkColor"),
+ GDK_TYPE_COLOR,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_FILL_COLOR_RGBA,
+ g_param_spec_uint ("fill_color_rgba",
+ _("Color"),
+ _("Text color, as an R/G/B/A combined integer"),
+ 0, G_MAXUINT, 0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_FILL_STIPPLE,
+ g_param_spec_object ("fill_stipple", NULL, NULL,
+ GDK_TYPE_DRAWABLE,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_TEXT_WIDTH,
+ g_param_spec_double ("text_width",
+ _("Text width"),
+ _("Width of the rendered text"),
+ 0.0, G_MAXDOUBLE, 0.0,
+ G_PARAM_READABLE));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_TEXT_HEIGHT,
+ g_param_spec_double ("text_height",
+ _("Text height"),
+ _("Height of the rendered text"),
+ 0.0, G_MAXDOUBLE, 0.0,
+ G_PARAM_READABLE));
+
+ /* Style props are set (explicitly applied) or not */
+#define ADD_SET_PROP(propname, propval, nick, blurb) g_object_class_install_property (gobject_class, propval, g_param_spec_boolean (propname, nick, blurb, FALSE, G_PARAM_READABLE | G_PARAM_WRITABLE))
+
+ ADD_SET_PROP ("family_set", PROP_FAMILY_SET,
+ _("Font family set"),
+ _("Whether this tag affects the font family"));
+
+ ADD_SET_PROP ("style_set", PROP_STYLE_SET,
+ _("Font style set"),
+ _("Whether this tag affects the font style"));
+
+ ADD_SET_PROP ("variant_set", PROP_VARIANT_SET,
+ _("Font variant set"),
+ _("Whether this tag affects the font variant"));
+
+ ADD_SET_PROP ("weight_set", PROP_WEIGHT_SET,
+ _("Font weight set"),
+ _("Whether this tag affects the font weight"));
+
+ ADD_SET_PROP ("stretch_set", PROP_STRETCH_SET,
+ _("Font stretch set"),
+ _("Whether this tag affects the font stretch"));
+
+ ADD_SET_PROP ("size_set", PROP_SIZE_SET,
+ _("Font size set"),
+ _("Whether this tag affects the font size"));
+
+ ADD_SET_PROP ("rise_set", PROP_RISE_SET,
+ _("Rise set"),
+ _("Whether this tag affects the rise"));
+
+ ADD_SET_PROP ("strikethrough_set", PROP_STRIKETHROUGH_SET,
+ _("Strikethrough set"),
+ _("Whether this tag affects strikethrough"));
+
+ ADD_SET_PROP ("underline_set", PROP_UNDERLINE_SET,
+ _("Underline set"),
+ _("Whether this tag affects underlining"));
+
+ ADD_SET_PROP ("scale_set", PROP_SCALE_SET,
+ _("Scale set"),
+ _("Whether this tag affects font scaling"));
+#undef ADD_SET_PROP
+
+ object_class->destroy = gnome_canvas_text_destroy;
+
+ item_class->update = gnome_canvas_text_update;
+ item_class->realize = gnome_canvas_text_realize;
+ item_class->unrealize = gnome_canvas_text_unrealize;
+ item_class->draw = gnome_canvas_text_draw;
+ item_class->point = gnome_canvas_text_point;
+ item_class->bounds = gnome_canvas_text_bounds;
+ item_class->render = gnome_canvas_text_render;
+}
+
+/* Object initialization function for the text item */
+static void
+gnome_canvas_text_init (GnomeCanvasText *text)
+{
+ text->x = 0.0;
+ text->y = 0.0;
+ text->anchor = GTK_ANCHOR_CENTER;
+ text->justification = GTK_JUSTIFY_LEFT;
+ text->clip_width = 0.0;
+ text->clip_height = 0.0;
+ text->xofs = 0.0;
+ text->yofs = 0.0;
+ text->layout = NULL;
+
+ text->font_desc = NULL;
+
+ text->underline = PANGO_UNDERLINE_NONE;
+ text->strikethrough = FALSE;
+ text->rise = 0;
+
+ text->underline_set = FALSE;
+ text->strike_set = FALSE;
+ text->rise_set = FALSE;
+
+ text->priv = g_new (GnomeCanvasTextPrivate, 1);
+ text->priv->bitmap.buffer = NULL;
+ text->priv->render_dirty = 1;
+}
+
+/* Destroy handler for the text item */
+static void
+gnome_canvas_text_destroy (GtkObject *object)
+{
+ GnomeCanvasText *text;
+
+ g_return_if_fail (GNOME_IS_CANVAS_TEXT (object));
+
+ text = GNOME_CANVAS_TEXT (object);
+
+ /* remember, destroy can be run multiple times! */
+
+ g_free (text->text);
+ text->text = NULL;
+
+ if (text->layout)
+ g_object_unref (G_OBJECT (text->layout));
+ text->layout = NULL;
+
+ if (text->font_desc) {
+ pango_font_description_free (text->font_desc);
+ text->font_desc = NULL;
+ }
+
+ if (text->attr_list)
+ pango_attr_list_unref (text->attr_list);
+ text->attr_list = NULL;
+
+ if (text->stipple)
+ gdk_bitmap_unref (text->stipple);
+ text->stipple = NULL;
+
+ if (text->priv && text->priv->bitmap.buffer) {
+ g_free (text->priv->bitmap.buffer);
+ }
+ g_free (text->priv);
+ text->priv = NULL;
+
+ if (GTK_OBJECT_CLASS (parent_class)->destroy)
+ (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+}
+
+static void
+get_bounds (GnomeCanvasText *text, double *px1, double *py1, double *px2, double *py2)
+{
+ GnomeCanvasItem *item;
+ double wx, wy;
+
+ item = GNOME_CANVAS_ITEM (text);
+
+ /* Get canvas pixel coordinates for text position */
+
+
+ wx = text->x;
+ wy = text->y;
+ gnome_canvas_item_i2w (item, &wx, &wy);
+ gnome_canvas_w2c (item->canvas, wx + text->xofs, wy + text->yofs, &text->cx, &text->cy);
+
+ /* Get canvas pixel coordinates for clip rectangle position */
+
+ gnome_canvas_w2c (item->canvas, wx, wy, &text->clip_cx, &text->clip_cy);
+ text->clip_cwidth = text->clip_width * item->canvas->pixels_per_unit;
+ text->clip_cheight = text->clip_height * item->canvas->pixels_per_unit;
+
+ /* Anchor text */
+
+ switch (text->anchor) {
+ case GTK_ANCHOR_NW:
+ case GTK_ANCHOR_W:
+ case GTK_ANCHOR_SW:
+ break;
+
+ case GTK_ANCHOR_N:
+ case GTK_ANCHOR_CENTER:
+ case GTK_ANCHOR_S:
+ text->cx -= text->max_width / 2;
+ text->clip_cx -= text->clip_cwidth / 2;
+ break;
+
+ case GTK_ANCHOR_NE:
+ case GTK_ANCHOR_E:
+ case GTK_ANCHOR_SE:
+ text->cx -= text->max_width;
+ text->clip_cx -= text->clip_cwidth;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (text->anchor) {
+ case GTK_ANCHOR_NW:
+ case GTK_ANCHOR_N:
+ case GTK_ANCHOR_NE:
+ break;
+
+ case GTK_ANCHOR_W:
+ case GTK_ANCHOR_CENTER:
+ case GTK_ANCHOR_E:
+ text->cy -= text->height / 2;
+ text->clip_cy -= text->clip_cheight / 2;
+ break;
+
+ case GTK_ANCHOR_SW:
+ case GTK_ANCHOR_S:
+ case GTK_ANCHOR_SE:
+ text->cy -= text->height;
+ text->clip_cy -= text->clip_cheight;
+ break;
+
+ default:
+ break;
+ }
+
+ /* Bounds */
+
+ if (text->clip) {
+ *px1 = text->clip_cx;
+ *py1 = text->clip_cy;
+ *px2 = text->clip_cx + text->clip_cwidth;
+ *py2 = text->clip_cy + text->clip_cheight;
+ } else {
+ *px1 = text->cx;
+ *py1 = text->cy;
+ *px2 = text->cx + text->max_width;
+ *py2 = text->cy + text->height;
+ }
+}
+
+/* Convenience function to set the text's GC's foreground color */
+static void
+set_text_gc_foreground (GnomeCanvasText *text)
+{
+ GdkColor c;
+
+ if (!text->gc)
+ return;
+
+ c.pixel = text->pixel;
+ gdk_gc_set_foreground (text->gc, &c);
+}
+
+/* Sets the stipple pattern for the text */
+static void
+set_stipple (GnomeCanvasText *text, GdkBitmap *stipple, int reconfigure)
+{
+ if (text->stipple && !reconfigure)
+ gdk_bitmap_unref (text->stipple);
+
+ text->stipple = stipple;
+ if (stipple && !reconfigure)
+ gdk_bitmap_ref (stipple);
+
+ if (text->gc) {
+ if (stipple) {
+ gdk_gc_set_stipple (text->gc, stipple);
+ gdk_gc_set_fill (text->gc, GDK_STIPPLED);
+ } else
+ gdk_gc_set_fill (text->gc, GDK_SOLID);
+ }
+}
+
+static PangoFontMask
+get_property_font_set_mask (guint prop_id)
+{
+ switch (prop_id)
+ {
+ case PROP_FAMILY_SET:
+ return PANGO_FONT_MASK_FAMILY;
+ case PROP_STYLE_SET:
+ return PANGO_FONT_MASK_STYLE;
+ case PROP_VARIANT_SET:
+ return PANGO_FONT_MASK_VARIANT;
+ case PROP_WEIGHT_SET:
+ return PANGO_FONT_MASK_WEIGHT;
+ case PROP_STRETCH_SET:
+ return PANGO_FONT_MASK_STRETCH;
+ case PROP_SIZE_SET:
+ return PANGO_FONT_MASK_SIZE;
+ }
+
+ return 0;
+}
+
+static void
+ensure_font (GnomeCanvasText *text)
+{
+ if (!text->font_desc)
+ text->font_desc = pango_font_description_new ();
+}
+
+/* Set_arg handler for the text item */
+static void
+gnome_canvas_text_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GnomeCanvasItem *item;
+ GnomeCanvasText *text;
+ GdkColor color = { 0, 0, 0, 0, };
+ GdkColor *pcolor;
+ gboolean color_changed;
+ int have_pixel;
+ PangoAlignment align;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GNOME_IS_CANVAS_TEXT (object));
+
+ item = GNOME_CANVAS_ITEM (object);
+ text = GNOME_CANVAS_TEXT (object);
+
+ color_changed = FALSE;
+ have_pixel = FALSE;
+
+
+ if (!text->layout) {
+
+ PangoContext *gtk_context, *context;
+ gtk_context = gtk_widget_get_pango_context (GTK_WIDGET (item->canvas));
+
+ if (item->canvas->aa) {
+ PangoLanguage *language;
+ gint pixels, mm;
+ double dpi_x;
+ double dpi_y;
+
+ pixels = gdk_screen_width ();
+ mm = gdk_screen_width_mm ();
+ dpi_x = (((double) pixels * 25.4) / (double) mm);
+
+ pixels = gdk_screen_height ();
+ mm = gdk_screen_height_mm ();
+ dpi_y = (((double) pixels * 25.4) / (double) mm);
+
+ context = pango_ft2_get_context (dpi_x, dpi_y);
+ language = pango_context_get_language (gtk_context);
+ pango_context_set_language (context, language);
+ pango_context_set_base_dir (context,
+ pango_context_get_base_dir (gtk_context));
+ pango_context_set_font_description (context,
+ pango_context_get_font_description (gtk_context));
+
+ } else
+ context = gtk_context;
+
+
+ text->layout = pango_layout_new (context);
+
+ if (item->canvas->aa)
+ g_object_unref (G_OBJECT (context));
+ }
+
+ switch (param_id) {
+ case PROP_TEXT:
+ g_free (text->text);
+
+ text->text = g_value_dup_string (value);
+ pango_layout_set_text (text->layout, text->text, -1);
+
+ text->priv->render_dirty = 1;
+ break;
+
+ case PROP_MARKUP:
+ gnome_canvas_text_set_markup (text,
+ g_value_get_string (value));
+ text->priv->render_dirty = 1;
+ break;
+
+ case PROP_X:
+ text->x = g_value_get_double (value);
+ break;
+
+ case PROP_Y:
+ text->y = g_value_get_double (value);
+ break;
+
+ case PROP_FONT: {
+ const char *font_name;
+ PangoFontDescription *font_desc;
+
+ font_name = g_value_get_string (value);
+ if (font_name)
+ font_desc = pango_font_description_from_string (font_name);
+ else
+ font_desc = NULL;
+
+ gnome_canvas_text_set_font_desc (text, font_desc);
+ if (font_desc)
+ pango_font_description_free (font_desc);
+
+ break;
+ }
+
+ case PROP_FONT_DESC:
+ gnome_canvas_text_set_font_desc (text, g_value_peek_pointer (value));
+ break;
+
+ case PROP_FAMILY:
+ case PROP_STYLE:
+ case PROP_VARIANT:
+ case PROP_WEIGHT:
+ case PROP_STRETCH:
+ case PROP_SIZE:
+ case PROP_SIZE_POINTS:
+ ensure_font (text);
+
+ switch (param_id) {
+ case PROP_FAMILY:
+ pango_font_description_set_family (text->font_desc,
+ g_value_get_string (value));
+ break;
+ case PROP_STYLE:
+ pango_font_description_set_style (text->font_desc,
+ g_value_get_enum (value));
+ break;
+ case PROP_VARIANT:
+ pango_font_description_set_variant (text->font_desc,
+ g_value_get_enum (value));
+ break;
+ case PROP_WEIGHT:
+ pango_font_description_set_weight (text->font_desc,
+ g_value_get_int (value));
+ break;
+ case PROP_STRETCH:
+ pango_font_description_set_stretch (text->font_desc,
+ g_value_get_enum (value));
+ break;
+ case PROP_SIZE:
+ /* FIXME: This is bogus! It should be pixels, not points/PANGO_SCALE! */
+ pango_font_description_set_size (text->font_desc,
+ g_value_get_int (value));
+ break;
+ case PROP_SIZE_POINTS:
+ pango_font_description_set_size (text->font_desc,
+ g_value_get_double (value) * PANGO_SCALE);
+ break;
+ }
+
+ gnome_canvas_text_apply_font_desc (text);
+ text->priv->render_dirty = 1;
+ break;
+
+ case PROP_FAMILY_SET:
+ case PROP_STYLE_SET:
+ case PROP_VARIANT_SET:
+ case PROP_WEIGHT_SET:
+ case PROP_STRETCH_SET:
+ case PROP_SIZE_SET:
+ if (!g_value_get_boolean (value) && text->font_desc)
+ pango_font_description_unset_fields (text->font_desc,
+ get_property_font_set_mask (param_id));
+ break;
+
+ case PROP_SCALE:
+ text->scale = g_value_get_double (value);
+ text->scale_set = TRUE;
+
+ gnome_canvas_text_apply_font_desc (text);
+ text->priv->render_dirty = 1;
+ break;
+
+ case PROP_SCALE_SET:
+ text->scale_set = g_value_get_boolean (value);
+
+ gnome_canvas_text_apply_font_desc (text);
+ text->priv->render_dirty = 1;
+ break;
+
+ case PROP_UNDERLINE:
+ text->underline = g_value_get_enum (value);
+ text->underline_set = TRUE;
+
+ gnome_canvas_text_apply_attributes (text);
+ text->priv->render_dirty = 1;
+ break;
+
+ case PROP_UNDERLINE_SET:
+ text->underline_set = g_value_get_boolean (value);
+
+ gnome_canvas_text_apply_attributes (text);
+ text->priv->render_dirty = 1;
+ break;
+
+ case PROP_STRIKETHROUGH:
+ text->strikethrough = g_value_get_boolean (value);
+ text->strike_set = TRUE;
+
+ gnome_canvas_text_apply_attributes (text);
+ text->priv->render_dirty = 1;
+ break;
+
+ case PROP_STRIKETHROUGH_SET:
+ text->strike_set = g_value_get_boolean (value);
+
+ gnome_canvas_text_apply_attributes (text);
+ text->priv->render_dirty = 1;
+ break;
+
+ case PROP_RISE:
+ text->rise = g_value_get_int (value);
+ text->rise_set = TRUE;
+
+ gnome_canvas_text_apply_attributes (text);
+ text->priv->render_dirty = 1;
+ break;
+
+ case PROP_RISE_SET:
+ text->rise_set = TRUE;
+
+ gnome_canvas_text_apply_attributes (text);
+ text->priv->render_dirty = 1;
+ break;
+
+ case PROP_ATTRIBUTES:
+ if (text->attr_list)
+ pango_attr_list_unref (text->attr_list);
+
+ text->attr_list = g_value_peek_pointer (value);
+ pango_attr_list_ref (text->attr_list);
+
+ gnome_canvas_text_apply_attributes (text);
+ text->priv->render_dirty = 1;
+ break;
+
+ case PROP_ANCHOR:
+ text->anchor = g_value_get_enum (value);
+ break;
+
+ case PROP_JUSTIFICATION:
+ text->justification = g_value_get_enum (value);
+
+ switch (text->justification) {
+ case GTK_JUSTIFY_LEFT:
+ align = PANGO_ALIGN_LEFT;
+ break;
+ case GTK_JUSTIFY_CENTER:
+ align = PANGO_ALIGN_CENTER;
+ break;
+ case GTK_JUSTIFY_RIGHT:
+ align = PANGO_ALIGN_RIGHT;
+ break;
+ default:
+ /* GTK_JUSTIFY_FILL isn't supported yet. */
+ align = PANGO_ALIGN_LEFT;
+ break;
+ }
+ pango_layout_set_alignment (text->layout, align);
+ text->priv->render_dirty = 1;
+ break;
+
+ case PROP_CLIP_WIDTH:
+ text->clip_width = fabs (g_value_get_double (value));
+ text->priv->render_dirty = 1;
+ break;
+
+ case PROP_CLIP_HEIGHT:
+ text->clip_height = fabs (g_value_get_double (value));
+ text->priv->render_dirty = 1;
+ break;
+
+ case PROP_CLIP:
+ text->clip = g_value_get_boolean (value);
+ text->priv->render_dirty = 1;
+ break;
+
+ case PROP_X_OFFSET:
+ text->xofs = g_value_get_double (value);
+ break;
+
+ case PROP_Y_OFFSET:
+ text->yofs = g_value_get_double (value);
+ break;
+
+ case PROP_FILL_COLOR: {
+ const char *color_name;
+
+ color_name = g_value_get_string (value);
+ if (color_name) {
+ gdk_color_parse (color_name, &color);
+
+ text->rgba = ((color.red & 0xff00) << 16 |
+ (color.green & 0xff00) << 8 |
+ (color.blue & 0xff00) |
+ 0xff);
+ color_changed = TRUE;
+ }
+ text->priv->render_dirty = 1;
+ break;
+ }
+
+ case PROP_FILL_COLOR_GDK:
+ pcolor = g_value_get_boxed (value);
+ if (pcolor) {
+ GdkColormap *colormap;
+
+ color = *pcolor;
+ colormap = gtk_widget_get_colormap (GTK_WIDGET (item->canvas));
+ gdk_rgb_find_color (colormap, &color);
+ have_pixel = TRUE;
+ }
+
+ text->rgba = ((color.red & 0xff00) << 16 |
+ (color.green & 0xff00) << 8|
+ (color.blue & 0xff00) |
+ 0xff);
+ color_changed = TRUE;
+ break;
+
+ case PROP_FILL_COLOR_RGBA:
+ text->rgba = g_value_get_uint (value);
+ color_changed = TRUE;
+ text->priv->render_dirty = 1;
+ break;
+
+ case PROP_FILL_STIPPLE:
+ set_stipple (text, (GdkBitmap *)g_value_get_object (value), FALSE);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+
+ if (color_changed) {
+ if (have_pixel)
+ text->pixel = color.pixel;
+ else
+ text->pixel = gnome_canvas_get_color_pixel (item->canvas, text->rgba);
+
+ if (!item->canvas->aa)
+ set_text_gc_foreground (text);
+ }
+
+ /* Calculate text dimensions */
+
+ if (text->layout)
+ pango_layout_get_pixel_size (text->layout,
+ &text->max_width,
+ &text->height);
+ else {
+ text->max_width = 0;
+ text->height = 0;
+ }
+
+ gnome_canvas_item_request_update (item);
+}
+
+/* Get_arg handler for the text item */
+static void
+gnome_canvas_text_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GnomeCanvasText *text;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GNOME_IS_CANVAS_TEXT (object));
+
+ text = GNOME_CANVAS_TEXT (object);
+
+ switch (param_id) {
+ case PROP_TEXT:
+ g_value_set_string (value, text->text);
+ break;
+
+ case PROP_X:
+ g_value_set_double (value, text->x);
+ break;
+
+ case PROP_Y:
+ g_value_set_double (value, text->y);
+ break;
+
+ case PROP_FONT:
+ case PROP_FONT_DESC:
+ case PROP_FAMILY:
+ case PROP_STYLE:
+ case PROP_VARIANT:
+ case PROP_WEIGHT:
+ case PROP_STRETCH:
+ case PROP_SIZE:
+ case PROP_SIZE_POINTS:
+ ensure_font (text);
+
+ switch (param_id) {
+ case PROP_FONT:
+ {
+ /* FIXME GValue imposes a totally gratuitous string copy
+ * here, we could just hand off string ownership
+ */
+ gchar *str;
+
+ str = pango_font_description_to_string (text->font_desc);
+ g_value_set_string (value, str);
+ g_free (str);
+
+ break;
+ }
+
+ case PROP_FONT_DESC:
+ g_value_set_boxed (value, text->font_desc);
+ break;
+
+ case PROP_FAMILY:
+ g_value_set_string (value, pango_font_description_get_family (text->font_desc));
+ break;
+
+ case PROP_STYLE:
+ g_value_set_enum (value, pango_font_description_get_style (text->font_desc));
+ break;
+
+ case PROP_VARIANT:
+ g_value_set_enum (value, pango_font_description_get_variant (text->font_desc));
+ break;
+
+ case PROP_WEIGHT:
+ g_value_set_int (value, pango_font_description_get_weight (text->font_desc));
+ break;
+
+ case PROP_STRETCH:
+ g_value_set_enum (value, pango_font_description_get_stretch (text->font_desc));
+ break;
+
+ case PROP_SIZE:
+ g_value_set_int (value, pango_font_description_get_size (text->font_desc));
+ break;
+
+ case PROP_SIZE_POINTS:
+ g_value_set_double (value, ((double)pango_font_description_get_size (text->font_desc)) / (double)PANGO_SCALE);
+ break;
+ }
+ break;
+
+ case PROP_FAMILY_SET:
+ case PROP_STYLE_SET:
+ case PROP_VARIANT_SET:
+ case PROP_WEIGHT_SET:
+ case PROP_STRETCH_SET:
+ case PROP_SIZE_SET:
+ {
+ PangoFontMask set_mask = text->font_desc ? pango_font_description_get_set_fields (text->font_desc) : 0;
+ PangoFontMask test_mask = get_property_font_set_mask (param_id);
+ g_value_set_boolean (value, (set_mask & test_mask) != 0);
+
+ break;
+ }
+
+ case PROP_SCALE:
+ g_value_set_double (value, text->scale);
+ break;
+ case PROP_SCALE_SET:
+ g_value_set_boolean (value, text->scale_set);
+ break;
+
+ case PROP_UNDERLINE:
+ g_value_set_enum (value, text->underline);
+ break;
+ case PROP_UNDERLINE_SET:
+ g_value_set_boolean (value, text->underline_set);
+ break;
+
+ case PROP_STRIKETHROUGH:
+ g_value_set_boolean (value, text->strikethrough);
+ break;
+ case PROP_STRIKETHROUGH_SET:
+ g_value_set_boolean (value, text->strike_set);
+ break;
+
+ case PROP_RISE:
+ g_value_set_int (value, text->rise);
+ break;
+ case PROP_RISE_SET:
+ g_value_set_boolean (value, text->rise_set);
+ break;
+
+ case PROP_ATTRIBUTES:
+ g_value_set_boxed (value, text->attr_list);
+ break;
+
+ case PROP_ANCHOR:
+ g_value_set_enum (value, text->anchor);
+ break;
+
+ case PROP_JUSTIFICATION:
+ g_value_set_enum (value, text->justification);
+ break;
+
+ case PROP_CLIP_WIDTH:
+ g_value_set_double (value, text->clip_width);
+ break;
+
+ case PROP_CLIP_HEIGHT:
+ g_value_set_double (value, text->clip_height);
+ break;
+
+ case PROP_CLIP:
+ g_value_set_boolean (value, text->clip);
+ break;
+
+ case PROP_X_OFFSET:
+ g_value_set_double (value, text->xofs);
+ break;
+
+ case PROP_Y_OFFSET:
+ g_value_set_double (value, text->yofs);
+ break;
+
+ case PROP_FILL_COLOR:
+ g_value_set_string_take_ownership (value,
+ g_strdup_printf ("#%02x%02x%02x",
+ text->rgba >> 24,
+ (text->rgba >> 16) & 0xff,
+ (text->rgba >> 8) & 0xff));
+ break;
+
+ case PROP_FILL_COLOR_GDK: {
+ GnomeCanvas *canvas = GNOME_CANVAS_ITEM (text)->canvas;
+ GdkColormap *colormap = gtk_widget_get_colormap (GTK_WIDGET (canvas));
+ GdkColor color;
+
+ gdk_colormap_query_color (colormap, text->pixel, &color);
+ g_value_set_boxed (value, &color);
+ break;
+ }
+ case PROP_FILL_COLOR_RGBA:
+ g_value_set_uint (value, text->rgba);
+ break;
+
+ case PROP_FILL_STIPPLE:
+ g_value_set_object (value, text->stipple);
+ break;
+
+ case PROP_TEXT_WIDTH:
+ g_value_set_double (value, text->max_width / text->item.canvas->pixels_per_unit);
+ break;
+
+ case PROP_TEXT_HEIGHT:
+ g_value_set_double (value, text->height / text->item.canvas->pixels_per_unit);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+/* */
+static void
+gnome_canvas_text_apply_font_desc (GnomeCanvasText *text)
+{
+ PangoFontDescription *font_desc =
+ pango_font_description_copy (
+ GTK_WIDGET (GNOME_CANVAS_ITEM (text)->canvas)->style->font_desc);
+
+ if (text->font_desc)
+ pango_font_description_merge (font_desc, text->font_desc, TRUE);
+
+ pango_layout_set_font_description (text->layout, font_desc);
+ pango_font_description_free (font_desc);
+}
+
+static void
+add_attr (PangoAttrList *attr_list,
+ PangoAttribute *attr)
+{
+ attr->start_index = 0;
+ attr->end_index = G_MAXINT;
+
+ pango_attr_list_insert (attr_list, attr);
+}
+
+/* */
+static void
+gnome_canvas_text_apply_attributes (GnomeCanvasText *text)
+{
+ PangoAttrList *attr_list;
+
+ if (text->attr_list)
+ attr_list = pango_attr_list_copy (text->attr_list);
+ else
+ attr_list = pango_attr_list_new ();
+
+ if (text->underline_set)
+ add_attr (attr_list, pango_attr_underline_new (text->underline));
+ if (text->strike_set)
+ add_attr (attr_list, pango_attr_strikethrough_new (text->strikethrough));
+ if (text->rise_set)
+ add_attr (attr_list, pango_attr_rise_new (text->rise));
+
+ pango_layout_set_attributes (text->layout, attr_list);
+ pango_attr_list_unref (attr_list);
+}
+
+static void
+gnome_canvas_text_set_font_desc (GnomeCanvasText *text,
+ PangoFontDescription *font_desc)
+{
+ if (text->font_desc)
+ pango_font_description_free (text->font_desc);
+
+ if (font_desc)
+ text->font_desc = pango_font_description_copy (font_desc);
+ else
+ text->font_desc = NULL;
+
+ gnome_canvas_text_apply_font_desc (text);
+ text->priv->render_dirty = 1;
+}
+
+/* Setting the text from a Pango markup string */
+static void
+gnome_canvas_text_set_markup (GnomeCanvasText *textitem,
+ const gchar *markup)
+{
+ PangoAttrList *attr_list = NULL;
+ gchar *text = NULL;
+ GError *error = NULL;
+
+ if (markup && !pango_parse_markup (markup, -1,
+ 0,
+ &attr_list, &text, NULL,
+ &error))
+ {
+ g_warning ("Failed to set cell text from markup due to error parsing markup: %s",
+ error->message);
+ g_error_free (error);
+ return;
+ }
+
+ g_free (textitem->text);
+ if (textitem->attr_list)
+ pango_attr_list_unref (textitem->attr_list);
+
+ textitem->text = text;
+ textitem->attr_list = attr_list;
+
+ pango_layout_set_text (textitem->layout, text, -1);
+
+ gnome_canvas_text_apply_attributes (textitem);
+}
+
+/* Update handler for the text item */
+static void
+gnome_canvas_text_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
+{
+ GnomeCanvasText *text;
+ double x1, y1, x2, y2;
+
+ text = GNOME_CANVAS_TEXT (item);
+
+ if (parent_class->update)
+ (* parent_class->update) (item, affine, clip_path, flags);
+
+ set_text_gc_foreground (text);
+ set_stipple (text, text->stipple, TRUE);
+ get_bounds (text, &x1, &y1, &x2, &y2);
+
+ gnome_canvas_update_bbox (item,
+ floor (x1), floor (y1),
+ ceil (x2), ceil (y2));
+}
+
+/* Realize handler for the text item */
+static void
+gnome_canvas_text_realize (GnomeCanvasItem *item)
+{
+ GnomeCanvasText *text;
+
+ text = GNOME_CANVAS_TEXT (item);
+
+ if (parent_class->realize)
+ (* parent_class->realize) (item);
+
+ text->gc = gdk_gc_new (item->canvas->layout.bin_window);
+}
+
+/* Unrealize handler for the text item */
+static void
+gnome_canvas_text_unrealize (GnomeCanvasItem *item)
+{
+ GnomeCanvasText *text;
+
+ text = GNOME_CANVAS_TEXT (item);
+
+ gdk_gc_unref (text->gc);
+ text->gc = NULL;
+
+ if (parent_class->unrealize)
+ (* parent_class->unrealize) (item);
+}
+
+/* Draw handler for the text item */
+static void
+gnome_canvas_text_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
+ int x, int y, int width, int height)
+{
+ GnomeCanvasText *text;
+ GdkRectangle rect;
+
+ text = GNOME_CANVAS_TEXT (item);
+
+ if (!text->text)
+ return;
+
+ if (text->clip) {
+ rect.x = text->clip_cx - x;
+ rect.y = text->clip_cy - y;
+ rect.width = text->clip_cwidth;
+ rect.height = text->clip_cheight;
+
+ gdk_gc_set_clip_rectangle (text->gc, &rect);
+ }
+
+ if (text->stipple)
+ gnome_canvas_set_stipple_origin (item->canvas, text->gc);
+
+
+ gdk_draw_layout (drawable, text->gc, text->cx - x, text->cy - y, text->layout);
+
+ if (text->clip)
+ gdk_gc_set_clip_rectangle (text->gc, NULL);
+}
+
+
+/* Render handler for the text item */
+static void
+gnome_canvas_text_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf)
+{
+ GnomeCanvasText *text;
+ guint32 fg_color;
+ int render_x = 0, render_y = 0; /* offsets for text rendering,
+ * for clipping rectangles */
+ int x, y;
+ int w, h;
+ guchar *dst, *src;
+ int src_dx, src_dy;
+ int i, alpha;
+ int bm_rows, bm_width;
+
+ text = GNOME_CANVAS_TEXT (item);
+
+ if (!text->text)
+ return;
+
+ fg_color = text->rgba;
+
+ gnome_canvas_buf_ensure_buf (buf);
+
+ bm_rows = (text->clip) ? text->clip_cheight : text->height;
+ bm_width = (text->clip) ? text->clip_cwidth : text->max_width;
+ if(text->priv->render_dirty ||
+ bm_rows != text->priv->bitmap.rows ||
+ bm_width != text->priv->bitmap.width) {
+ if(text->priv->bitmap.buffer) {
+ g_free(text->priv->bitmap.buffer);
+ }
+ text->priv->bitmap.rows = bm_rows;
+ text->priv->bitmap.width = bm_width;
+ text->priv->bitmap.pitch = (text->priv->bitmap.width+3)&~3;
+ text->priv->bitmap.buffer = g_malloc0 (text->priv->bitmap.rows * text->priv->bitmap.pitch);
+ text->priv->bitmap.num_grays = 256;
+ text->priv->bitmap.pixel_mode = ft_pixel_mode_grays;
+
+ /* What this does is when a clipping rectangle is
+ being used shift the rendering of the text by the
+ correct amount so that the correct result is
+ obtained as if all text was rendered, then clipped.
+ In this sense we can use smaller buffers and less
+ rendeirng since hopefully FreeType2 checks to see
+ if the glyph falls in the bounding box before
+ rasterizing it. */
+
+ if(text->clip) {
+ render_x = text->cx - text->clip_cx;
+ render_y = text->cy - text->clip_cy;
+ }
+
+ pango_ft2_render_layout (&text->priv->bitmap, text->layout, render_x, render_y);
+
+ text->priv->render_dirty = 0;
+ }
+
+ if (text->clip) {
+ x = text->clip_cx - buf->rect.x0;
+ y = text->clip_cy - buf->rect.y0;
+ } else {
+ x = text->cx - buf->rect.x0;
+ y = text->cy - buf->rect.y0;
+ }
+
+ w = text->priv->bitmap.width;
+ h = text->priv->bitmap.rows;
+
+ src_dx = src_dy = 0;
+
+ if (x + w > buf->rect.x1 - buf->rect.x0) {
+ w = buf->rect.x1 - buf->rect.x0 - x;
+ }
+
+ if (y + h > buf->rect.y1 - buf->rect.y0) {
+ h = buf->rect.y1 - buf->rect.y0 - y;
+ }
+
+ if (x < 0) {
+ w -= - x;
+ src_dx += - x;
+ x = 0;
+ }
+
+ if (y < 0) {
+ h -= -y;
+ src_dy += - y;
+ y = 0;
+ }
+
+ dst = buf->buf + y * buf->buf_rowstride + x * 3;
+ src = text->priv->bitmap.buffer +
+ src_dy * text->priv->bitmap.pitch + src_dx;
+ while (h-- > 0) {
+ i = w;
+ while (i-- > 0) {
+ /* FIXME: Do the libart thing instead of divide by 255 */
+ alpha = ((fg_color & 0xff) * (*src)) / 255;
+ dst[0] = (dst[0] * (255 - alpha) + ((fg_color >> 24) & 0xff) * alpha) / 255;
+ dst[1] = (dst[1] * (255 - alpha) + ((fg_color >> 16) & 0xff) * alpha) / 255;
+ dst[2] = (dst[2] * (255 - alpha) + ((fg_color >> 8) & 0xff) * alpha) / 255;
+ dst += 3;
+ src += 1;
+ }
+ dst += buf->buf_rowstride - w*3;
+ src += text->priv->bitmap.pitch - w;
+ }
+
+ buf->is_bg = 0;
+ return;
+}
+
+/* Point handler for the text item */
+static double
+gnome_canvas_text_point (GnomeCanvasItem *item, double x, double y,
+ int cx, int cy, GnomeCanvasItem **actual_item)
+{
+ GnomeCanvasText *text;
+ PangoLayoutIter *iter;
+ int x1, y1, x2, y2;
+ int dx, dy;
+ double dist, best;
+
+ text = GNOME_CANVAS_TEXT (item);
+
+ *actual_item = item;
+
+ /* The idea is to build bounding rectangles for each of the lines of
+ * text (clipped by the clipping rectangle, if it is activated) and see
+ * whether the point is inside any of these. If it is, we are done.
+ * Otherwise, calculate the distance to the nearest rectangle.
+ */
+
+ best = 1.0e36;
+
+ iter = pango_layout_get_iter (text->layout);
+ do {
+ PangoRectangle log_rect;
+
+ pango_layout_iter_get_line_extents (iter, NULL, &log_rect);
+
+ x1 = text->cx + PANGO_PIXELS (log_rect.x);
+ y1 = text->cy + PANGO_PIXELS (log_rect.y);
+ x2 = x1 + PANGO_PIXELS (log_rect.width);
+ y2 = y1 + PANGO_PIXELS (log_rect.height);
+
+ if (text->clip) {
+ if (x1 < text->clip_cx)
+ x1 = text->clip_cx;
+
+ if (y1 < text->clip_cy)
+ y1 = text->clip_cy;
+
+ if (x2 > (text->clip_cx + text->clip_width))
+ x2 = text->clip_cx + text->clip_width;
+
+ if (y2 > (text->clip_cy + text->clip_height))
+ y2 = text->clip_cy + text->clip_height;
+
+ if ((x1 >= x2) || (y1 >= y2))
+ continue;
+ }
+
+ /* Calculate distance from point to rectangle */
+
+ if (cx < x1)
+ dx = x1 - cx;
+ else if (cx >= x2)
+ dx = cx - x2 + 1;
+ else
+ dx = 0;
+
+ if (cy < y1)
+ dy = y1 - cy;
+ else if (cy >= y2)
+ dy = cy - y2 + 1;
+ else
+ dy = 0;
+
+ if ((dx == 0) && (dy == 0)) {
+ pango_layout_iter_free(iter);
+ return 0.0;
+ }
+
+ dist = sqrt (dx * dx + dy * dy);
+ if (dist < best)
+ best = dist;
+
+ } while (pango_layout_iter_next_line(iter));
+
+ pango_layout_iter_free(iter);
+
+ return best / item->canvas->pixels_per_unit;
+}
+
+/* Bounds handler for the text item */
+static void
+gnome_canvas_text_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
+{
+ GnomeCanvasText *text;
+ double width, height;
+
+ text = GNOME_CANVAS_TEXT (item);
+
+ *x1 = text->x;
+ *y1 = text->y;
+
+ if (text->clip) {
+ width = text->clip_width;
+ height = text->clip_height;
+ } else {
+ width = text->max_width / item->canvas->pixels_per_unit;
+ height = text->height / item->canvas->pixels_per_unit;
+ }
+
+ switch (text->anchor) {
+ case GTK_ANCHOR_NW:
+ case GTK_ANCHOR_W:
+ case GTK_ANCHOR_SW:
+ break;
+
+ case GTK_ANCHOR_N:
+ case GTK_ANCHOR_CENTER:
+ case GTK_ANCHOR_S:
+ *x1 -= width / 2.0;
+ break;
+
+ case GTK_ANCHOR_NE:
+ case GTK_ANCHOR_E:
+ case GTK_ANCHOR_SE:
+ *x1 -= width;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (text->anchor) {
+ case GTK_ANCHOR_NW:
+ case GTK_ANCHOR_N:
+ case GTK_ANCHOR_NE:
+ break;
+
+ case GTK_ANCHOR_W:
+ case GTK_ANCHOR_CENTER:
+ case GTK_ANCHOR_E:
+ *y1 -= height / 2.0;
+ break;
+
+ case GTK_ANCHOR_SW:
+ case GTK_ANCHOR_S:
+ case GTK_ANCHOR_SE:
+ *y1 -= height;
+ break;
+
+ default:
+ break;
+ }
+
+ *x2 = *x1 + width;
+ *y2 = *y1 + height;
+}
diff --git a/src/libgnomecanvas/gnome-canvas-text.h b/src/libgnomecanvas/gnome-canvas-text.h
new file mode 100644
index 0000000..36ed844
--- /dev/null
+++ b/src/libgnomecanvas/gnome-canvas-text.h
@@ -0,0 +1,170 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ @NOTATION@
+ */
+/* Text item type for GnomeCanvas widget
+ *
+ * GnomeCanvas is basically a port of the Tk toolkit's most excellent canvas widget. Tk is
+ * copyrighted by the Regents of the University of California, Sun Microsystems, and other parties.
+ *
+ *
+ * Author: Federico Mena <federico@nuclecu.unam.mx>
+ * Port to Pango co-done by Gergõ Érdi <cactus@cactus.rulez.org>
+ */
+
+#ifndef GNOME_CANVAS_TEXT_H
+#define GNOME_CANVAS_TEXT_H
+
+
+#include <libgnomecanvas/gnome-canvas.h>
+
+
+G_BEGIN_DECLS
+
+
+/* Text item for the canvas. Text items are positioned by an anchor point and an anchor direction.
+ *
+ * A clipping rectangle may be specified for the text. The rectangle is anchored at the text's anchor
+ * point, and is specified by clipping width and height parameters. If the clipping rectangle is
+ * enabled, it will clip the text.
+ *
+ * In addition, x and y offset values may be specified. These specify an offset from the anchor
+ * position. If used in conjunction with the clipping rectangle, these could be used to implement
+ * simple scrolling of the text within the clipping rectangle.
+ *
+ * Properties marked with [*] also have _set properties associated
+ * with them, that determine if the specified value should be used
+ * instead of the default (style-defined) values
+ *
+ * The following object arguments are available:
+ *
+ * name type read/write description
+ * ------------------------------------------------------------------------------------------
+ * text string RW The string of the text label
+ * markup string W A Pango markup string for the text label
+ *
+ * x double RW X coordinate of anchor point
+ * y double RW Y coordinate of anchor point
+ *
+ * font string W A string describing the font
+ * font_desc PangoFontDescription* RW Pointer to a PangoFontDescriptor
+ * attributes PangoAttrList* RW Pointer to a Pango attribute list
+ * style PangoStyle RW Pango style of font to use [*]
+ * variant PangoVariant RW Pango variant of font to use [*]
+ * weight int RW Pango weight of font to use [*]
+ * stretch PangoStretch RW Pango stretch of font to use [*]
+ * size int RW Size (in pixels) of font [*]
+ * size_points double RW Size (in points) of font
+ * scale double RW Ratio to scale font [*]
+ *
+ * anchor GtkAnchorType RW Anchor side for the text
+ * justification GtkJustification RW Justification for multiline text
+ * clip_width double RW Width of clip rectangle
+ * clip_height double RW Height of clip rectangle
+ * clip boolean RW Use clipping rectangle?
+ * x_offset double RW Horizontal offset distance from anchor position
+ * y_offset double RW Vertical offset distance from anchor position
+ *
+ * text_width double R Used to query the width of the rendered text
+ * text_height double R Used to query the rendered height of the text
+ *
+ * fill_color string W X color specification for text
+ * fill_color_gdk GdkColor* RW Pointer to an allocated GdkColor
+ * fill_color_rgba guint RW RGBA value used for AA color.
+ * fill_stipple GdkBitmap* RW Stipple pattern for filling the text
+ */
+
+#define GNOME_TYPE_CANVAS_TEXT (gnome_canvas_text_get_type ())
+#define GNOME_CANVAS_TEXT(obj) (GTK_CHECK_CAST ((obj), GNOME_TYPE_CANVAS_TEXT, GnomeCanvasText))
+#define GNOME_CANVAS_TEXT_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GNOME_TYPE_CANVAS_TEXT, GnomeCanvasTextClass))
+#define GNOME_IS_CANVAS_TEXT(obj) (GTK_CHECK_TYPE ((obj), GNOME_TYPE_CANVAS_TEXT))
+#define GNOME_IS_CANVAS_TEXT_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_CANVAS_TEXT))
+#define GNOME_CANVAS_TEXT_GET_CLASS(obj) (GTK_CHECK_GET_CLASS ((obj), GNOME_TYPE_CANVAS_TEXT, GnomeCanvasTextClass))
+
+
+typedef struct _GnomeCanvasText GnomeCanvasText;
+typedef struct _GnomeCanvasTextClass GnomeCanvasTextClass;
+
+typedef struct _GnomeCanvasTextPrivate GnomeCanvasTextPrivate;
+
+struct _GnomeCanvasText {
+ GnomeCanvasItem item;
+
+ PangoFontDescription *font_desc; /* Font description for text */
+ PangoAttrList *attr_list; /* Attribute list of the text (caching) */
+ PangoUnderline underline;
+ gboolean strikethrough;
+ int rise;
+ double scale;
+
+ char *text; /* Text to display */
+ GdkBitmap *stipple; /* Stipple for text */
+ GdkGC *gc; /* GC for drawing text */
+ PangoLayout *layout; /* The PangoLayout containing the text */
+
+ gulong pixel; /* Fill color */
+
+ double x, y; /* Position at anchor */
+
+ double clip_width; /* Width of optional clip rectangle */
+ double clip_height; /* Height of optional clip rectangle */
+
+ double xofs, yofs; /* Text offset distance from anchor position */
+
+ double affine[6]; /* The item -> canvas affine */ /*AA*/
+
+ GtkAnchorType anchor; /* Anchor side for text */
+ GtkJustification justification; /* Justification for text */
+
+ int cx, cy; /* Top-left canvas coordinates for text */
+ int clip_cx, clip_cy; /* Top-left canvas coordinates for clip rectangle */
+ int clip_cwidth, clip_cheight; /* Size of clip rectangle in pixels */
+ int max_width; /* Maximum width of text lines */
+ int height; /* Rendered text height in pixels */
+
+ guint32 rgba; /* RGBA color for text */ /*AA*/
+
+ guint clip : 1; /* Use clip rectangle? */
+
+ guint underline_set : 1; /* Apply specified underline style? */
+ guint strike_set : 1; /* Apply specified strikethrough style? */
+ guint rise_set : 1; /* Apply specified ascension/descension? */
+
+ guint scale_set : 1; /* Apply specified font scaling ratio? */
+
+ GnomeCanvasTextPrivate *priv;
+};
+
+struct _GnomeCanvasTextClass {
+ GnomeCanvasItemClass parent_class;
+};
+
+
+/* Standard Gtk function */
+GType gnome_canvas_text_get_type (void) G_GNUC_CONST;
+
+
+G_END_DECLS
+
+#endif
diff --git a/src/libgnomecanvas/gnome-canvas-util.c b/src/libgnomecanvas/gnome-canvas-util.c
new file mode 100644
index 0000000..d306292
--- /dev/null
+++ b/src/libgnomecanvas/gnome-canvas-util.c
@@ -0,0 +1,700 @@
+/*
+ * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ @NOTATION@
+ */
+/* Miscellaneous utility functions for the GnomeCanvas widget
+ *
+ * GnomeCanvas is basically a port of the Tk toolkit's most excellent canvas widget. Tk is
+ * copyrighted by the Regents of the University of California, Sun Microsystems, and other parties.
+ *
+ *
+ * Author: Federico Mena <federico@nuclecu.unam.mx>
+ */
+
+#include <config.h>
+
+/* needed for M_PI_2 under 'gcc -ansi -predantic' on GNU/Linux */
+#ifndef _BSD_SOURCE
+# define _BSD_SOURCE 1
+#endif
+#include <sys/types.h>
+
+#include <glib.h>
+#include <math.h>
+#include "gnome-canvas.h"
+#include "gnome-canvas-util.h"
+#include <libart_lgpl/art_uta.h>
+#include <libart_lgpl/art_svp.h>
+#include <libart_lgpl/art_svp_ops.h>
+#include <libart_lgpl/art_rgb.h>
+#include <libart_lgpl/art_rgb_svp.h>
+#include <libart_lgpl/art_uta_svp.h>
+#include <libart_lgpl/art_rect_svp.h>
+
+/**
+ * gnome_canvas_points_new:
+ * @num_points: The number of points to allocate space for in the array.
+ *
+ * Creates a structure that should be used to pass an array of points to
+ * items.
+ *
+ * Return value: A newly-created array of points. It should be filled in
+ * by the user.
+ **/
+GnomeCanvasPoints *
+gnome_canvas_points_new (int num_points)
+{
+ GnomeCanvasPoints *points;
+
+ g_return_val_if_fail (num_points > 1, NULL);
+
+ points = g_new (GnomeCanvasPoints, 1);
+ points->num_points = num_points;
+ points->coords = g_new (double, 2 * num_points);
+ points->ref_count = 1;
+
+ return points;
+}
+
+/**
+ * gnome_canvas_points_ref:
+ * @points: A canvas points structure.
+ *
+ * Increases the reference count of the specified points structure.
+ *
+ * Return value: The canvas points structure itself.
+ **/
+GnomeCanvasPoints *
+gnome_canvas_points_ref (GnomeCanvasPoints *points)
+{
+ g_return_val_if_fail (points != NULL, NULL);
+
+ points->ref_count += 1;
+ return points;
+}
+
+/**
+ * gnome_canvas_points_free:
+ * @points: A canvas points structure.
+ *
+ * Decreases the reference count of the specified points structure. If it
+ * reaches zero, then the structure is freed.
+ **/
+void
+gnome_canvas_points_free (GnomeCanvasPoints *points)
+{
+ g_return_if_fail (points != NULL);
+
+ points->ref_count -= 1;
+ if (points->ref_count == 0) {
+ g_free (points->coords);
+ g_free (points);
+ }
+}
+
+/**
+ * gnome_canvas_get_miter_points:
+ * @x1: X coordinate of the first point
+ * @y1: Y coordinate of the first point
+ * @x2: X coordinate of the second (angle) point
+ * @y2: Y coordinate of the second (angle) point
+ * @x3: X coordinate of the third point
+ * @y3: Y coordinate of the third point
+ * @width: Width of the line
+ * @mx1: The X coordinate of the first miter point is returned here.
+ * @my1: The Y coordinate of the first miter point is returned here.
+ * @mx2: The X coordinate of the second miter point is returned here.
+ * @my2: The Y coordinate of the second miter point is returned here.
+ *
+ * Given three points forming an angle, computes the coordinates of the inside
+ * and outside points of the mitered corner formed by a line of a given width at
+ * that angle.
+ *
+ * Return value: FALSE if the angle is less than 11 degrees (this is the same
+ * threshold as X uses. If this occurs, the return points are not modified.
+ * Otherwise, returns TRUE.
+ **/
+int
+gnome_canvas_get_miter_points (double x1, double y1, double x2, double y2, double x3, double y3,
+ double width,
+ double *mx1, double *my1, double *mx2, double *my2)
+{
+ double theta1; /* angle of segment p2-p1 */
+ double theta2; /* angle of segment p2-p3 */
+ double theta; /* angle between line segments */
+ double theta3; /* angle that bisects theta1 and theta2 and points to p1 */
+ double dist; /* distance of miter points from p2 */
+ double dx, dy; /* x and y offsets corresponding to dist */
+
+#define ELEVEN_DEGREES (11.0 * G_PI / 180.0)
+
+ if (y2 == y1)
+ theta1 = (x2 < x1) ? 0.0 : G_PI;
+ else if (x2 == x1)
+ theta1 = (y2 < y1) ? G_PI_2 : -G_PI_2;
+ else
+ theta1 = atan2 (y1 - y2, x1 - x2);
+
+ if (y3 == y2)
+ theta2 = (x3 > x2) ? 0 : G_PI;
+ else if (x3 == x2)
+ theta2 = (y3 > y2) ? G_PI_2 : -G_PI_2;
+ else
+ theta2 = atan2 (y3 - y2, x3 - x2);
+
+ theta = theta1 - theta2;
+
+ if (theta > G_PI)
+ theta -= 2.0 * G_PI;
+ else if (theta < -G_PI)
+ theta += 2.0 * G_PI;
+
+ if ((theta < ELEVEN_DEGREES) && (theta > -ELEVEN_DEGREES))
+ return FALSE;
+
+ dist = 0.5 * width / sin (0.5 * theta);
+ if (dist < 0.0)
+ dist = -dist;
+
+ theta3 = (theta1 + theta2) / 2.0;
+ if (sin (theta3 - (theta1 + G_PI)) < 0.0)
+ theta3 += G_PI;
+
+ dx = dist * cos (theta3);
+ dy = dist * sin (theta3);
+
+ *mx1 = x2 + dx;
+ *mx2 = x2 - dx;
+ *my1 = y2 + dy;
+ *my2 = y2 - dy;
+
+ return TRUE;
+}
+
+/**
+ * gnome_canvas_get_butt_points:
+ * @x1: X coordinate of first point in the line
+ * @y1: Y cooordinate of first point in the line
+ * @x2: X coordinate of second point (endpoint) of the line
+ * @y2: Y coordinate of second point (endpoint) of the line
+ * @width: Width of the line
+ * @project: Whether the butt points should project out by width/2 distance
+ * @bx1: X coordinate of first butt point is returned here
+ * @by1: Y coordinate of first butt point is returned here
+ * @bx2: X coordinate of second butt point is returned here
+ * @by2: Y coordinate of second butt point is returned here
+ *
+ * Computes the butt points of a line segment.
+ **/
+void
+gnome_canvas_get_butt_points (double x1, double y1, double x2, double y2,
+ double width, int project,
+ double *bx1, double *by1, double *bx2, double *by2)
+{
+ double length;
+ double dx, dy;
+
+ width *= 0.5;
+ dx = x2 - x1;
+ dy = y2 - y1;
+ length = sqrt (dx * dx + dy * dy);
+
+ if (length < GNOME_CANVAS_EPSILON) {
+ *bx1 = *bx2 = x2;
+ *by1 = *by2 = y2;
+ } else {
+ dx = -width * (y2 - y1) / length;
+ dy = width * (x2 - x1) / length;
+
+ *bx1 = x2 + dx;
+ *bx2 = x2 - dx;
+ *by1 = y2 + dy;
+ *by2 = y2 - dy;
+
+ if (project) {
+ *bx1 += dy;
+ *bx2 += dy;
+ *by1 -= dx;
+ *by2 -= dx;
+ }
+ }
+}
+
+/**
+ * gnome_canvas_polygon_to_point:
+ * @poly: Vertices of the polygon. X coordinates are in the even indices, and Y
+ * coordinates are in the odd indices
+ * @num_points: Number of points in the polygon
+ * @x: X coordinate of the point
+ * @y: Y coordinate of the point
+ *
+ * Computes the distance between a point and a polygon.
+ *
+ * Return value: The distance from the point to the polygon, or zero if the
+ * point is inside the polygon.
+ **/
+double
+gnome_canvas_polygon_to_point (double *poly, int num_points, double x, double y)
+{
+ double best;
+ int intersections;
+ int i;
+ double *p;
+ double dx, dy;
+
+ /* Iterate through all the edges in the polygon, updating best and intersections.
+ *
+ * When computing intersections, include left X coordinate of line within its range, but not
+ * Y coordinate. Otherwise if the point lies exactly below a vertex we'll count it as two
+ * intersections.
+ */
+
+ best = 1.0e36;
+ intersections = 0;
+
+ for (i = num_points, p = poly; i > 1; i--, p += 2) {
+ double px, py, dist;
+
+ /* Compute the point on the current edge closest to the point and update the
+ * intersection count. This must be done separately for vertical edges, horizontal
+ * edges, and others.
+ */
+
+ if (p[2] == p[0]) {
+ /* Vertical edge */
+
+ px = p[0];
+
+ if (p[1] >= p[3]) {
+ py = MIN (p[1], y);
+ py = MAX (py, p[3]);
+ } else {
+ py = MIN (p[3], y);
+ py = MAX (py, p[1]);
+ }
+ } else if (p[3] == p[1]) {
+ /* Horizontal edge */
+
+ py = p[1];
+
+ if (p[0] >= p[2]) {
+ px = MIN (p[0], x);
+ px = MAX (px, p[2]);
+
+ if ((y < py) && (x < p[0]) && (x >= p[2]))
+ intersections++;
+ } else {
+ px = MIN (p[2], x);
+ px = MAX (px, p[0]);
+
+ if ((y < py) && (x < p[2]) && (x >= p[0]))
+ intersections++;
+ }
+ } else {
+ double m1, b1, m2, b2;
+ int lower;
+
+ /* Diagonal edge. Convert the edge to a line equation (y = m1*x + b1), then
+ * compute a line perpendicular to this edge but passing through the point,
+ * (y = m2*x + b2).
+ */
+
+ m1 = (p[3] - p[1]) / (p[2] - p[0]);
+ b1 = p[1] - m1 * p[0];
+
+ m2 = -1.0 / m1;
+ b2 = y - m2 * x;
+
+ px = (b2 - b1) / (m1 - m2);
+ py = m1 * px + b1;
+
+ if (p[0] > p[2]) {
+ if (px > p[0]) {
+ px = p[0];
+ py = p[1];
+ } else if (px < p[2]) {
+ px = p[2];
+ py = p[3];
+ }
+ } else {
+ if (px > p[2]) {
+ px = p[2];
+ py = p[3];
+ } else if (px < p[0]) {
+ px = p[0];
+ py = p[1];
+ }
+ }
+
+ lower = (m1 * x + b1) > y;
+
+ if (lower && (x >= MIN (p[0], p[2])) && (x < MAX (p[0], p[2])))
+ intersections++;
+ }
+
+ /* Compute the distance to the closest point, and see if that is the best so far */
+
+ dx = x - px;
+ dy = y - py;
+ dist = sqrt (dx * dx + dy * dy);
+ if (dist < best)
+ best = dist;
+ }
+
+ /* We've processed all the points. If the number of intersections is odd, the point is
+ * inside the polygon.
+ */
+
+ if (intersections & 0x1)
+ return 0.0;
+ else
+ return best;
+}
+
+/* Here are some helper functions for aa rendering: */
+
+/**
+ * gnome_canvas_render_svp:
+ * @buf: the canvas buffer to render over
+ * @svp: the vector path to render
+ * @rgba: the rgba color to render
+ *
+ * Render the svp over the buf.
+ **/
+void
+gnome_canvas_render_svp (GnomeCanvasBuf *buf, ArtSVP *svp, guint32 rgba)
+{
+ guint32 fg_color, bg_color;
+ int alpha;
+
+ if (buf->is_bg) {
+ bg_color = buf->bg_color;
+ alpha = rgba & 0xff;
+ if (alpha == 0xff)
+ fg_color = rgba >> 8;
+ else {
+ /* composite over background color */
+ int bg_r, bg_g, bg_b;
+ int fg_r, fg_g, fg_b;
+ int tmp;
+
+ bg_r = (bg_color >> 16) & 0xff;
+ fg_r = (rgba >> 24) & 0xff;
+ tmp = (fg_r - bg_r) * alpha;
+ fg_r = bg_r + ((tmp + (tmp >> 8) + 0x80) >> 8);
+
+ bg_g = (bg_color >> 8) & 0xff;
+ fg_g = (rgba >> 16) & 0xff;
+ tmp = (fg_g - bg_g) * alpha;
+ fg_g = bg_g + ((tmp + (tmp >> 8) + 0x80) >> 8);
+
+ bg_b = bg_color & 0xff;
+ fg_b = (rgba >> 8) & 0xff;
+ tmp = (fg_b - bg_b) * alpha;
+ fg_b = bg_b + ((tmp + (tmp >> 8) + 0x80) >> 8);
+
+ fg_color = (fg_r << 16) | (fg_g << 8) | fg_b;
+ }
+ art_rgb_svp_aa (svp,
+ buf->rect.x0, buf->rect.y0, buf->rect.x1, buf->rect.y1,
+ fg_color, bg_color,
+ buf->buf, buf->buf_rowstride,
+ NULL);
+ buf->is_bg = 0;
+ buf->is_buf = 1;
+ } else {
+ art_rgb_svp_alpha (svp,
+ buf->rect.x0, buf->rect.y0, buf->rect.x1, buf->rect.y1,
+ rgba,
+ buf->buf, buf->buf_rowstride,
+ NULL);
+ }
+}
+
+/**
+ * gnome_canvas_update_svp:
+ * @canvas: the canvas containing the svp that needs updating.
+ * @p_svp: a pointer to the existing svp
+ * @new_svp: the new svp
+ *
+ * Sets the svp to the new value, requesting repaint on what's changed. This
+ * function takes responsibility for freeing new_svp.
+ **/
+void
+gnome_canvas_update_svp (GnomeCanvas *canvas, ArtSVP **p_svp, ArtSVP *new_svp)
+{
+ ArtSVP *old_svp;
+ ArtSVP *diff G_GNUC_UNUSED;
+ ArtUta *repaint_uta;
+
+ old_svp = *p_svp;
+
+ if (old_svp != NULL) {
+ ArtDRect bb;
+ art_drect_svp (&bb, old_svp);
+ if ((bb.x1 - bb.x0) * (bb.y1 - bb.y0) > (64 * 64)) {
+ repaint_uta = art_uta_from_svp (old_svp);
+ gnome_canvas_request_redraw_uta (canvas, repaint_uta);
+ } else {
+ ArtIRect ib;
+ art_drect_to_irect (&ib, &bb);
+ gnome_canvas_request_redraw (canvas, ib.x0, ib.y0, ib.x1, ib.y1);
+ }
+ art_svp_free (old_svp);
+ }
+
+ if (new_svp != NULL) {
+ ArtDRect bb;
+ art_drect_svp (&bb, new_svp);
+ if ((bb.x1 - bb.x0) * (bb.y1 - bb.y0) > (64 * 64)) {
+ repaint_uta = art_uta_from_svp (new_svp);
+ gnome_canvas_request_redraw_uta (canvas, repaint_uta);
+ } else {
+ ArtIRect ib;
+ art_drect_to_irect (&ib, &bb);
+ gnome_canvas_request_redraw (canvas, ib.x0, ib.y0, ib.x1, ib.y1);
+ }
+ }
+
+ *p_svp = new_svp;
+}
+
+/**
+ * gnome_canvas_update_svp_clip:
+ * @canvas: the canvas containing the svp that needs updating.
+ * @p_svp: a pointer to the existing svp
+ * @new_svp: the new svp
+ * @clip_svp: a clip path, if non-null
+ *
+ * Sets the svp to the new value, clipping if necessary, and requesting repaint
+ * on what's changed. This function takes responsibility for freeing new_svp.
+ **/
+void
+gnome_canvas_update_svp_clip (GnomeCanvas *canvas, ArtSVP **p_svp, ArtSVP *new_svp, ArtSVP *clip_svp)
+{
+ ArtSVP *clipped_svp;
+
+ if (clip_svp != NULL) {
+ clipped_svp = art_svp_intersect (new_svp, clip_svp);
+ art_svp_free (new_svp);
+ } else {
+ clipped_svp = new_svp;
+ }
+ gnome_canvas_update_svp (canvas, p_svp, clipped_svp);
+}
+
+/**
+ * gnome_canvas_item_reset_bounds:
+ * @item: A canvas item
+ *
+ * Resets the bounding box of a canvas item to an empty rectangle.
+ **/
+void
+gnome_canvas_item_reset_bounds (GnomeCanvasItem *item)
+{
+ item->x1 = 0.0;
+ item->y1 = 0.0;
+ item->x2 = 0.0;
+ item->y2 = 0.0;
+}
+
+/**
+ * gnome_canvas_item_update_svp:
+ * @item: the canvas item containing the svp that needs updating.
+ * @p_svp: a pointer to the existing svp
+ * @new_svp: the new svp
+ *
+ * Sets the svp to the new value, requesting repaint on what's changed. This
+ * function takes responsibility for freeing new_svp. This routine also adds the
+ * svp's bbox to the item's.
+ **/
+void
+gnome_canvas_item_update_svp (GnomeCanvasItem *item, ArtSVP **p_svp, ArtSVP *new_svp)
+{
+ ArtDRect bbox;
+
+ gnome_canvas_update_svp (item->canvas, p_svp, new_svp);
+ if (new_svp) {
+ bbox.x0 = item->x1;
+ bbox.y0 = item->y1;
+ bbox.x1 = item->x2;
+ bbox.y1 = item->y2;
+ art_drect_svp_union (&bbox, new_svp);
+ item->x1 = bbox.x0;
+ item->y1 = bbox.y0;
+ item->x2 = bbox.x1;
+ item->y2 = bbox.y1;
+ }
+}
+
+/**
+ * gnome_canvas_item_update_svp_clip:
+ * @item: the canvas item containing the svp that needs updating.
+ * @p_svp: a pointer to the existing svp
+ * @new_svp: the new svp
+ * @clip_svp: a clip path, if non-null
+ *
+ * Sets the svp to the new value, clipping if necessary, and requesting repaint
+ * on what's changed. This function takes responsibility for freeing new_svp.
+ **/
+void
+gnome_canvas_item_update_svp_clip (GnomeCanvasItem *item, ArtSVP **p_svp, ArtSVP *new_svp,
+ ArtSVP *clip_svp)
+{
+ ArtSVP *clipped_svp;
+
+ if (clip_svp != NULL) {
+ clipped_svp = art_svp_intersect (new_svp, clip_svp);
+ art_svp_free (new_svp);
+ } else {
+ clipped_svp = new_svp;
+ }
+
+ gnome_canvas_item_update_svp (item, p_svp, clipped_svp);
+}
+
+/**
+ * gnome_canvas_item_request_redraw_svp
+ * @item: the item containing the svp
+ * @svp: the svp that needs to be redrawn
+ *
+ * Request redraw of the svp if in aa mode, or the entire item in in xlib mode.
+ **/
+void
+gnome_canvas_item_request_redraw_svp (GnomeCanvasItem *item, const ArtSVP *svp)
+{
+ GnomeCanvas *canvas;
+ ArtUta *uta;
+
+ canvas = item->canvas;
+ if (canvas->aa) {
+ if (svp != NULL) {
+ uta = art_uta_from_svp (svp);
+ gnome_canvas_request_redraw_uta (canvas, uta);
+ }
+ } else {
+ gnome_canvas_request_redraw (canvas, item->x1, item->y1, item->x2, item->y2);
+ }
+}
+
+/**
+ * gnome_canvas_update_bbox:
+ * @item: the canvas item needing update
+ * @x1: Left coordinate of the new bounding box
+ * @y1: Top coordinate of the new bounding box
+ * @x2: Right coordinate of the new bounding box
+ * @y2: Bottom coordinate of the new bounding box
+ *
+ * Sets the bbox to the new value, requesting full repaint.
+ **/
+void
+gnome_canvas_update_bbox (GnomeCanvasItem *item, int x1, int y1, int x2, int y2)
+{
+ gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2);
+ item->x1 = x1;
+ item->y1 = y1;
+ item->x2 = x2;
+ item->y2 = y2;
+ gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2);
+}
+
+/**
+ * gnome_canvas_buf_ensure_buf:
+ * @buf: the buf that needs to be represened in RGB format
+ *
+ * Ensure that the buffer is in RGB format, suitable for compositing.
+ **/
+void
+gnome_canvas_buf_ensure_buf (GnomeCanvasBuf *buf)
+{
+ guchar *bufptr;
+ int y;
+
+ if (!buf->is_buf) {
+ bufptr = buf->buf;
+ for (y = buf->rect.y0; y < buf->rect.y1; y++) {
+ art_rgb_fill_run (bufptr,
+ buf->bg_color >> 16,
+ (buf->bg_color >> 8) & 0xff,
+ buf->bg_color & 0xff,
+ buf->rect.x1 - buf->rect.x0);
+ bufptr += buf->buf_rowstride;
+ }
+ buf->is_buf = 1;
+ }
+}
+
+/**
+ * gnome_canvas_join_gdk_to_art
+ * @gdk_join: a join type, represented in GDK format
+ *
+ * Convert from GDK line join specifier to libart.
+ *
+ * Return value: The line join specifier in libart format.
+ **/
+ArtPathStrokeJoinType
+gnome_canvas_join_gdk_to_art (GdkJoinStyle gdk_join)
+{
+ switch (gdk_join) {
+ case GDK_JOIN_MITER:
+ return ART_PATH_STROKE_JOIN_MITER;
+
+ case GDK_JOIN_ROUND:
+ return ART_PATH_STROKE_JOIN_ROUND;
+
+ case GDK_JOIN_BEVEL:
+ return ART_PATH_STROKE_JOIN_BEVEL;
+
+ default:
+ g_assert_not_reached ();
+ return ART_PATH_STROKE_JOIN_MITER; /* shut up the compiler */
+ }
+}
+
+/**
+ * gnome_canvas_cap_gdk_to_art
+ * @gdk_cap: a cap type, represented in GDK format
+ *
+ * Convert from GDK line cap specifier to libart.
+ *
+ * Return value: The line cap specifier in libart format.
+ **/
+ArtPathStrokeCapType
+gnome_canvas_cap_gdk_to_art (GdkCapStyle gdk_cap)
+{
+ switch (gdk_cap) {
+ case GDK_CAP_BUTT:
+ case GDK_CAP_NOT_LAST:
+ return ART_PATH_STROKE_CAP_BUTT;
+
+ case GDK_CAP_ROUND:
+ return ART_PATH_STROKE_CAP_ROUND;
+
+ case GDK_CAP_PROJECTING:
+ return ART_PATH_STROKE_CAP_SQUARE;
+
+ default:
+ g_assert_not_reached ();
+ return ART_PATH_STROKE_CAP_BUTT; /* shut up the compiler */
+ }
+}
diff --git a/src/libgnomecanvas/gnome-canvas-util.h b/src/libgnomecanvas/gnome-canvas-util.h
new file mode 100644
index 0000000..cfd32c3
--- /dev/null
+++ b/src/libgnomecanvas/gnome-canvas-util.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ @NOTATION@
+ */
+/* Miscellaneous utility functions for the GnomeCanvas widget
+ *
+ * GnomeCanvas is basically a port of the Tk toolkit's most excellent canvas widget. Tk is
+ * copyrighted by the Regents of the University of California, Sun Microsystems, and other parties.
+ *
+ * Author: Federico Mena <federico@nuclecu.unam.mx>
+ */
+
+#ifndef GNOME_CANVAS_UTIL_H
+#define GNOME_CANVAS_UTIL_H
+
+#include <libgnomecanvas/gnome-canvas.h>
+
+#include <libart_lgpl/art_svp.h>
+#include <libart_lgpl/art_vpath.h>
+#include <libart_lgpl/art_svp_vpath_stroke.h>
+
+
+G_BEGIN_DECLS
+
+typedef struct _GnomeCanvasPoints GnomeCanvasPoints;
+
+/* This structure defines an array of points. X coordinates are stored in the even-numbered
+ * indices, and Y coordinates are stored in the odd-numbered indices. num_points indicates the
+ * number of points, so the array is 2*num_points elements big.
+ */
+struct _GnomeCanvasPoints {
+ double *coords;
+ int num_points;
+ int ref_count;
+};
+
+
+/* Allocate a new GnomeCanvasPoints structure with enough space for the specified number of points */
+GnomeCanvasPoints *gnome_canvas_points_new (int num_points);
+
+/* Increate ref count */
+GnomeCanvasPoints *gnome_canvas_points_ref (GnomeCanvasPoints *points);
+#define gnome_canvas_points_unref gnome_canvas_points_free
+
+/* Decrease ref count and free structure if it has reached zero */
+void gnome_canvas_points_free (GnomeCanvasPoints *points);
+
+/* Given three points forming an angle, compute the coordinates of the inside and outside points of
+ * the mitered corner formed by a line of a given width at that angle.
+ *
+ * If the angle is less than 11 degrees, then FALSE is returned and the return points are not
+ * modified. Otherwise, TRUE is returned.
+ */
+int gnome_canvas_get_miter_points (double x1, double y1, double x2, double y2, double x3, double y3,
+ double width,
+ double *mx1, double *my1, double *mx2, double *my2);
+
+/* Compute the butt points of a line segment. If project is FALSE, then the results are as follows:
+ *
+ * -------------------* (bx1, by1)
+ * |
+ * (x1, y1) *------------------* (x2, y2)
+ * |
+ * -------------------* (bx2, by2)
+ *
+ * that is, the line is not projected beyond (x2, y2). If project is TRUE, then the results are as
+ * follows:
+ *
+ * -------------------* (bx1, by1)
+ * (x2, y2) |
+ * (x1, y1) *-------------* |
+ * |
+ * -------------------* (bx2, by2)
+ */
+void gnome_canvas_get_butt_points (double x1, double y1, double x2, double y2,
+ double width, int project,
+ double *bx1, double *by1, double *bx2, double *by2);
+
+/* Calculate the distance from a polygon to a point. The polygon's X coordinates are in the even
+ * indices of the poly array, and the Y coordinates are in the odd indices.
+ */
+double gnome_canvas_polygon_to_point (double *poly, int num_points, double x, double y);
+
+
+/* Render the svp over the buf. */
+void gnome_canvas_render_svp (GnomeCanvasBuf *buf, ArtSVP *svp, guint32 rgba);
+
+/* Sets the svp to the new value, requesting repaint on what's changed. This function takes responsibility for
+ * freeing new_svp.
+ */
+void gnome_canvas_update_svp (GnomeCanvas *canvas, ArtSVP **p_svp, ArtSVP *new_svp);
+
+/* Sets the svp to the new value, clipping if necessary, and requesting repaint
+ * on what's changed. This function takes responsibility for freeing new_svp.
+ */
+void gnome_canvas_update_svp_clip (GnomeCanvas *canvas, ArtSVP **p_svp, ArtSVP *new_svp,
+ ArtSVP *clip_svp);
+
+/* Sets the svp to the new value, requesting repaint on what's changed. This
+ * function takes responsibility for freeing new_svp. This routine also adds the
+ * svp's bbox to the item's.
+ */
+void gnome_canvas_item_reset_bounds (GnomeCanvasItem *item);
+
+/* Sets the svp to the new value, requesting repaint on what's changed. This function takes responsibility for
+ * freeing new_svp. This routine also adds the svp's bbox to the item's.
+ */
+void gnome_canvas_item_update_svp (GnomeCanvasItem *item, ArtSVP **p_svp, ArtSVP *new_svp);
+
+/* Sets the svp to the new value, clipping if necessary, and requesting repaint
+ * on what's changed. This function takes responsibility for freeing new_svp.
+ */
+void gnome_canvas_item_update_svp_clip (GnomeCanvasItem *item, ArtSVP **p_svp, ArtSVP *new_svp,
+ ArtSVP *clip_svp);
+
+/* Request redraw of the svp if in aa mode, or the entire item in in xlib
+ * mode.
+ */
+void gnome_canvas_item_request_redraw_svp (GnomeCanvasItem *item, const ArtSVP *svp);
+
+/* Sets the bbox to the new value, requesting full repaint. */
+void gnome_canvas_update_bbox (GnomeCanvasItem *item, int x1, int y1, int x2, int y2);
+
+/* Ensure that the buffer is in RGB format, suitable for compositing. */
+void gnome_canvas_buf_ensure_buf (GnomeCanvasBuf *buf);
+
+/* Convert from GDK line join specifier to libart. */
+ArtPathStrokeJoinType gnome_canvas_join_gdk_to_art (GdkJoinStyle gdk_join);
+
+/* Convert from GDK line cap specifier to libart. */
+ArtPathStrokeCapType gnome_canvas_cap_gdk_to_art (GdkCapStyle gdk_cap);
+
+G_END_DECLS
+
+#endif
diff --git a/src/libgnomecanvas/gnome-canvas-widget.c b/src/libgnomecanvas/gnome-canvas-widget.c
new file mode 100644
index 0000000..dd7cbb6
--- /dev/null
+++ b/src/libgnomecanvas/gnome-canvas-widget.c
@@ -0,0 +1,599 @@
+/*
+ * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ @NOTATION@
+ */
+/* Widget item type for GnomeCanvas widget
+ *
+ * GnomeCanvas is basically a port of the Tk toolkit's most excellent canvas widget. Tk is
+ * copyrighted by the Regents of the University of California, Sun Microsystems, and other parties.
+ *
+ *
+ * Author: Federico Mena <federico@nuclecu.unam.mx>
+ */
+
+#include <config.h>
+#include <math.h>
+#include <gtk/gtksignal.h>
+#include "gnome-canvas-widget.h"
+
+enum {
+ PROP_0,
+ PROP_WIDGET,
+ PROP_X,
+ PROP_Y,
+ PROP_WIDTH,
+ PROP_HEIGHT,
+ PROP_ANCHOR,
+ PROP_SIZE_PIXELS
+};
+
+
+static void gnome_canvas_widget_class_init (GnomeCanvasWidgetClass *class);
+static void gnome_canvas_widget_init (GnomeCanvasWidget *witem);
+static void gnome_canvas_widget_destroy (GtkObject *object);
+static void gnome_canvas_widget_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void gnome_canvas_widget_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+
+static void gnome_canvas_widget_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags);
+static double gnome_canvas_widget_point (GnomeCanvasItem *item, double x, double y,
+ int cx, int cy, GnomeCanvasItem **actual_item);
+static void gnome_canvas_widget_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2);
+
+static void gnome_canvas_widget_render (GnomeCanvasItem *item,
+ GnomeCanvasBuf *buf);
+static void gnome_canvas_widget_draw (GnomeCanvasItem *item,
+ GdkDrawable *drawable,
+ int x, int y,
+ int width, int height);
+
+static GnomeCanvasItemClass *parent_class;
+
+
+GType
+gnome_canvas_widget_get_type (void)
+{
+ static GType widget_type;
+
+ if (!widget_type) {
+ static const GTypeInfo object_info = {
+ sizeof (GnomeCanvasWidgetClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gnome_canvas_widget_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (GnomeCanvasWidget),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) gnome_canvas_widget_init,
+ NULL /* value_table */
+ };
+
+ widget_type = g_type_register_static (GNOME_TYPE_CANVAS_ITEM, "GnomeCanvasWidget",
+ &object_info, 0);
+ }
+
+ return widget_type;
+}
+
+static void
+gnome_canvas_widget_class_init (GnomeCanvasWidgetClass *class)
+{
+ GObjectClass *gobject_class;
+ GtkObjectClass *object_class;
+ GnomeCanvasItemClass *item_class;
+
+ gobject_class = (GObjectClass *) class;
+ object_class = (GtkObjectClass *) class;
+ item_class = (GnomeCanvasItemClass *) class;
+
+ parent_class = g_type_class_peek_parent (class);
+
+ gobject_class->set_property = gnome_canvas_widget_set_property;
+ gobject_class->get_property = gnome_canvas_widget_get_property;
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_WIDGET,
+ g_param_spec_object ("widget", NULL, NULL,
+ GTK_TYPE_WIDGET,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_X,
+ g_param_spec_double ("x", NULL, NULL,
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_Y,
+ g_param_spec_double ("y", NULL, NULL,
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_WIDTH,
+ g_param_spec_double ("width", NULL, NULL,
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_HEIGHT,
+ g_param_spec_double ("height", NULL, NULL,
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_ANCHOR,
+ g_param_spec_enum ("anchor", NULL, NULL,
+ GTK_TYPE_ANCHOR_TYPE,
+ GTK_ANCHOR_NW,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_SIZE_PIXELS,
+ g_param_spec_boolean ("size_pixels", NULL, NULL,
+ FALSE,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+
+ object_class->destroy = gnome_canvas_widget_destroy;
+
+ item_class->update = gnome_canvas_widget_update;
+ item_class->point = gnome_canvas_widget_point;
+ item_class->bounds = gnome_canvas_widget_bounds;
+ item_class->render = gnome_canvas_widget_render;
+ item_class->draw = gnome_canvas_widget_draw;
+}
+
+static void
+gnome_canvas_widget_init (GnomeCanvasWidget *witem)
+{
+ witem->x = 0.0;
+ witem->y = 0.0;
+ witem->width = 0.0;
+ witem->height = 0.0;
+ witem->anchor = GTK_ANCHOR_NW;
+ witem->size_pixels = FALSE;
+}
+
+static void
+gnome_canvas_widget_destroy (GtkObject *object)
+{
+ GnomeCanvasWidget *witem;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GNOME_IS_CANVAS_WIDGET (object));
+
+ witem = GNOME_CANVAS_WIDGET (object);
+
+ if (witem->widget && !witem->in_destroy) {
+ g_signal_handler_disconnect (witem->widget, witem->destroy_id);
+ gtk_widget_destroy (witem->widget);
+ witem->widget = NULL;
+ }
+
+ if (GTK_OBJECT_CLASS (parent_class)->destroy)
+ (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+}
+
+static void
+recalc_bounds (GnomeCanvasWidget *witem)
+{
+ GnomeCanvasItem *item;
+ double wx, wy;
+
+ item = GNOME_CANVAS_ITEM (witem);
+
+ /* Get world coordinates */
+
+ wx = witem->x;
+ wy = witem->y;
+ gnome_canvas_item_i2w (item, &wx, &wy);
+
+ /* Get canvas pixel coordinates */
+
+ gnome_canvas_w2c (item->canvas, wx, wy, &witem->cx, &witem->cy);
+
+ /* Anchor widget item */
+
+ switch (witem->anchor) {
+ case GTK_ANCHOR_NW:
+ case GTK_ANCHOR_W:
+ case GTK_ANCHOR_SW:
+ break;
+
+ case GTK_ANCHOR_N:
+ case GTK_ANCHOR_CENTER:
+ case GTK_ANCHOR_S:
+ witem->cx -= witem->cwidth / 2;
+ break;
+
+ case GTK_ANCHOR_NE:
+ case GTK_ANCHOR_E:
+ case GTK_ANCHOR_SE:
+ witem->cx -= witem->cwidth;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (witem->anchor) {
+ case GTK_ANCHOR_NW:
+ case GTK_ANCHOR_N:
+ case GTK_ANCHOR_NE:
+ break;
+
+ case GTK_ANCHOR_W:
+ case GTK_ANCHOR_CENTER:
+ case GTK_ANCHOR_E:
+ witem->cy -= witem->cheight / 2;
+ break;
+
+ case GTK_ANCHOR_SW:
+ case GTK_ANCHOR_S:
+ case GTK_ANCHOR_SE:
+ witem->cy -= witem->cheight;
+ break;
+
+ default:
+ break;
+ }
+
+ /* Bounds */
+
+ item->x1 = witem->cx;
+ item->y1 = witem->cy;
+ item->x2 = witem->cx + witem->cwidth;
+ item->y2 = witem->cy + witem->cheight;
+
+ if (witem->widget)
+ gtk_layout_move (GTK_LAYOUT (item->canvas), witem->widget,
+ witem->cx + item->canvas->zoom_xofs,
+ witem->cy + item->canvas->zoom_yofs);
+}
+
+static void
+do_destroy (GtkObject *object, gpointer data)
+{
+ GnomeCanvasWidget *witem;
+
+ witem = data;
+
+ witem->in_destroy = TRUE;
+
+ gtk_object_destroy (data);
+}
+
+static void
+gnome_canvas_widget_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GnomeCanvasItem *item;
+ GnomeCanvasWidget *witem;
+ GObject *obj;
+ int update;
+ int calc_bounds;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GNOME_IS_CANVAS_WIDGET (object));
+
+ item = GNOME_CANVAS_ITEM (object);
+ witem = GNOME_CANVAS_WIDGET (object);
+
+ update = FALSE;
+ calc_bounds = FALSE;
+
+ switch (param_id) {
+ case PROP_WIDGET:
+ if (witem->widget) {
+ g_signal_handler_disconnect (witem->widget, witem->destroy_id);
+ gtk_container_remove (GTK_CONTAINER (item->canvas), witem->widget);
+ }
+
+ obj = g_value_get_object (value);
+ if (obj) {
+ witem->widget = GTK_WIDGET (obj);
+ witem->destroy_id = g_signal_connect (obj, "destroy",
+ G_CALLBACK (do_destroy),
+ witem);
+ gtk_layout_put (GTK_LAYOUT (item->canvas), witem->widget,
+ witem->cx + item->canvas->zoom_xofs,
+ witem->cy + item->canvas->zoom_yofs);
+ }
+
+ update = TRUE;
+ break;
+
+ case PROP_X:
+ if (witem->x != g_value_get_double (value))
+ {
+ witem->x = g_value_get_double (value);
+ calc_bounds = TRUE;
+ }
+ break;
+
+ case PROP_Y:
+ if (witem->y != g_value_get_double (value))
+ {
+ witem->y = g_value_get_double (value);
+ calc_bounds = TRUE;
+ }
+ break;
+
+ case PROP_WIDTH:
+ if (witem->width != fabs (g_value_get_double (value)))
+ {
+ witem->width = fabs (g_value_get_double (value));
+ update = TRUE;
+ }
+ break;
+
+ case PROP_HEIGHT:
+ if (witem->height != fabs (g_value_get_double (value)))
+ {
+ witem->height = fabs (g_value_get_double (value));
+ update = TRUE;
+ }
+ break;
+
+ case PROP_ANCHOR:
+ if (witem->anchor != g_value_get_enum (value))
+ {
+ witem->anchor = g_value_get_enum (value);
+ update = TRUE;
+ }
+ break;
+
+ case PROP_SIZE_PIXELS:
+ if (witem->size_pixels != g_value_get_boolean (value))
+ {
+ witem->size_pixels = g_value_get_boolean (value);
+ update = TRUE;
+ }
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+
+ if (update)
+ (* GNOME_CANVAS_ITEM_GET_CLASS (item)->update) (item, NULL, NULL, 0);
+
+ if (calc_bounds)
+ recalc_bounds (witem);
+}
+
+static void
+gnome_canvas_widget_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GnomeCanvasWidget *witem;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GNOME_IS_CANVAS_WIDGET (object));
+
+ witem = GNOME_CANVAS_WIDGET (object);
+
+ switch (param_id) {
+ case PROP_WIDGET:
+ g_value_set_object (value, (GObject *) witem->widget);
+ break;
+
+ case PROP_X:
+ g_value_set_double (value, witem->x);
+ break;
+
+ case PROP_Y:
+ g_value_set_double (value, witem->y);
+ break;
+
+ case PROP_WIDTH:
+ g_value_set_double (value, witem->width);
+ break;
+
+ case PROP_HEIGHT:
+ g_value_set_double (value, witem->height);
+ break;
+
+ case PROP_ANCHOR:
+ g_value_set_enum (value, witem->anchor);
+ break;
+
+ case PROP_SIZE_PIXELS:
+ g_value_set_boolean (value, witem->size_pixels);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+gnome_canvas_widget_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
+{
+ GnomeCanvasWidget *witem;
+
+ witem = GNOME_CANVAS_WIDGET (item);
+
+ if (parent_class->update)
+ (* parent_class->update) (item, affine, clip_path, flags);
+
+ if (witem->widget) {
+ if (witem->size_pixels) {
+ witem->cwidth = (int) (witem->width + 0.5);
+ witem->cheight = (int) (witem->height + 0.5);
+ } else {
+ witem->cwidth = (int) (witem->width * item->canvas->pixels_per_unit + 0.5);
+ witem->cheight = (int) (witem->height * item->canvas->pixels_per_unit + 0.5);
+ }
+
+ gtk_widget_set_size_request (witem->widget, witem->cwidth, witem->cheight);
+ } else {
+ witem->cwidth = 0.0;
+ witem->cheight = 0.0;
+ }
+
+ recalc_bounds (witem);
+}
+
+static void
+gnome_canvas_widget_render (GnomeCanvasItem *item,
+ GnomeCanvasBuf *buf)
+{
+#if 0
+ GnomeCanvasWidget *witem;
+
+ witem = GNOME_CANVAS_WIDGET (item);
+
+ if (witem->widget)
+ gtk_widget_queue_draw (witem->widget);
+#endif
+
+}
+
+static void
+gnome_canvas_widget_draw (GnomeCanvasItem *item,
+ GdkDrawable *drawable,
+ int x, int y,
+ int width, int height)
+{
+#if 0
+ GnomeCanvasWidget *witem;
+
+ witem = GNOME_CANVAS_WIDGET (item);
+
+ if (witem->widget)
+ gtk_widget_queue_draw (witem->widget);
+#endif
+}
+
+static double
+gnome_canvas_widget_point (GnomeCanvasItem *item, double x, double y,
+ int cx, int cy, GnomeCanvasItem **actual_item)
+{
+ GnomeCanvasWidget *witem;
+ double x1, y1, x2, y2;
+ double dx, dy;
+
+ witem = GNOME_CANVAS_WIDGET (item);
+
+ *actual_item = item;
+
+ gnome_canvas_c2w (item->canvas, witem->cx, witem->cy, &x1, &y1);
+
+ x2 = x1 + (witem->cwidth - 1) / item->canvas->pixels_per_unit;
+ y2 = y1 + (witem->cheight - 1) / item->canvas->pixels_per_unit;
+
+ /* Is point inside widget bounds? */
+
+ if ((x >= x1) && (y >= y1) && (x <= x2) && (y <= y2))
+ return 0.0;
+
+ /* Point is outside widget bounds */
+
+ if (x < x1)
+ dx = x1 - x;
+ else if (x > x2)
+ dx = x - x2;
+ else
+ dx = 0.0;
+
+ if (y < y1)
+ dy = y1 - y;
+ else if (y > y2)
+ dy = y - y2;
+ else
+ dy = 0.0;
+
+ return sqrt (dx * dx + dy * dy);
+}
+
+static void
+gnome_canvas_widget_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
+{
+ GnomeCanvasWidget *witem;
+
+ witem = GNOME_CANVAS_WIDGET (item);
+
+ *x1 = witem->x;
+ *y1 = witem->y;
+
+ switch (witem->anchor) {
+ case GTK_ANCHOR_NW:
+ case GTK_ANCHOR_W:
+ case GTK_ANCHOR_SW:
+ break;
+
+ case GTK_ANCHOR_N:
+ case GTK_ANCHOR_CENTER:
+ case GTK_ANCHOR_S:
+ *x1 -= witem->width / 2.0;
+ break;
+
+ case GTK_ANCHOR_NE:
+ case GTK_ANCHOR_E:
+ case GTK_ANCHOR_SE:
+ *x1 -= witem->width;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (witem->anchor) {
+ case GTK_ANCHOR_NW:
+ case GTK_ANCHOR_N:
+ case GTK_ANCHOR_NE:
+ break;
+
+ case GTK_ANCHOR_W:
+ case GTK_ANCHOR_CENTER:
+ case GTK_ANCHOR_E:
+ *y1 -= witem->height / 2.0;
+ break;
+
+ case GTK_ANCHOR_SW:
+ case GTK_ANCHOR_S:
+ case GTK_ANCHOR_SE:
+ *y1 -= witem->height;
+ break;
+
+ default:
+ break;
+ }
+
+ *x2 = *x1 + witem->width;
+ *y2 = *y1 + witem->height;
+}
diff --git a/src/libgnomecanvas/gnome-canvas-widget.h b/src/libgnomecanvas/gnome-canvas-widget.h
new file mode 100644
index 0000000..3eef1d9
--- /dev/null
+++ b/src/libgnomecanvas/gnome-canvas-widget.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ @NOTATION@
+ */
+/* Widget item type for GnomeCanvas widget
+ *
+ * GnomeCanvas is basically a port of the Tk toolkit's most excellent canvas widget. Tk is
+ * copyrighted by the Regents of the University of California, Sun Microsystems, and other parties.
+ *
+ *
+ * Author: Federico Mena <federico@nuclecu.unam.mx>
+ */
+
+#ifndef GNOME_CANVAS_WIDGET_H
+#define GNOME_CANVAS_WIDGET_H
+
+
+#include <libgnomecanvas/gnome-canvas.h>
+
+
+G_BEGIN_DECLS
+
+
+/* Widget item for canvas. The widget is positioned with respect to an anchor point.
+ * The following object arguments are available:
+ *
+ * name type read/write description
+ * ------------------------------------------------------------------------------------------
+ * widget GtkWidget* RW Pointer to the widget
+ * x double RW X coordinate of anchor point
+ * y double RW Y coordinate of anchor point
+ * width double RW Width of widget (see below)
+ * height double RW Height of widget (see below)
+ * anchor GtkAnchorType RW Anchor side for widget
+ * size_pixels boolean RW Specifies whether the widget size
+ * is specified in pixels or canvas units.
+ * If it is in pixels, then the widget will not
+ * be scaled when the canvas zoom factor changes.
+ * Otherwise, it will be scaled.
+ */
+
+
+#define GNOME_TYPE_CANVAS_WIDGET (gnome_canvas_widget_get_type ())
+#define GNOME_CANVAS_WIDGET(obj) (GTK_CHECK_CAST ((obj), GNOME_TYPE_CANVAS_WIDGET, GnomeCanvasWidget))
+#define GNOME_CANVAS_WIDGET_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GNOME_TYPE_CANVAS_WIDGET, GnomeCanvasWidgetClass))
+#define GNOME_IS_CANVAS_WIDGET(obj) (GTK_CHECK_TYPE ((obj), GNOME_TYPE_CANVAS_WIDGET))
+#define GNOME_IS_CANVAS_WIDGET_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_CANVAS_WIDGET))
+#define GNOME_CANVAS_WIDGET_GET_CLASS(obj) (GTK_CHECK_GET_CLASS ((obj), GNOME_TYPE_CANVAS_WIDGET, GnomeCanvasWidgetClass))
+
+
+typedef struct _GnomeCanvasWidget GnomeCanvasWidget;
+typedef struct _GnomeCanvasWidgetClass GnomeCanvasWidgetClass;
+
+struct _GnomeCanvasWidget {
+ GnomeCanvasItem item;
+
+ GtkWidget *widget; /* The child widget */
+
+ double x, y; /* Position at anchor */
+ double width, height; /* Dimensions of widget */
+ GtkAnchorType anchor; /* Anchor side for widget */
+
+ int cx, cy; /* Top-left canvas coordinates for widget */
+ int cwidth, cheight; /* Size of widget in pixels */
+
+ guint destroy_id; /* Signal connection id for destruction of child widget */
+
+ guint size_pixels : 1; /* Is size specified in (unchanging) pixels or units (get scaled)? */
+ guint in_destroy : 1; /* Is child widget being destroyed? */
+};
+
+struct _GnomeCanvasWidgetClass {
+ GnomeCanvasItemClass parent_class;
+};
+
+
+/* Standard Gtk function */
+GType gnome_canvas_widget_get_type (void) G_GNUC_CONST;
+
+
+G_END_DECLS
+
+#endif
diff --git a/src/libgnomecanvas/gnome-canvas.c b/src/libgnomecanvas/gnome-canvas.c
new file mode 100644
index 0000000..dda2607
--- /dev/null
+++ b/src/libgnomecanvas/gnome-canvas.c
@@ -0,0 +1,4081 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: 8; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ @NOTATION@
+ */
+/*
+ * GnomeCanvas widget - Tk-like canvas widget for Gnome
+ *
+ * GnomeCanvas is basically a port of the Tk toolkit's most excellent canvas widget. Tk is
+ * copyrighted by the Regents of the University of California, Sun Microsystems, and other parties.
+ *
+ *
+ * Authors: Federico Mena <federico@nuclecu.unam.mx>
+ * Raph Levien <raph@gimp.org>
+ */
+
+/*
+ * TO-DO list for the canvas:
+ *
+ * - Allow to specify whether GnomeCanvasImage sizes are in units or pixels (scale or don't scale).
+ *
+ * - Implement a flag for gnome_canvas_item_reparent() that tells the function to keep the item
+ * visually in the same place, that is, to keep it in the same place with respect to the canvas
+ * origin.
+ *
+ * - GC put functions for items.
+ *
+ * - Widget item (finish it).
+ *
+ * - GList *gnome_canvas_gimme_all_items_contained_in_this_area (GnomeCanvas *canvas, Rectangle area);
+ *
+ * - Retrofit all the primitive items with microtile support.
+ *
+ * - Curve support for line item.
+ *
+ * - Arc item (Havoc has it; to be integrated in GnomeCanvasEllipse).
+ *
+ * - Sane font handling API.
+ *
+ * - Get_arg methods for items:
+ * - How to fetch the outline width and know whether it is in pixels or units?
+ */
+
+/*
+ * Raph's TODO list for the antialiased canvas integration:
+ *
+ * - ::point() method for text item not accurate when affine transformed.
+ *
+ * - Clip rectangle not implemented in aa renderer for text item.
+ *
+ * - Clip paths only partially implemented.
+ *
+ * - Add more image loading techniques to work around imlib deficiencies.
+ */
+
+#include <config.h>
+
+#include <math.h>
+#include <string.h>
+#include <stdio.h>
+#include <gdk/gdkprivate.h>
+#include <gtk/gtkmain.h>
+#include <gtk/gtksignal.h>
+#include "gnome-canvas.h"
+#include "gnome-canvas-i18n.h"
+#include "libart_lgpl/art_rect.h"
+#include "libart_lgpl/art_rect_uta.h"
+#include "libart_lgpl/art_uta_rect.h"
+#include "libart_lgpl/art_uta_ops.h"
+
+#include "gnome-canvas-marshal.h"
+#include "gnome-canvas-marshal.c"
+
+
+/* We must run our idle update handler *before* GDK wants to redraw. */
+#define CANVAS_IDLE_PRIORITY (GDK_PRIORITY_REDRAW - 5)
+
+
+static void gnome_canvas_request_update (GnomeCanvas *canvas);
+static void group_add (GnomeCanvasGroup *group,
+ GnomeCanvasItem *item);
+static void group_remove (GnomeCanvasGroup *group,
+ GnomeCanvasItem *item);
+static void add_idle (GnomeCanvas *canvas);
+
+
+/*** GnomeCanvasItem ***/
+
+/* Some convenience stuff */
+#define GCI_UPDATE_MASK (GNOME_CANVAS_UPDATE_REQUESTED | GNOME_CANVAS_UPDATE_AFFINE | GNOME_CANVAS_UPDATE_CLIP | GNOME_CANVAS_UPDATE_VISIBILITY)
+#define GCI_EPSILON 1e-18
+#define GCI_PRINT_MATRIX(s,a) g_print ("%s %g %g %g %g %g %g\n", s, (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5])
+
+enum {
+ ITEM_PROP_0,
+ ITEM_PROP_PARENT
+};
+
+enum {
+ ITEM_EVENT,
+ ITEM_LAST_SIGNAL
+};
+
+static void gnome_canvas_item_class_init (GnomeCanvasItemClass *class);
+static void gnome_canvas_item_init (GnomeCanvasItem *item);
+static int emit_event (GnomeCanvas *canvas, GdkEvent *event);
+
+static guint item_signals[ITEM_LAST_SIGNAL];
+
+static GtkObjectClass *item_parent_class;
+
+
+/**
+ * gnome_canvas_item_get_type:
+ *
+ * Registers the &GnomeCanvasItem class if necessary, and returns the type ID
+ * associated to it.
+ *
+ * Return value: The type ID of the &GnomeCanvasItem class.
+ **/
+GType
+gnome_canvas_item_get_type (void)
+{
+ static GType canvas_item_type;
+
+ if (!canvas_item_type) {
+ static const GTypeInfo object_info = {
+ sizeof (GnomeCanvasItemClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gnome_canvas_item_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (GnomeCanvasItem),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) gnome_canvas_item_init,
+ NULL /* value_table */
+ };
+
+ canvas_item_type = g_type_register_static (GTK_TYPE_OBJECT, "GnomeCanvasItem",
+ &object_info, 0);
+ }
+
+ return canvas_item_type;
+}
+
+/* Object initialization function for GnomeCanvasItem */
+static void
+gnome_canvas_item_init (GnomeCanvasItem *item)
+{
+ item->object.flags |= GNOME_CANVAS_ITEM_VISIBLE;
+}
+
+/**
+ * gnome_canvas_item_new:
+ * @parent: The parent group for the new item.
+ * @type: The object type of the item.
+ * @first_arg_name: A list of object argument name/value pairs, NULL-terminated,
+ * used to configure the item. For example, "fill_color", "black",
+ * "width_units", 5.0, NULL.
+ * @Varargs:
+ *
+ * Creates a new canvas item with @parent as its parent group. The item is
+ * created at the top of its parent's stack, and starts up as visible. The item
+ * is of the specified @type, for example, it can be
+ * gnome_canvas_rect_get_type(). The list of object arguments/value pairs is
+ * used to configure the item. If you need to pass construct time parameters, you
+ * should use g_object_new() to pass the parameters and
+ * gnome_canvas_item_construct() to set up the canvas item.
+ *
+ * Return value: The newly-created item.
+ **/
+GnomeCanvasItem *
+gnome_canvas_item_new (GnomeCanvasGroup *parent, GType type, const gchar *first_arg_name, ...)
+{
+ GnomeCanvasItem *item;
+ va_list args;
+
+ g_return_val_if_fail (GNOME_IS_CANVAS_GROUP (parent), NULL);
+ g_return_val_if_fail (g_type_is_a (type, gnome_canvas_item_get_type ()), NULL);
+
+ item = GNOME_CANVAS_ITEM (g_object_new (type, NULL));
+
+ va_start (args, first_arg_name);
+ gnome_canvas_item_construct (item, parent, first_arg_name, args);
+ va_end (args);
+
+ return item;
+}
+
+
+/* Performs post-creation operations on a canvas item (adding it to its parent
+ * group, etc.)
+ */
+static void
+item_post_create_setup (GnomeCanvasItem *item)
+{
+ group_add (GNOME_CANVAS_GROUP (item->parent), item);
+
+ gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2 + 1, item->y2 + 1);
+ item->canvas->need_repick = TRUE;
+}
+
+/* Set_property handler for canvas items */
+static void
+gnome_canvas_item_set_property (GObject *gobject, guint param_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ GnomeCanvasItem *item;
+
+ g_return_if_fail (GNOME_IS_CANVAS_ITEM (gobject));
+
+ item = GNOME_CANVAS_ITEM (gobject);
+
+ switch (param_id) {
+ case ITEM_PROP_PARENT:
+ if (item->parent != NULL) {
+ g_warning ("Cannot set `parent' argument after item has "
+ "already been constructed.");
+ } else if (g_value_get_object (value)) {
+ item->parent = GNOME_CANVAS_ITEM (g_value_get_object (value));
+ item->canvas = item->parent->canvas;
+ item_post_create_setup (item);
+ }
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
+ break;
+ }
+}
+
+/* Get_property handler for canvas items */
+static void
+gnome_canvas_item_get_property (GObject *gobject, guint param_id,
+ GValue *value, GParamSpec *pspec)
+{
+ GnomeCanvasItem *item;
+
+ g_return_if_fail (GNOME_IS_CANVAS_ITEM (gobject));
+
+ item = GNOME_CANVAS_ITEM (gobject);
+
+ switch (param_id) {
+ case ITEM_PROP_PARENT:
+ g_value_set_object (value, item->parent);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
+ break;
+ }
+}
+
+/**
+ * gnome_canvas_item_construct:
+ * @item: An unconstructed canvas item.
+ * @parent: The parent group for the item.
+ * @first_arg_name: The name of the first argument for configuring the item.
+ * @args: The list of arguments used to configure the item.
+ *
+ * Constructs a canvas item; meant for use only by item implementations.
+ **/
+void
+gnome_canvas_item_construct (GnomeCanvasItem *item, GnomeCanvasGroup *parent,
+ const gchar *first_arg_name, va_list args)
+{
+ g_return_if_fail (GNOME_IS_CANVAS_GROUP (parent));
+ g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
+
+ item->parent = GNOME_CANVAS_ITEM (parent);
+ item->canvas = item->parent->canvas;
+
+ g_object_set_valist (G_OBJECT (item), first_arg_name, args);
+
+ item_post_create_setup (item);
+}
+
+
+/* If the item is visible, requests a redraw of it. */
+static void
+redraw_if_visible (GnomeCanvasItem *item)
+{
+ if (item->object.flags & GNOME_CANVAS_ITEM_VISIBLE)
+ gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2 + 1, item->y2 + 1);
+}
+
+/* Standard object dispose function for canvas items */
+static void
+gnome_canvas_item_dispose (GObject *object)
+{
+ GnomeCanvasItem *item;
+
+ g_return_if_fail (GNOME_IS_CANVAS_ITEM (object));
+
+ item = GNOME_CANVAS_ITEM (object);
+
+ if (item->canvas)
+ redraw_if_visible (item);
+
+ /* Make the canvas forget about us */
+
+ if (item->canvas && item == item->canvas->current_item) {
+ item->canvas->current_item = NULL;
+ item->canvas->need_repick = TRUE;
+ }
+
+ if (item->canvas && item == item->canvas->new_current_item) {
+ item->canvas->new_current_item = NULL;
+ item->canvas->need_repick = TRUE;
+ }
+
+ if (item->canvas && item == item->canvas->grabbed_item) {
+ item->canvas->grabbed_item = NULL;
+ gdk_pointer_ungrab (GDK_CURRENT_TIME);
+ }
+
+ if (item->canvas && item == item->canvas->focused_item)
+ item->canvas->focused_item = NULL;
+
+ /* Normal destroy stuff */
+
+ if (item->object.flags & GNOME_CANVAS_ITEM_MAPPED)
+ (* GNOME_CANVAS_ITEM_GET_CLASS (item)->unmap) (item);
+
+ if (item->object.flags & GNOME_CANVAS_ITEM_REALIZED)
+ (* GNOME_CANVAS_ITEM_GET_CLASS (item)->unrealize) (item);
+
+ if (item->parent)
+ group_remove (GNOME_CANVAS_GROUP (item->parent), item);
+
+ g_free (item->xform);
+ item->xform = NULL;
+
+ G_OBJECT_CLASS (item_parent_class)->dispose (object);
+ /* items should remove any reference to item->canvas after the
+ first ::destroy */
+ item->canvas = NULL;
+}
+
+/* Realize handler for canvas items */
+static void
+gnome_canvas_item_realize (GnomeCanvasItem *item)
+{
+ GTK_OBJECT_SET_FLAGS (item, GNOME_CANVAS_ITEM_REALIZED);
+
+ gnome_canvas_item_request_update (item);
+}
+
+/* Unrealize handler for canvas items */
+static void
+gnome_canvas_item_unrealize (GnomeCanvasItem *item)
+{
+ GTK_OBJECT_UNSET_FLAGS (item, GNOME_CANVAS_ITEM_REALIZED);
+}
+
+/* Map handler for canvas items */
+static void
+gnome_canvas_item_map (GnomeCanvasItem *item)
+{
+ GTK_OBJECT_SET_FLAGS (item, GNOME_CANVAS_ITEM_MAPPED);
+}
+
+/* Unmap handler for canvas items */
+static void
+gnome_canvas_item_unmap (GnomeCanvasItem *item)
+{
+ GTK_OBJECT_UNSET_FLAGS (item, GNOME_CANVAS_ITEM_MAPPED);
+}
+
+/* Update handler for canvas items */
+static void
+gnome_canvas_item_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
+{
+ GTK_OBJECT_UNSET_FLAGS (item, GNOME_CANVAS_ITEM_NEED_UPDATE);
+ GTK_OBJECT_UNSET_FLAGS (item, GNOME_CANVAS_ITEM_NEED_AFFINE);
+ GTK_OBJECT_UNSET_FLAGS (item, GNOME_CANVAS_ITEM_NEED_CLIP);
+ GTK_OBJECT_UNSET_FLAGS (item, GNOME_CANVAS_ITEM_NEED_VIS);
+}
+
+#define noHACKISH_AFFINE
+
+/*
+ * This routine invokes the update method of the item
+ * Please notice, that we take parent to canvas pixel matrix as argument
+ * unlike virtual method ::update, whose argument is item 2 canvas pixel
+ * matrix
+ *
+ * I will try to force somewhat meaningful naming for affines (Lauris)
+ * General naming rule is FROM2TO, where FROM and TO are abbreviations
+ * So p2cpx is Parent2CanvasPixel and i2cpx is Item2CanvasPixel
+ * I hope that this helps to keep track of what really happens
+ *
+ */
+
+static void
+gnome_canvas_item_invoke_update (GnomeCanvasItem *item, double *p2cpx, ArtSVP *clip_path, int flags)
+{
+ int child_flags;
+ gdouble i2cpx[6];
+
+#ifdef HACKISH_AFFINE
+ double i2w[6], w2c[6], i2c[6];
+#endif
+
+ child_flags = flags;
+ if (!(item->object.flags & GNOME_CANVAS_ITEM_VISIBLE))
+ child_flags &= ~GNOME_CANVAS_UPDATE_IS_VISIBLE;
+
+ /* Calculate actual item transformation matrix */
+
+ if (item->xform) {
+ if (item->object.flags & GNOME_CANVAS_ITEM_AFFINE_FULL) {
+ /* Item has full affine */
+ art_affine_multiply (i2cpx, item->xform, p2cpx);
+ } else {
+ /* Item has only translation */
+ memcpy (i2cpx, p2cpx, 4 * sizeof (gdouble));
+ i2cpx[4] = item->xform[0] * p2cpx[0] + item->xform[1] * p2cpx[2] + p2cpx[4];
+ i2cpx[5] = item->xform[0] * p2cpx[1] + item->xform[1] * p2cpx[3] + p2cpx[5];
+ }
+ } else {
+ /* Item has no matrix (i.e. identity) */
+ memcpy (i2cpx, p2cpx, 6 * sizeof (gdouble));
+ }
+
+#ifdef HACKISH_AFFINE
+ gnome_canvas_item_i2w_affine (item, i2w);
+ gnome_canvas_w2c_affine (item->canvas, w2c);
+ art_affine_multiply (i2c, i2w, w2c);
+ /* invariant (doesn't hold now): child_affine == i2c */
+ child_affine = i2c;
+#endif
+
+ /* apply object flags to child flags */
+
+ child_flags &= ~GNOME_CANVAS_UPDATE_REQUESTED;
+
+ if (item->object.flags & GNOME_CANVAS_ITEM_NEED_UPDATE)
+ child_flags |= GNOME_CANVAS_UPDATE_REQUESTED;
+
+ if (item->object.flags & GNOME_CANVAS_ITEM_NEED_AFFINE)
+ child_flags |= GNOME_CANVAS_UPDATE_AFFINE;
+
+ if (item->object.flags & GNOME_CANVAS_ITEM_NEED_CLIP)
+ child_flags |= GNOME_CANVAS_UPDATE_CLIP;
+
+ if (item->object.flags & GNOME_CANVAS_ITEM_NEED_VIS)
+ child_flags |= GNOME_CANVAS_UPDATE_VISIBILITY;
+
+ if (child_flags & GCI_UPDATE_MASK) {
+ if (GNOME_CANVAS_ITEM_GET_CLASS (item)->update)
+ GNOME_CANVAS_ITEM_GET_CLASS (item)->update (item, i2cpx, clip_path, child_flags);
+ }
+}
+
+/*
+ * This routine invokes the point method of the item.
+ * The arguments x, y should be in the parent item local coordinates.
+ *
+ * This is potentially evil, as we are relying on matrix inversion (Lauris)
+ */
+
+static double
+gnome_canvas_item_invoke_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, GnomeCanvasItem **actual_item)
+{
+ /* Calculate x & y in item local coordinates */
+
+ if (item->xform) {
+ if (item->object.flags & GNOME_CANVAS_ITEM_AFFINE_FULL) {
+ gdouble p2i[6], t;
+ /* Item has full affine */
+ art_affine_invert (p2i, item->xform);
+ t = x * p2i[0] + y * p2i[2] + p2i[4];
+ y = x * p2i[1] + y * p2i[3] + p2i[5];
+ x = t;
+ } else {
+ /* Item has only translation */
+ x -= item->xform[0];
+ y -= item->xform[1];
+ }
+ }
+
+#ifdef HACKISH_AFFINE
+ double i2w[6], w2c[6], i2c[6], c2i[6];
+ ArtPoint c, i;
+#endif
+
+#ifdef HACKISH_AFFINE
+ gnome_canvas_item_i2w_affine (item, i2w);
+ gnome_canvas_w2c_affine (item->canvas, w2c);
+ art_affine_multiply (i2c, i2w, w2c);
+ art_affine_invert (c2i, i2c);
+ c.x = cx;
+ c.y = cy;
+ art_affine_point (&i, &c, c2i);
+ x = i.x;
+ y = i.y;
+#endif
+
+ if (GNOME_CANVAS_ITEM_GET_CLASS (item)->point)
+ return GNOME_CANVAS_ITEM_GET_CLASS (item)->point (item, x, y, cx, cy, actual_item);
+
+ return 1e18;
+}
+
+/**
+ * gnome_canvas_item_set:
+ * @item: A canvas item.
+ * @first_arg_name: The list of object argument name/value pairs used to configure the item.
+ * @Varargs:
+ *
+ * Configures a canvas item. The arguments in the item are set to the specified
+ * values, and the item is repainted as appropriate.
+ **/
+void
+gnome_canvas_item_set (GnomeCanvasItem *item, const gchar *first_arg_name, ...)
+{
+ va_list args;
+
+ va_start (args, first_arg_name);
+ gnome_canvas_item_set_valist (item, first_arg_name, args);
+ va_end (args);
+}
+
+
+/**
+ * gnome_canvas_item_set_valist:
+ * @item: A canvas item.
+ * @first_arg_name: The name of the first argument used to configure the item.
+ * @args: The list of object argument name/value pairs used to configure the item.
+ *
+ * Configures a canvas item. The arguments in the item are set to the specified
+ * values, and the item is repainted as appropriate.
+ **/
+void
+gnome_canvas_item_set_valist (GnomeCanvasItem *item, const gchar *first_arg_name, va_list args)
+{
+ g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
+
+ g_object_set_valist (G_OBJECT (item), first_arg_name, args);
+
+#if 0
+ /* I commented this out, because item implementations have to schedule update/redraw */
+ redraw_if_visible (item);
+#endif
+
+ item->canvas->need_repick = TRUE;
+}
+
+
+/**
+ * gnome_canvas_item_affine_relative:
+ * @item: A canvas item.
+ * @affine: An affine transformation matrix.
+ *
+ * Combines the specified affine transformation matrix with the item's current
+ * transformation. NULL affine is not allowed.
+ **/
+#define GCIAR_EPSILON 1e-6
+void
+gnome_canvas_item_affine_relative (GnomeCanvasItem *item, const double affine[6])
+{
+ gdouble i2p[6];
+
+ g_return_if_fail (item != NULL);
+ g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
+ g_return_if_fail (affine != NULL);
+
+ /* Calculate actual item transformation matrix */
+
+ if (item->xform) {
+ if (item->object.flags & GNOME_CANVAS_ITEM_AFFINE_FULL) {
+ /* Item has full affine */
+ art_affine_multiply (i2p, affine, item->xform);
+ } else {
+ /* Item has only translation */
+ memcpy (i2p, affine, 6 * sizeof (gdouble));
+ i2p[4] += item->xform[0];
+ i2p[5] += item->xform[1];
+ }
+ } else {
+ /* Item has no matrix (i.e. identity) */
+ memcpy (i2p, affine, 6 * sizeof (gdouble));
+ }
+
+ gnome_canvas_item_affine_absolute (item, i2p);
+}
+
+/**
+ * gnome_canvas_item_affine_absolute:
+ * @item: A canvas item.
+ * @affine: An affine transformation matrix.
+ *
+ * Makes the item's affine transformation matrix be equal to the specified
+ * matrix. NULL affine is treated as identity.
+ **/
+void
+gnome_canvas_item_affine_absolute (GnomeCanvasItem *item, const double i2p[6])
+{
+ g_return_if_fail (item != NULL);
+ g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
+
+ if (i2p &&
+ (fabs (i2p[0] - 1.0) < GCI_EPSILON) &&
+ (fabs (i2p[1] - 0.0) < GCI_EPSILON) &&
+ (fabs (i2p[2] - 0.0) < GCI_EPSILON) &&
+ (fabs (i2p[3] - 1.0) < GCI_EPSILON) &&
+ (fabs (i2p[4] - 0.0) < GCI_EPSILON) &&
+ (fabs (i2p[5] - 0.0) < GCI_EPSILON)) {
+ /* We are identity */
+ i2p = NULL;
+ }
+
+ if (i2p) {
+ if (item->xform && !(item->object.flags & GNOME_CANVAS_ITEM_AFFINE_FULL)) {
+ /* We do not want to deal with translation-only affines */
+ g_free (item->xform);
+ item->xform = NULL;
+ }
+ if (!item->xform) item->xform = g_new (gdouble, 6);
+ memcpy (item->xform, i2p, 6 * sizeof (gdouble));
+ item->object.flags |= GNOME_CANVAS_ITEM_AFFINE_FULL;
+ } else {
+ if (item->xform) {
+ g_free (item->xform);
+ item->xform = NULL;
+ }
+ }
+
+ if (!(item->object.flags & GNOME_CANVAS_ITEM_NEED_AFFINE)) {
+ /* Request update */
+ item->object.flags |= GNOME_CANVAS_ITEM_NEED_AFFINE;
+ gnome_canvas_item_request_update (item);
+ }
+
+ item->canvas->need_repick = TRUE;
+}
+
+
+/**
+ * gnome_canvas_item_move:
+ * @item: A canvas item.
+ * @dx: Horizontal offset.
+ * @dy: Vertical offset.
+ *
+ * Moves a canvas item by creating an affine transformation matrix for
+ * translation by using the specified values. This happens in item
+ * local coordinate system, so if you have nontrivial transform, it
+ * most probably does not do, what you want.
+ **/
+void
+gnome_canvas_item_move (GnomeCanvasItem *item, double dx, double dy)
+{
+ double translate[6];
+
+ g_return_if_fail (item != NULL);
+ g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
+
+ art_affine_translate (translate, dx, dy);
+
+ gnome_canvas_item_affine_relative (item, translate);
+}
+
+/* Convenience function to reorder items in a group's child list. This puts the
+ * specified link after the "before" link. Returns TRUE if the list was changed.
+ */
+static gboolean
+put_item_after (GList *link, GList *before)
+{
+ GnomeCanvasGroup *parent;
+ GList *old_before, *old_after;
+ GList *after;
+
+ parent = GNOME_CANVAS_GROUP (GNOME_CANVAS_ITEM (link->data)->parent);
+
+ if (before)
+ after = before->next;
+ else
+ after = parent->item_list;
+
+ if (before == link || after == link)
+ return FALSE;
+
+ /* Unlink */
+
+ old_before = link->prev;
+ old_after = link->next;
+
+ if (old_before)
+ old_before->next = old_after;
+ else
+ parent->item_list = old_after;
+
+ if (old_after)
+ old_after->prev = old_before;
+ else
+ parent->item_list_end = old_before;
+
+ /* Relink */
+
+ link->prev = before;
+ if (before)
+ before->next = link;
+ else
+ parent->item_list = link;
+
+ link->next = after;
+ if (after)
+ after->prev = link;
+ else
+ parent->item_list_end = link;
+
+ return TRUE;
+}
+
+
+/**
+ * gnome_canvas_item_raise:
+ * @item: A canvas item.
+ * @positions: Number of steps to raise the item.
+ *
+ * Raises the item in its parent's stack by the specified number of positions.
+ * If the number of positions is greater than the distance to the top of the
+ * stack, then the item is put at the top.
+ **/
+void
+gnome_canvas_item_raise (GnomeCanvasItem *item, int positions)
+{
+ GList *link, *before;
+ GnomeCanvasGroup *parent;
+
+ g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
+ g_return_if_fail (positions >= 0);
+
+ if (!item->parent || positions == 0)
+ return;
+
+ parent = GNOME_CANVAS_GROUP (item->parent);
+ link = g_list_find (parent->item_list, item);
+ g_assert (link != NULL);
+
+ for (before = link; positions && before; positions--)
+ before = before->next;
+
+ if (!before)
+ before = parent->item_list_end;
+
+ if (put_item_after (link, before)) {
+ redraw_if_visible (item);
+ item->canvas->need_repick = TRUE;
+ }
+}
+
+
+/**
+ * gnome_canvas_item_lower:
+ * @item: A canvas item.
+ * @positions: Number of steps to lower the item.
+ *
+ * Lowers the item in its parent's stack by the specified number of positions.
+ * If the number of positions is greater than the distance to the bottom of the
+ * stack, then the item is put at the bottom.
+ **/
+void
+gnome_canvas_item_lower (GnomeCanvasItem *item, int positions)
+{
+ GList *link, *before;
+ GnomeCanvasGroup *parent;
+
+ g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
+ g_return_if_fail (positions >= 1);
+
+ if (!item->parent || positions == 0)
+ return;
+
+ parent = GNOME_CANVAS_GROUP (item->parent);
+ link = g_list_find (parent->item_list, item);
+ g_assert (link != NULL);
+
+ if (link->prev)
+ for (before = link->prev; positions && before; positions--)
+ before = before->prev;
+ else
+ before = NULL;
+
+ if (put_item_after (link, before)) {
+ redraw_if_visible (item);
+ item->canvas->need_repick = TRUE;
+ }
+}
+
+
+/**
+ * gnome_canvas_item_raise_to_top:
+ * @item: A canvas item.
+ *
+ * Raises an item to the top of its parent's stack.
+ **/
+void
+gnome_canvas_item_raise_to_top (GnomeCanvasItem *item)
+{
+ GList *link;
+ GnomeCanvasGroup *parent;
+
+ g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
+
+ if (!item->parent)
+ return;
+
+ parent = GNOME_CANVAS_GROUP (item->parent);
+ link = g_list_find (parent->item_list, item);
+ g_assert (link != NULL);
+
+ if (put_item_after (link, parent->item_list_end)) {
+ redraw_if_visible (item);
+ item->canvas->need_repick = TRUE;
+ }
+}
+
+
+/**
+ * gnome_canvas_item_lower_to_bottom:
+ * @item: A canvas item.
+ *
+ * Lowers an item to the bottom of its parent's stack.
+ **/
+void
+gnome_canvas_item_lower_to_bottom (GnomeCanvasItem *item)
+{
+ GList *link;
+ GnomeCanvasGroup *parent;
+
+ g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
+
+ if (!item->parent)
+ return;
+
+ parent = GNOME_CANVAS_GROUP (item->parent);
+ link = g_list_find (parent->item_list, item);
+ g_assert (link != NULL);
+
+ if (put_item_after (link, NULL)) {
+ redraw_if_visible (item);
+ item->canvas->need_repick = TRUE;
+ }
+}
+
+
+/**
+ * gnome_canvas_item_show:
+ * @item: A canvas item.
+ *
+ * Shows a canvas item. If the item was already shown, then no action is taken.
+ **/
+void
+gnome_canvas_item_show (GnomeCanvasItem *item)
+{
+ g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
+
+ if (!(item->object.flags & GNOME_CANVAS_ITEM_VISIBLE)) {
+ item->object.flags |= GNOME_CANVAS_ITEM_VISIBLE;
+ gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2 + 1, item->y2 + 1);
+ item->canvas->need_repick = TRUE;
+ }
+}
+
+
+/**
+ * gnome_canvas_item_hide:
+ * @item: A canvas item.
+ *
+ * Hides a canvas item. If the item was already hidden, then no action is
+ * taken.
+ **/
+void
+gnome_canvas_item_hide (GnomeCanvasItem *item)
+{
+ g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
+
+ if (item->object.flags & GNOME_CANVAS_ITEM_VISIBLE) {
+ item->object.flags &= ~GNOME_CANVAS_ITEM_VISIBLE;
+ gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2 + 1, item->y2 + 1);
+ item->canvas->need_repick = TRUE;
+ }
+}
+
+
+/**
+ * gnome_canvas_item_grab:
+ * @item: A canvas item.
+ * @event_mask: Mask of events that will be sent to this item.
+ * @cursor: If non-NULL, the cursor that will be used while the grab is active.
+ * @etime: The timestamp required for grabbing the mouse, or GDK_CURRENT_TIME.
+ *
+ * Specifies that all events that match the specified event mask should be sent
+ * to the specified item, and also grabs the mouse by calling
+ * gdk_pointer_grab(). The event mask is also used when grabbing the pointer.
+ * If @cursor is not NULL, then that cursor is used while the grab is active.
+ * The @etime parameter is the timestamp required for grabbing the mouse.
+ *
+ * Return value: If an item was already grabbed, it returns %GDK_GRAB_ALREADY_GRABBED. If
+ * the specified item was hidden by calling gnome_canvas_item_hide(), then it
+ * returns %GDK_GRAB_NOT_VIEWABLE. Else, it returns the result of calling
+ * gdk_pointer_grab().
+ **/
+int
+gnome_canvas_item_grab (GnomeCanvasItem *item, guint event_mask, GdkCursor *cursor, guint32 etime)
+{
+ int retval;
+
+ g_return_val_if_fail (GNOME_IS_CANVAS_ITEM (item), GDK_GRAB_NOT_VIEWABLE);
+ g_return_val_if_fail (GTK_WIDGET_MAPPED (item->canvas), GDK_GRAB_NOT_VIEWABLE);
+
+ if (item->canvas->grabbed_item)
+ return GDK_GRAB_ALREADY_GRABBED;
+
+ if (!(item->object.flags & GNOME_CANVAS_ITEM_VISIBLE))
+ return GDK_GRAB_NOT_VIEWABLE;
+
+ retval = gdk_pointer_grab (item->canvas->layout.bin_window,
+ FALSE,
+ event_mask,
+ NULL,
+ cursor,
+ etime);
+
+ if (retval != GDK_GRAB_SUCCESS)
+ return retval;
+
+ item->canvas->grabbed_item = item;
+ item->canvas->grabbed_event_mask = event_mask;
+ item->canvas->current_item = item; /* So that events go to the grabbed item */
+
+ return retval;
+}
+
+
+/**
+ * gnome_canvas_item_ungrab:
+ * @item: A canvas item that holds a grab.
+ * @etime: The timestamp for ungrabbing the mouse.
+ *
+ * Ungrabs the item, which must have been grabbed in the canvas, and ungrabs the
+ * mouse.
+ **/
+void
+gnome_canvas_item_ungrab (GnomeCanvasItem *item, guint32 etime)
+{
+ g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
+
+ if (item->canvas->grabbed_item != item)
+ return;
+
+ item->canvas->grabbed_item = NULL;
+
+ gdk_pointer_ungrab (etime);
+}
+
+
+/**
+ * gnome_canvas_item_i2w_affine:
+ * @item: A canvas item
+ * @affine: An affine transformation matrix (return value).
+ *
+ * Gets the affine transform that converts from the item's coordinate system to
+ * world coordinates.
+ **/
+void
+gnome_canvas_item_i2w_affine (GnomeCanvasItem *item, double affine[6])
+{
+ g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
+ g_return_if_fail (affine != NULL);
+
+ art_affine_identity (affine);
+
+ while (item) {
+ if (item->xform != NULL) {
+ if (item->object.flags & GNOME_CANVAS_ITEM_AFFINE_FULL) {
+ art_affine_multiply (affine, affine, item->xform);
+ } else {
+ affine[4] += item->xform[0];
+ affine[5] += item->xform[1];
+ }
+ }
+
+ item = item->parent;
+ }
+}
+
+/**
+ * gnome_canvas_item_w2i:
+ * @item: A canvas item.
+ * @x: X coordinate to convert (input/output value).
+ * @y: Y coordinate to convert (input/output value).
+ *
+ * Converts a coordinate pair from world coordinates to item-relative
+ * coordinates.
+ **/
+void
+gnome_canvas_item_w2i (GnomeCanvasItem *item, double *x, double *y)
+{
+ double affine[6], inv[6];
+ ArtPoint w, i;
+
+ g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
+ g_return_if_fail (x != NULL);
+ g_return_if_fail (y != NULL);
+
+ gnome_canvas_item_i2w_affine (item, affine);
+ art_affine_invert (inv, affine);
+ w.x = *x;
+ w.y = *y;
+ art_affine_point (&i, &w, inv);
+ *x = i.x;
+ *y = i.y;
+}
+
+
+/**
+ * gnome_canvas_item_i2w:
+ * @item: A canvas item.
+ * @x: X coordinate to convert (input/output value).
+ * @y: Y coordinate to convert (input/output value).
+ *
+ * Converts a coordinate pair from item-relative coordinates to world
+ * coordinates.
+ **/
+void
+gnome_canvas_item_i2w (GnomeCanvasItem *item, double *x, double *y)
+{
+ double affine[6];
+ ArtPoint w, i;
+
+ g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
+ g_return_if_fail (x != NULL);
+ g_return_if_fail (y != NULL);
+
+ gnome_canvas_item_i2w_affine (item, affine);
+ i.x = *x;
+ i.y = *y;
+ art_affine_point (&w, &i, affine);
+ *x = w.x;
+ *y = w.y;
+}
+
+/**
+ * gnome_canvas_item_i2c_affine:
+ * @item: A canvas item.
+ * @affine: An affine transformation matrix (return value).
+ *
+ * Gets the affine transform that converts from item-relative coordinates to
+ * canvas pixel coordinates.
+ **/
+void
+gnome_canvas_item_i2c_affine (GnomeCanvasItem *item, double affine[6])
+{
+ double i2w[6], w2c[6];
+
+ gnome_canvas_item_i2w_affine (item, i2w);
+ gnome_canvas_w2c_affine (item->canvas, w2c);
+ art_affine_multiply (affine, i2w, w2c);
+}
+
+/* Returns whether the item is an inferior of or is equal to the parent. */
+static int
+is_descendant (GnomeCanvasItem *item, GnomeCanvasItem *parent)
+{
+ for (; item; item = item->parent)
+ if (item == parent)
+ return TRUE;
+
+ return FALSE;
+}
+
+/**
+ * gnome_canvas_item_reparent:
+ * @item: A canvas item.
+ * @new_group: A canvas group.
+ *
+ * Changes the parent of the specified item to be the new group. The item keeps
+ * its group-relative coordinates as for its old parent, so the item may change
+ * its absolute position within the canvas.
+ **/
+void
+gnome_canvas_item_reparent (GnomeCanvasItem *item, GnomeCanvasGroup *new_group)
+{
+ g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
+ g_return_if_fail (GNOME_IS_CANVAS_GROUP (new_group));
+
+ /* Both items need to be in the same canvas */
+ g_return_if_fail (item->canvas == GNOME_CANVAS_ITEM (new_group)->canvas);
+
+ /* The group cannot be an inferior of the item or be the item itself --
+ * this also takes care of the case where the item is the root item of
+ * the canvas. */
+ g_return_if_fail (!is_descendant (GNOME_CANVAS_ITEM (new_group), item));
+
+ /* Everything is ok, now actually reparent the item */
+
+ g_object_ref (G_OBJECT (item)); /* protect it from the unref in group_remove */
+
+ redraw_if_visible (item);
+
+ group_remove (GNOME_CANVAS_GROUP (item->parent), item);
+ item->parent = GNOME_CANVAS_ITEM (new_group);
+ group_add (new_group, item);
+
+ /* Redraw and repick */
+
+ redraw_if_visible (item);
+ item->canvas->need_repick = TRUE;
+
+ g_object_unref (G_OBJECT (item));
+}
+
+/**
+ * gnome_canvas_item_grab_focus:
+ * @item: A canvas item.
+ *
+ * Makes the specified item take the keyboard focus, so all keyboard events will
+ * be sent to it. If the canvas widget itself did not have the focus, it grabs
+ * it as well.
+ **/
+void
+gnome_canvas_item_grab_focus (GnomeCanvasItem *item)
+{
+ GnomeCanvasItem *focused_item;
+ GdkEvent ev;
+
+ g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
+ g_return_if_fail (GTK_WIDGET_CAN_FOCUS (GTK_WIDGET (item->canvas)));
+
+ focused_item = item->canvas->focused_item;
+
+ if (focused_item) {
+ ev.focus_change.type = GDK_FOCUS_CHANGE;
+ ev.focus_change.window = GTK_LAYOUT (item->canvas)->bin_window;
+ ev.focus_change.send_event = FALSE;
+ ev.focus_change.in = FALSE;
+
+ emit_event (item->canvas, &ev);
+ }
+
+ item->canvas->focused_item = item;
+ gtk_widget_grab_focus (GTK_WIDGET (item->canvas));
+
+ if (focused_item) {
+ ev.focus_change.type = GDK_FOCUS_CHANGE;
+ ev.focus_change.window = GTK_LAYOUT (item->canvas)->bin_window;
+ ev.focus_change.send_event = FALSE;
+ ev.focus_change.in = TRUE;
+
+ emit_event (item->canvas, &ev);
+ }
+}
+
+
+/**
+ * gnome_canvas_item_get_bounds:
+ * @item: A canvas item.
+ * @x1: Leftmost edge of the bounding box (return value).
+ * @y1: Upper edge of the bounding box (return value).
+ * @x2: Rightmost edge of the bounding box (return value).
+ * @y2: Lower edge of the bounding box (return value).
+ *
+ * Queries the bounding box of a canvas item. The bounds are returned in the
+ * coordinate system of the item's parent.
+ **/
+void
+gnome_canvas_item_get_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
+{
+ double tx1, ty1, tx2, ty2;
+ ArtPoint p1, p2, p3, p4;
+ ArtPoint q1, q2, q3, q4;
+ double min_x1, min_y1, min_x2, min_y2;
+ double max_x1, max_y1, max_x2, max_y2;
+
+ g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
+
+ tx1 = ty1 = tx2 = ty2 = 0.0;
+
+ /* Get the item's bounds in its coordinate system */
+
+ if (GNOME_CANVAS_ITEM_GET_CLASS (item)->bounds)
+ (* GNOME_CANVAS_ITEM_GET_CLASS (item)->bounds) (item, &tx1, &ty1, &tx2, &ty2);
+
+ /* Make the bounds relative to the item's parent coordinate system */
+
+ if (item->xform && (item->object.flags & GNOME_CANVAS_ITEM_AFFINE_FULL)) {
+ p1.x = p2.x = tx1;
+ p1.y = p4.y = ty1;
+ p3.x = p4.x = tx2;
+ p2.y = p3.y = ty2;
+
+ art_affine_point (&q1, &p1, item->xform);
+ art_affine_point (&q2, &p2, item->xform);
+ art_affine_point (&q3, &p3, item->xform);
+ art_affine_point (&q4, &p4, item->xform);
+
+ if (q1.x < q2.x) {
+ min_x1 = q1.x;
+ max_x1 = q2.x;
+ } else {
+ min_x1 = q2.x;
+ max_x1 = q1.x;
+ }
+
+ if (q1.y < q2.y) {
+ min_y1 = q1.y;
+ max_y1 = q2.y;
+ } else {
+ min_y1 = q2.y;
+ max_y1 = q1.y;
+ }
+
+ if (q3.x < q4.x) {
+ min_x2 = q3.x;
+ max_x2 = q4.x;
+ } else {
+ min_x2 = q4.x;
+ max_x2 = q3.x;
+ }
+
+ if (q3.y < q4.y) {
+ min_y2 = q3.y;
+ max_y2 = q4.y;
+ } else {
+ min_y2 = q4.y;
+ max_y2 = q3.y;
+ }
+
+ tx1 = MIN (min_x1, min_x2);
+ ty1 = MIN (min_y1, min_y2);
+ tx2 = MAX (max_x1, max_x2);
+ ty2 = MAX (max_y1, max_y2);
+ } else if (item->xform) {
+ tx1 += item->xform[0];
+ ty1 += item->xform[1];
+ tx2 += item->xform[0];
+ ty2 += item->xform[1];
+ }
+
+ /* Return the values */
+
+ if (x1)
+ *x1 = tx1;
+
+ if (y1)
+ *y1 = ty1;
+
+ if (x2)
+ *x2 = tx2;
+
+ if (y2)
+ *y2 = ty2;
+}
+
+
+/**
+ * gnome_canvas_item_request_update
+ * @item: A canvas item.
+ *
+ * To be used only by item implementations. Requests that the canvas queue an
+ * update for the specified item.
+ **/
+void
+gnome_canvas_item_request_update (GnomeCanvasItem *item)
+{
+ if (item->object.flags & GNOME_CANVAS_ITEM_NEED_UPDATE)
+ return;
+
+ item->object.flags |= GNOME_CANVAS_ITEM_NEED_UPDATE;
+
+ if (item->parent != NULL) {
+ /* Recurse up the tree */
+ gnome_canvas_item_request_update (item->parent);
+ } else {
+ /* Have reached the top of the tree, make sure the update call gets scheduled. */
+ gnome_canvas_request_update (item->canvas);
+ }
+}
+
+/*** GnomeCanvasGroup ***/
+
+
+enum {
+ GROUP_PROP_0,
+ GROUP_PROP_X,
+ GROUP_PROP_Y
+};
+
+
+static void gnome_canvas_group_class_init (GnomeCanvasGroupClass *class);
+static void gnome_canvas_group_init (GnomeCanvasGroup *group);
+static void gnome_canvas_group_set_property(GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gnome_canvas_group_get_property(GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+static void gnome_canvas_group_destroy (GtkObject *object);
+
+static void gnome_canvas_group_update (GnomeCanvasItem *item, double *affine,
+ ArtSVP *clip_path, int flags);
+static void gnome_canvas_group_realize (GnomeCanvasItem *item);
+static void gnome_canvas_group_unrealize (GnomeCanvasItem *item);
+static void gnome_canvas_group_map (GnomeCanvasItem *item);
+static void gnome_canvas_group_unmap (GnomeCanvasItem *item);
+static void gnome_canvas_group_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
+ int x, int y, int width, int height);
+static double gnome_canvas_group_point (GnomeCanvasItem *item, double x, double y,
+ int cx, int cy,
+ GnomeCanvasItem **actual_item);
+static void gnome_canvas_group_bounds (GnomeCanvasItem *item, double *x1, double *y1,
+ double *x2, double *y2);
+static void gnome_canvas_group_render (GnomeCanvasItem *item,
+ GnomeCanvasBuf *buf);
+
+
+static GnomeCanvasItemClass *group_parent_class;
+
+
+/**
+ * gnome_canvas_group_get_type:
+ *
+ * Registers the &GnomeCanvasGroup class if necessary, and returns the type ID
+ * associated to it.
+ *
+ * Return value: The type ID of the &GnomeCanvasGroup class.
+ **/
+GType
+gnome_canvas_group_get_type (void)
+{
+ static GType canvas_group_type;
+
+ if (!canvas_group_type) {
+ static const GTypeInfo object_info = {
+ sizeof (GnomeCanvasGroupClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gnome_canvas_group_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (GnomeCanvasGroup),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) gnome_canvas_group_init,
+ NULL /* value_table */
+ };
+
+ canvas_group_type = g_type_register_static (GNOME_TYPE_CANVAS_ITEM, "GnomeCanvasGroup",
+ &object_info, 0);
+ }
+
+ return canvas_group_type;
+}
+
+/* Class initialization function for GnomeCanvasGroupClass */
+static void
+gnome_canvas_group_class_init (GnomeCanvasGroupClass *class)
+{
+ GObjectClass *gobject_class;
+ GtkObjectClass *object_class;
+ GnomeCanvasItemClass *item_class;
+
+ gobject_class = (GObjectClass *) class;
+ object_class = (GtkObjectClass *) class;
+ item_class = (GnomeCanvasItemClass *) class;
+
+ group_parent_class = g_type_class_peek_parent (class);
+
+ gobject_class->set_property = gnome_canvas_group_set_property;
+ gobject_class->get_property = gnome_canvas_group_get_property;
+
+ g_object_class_install_property
+ (gobject_class, GROUP_PROP_X,
+ g_param_spec_double ("x",
+ _("X"),
+ _("X"),
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class, GROUP_PROP_Y,
+ g_param_spec_double ("y",
+ _("Y"),
+ _("Y"),
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+
+ object_class->destroy = gnome_canvas_group_destroy;
+
+ item_class->update = gnome_canvas_group_update;
+ item_class->realize = gnome_canvas_group_realize;
+ item_class->unrealize = gnome_canvas_group_unrealize;
+ item_class->map = gnome_canvas_group_map;
+ item_class->unmap = gnome_canvas_group_unmap;
+ item_class->draw = gnome_canvas_group_draw;
+ item_class->render = gnome_canvas_group_render;
+ item_class->point = gnome_canvas_group_point;
+ item_class->bounds = gnome_canvas_group_bounds;
+}
+
+/* Object initialization function for GnomeCanvasGroup */
+static void
+gnome_canvas_group_init (GnomeCanvasGroup *group)
+{
+#if 0
+ group->xpos = 0.0;
+ group->ypos = 0.0;
+#endif
+}
+
+/* Translate handler for canvas groups */
+static double *
+gnome_canvas_ensure_translate (GnomeCanvasItem *item)
+{
+ if (item->xform == NULL) {
+ GTK_OBJECT_UNSET_FLAGS (item, GNOME_CANVAS_ITEM_AFFINE_FULL);
+ item->xform = g_new (double, 2);
+ item->xform[0] = 0.0;
+ item->xform[1] = 0.0;
+ return item->xform;
+ } else if (item->object.flags & GNOME_CANVAS_ITEM_AFFINE_FULL) {
+ return item->xform + 4;
+ } else {
+ return item->xform;
+ }
+}
+
+/* Set_property handler for canvas groups */
+static void
+gnome_canvas_group_set_property (GObject *gobject, guint param_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ GnomeCanvasItem *item;
+ double *xlat;
+
+ g_return_if_fail (GNOME_IS_CANVAS_GROUP (gobject));
+
+ item = GNOME_CANVAS_ITEM (gobject);
+
+ switch (param_id) {
+ case GROUP_PROP_X:
+ xlat = gnome_canvas_ensure_translate (item);
+ xlat[0] = g_value_get_double (value);
+ break;
+
+ case GROUP_PROP_Y:
+ xlat = gnome_canvas_ensure_translate (item);
+ xlat[1] = g_value_get_double (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
+ break;
+ }
+}
+
+/* Get_property handler for canvas groups */
+static void
+gnome_canvas_group_get_property (GObject *gobject, guint param_id,
+ GValue *value, GParamSpec *pspec)
+{
+ GnomeCanvasItem *item;
+
+ g_return_if_fail (GNOME_IS_CANVAS_GROUP (gobject));
+
+ item = GNOME_CANVAS_ITEM (gobject);
+
+ switch (param_id) {
+ case GROUP_PROP_X:
+ if (item->xform == NULL)
+ g_value_set_double (value, 0);
+ else if (GTK_OBJECT (gobject)->flags & GNOME_CANVAS_ITEM_AFFINE_FULL)
+ g_value_set_double (value, item->xform[4]);
+ else
+ g_value_set_double (value, item->xform[0]);
+ break;
+
+ case GROUP_PROP_Y:
+ if (item->xform == NULL)
+ g_value_set_double (value, 0);
+ else if (GTK_OBJECT (gobject)->flags & GNOME_CANVAS_ITEM_AFFINE_FULL)
+ g_value_set_double (value, item->xform[5]);
+ else
+ g_value_set_double (value, item->xform[1]);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
+ break;
+ }
+}
+
+/* Destroy handler for canvas groups */
+static void
+gnome_canvas_group_destroy (GtkObject *object)
+{
+ GnomeCanvasGroup *group;
+
+ g_return_if_fail (GNOME_IS_CANVAS_GROUP (object));
+
+ group = GNOME_CANVAS_GROUP (object);
+
+ while (group->item_list) {
+ // child is unref'ed by the child's group_remove().
+ gtk_object_destroy (GTK_OBJECT (group->item_list->data));
+ }
+
+ if (GTK_OBJECT_CLASS (group_parent_class)->destroy)
+ (* GTK_OBJECT_CLASS (group_parent_class)->destroy) (object);
+}
+
+/* Update handler for canvas groups */
+static void
+gnome_canvas_group_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
+{
+ GnomeCanvasGroup *group;
+ GList *list;
+ GnomeCanvasItem *i;
+ ArtDRect bbox, child_bbox;
+
+ group = GNOME_CANVAS_GROUP (item);
+
+ (* group_parent_class->update) (item, affine, clip_path, flags);
+
+ bbox.x0 = 0;
+ bbox.y0 = 0;
+ bbox.x1 = 0;
+ bbox.y1 = 0;
+
+ for (list = group->item_list; list; list = list->next) {
+ i = list->data;
+
+ gnome_canvas_item_invoke_update (i, affine, clip_path, flags);
+
+ child_bbox.x0 = i->x1;
+ child_bbox.y0 = i->y1;
+ child_bbox.x1 = i->x2;
+ child_bbox.y1 = i->y2;
+ art_drect_union (&bbox, &bbox, &child_bbox);
+ }
+ item->x1 = bbox.x0;
+ item->y1 = bbox.y0;
+ item->x2 = bbox.x1;
+ item->y2 = bbox.y1;
+}
+
+/* Realize handler for canvas groups */
+static void
+gnome_canvas_group_realize (GnomeCanvasItem *item)
+{
+ GnomeCanvasGroup *group;
+ GList *list;
+ GnomeCanvasItem *i;
+
+ group = GNOME_CANVAS_GROUP (item);
+
+ for (list = group->item_list; list; list = list->next) {
+ i = list->data;
+
+ if (!(i->object.flags & GNOME_CANVAS_ITEM_REALIZED))
+ (* GNOME_CANVAS_ITEM_GET_CLASS (i)->realize) (i);
+ }
+
+ (* group_parent_class->realize) (item);
+}
+
+/* Unrealize handler for canvas groups */
+static void
+gnome_canvas_group_unrealize (GnomeCanvasItem *item)
+{
+ GnomeCanvasGroup *group;
+ GList *list;
+ GnomeCanvasItem *i;
+
+ group = GNOME_CANVAS_GROUP (item);
+
+ for (list = group->item_list; list; list = list->next) {
+ i = list->data;
+
+ if (i->object.flags & GNOME_CANVAS_ITEM_REALIZED)
+ (* GNOME_CANVAS_ITEM_GET_CLASS (i)->unrealize) (i);
+ }
+
+ (* group_parent_class->unrealize) (item);
+}
+
+/* Map handler for canvas groups */
+static void
+gnome_canvas_group_map (GnomeCanvasItem *item)
+{
+ GnomeCanvasGroup *group;
+ GList *list;
+ GnomeCanvasItem *i;
+
+ group = GNOME_CANVAS_GROUP (item);
+
+ for (list = group->item_list; list; list = list->next) {
+ i = list->data;
+
+ if (!(i->object.flags & GNOME_CANVAS_ITEM_MAPPED))
+ (* GNOME_CANVAS_ITEM_GET_CLASS (i)->map) (i);
+ }
+
+ (* group_parent_class->map) (item);
+}
+
+/* Unmap handler for canvas groups */
+static void
+gnome_canvas_group_unmap (GnomeCanvasItem *item)
+{
+ GnomeCanvasGroup *group;
+ GList *list;
+ GnomeCanvasItem *i;
+
+ group = GNOME_CANVAS_GROUP (item);
+
+ for (list = group->item_list; list; list = list->next) {
+ i = list->data;
+
+ if (i->object.flags & GNOME_CANVAS_ITEM_MAPPED)
+ (* GNOME_CANVAS_ITEM_GET_CLASS (i)->unmap) (i);
+ }
+
+ (* group_parent_class->unmap) (item);
+}
+
+/* Draw handler for canvas groups */
+static void
+gnome_canvas_group_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
+ int x, int y, int width, int height)
+{
+ GnomeCanvasGroup *group;
+ GList *list;
+ GnomeCanvasItem *child = NULL;
+
+ group = GNOME_CANVAS_GROUP (item);
+
+ for (list = group->item_list; list; list = list->next) {
+ child = list->data;
+
+ if (((child->object.flags & GNOME_CANVAS_ITEM_VISIBLE)
+ && ((child->x1 < (x + width))
+ && (child->y1 < (y + height))
+ && (child->x2 > x)
+ && (child->y2 > y)))
+ || ((GTK_OBJECT_FLAGS (child) & GNOME_CANVAS_ITEM_ALWAYS_REDRAW)
+ && (child->x1 < child->canvas->redraw_x2)
+ && (child->y1 < child->canvas->redraw_y2)
+ && (child->x2 > child->canvas->redraw_x1)
+ && (child->y2 > child->canvas->redraw_y2)))
+ if (GNOME_CANVAS_ITEM_GET_CLASS (child)->draw)
+ (* GNOME_CANVAS_ITEM_GET_CLASS (child)->draw) (
+ child, drawable, x, y, width, height);
+ }
+}
+
+/* Point handler for canvas groups */
+static double
+gnome_canvas_group_point (GnomeCanvasItem *item, double x, double y, int cx, int cy,
+ GnomeCanvasItem **actual_item)
+{
+ GnomeCanvasGroup *group;
+ GList *list;
+ GnomeCanvasItem *child, *point_item;
+ int x1, y1, x2, y2;
+ double gx, gy;
+ double dist, best;
+ int has_point;
+
+ group = GNOME_CANVAS_GROUP (item);
+
+ x1 = cx - item->canvas->close_enough;
+ y1 = cy - item->canvas->close_enough;
+ x2 = cx + item->canvas->close_enough;
+ y2 = cy + item->canvas->close_enough;
+
+ best = 0.0;
+ *actual_item = NULL;
+
+ gx = x;
+ gy = y;
+
+ dist = 0.0; /* keep gcc happy */
+
+ for (list = group->item_list; list; list = list->next) {
+ child = list->data;
+
+ if ((child->x1 > x2) || (child->y1 > y2) || (child->x2 < x1) || (child->y2 < y1))
+ continue;
+
+ point_item = NULL; /* cater for incomplete item implementations */
+
+ if ((child->object.flags & GNOME_CANVAS_ITEM_VISIBLE)
+ && GNOME_CANVAS_ITEM_GET_CLASS (child)->point) {
+ dist = gnome_canvas_item_invoke_point (child, gx, gy, cx, cy, &point_item);
+ has_point = TRUE;
+ } else
+ has_point = FALSE;
+
+ if (has_point
+ && point_item
+ && ((int) (dist * item->canvas->pixels_per_unit + 0.5)
+ <= item->canvas->close_enough)) {
+ best = dist;
+ *actual_item = point_item;
+ }
+ }
+
+ return best;
+}
+
+/* Bounds handler for canvas groups */
+static void
+gnome_canvas_group_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
+{
+ GnomeCanvasGroup *group;
+ GnomeCanvasItem *child;
+ GList *list;
+ double tx1, ty1, tx2, ty2;
+ double minx, miny, maxx, maxy;
+ int set;
+
+ group = GNOME_CANVAS_GROUP (item);
+
+ /* Get the bounds of the first visible item */
+
+ child = NULL; /* Unnecessary but eliminates a warning. */
+
+ set = FALSE;
+
+ for (list = group->item_list; list; list = list->next) {
+ child = list->data;
+
+ if (child->object.flags & GNOME_CANVAS_ITEM_VISIBLE) {
+ set = TRUE;
+ gnome_canvas_item_get_bounds (child, &minx, &miny, &maxx, &maxy);
+ break;
+ }
+ }
+
+ /* If there were no visible items, return an empty bounding box */
+
+ if (!set) {
+ *x1 = *y1 = *x2 = *y2 = 0.0;
+ return;
+ }
+
+ /* Now we can grow the bounds using the rest of the items */
+
+ list = list->next;
+
+ for (; list; list = list->next) {
+ child = list->data;
+
+ if (!(child->object.flags & GNOME_CANVAS_ITEM_VISIBLE))
+ continue;
+
+ gnome_canvas_item_get_bounds (child, &tx1, &ty1, &tx2, &ty2);
+
+ if (tx1 < minx)
+ minx = tx1;
+
+ if (ty1 < miny)
+ miny = ty1;
+
+ if (tx2 > maxx)
+ maxx = tx2;
+
+ if (ty2 > maxy)
+ maxy = ty2;
+ }
+
+ *x1 = minx;
+ *y1 = miny;
+ *x2 = maxx;
+ *y2 = maxy;
+}
+
+/* Render handler for canvas groups */
+static void
+gnome_canvas_group_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf)
+{
+ GnomeCanvasGroup *group;
+ GnomeCanvasItem *child;
+ GList *list;
+
+ group = GNOME_CANVAS_GROUP (item);
+
+ for (list = group->item_list; list; list = list->next) {
+ child = list->data;
+
+ if (((child->object.flags & GNOME_CANVAS_ITEM_VISIBLE)
+ && ((child->x1 < buf->rect.x1)
+ && (child->y1 < buf->rect.y1)
+ && (child->x2 > buf->rect.x0)
+ && (child->y2 > buf->rect.y0)))
+ || ((GTK_OBJECT_FLAGS (child) & GNOME_CANVAS_ITEM_ALWAYS_REDRAW)
+ && (child->x1 < child->canvas->redraw_x2)
+ && (child->y1 < child->canvas->redraw_y2)
+ && (child->x2 > child->canvas->redraw_x1)
+ && (child->y2 > child->canvas->redraw_y2)))
+ if (GNOME_CANVAS_ITEM_GET_CLASS (child)->render)
+ (* GNOME_CANVAS_ITEM_GET_CLASS (child)->render) (
+ child, buf);
+ }
+}
+
+/* Adds an item to a group */
+static void
+group_add (GnomeCanvasGroup *group, GnomeCanvasItem *item)
+{
+ g_object_ref (G_OBJECT (item));
+ gtk_object_sink (GTK_OBJECT (item));
+
+ if (!group->item_list) {
+ group->item_list = g_list_append (group->item_list, item);
+ group->item_list_end = group->item_list;
+ } else
+ group->item_list_end = g_list_append (group->item_list_end, item)->next;
+
+ if (group->item.object.flags & GNOME_CANVAS_ITEM_REALIZED)
+ (* GNOME_CANVAS_ITEM_GET_CLASS (item)->realize) (item);
+
+ if (group->item.object.flags & GNOME_CANVAS_ITEM_MAPPED)
+ (* GNOME_CANVAS_ITEM_GET_CLASS (item)->map) (item);
+
+ g_object_notify (G_OBJECT (item), "parent");
+}
+
+/* Removes an item from a group */
+static void
+group_remove (GnomeCanvasGroup *group, GnomeCanvasItem *item)
+{
+ GList *children;
+
+ g_return_if_fail (GNOME_IS_CANVAS_GROUP (group));
+ g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
+
+ for (children = group->item_list; children; children = children->next)
+ if (children->data == item) {
+ if (item->object.flags & GNOME_CANVAS_ITEM_MAPPED)
+ (* GNOME_CANVAS_ITEM_GET_CLASS (item)->unmap) (item);
+
+ if (item->object.flags & GNOME_CANVAS_ITEM_REALIZED)
+ (* GNOME_CANVAS_ITEM_GET_CLASS (item)->unrealize) (item);
+
+ /* Unparent the child */
+
+ item->parent = NULL;
+ g_object_unref (G_OBJECT (item));
+
+ /* Remove it from the list */
+
+ if (children == group->item_list_end)
+ group->item_list_end = children->prev;
+
+ group->item_list = g_list_remove_link (group->item_list, children);
+ g_list_free (children);
+ break;
+ }
+}
+
+
+/*** GnomeCanvas ***/
+
+
+enum {
+ DRAW_BACKGROUND,
+ RENDER_BACKGROUND,
+ LAST_SIGNAL
+};
+
+static void gnome_canvas_class_init (GnomeCanvasClass *class);
+static void gnome_canvas_init (GnomeCanvas *canvas);
+static void gnome_canvas_destroy (GtkObject *object);
+static void gnome_canvas_map (GtkWidget *widget);
+static void gnome_canvas_unmap (GtkWidget *widget);
+static void gnome_canvas_realize (GtkWidget *widget);
+static void gnome_canvas_unrealize (GtkWidget *widget);
+static void gnome_canvas_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation);
+static gint gnome_canvas_button (GtkWidget *widget,
+ GdkEventButton *event);
+static gint gnome_canvas_motion (GtkWidget *widget,
+ GdkEventMotion *event);
+static gint gnome_canvas_expose (GtkWidget *widget,
+ GdkEventExpose *event);
+static gboolean gnome_canvas_key (GtkWidget *widget,
+ GdkEventKey *event);
+static gint gnome_canvas_crossing (GtkWidget *widget,
+ GdkEventCrossing *event);
+static gint gnome_canvas_focus_in (GtkWidget *widget,
+ GdkEventFocus *event);
+static gint gnome_canvas_focus_out (GtkWidget *widget,
+ GdkEventFocus *event);
+static void gnome_canvas_request_update_real (GnomeCanvas *canvas);
+static void gnome_canvas_draw_background (GnomeCanvas *canvas,
+ GdkDrawable *drawable,
+ int x,
+ int y,
+ int width,
+ int height);
+
+
+static GtkLayoutClass *canvas_parent_class;
+
+static guint canvas_signals[LAST_SIGNAL];
+
+enum {
+ PROP_AA = 1
+};
+
+/**
+ * gnome_canvas_get_type:
+ *
+ * Registers the &GnomeCanvas class if necessary, and returns the type ID
+ * associated to it.
+ *
+ * Return value: The type ID of the &GnomeCanvas class.
+ **/
+GType
+gnome_canvas_get_type (void)
+{
+ static GType canvas_type;
+
+ if (!canvas_type) {
+ static const GTypeInfo object_info = {
+ sizeof (GnomeCanvasClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gnome_canvas_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (GnomeCanvas),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) gnome_canvas_init,
+ NULL /* value_table */
+ };
+
+ canvas_type = g_type_register_static (GTK_TYPE_LAYOUT, "GnomeCanvas",
+ &object_info, 0);
+ }
+
+ return canvas_type;
+}
+
+static void
+gnome_canvas_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (prop_id) {
+ case PROP_AA:
+ g_value_set_boolean (value, GNOME_CANVAS (object)->aa);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gnome_canvas_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (prop_id) {
+ case PROP_AA:
+ GNOME_CANVAS (object)->aa = g_value_get_boolean (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+/* Class initialization function for GnomeCanvasClass */
+static void
+gnome_canvas_class_init (GnomeCanvasClass *klass)
+{
+ GObjectClass *gobject_class;
+ GtkObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+
+ gobject_class = (GObjectClass *)klass;
+ object_class = (GtkObjectClass *) klass;
+ widget_class = (GtkWidgetClass *) klass;
+
+ canvas_parent_class = g_type_class_peek_parent (klass);
+
+ gobject_class->set_property = gnome_canvas_set_property;
+ gobject_class->get_property = gnome_canvas_get_property;
+
+ object_class->destroy = gnome_canvas_destroy;
+
+ widget_class->map = gnome_canvas_map;
+ widget_class->unmap = gnome_canvas_unmap;
+ widget_class->realize = gnome_canvas_realize;
+ widget_class->unrealize = gnome_canvas_unrealize;
+ widget_class->size_allocate = gnome_canvas_size_allocate;
+ widget_class->button_press_event = gnome_canvas_button;
+ widget_class->button_release_event = gnome_canvas_button;
+ widget_class->motion_notify_event = gnome_canvas_motion;
+ widget_class->expose_event = gnome_canvas_expose;
+ widget_class->key_press_event = gnome_canvas_key;
+ widget_class->key_release_event = gnome_canvas_key;
+ widget_class->enter_notify_event = gnome_canvas_crossing;
+ widget_class->leave_notify_event = gnome_canvas_crossing;
+ widget_class->focus_in_event = gnome_canvas_focus_in;
+ widget_class->focus_out_event = gnome_canvas_focus_out;
+
+ klass->draw_background = gnome_canvas_draw_background;
+ klass->render_background = NULL;
+ klass->request_update = gnome_canvas_request_update_real;
+
+ g_object_class_install_property (G_OBJECT_CLASS (object_class),
+ PROP_AA,
+ g_param_spec_boolean ("aa",
+ _("Antialiased"),
+ _("The antialiasing mode of the canvas."),
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ canvas_signals[DRAW_BACKGROUND] =
+ g_signal_new ("draw_background",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GnomeCanvasClass, draw_background),
+ NULL, NULL,
+ gnome_canvas_marshal_VOID__OBJECT_INT_INT_INT_INT,
+ G_TYPE_NONE, 5, GDK_TYPE_DRAWABLE,
+ G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT);
+ canvas_signals[RENDER_BACKGROUND] =
+ g_signal_new ("render_background",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GnomeCanvasClass, render_background),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE, 1, G_TYPE_POINTER);
+}
+
+/* Callback used when the root item of a canvas is destroyed. The user should
+ * never ever do this, so we panic if this happens.
+ */
+static void
+panic_root_destroyed (GtkObject *object, gpointer data)
+{
+ g_error ("Eeeek, root item %p of canvas %p was destroyed!", object, data);
+}
+
+/* Object initialization function for GnomeCanvas */
+static void
+gnome_canvas_init (GnomeCanvas *canvas)
+{
+ GTK_WIDGET_SET_FLAGS (canvas, GTK_CAN_FOCUS);
+
+ canvas->need_update = FALSE;
+ canvas->need_redraw = FALSE;
+ canvas->redraw_area = NULL;
+ canvas->idle_id = 0;
+
+ canvas->scroll_x1 = 0.0;
+ canvas->scroll_y1 = 0.0;
+ canvas->scroll_x2 = canvas->layout.width;
+ canvas->scroll_y2 = canvas->layout.height;
+
+ canvas->pixels_per_unit = 1.0;
+
+ canvas->pick_event.type = GDK_LEAVE_NOTIFY;
+ canvas->pick_event.crossing.x = 0;
+ canvas->pick_event.crossing.y = 0;
+
+ canvas->dither = GDK_RGB_DITHER_MAX;
+
+ /* This may not be what people want, but it is set to be turned on by
+ * default to have the same initial behavior as the canvas in GNOME 1.4.
+ */
+ canvas->center_scroll_region = TRUE;
+
+ gtk_layout_set_hadjustment (GTK_LAYOUT (canvas), NULL);
+ gtk_layout_set_vadjustment (GTK_LAYOUT (canvas), NULL);
+
+ /* Disable the gtk+ double buffering since the canvas uses it's own. */
+ gtk_widget_set_double_buffered (GTK_WIDGET (canvas), FALSE);
+
+ /* Create the root item as a special case */
+
+ canvas->root = GNOME_CANVAS_ITEM (g_object_new (gnome_canvas_group_get_type (), NULL));
+ canvas->root->canvas = canvas;
+
+ g_object_ref (canvas->root);
+ gtk_object_sink (GTK_OBJECT (canvas->root));
+
+ canvas->root_destroy_id = g_signal_connect (canvas->root, "destroy",
+ G_CALLBACK (panic_root_destroyed),
+ canvas);
+
+ canvas->need_repick = TRUE;
+}
+
+/* Convenience function to remove the idle handler of a canvas */
+static void
+remove_idle (GnomeCanvas *canvas)
+{
+ if (canvas->idle_id == 0)
+ return;
+
+ gtk_idle_remove (canvas->idle_id);
+ canvas->idle_id = 0;
+}
+
+/* Removes the transient state of the canvas (idle handler, grabs). */
+static void
+shutdown_transients (GnomeCanvas *canvas)
+{
+ /* We turn off the need_redraw flag, since if the canvas is mapped again
+ * it will request a redraw anyways. We do not turn off the need_update
+ * flag, though, because updates are not queued when the canvas remaps
+ * itself.
+ */
+ if (canvas->need_redraw) {
+ canvas->need_redraw = FALSE;
+ art_uta_free (canvas->redraw_area);
+ canvas->redraw_area = NULL;
+ canvas->redraw_x1 = 0;
+ canvas->redraw_y1 = 0;
+ canvas->redraw_x2 = 0;
+ canvas->redraw_y2 = 0;
+ }
+
+ if (canvas->grabbed_item) {
+ canvas->grabbed_item = NULL;
+ gdk_pointer_ungrab (GDK_CURRENT_TIME);
+ }
+
+ remove_idle (canvas);
+}
+
+/* Destroy handler for GnomeCanvas */
+static void
+gnome_canvas_destroy (GtkObject *object)
+{
+ GnomeCanvas *canvas;
+
+ g_return_if_fail (GNOME_IS_CANVAS (object));
+
+ /* remember, destroy can be run multiple times! */
+
+ canvas = GNOME_CANVAS (object);
+
+ if (canvas->root_destroy_id) {
+ g_signal_handler_disconnect (canvas->root, canvas->root_destroy_id);
+ canvas->root_destroy_id = 0;
+ }
+ if (canvas->root) {
+ gtk_object_destroy (GTK_OBJECT (canvas->root));
+ g_object_unref (G_OBJECT (canvas->root));
+ canvas->root = NULL;
+ }
+
+ shutdown_transients (canvas);
+
+ if (GTK_OBJECT_CLASS (canvas_parent_class)->destroy)
+ (* GTK_OBJECT_CLASS (canvas_parent_class)->destroy) (object);
+}
+
+/**
+ * gnome_canvas_new:
+ *
+ * Creates a new empty canvas in non-antialiased mode.
+ *
+ * Return value: A newly-created canvas.
+ **/
+GtkWidget *
+gnome_canvas_new (void)
+{
+ return GTK_WIDGET (g_object_new (gnome_canvas_get_type (), NULL));
+}
+
+/**
+ * gnome_canvas_new_aa:
+ *
+ * Creates a new empty canvas in antialiased mode.
+ *
+ * Return value: A newly-created antialiased canvas.
+ **/
+GtkWidget *
+gnome_canvas_new_aa (void)
+{
+ return GTK_WIDGET (g_object_new (GNOME_TYPE_CANVAS,
+ "aa", TRUE,
+ NULL));
+}
+
+/* Map handler for the canvas */
+static void
+gnome_canvas_map (GtkWidget *widget)
+{
+ GnomeCanvas *canvas;
+
+ g_return_if_fail (GNOME_IS_CANVAS (widget));
+
+ /* Normal widget mapping stuff */
+
+ if (GTK_WIDGET_CLASS (canvas_parent_class)->map)
+ (* GTK_WIDGET_CLASS (canvas_parent_class)->map) (widget);
+
+ canvas = GNOME_CANVAS (widget);
+
+ if (canvas->need_update)
+ add_idle (canvas);
+
+ /* Map items */
+
+ if (GNOME_CANVAS_ITEM_GET_CLASS (canvas->root)->map)
+ (* GNOME_CANVAS_ITEM_GET_CLASS (canvas->root)->map) (canvas->root);
+}
+
+/* Unmap handler for the canvas */
+static void
+gnome_canvas_unmap (GtkWidget *widget)
+{
+ GnomeCanvas *canvas;
+
+ g_return_if_fail (GNOME_IS_CANVAS (widget));
+
+ canvas = GNOME_CANVAS (widget);
+
+ shutdown_transients (canvas);
+
+ /* Unmap items */
+
+ if (GNOME_CANVAS_ITEM_GET_CLASS (canvas->root)->unmap)
+ (* GNOME_CANVAS_ITEM_GET_CLASS (canvas->root)->unmap) (canvas->root);
+
+ /* Normal widget unmapping stuff */
+
+ if (GTK_WIDGET_CLASS (canvas_parent_class)->unmap)
+ (* GTK_WIDGET_CLASS (canvas_parent_class)->unmap) (widget);
+}
+
+/* Realize handler for the canvas */
+static void
+gnome_canvas_realize (GtkWidget *widget)
+{
+ GnomeCanvas *canvas;
+
+ g_return_if_fail (GNOME_IS_CANVAS (widget));
+
+ /* Normal widget realization stuff */
+
+ if (GTK_WIDGET_CLASS (canvas_parent_class)->realize)
+ (* GTK_WIDGET_CLASS (canvas_parent_class)->realize) (widget);
+
+ canvas = GNOME_CANVAS (widget);
+
+ gdk_window_set_events (canvas->layout.bin_window,
+ (gdk_window_get_events (canvas->layout.bin_window)
+ | GDK_EXPOSURE_MASK
+ | GDK_BUTTON_PRESS_MASK
+ | GDK_BUTTON_RELEASE_MASK
+ | GDK_POINTER_MOTION_MASK
+ | GDK_KEY_PRESS_MASK
+ | GDK_KEY_RELEASE_MASK
+ | GDK_ENTER_NOTIFY_MASK
+ | GDK_LEAVE_NOTIFY_MASK
+ | GDK_FOCUS_CHANGE_MASK));
+
+ /* Create our own temporary pixmap gc and realize all the items */
+
+ canvas->pixmap_gc = gdk_gc_new (canvas->layout.bin_window);
+
+ (* GNOME_CANVAS_ITEM_GET_CLASS (canvas->root)->realize) (canvas->root);
+}
+
+/* Unrealize handler for the canvas */
+static void
+gnome_canvas_unrealize (GtkWidget *widget)
+{
+ GnomeCanvas *canvas;
+
+ g_return_if_fail (GNOME_IS_CANVAS (widget));
+
+ canvas = GNOME_CANVAS (widget);
+
+ shutdown_transients (canvas);
+
+ /* Unrealize items and parent widget */
+
+ (* GNOME_CANVAS_ITEM_GET_CLASS (canvas->root)->unrealize) (canvas->root);
+
+ gdk_gc_destroy (canvas->pixmap_gc);
+ canvas->pixmap_gc = NULL;
+
+ if (GTK_WIDGET_CLASS (canvas_parent_class)->unrealize)
+ (* GTK_WIDGET_CLASS (canvas_parent_class)->unrealize) (widget);
+}
+
+/* Handles scrolling of the canvas. Adjusts the scrolling and zooming offset to
+ * keep as much as possible of the canvas scrolling region in view.
+ */
+static void
+scroll_to (GnomeCanvas *canvas, int cx, int cy)
+{
+ int scroll_width, scroll_height;
+ int right_limit, bottom_limit;
+ int old_zoom_xofs, old_zoom_yofs;
+ int changed_x = FALSE, changed_y = FALSE;
+ int canvas_width, canvas_height;
+
+ canvas_width = GTK_WIDGET (canvas)->allocation.width;
+ canvas_height = GTK_WIDGET (canvas)->allocation.height;
+
+ scroll_width = floor ((canvas->scroll_x2 - canvas->scroll_x1) * canvas->pixels_per_unit
+ + 0.5);
+ scroll_height = floor ((canvas->scroll_y2 - canvas->scroll_y1) * canvas->pixels_per_unit
+ + 0.5);
+
+ right_limit = scroll_width - canvas_width;
+ bottom_limit = scroll_height - canvas_height;
+
+ old_zoom_xofs = canvas->zoom_xofs;
+ old_zoom_yofs = canvas->zoom_yofs;
+
+ if (right_limit < 0) {
+ cx = 0;
+
+ if (canvas->center_scroll_region) {
+ canvas->zoom_xofs = (canvas_width - scroll_width) / 2;
+ scroll_width = canvas_width;
+ } else
+ canvas->zoom_xofs = 0;
+ } else if (cx < 0) {
+ cx = 0;
+ canvas->zoom_xofs = 0;
+ } else if (cx > right_limit) {
+ cx = right_limit;
+ canvas->zoom_xofs = 0;
+ } else
+ canvas->zoom_xofs = 0;
+
+ if (bottom_limit < 0) {
+ cy = 0;
+
+ if (canvas->center_scroll_region) {
+ canvas->zoom_yofs = (canvas_height - scroll_height) / 2;
+ scroll_height = canvas_height;
+ } else
+ canvas->zoom_yofs = 0;
+ } else if (cy < 0) {
+ cy = 0;
+ canvas->zoom_yofs = 0;
+ } else if (cy > bottom_limit) {
+ cy = bottom_limit;
+ canvas->zoom_yofs = 0;
+ } else
+ canvas->zoom_yofs = 0;
+
+ if ((canvas->zoom_xofs != old_zoom_xofs) || (canvas->zoom_yofs != old_zoom_yofs)) {
+ /* This can only occur, if either canvas size or widget size changes */
+ /* So I think we can request full redraw here */
+ /* The reason is, that coverage UTA will be invalidated by offset change */
+ /* fixme: Strictly this is not correct - we have to remove our own idle (Lauris) */
+ /* More stuff - we have to mark root as needing fresh affine (Lauris) */
+ if (!(canvas->root->object.flags & GNOME_CANVAS_ITEM_NEED_AFFINE)) {
+ canvas->root->object.flags |= GNOME_CANVAS_ITEM_NEED_AFFINE;
+ gnome_canvas_request_update (canvas);
+ }
+ gtk_widget_queue_draw (GTK_WIDGET (canvas));
+ }
+
+ if (canvas->layout.hadjustment && ((int) canvas->layout.hadjustment->value) != cx) {
+ canvas->layout.hadjustment->value = cx;
+ changed_x = TRUE;
+ }
+
+ if (canvas->layout.vadjustment && ((int) canvas->layout.vadjustment->value) != cy) {
+ canvas->layout.vadjustment->value = cy;
+ changed_y = TRUE;
+ }
+
+ if ((scroll_width != (int) canvas->layout.width)
+ || (scroll_height != (int) canvas->layout.height))
+ gtk_layout_set_size (GTK_LAYOUT (canvas), scroll_width, scroll_height);
+
+ /* Signal GtkLayout that it should do a redraw. */
+
+ if (changed_x)
+ g_signal_emit_by_name (canvas->layout.hadjustment, "value_changed");
+
+ if (changed_y)
+ g_signal_emit_by_name (canvas->layout.vadjustment, "value_changed");
+}
+
+/* Size allocation handler for the canvas */
+static void
+gnome_canvas_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
+{
+ GnomeCanvas *canvas;
+
+ g_return_if_fail (GNOME_IS_CANVAS (widget));
+ g_return_if_fail (allocation != NULL);
+
+ if (GTK_WIDGET_CLASS (canvas_parent_class)->size_allocate)
+ (* GTK_WIDGET_CLASS (canvas_parent_class)->size_allocate) (widget, allocation);
+
+ canvas = GNOME_CANVAS (widget);
+
+ /* Recenter the view, if appropriate */
+
+ canvas->layout.hadjustment->page_size = allocation->width;
+ canvas->layout.hadjustment->page_increment = allocation->width / 2;
+
+ canvas->layout.vadjustment->page_size = allocation->height;
+ canvas->layout.vadjustment->page_increment = allocation->height / 2;
+
+ scroll_to (canvas,
+ canvas->layout.hadjustment->value,
+ canvas->layout.vadjustment->value);
+
+ g_signal_emit_by_name (canvas->layout.hadjustment, "changed");
+ g_signal_emit_by_name (canvas->layout.vadjustment, "changed");
+}
+
+/* Emits an event for an item in the canvas, be it the current item, grabbed
+ * item, or focused item, as appropriate.
+ */
+
+static int
+emit_event (GnomeCanvas *canvas, GdkEvent *event)
+{
+ GdkEvent *ev;
+ gint finished;
+ GnomeCanvasItem *item;
+ GnomeCanvasItem *parent;
+ guint mask;
+
+ /* Perform checks for grabbed items */
+
+ if (canvas->grabbed_item &&
+ !is_descendant (canvas->current_item, canvas->grabbed_item)) {
+ /* I think this warning is annoying and I don't know what it's for
+ * so I'll disable it for now.
+ */
+/* g_warning ("emit_event() returning FALSE!\n");*/
+ return FALSE;
+ }
+
+ if (canvas->grabbed_item) {
+ switch (event->type) {
+ case GDK_ENTER_NOTIFY:
+ mask = GDK_ENTER_NOTIFY_MASK;
+ break;
+
+ case GDK_LEAVE_NOTIFY:
+ mask = GDK_LEAVE_NOTIFY_MASK;
+ break;
+
+ case GDK_MOTION_NOTIFY:
+ mask = GDK_POINTER_MOTION_MASK;
+ break;
+
+ case GDK_BUTTON_PRESS:
+ case GDK_2BUTTON_PRESS:
+ case GDK_3BUTTON_PRESS:
+ mask = GDK_BUTTON_PRESS_MASK;
+ break;
+
+ case GDK_BUTTON_RELEASE:
+ mask = GDK_BUTTON_RELEASE_MASK;
+ break;
+
+ case GDK_KEY_PRESS:
+ mask = GDK_KEY_PRESS_MASK;
+ break;
+
+ case GDK_KEY_RELEASE:
+ mask = GDK_KEY_RELEASE_MASK;
+ break;
+
+ default:
+ mask = 0;
+ break;
+ }
+
+ if (!(mask & canvas->grabbed_event_mask))
+ return FALSE;
+ }
+
+ /* Convert to world coordinates -- we have two cases because of diferent
+ * offsets of the fields in the event structures.
+ */
+
+ ev = gdk_event_copy (event);
+
+ switch (ev->type)
+ {
+ case GDK_ENTER_NOTIFY:
+ case GDK_LEAVE_NOTIFY:
+ gnome_canvas_window_to_world (canvas,
+ ev->crossing.x, ev->crossing.y,
+ &ev->crossing.x, &ev->crossing.y);
+ break;
+
+ case GDK_MOTION_NOTIFY:
+ case GDK_BUTTON_PRESS:
+ case GDK_2BUTTON_PRESS:
+ case GDK_3BUTTON_PRESS:
+ case GDK_BUTTON_RELEASE:
+ gnome_canvas_window_to_world (canvas,
+ ev->motion.x, ev->motion.y,
+ &ev->motion.x, &ev->motion.y);
+ break;
+
+ default:
+ break;
+ }
+
+ /* Choose where we send the event */
+
+ item = canvas->current_item;
+
+ if (canvas->focused_item
+ && ((event->type == GDK_KEY_PRESS) ||
+ (event->type == GDK_KEY_RELEASE) ||
+ (event->type == GDK_FOCUS_CHANGE)))
+ item = canvas->focused_item;
+
+ /* The event is propagated up the hierarchy (for if someone connected to
+ * a group instead of a leaf event), and emission is stopped if a
+ * handler returns TRUE, just like for GtkWidget events.
+ */
+
+ finished = FALSE;
+
+ while (item && !finished) {
+ g_object_ref (G_OBJECT (item));
+
+ g_signal_emit (item, item_signals[ITEM_EVENT], 0,
+ ev, &finished);
+
+ parent = item->parent;
+ g_object_unref (G_OBJECT (item));
+
+ item = parent;
+ }
+
+ gdk_event_free (ev);
+
+ return finished;
+}
+
+/* Re-picks the current item in the canvas, based on the event's coordinates.
+ * Also emits enter/leave events for items as appropriate.
+ */
+static int
+pick_current_item (GnomeCanvas *canvas, GdkEvent *event)
+{
+ int button_down;
+ double x, y;
+ int cx, cy;
+ int retval;
+
+ retval = FALSE;
+
+ /* If a button is down, we'll perform enter and leave events on the
+ * current item, but not enter on any other item. This is more or less
+ * like X pointer grabbing for canvas items.
+ */
+ button_down = canvas->state & (GDK_BUTTON1_MASK
+ | GDK_BUTTON2_MASK
+ | GDK_BUTTON3_MASK
+ | GDK_BUTTON4_MASK
+ | GDK_BUTTON5_MASK);
+ if (!button_down)
+ canvas->left_grabbed_item = FALSE;
+
+ /* Save the event in the canvas. This is used to synthesize enter and
+ * leave events in case the current item changes. It is also used to
+ * re-pick the current item if the current one gets deleted. Also,
+ * synthesize an enter event.
+ */
+ if (event != &canvas->pick_event) {
+ if ((event->type == GDK_MOTION_NOTIFY) || (event->type == GDK_BUTTON_RELEASE)) {
+ /* these fields have the same offsets in both types of events */
+
+ canvas->pick_event.crossing.type = GDK_ENTER_NOTIFY;
+ canvas->pick_event.crossing.window = event->motion.window;
+ canvas->pick_event.crossing.send_event = event->motion.send_event;
+ canvas->pick_event.crossing.subwindow = NULL;
+ canvas->pick_event.crossing.x = event->motion.x;
+ canvas->pick_event.crossing.y = event->motion.y;
+ canvas->pick_event.crossing.mode = GDK_CROSSING_NORMAL;
+ canvas->pick_event.crossing.detail = GDK_NOTIFY_NONLINEAR;
+ canvas->pick_event.crossing.focus = FALSE;
+ canvas->pick_event.crossing.state = event->motion.state;
+
+ /* these fields don't have the same offsets in both types of events */
+
+ if (event->type == GDK_MOTION_NOTIFY) {
+ canvas->pick_event.crossing.x_root = event->motion.x_root;
+ canvas->pick_event.crossing.y_root = event->motion.y_root;
+ } else {
+ canvas->pick_event.crossing.x_root = event->button.x_root;
+ canvas->pick_event.crossing.y_root = event->button.y_root;
+ }
+ } else
+ canvas->pick_event = *event;
+ }
+
+ /* Don't do anything else if this is a recursive call */
+
+ if (canvas->in_repick)
+ return retval;
+
+ /* LeaveNotify means that there is no current item, so we don't look for one */
+
+ if (canvas->pick_event.type != GDK_LEAVE_NOTIFY) {
+ /* these fields don't have the same offsets in both types of events */
+
+ if (canvas->pick_event.type == GDK_ENTER_NOTIFY) {
+ x = canvas->pick_event.crossing.x - canvas->zoom_xofs;
+ y = canvas->pick_event.crossing.y - canvas->zoom_yofs;
+ } else {
+ x = canvas->pick_event.motion.x - canvas->zoom_xofs;
+ y = canvas->pick_event.motion.y - canvas->zoom_yofs;
+ }
+
+ /* canvas pixel coords */
+
+ cx = (int) (x + 0.5);
+ cy = (int) (y + 0.5);
+
+ /* world coords */
+
+ x = canvas->scroll_x1 + x / canvas->pixels_per_unit;
+ y = canvas->scroll_y1 + y / canvas->pixels_per_unit;
+
+ /* find the closest item */
+
+ if (canvas->root->object.flags & GNOME_CANVAS_ITEM_VISIBLE)
+ gnome_canvas_item_invoke_point (canvas->root, x, y, cx, cy,
+ &canvas->new_current_item);
+ else
+ canvas->new_current_item = NULL;
+ } else
+ canvas->new_current_item = NULL;
+
+ if ((canvas->new_current_item == canvas->current_item) && !canvas->left_grabbed_item)
+ return retval; /* current item did not change */
+
+ /* Synthesize events for old and new current items */
+
+ if ((canvas->new_current_item != canvas->current_item)
+ && (canvas->current_item != NULL)
+ && !canvas->left_grabbed_item) {
+ GdkEvent new_event;
+
+ new_event = canvas->pick_event;
+ new_event.type = GDK_LEAVE_NOTIFY;
+
+ new_event.crossing.detail = GDK_NOTIFY_ANCESTOR;
+ new_event.crossing.subwindow = NULL;
+ canvas->in_repick = TRUE;
+ retval = emit_event (canvas, &new_event);
+ canvas->in_repick = FALSE;
+ }
+
+ /* new_current_item may have been set to NULL during the call to emit_event() above */
+
+ if ((canvas->new_current_item != canvas->current_item) && button_down) {
+ canvas->left_grabbed_item = TRUE;
+ return retval;
+ }
+
+ /* Handle the rest of cases */
+
+ canvas->left_grabbed_item = FALSE;
+ canvas->current_item = canvas->new_current_item;
+
+ if (canvas->current_item != NULL) {
+ GdkEvent new_event;
+
+ new_event = canvas->pick_event;
+ new_event.type = GDK_ENTER_NOTIFY;
+ new_event.crossing.detail = GDK_NOTIFY_ANCESTOR;
+ new_event.crossing.subwindow = NULL;
+ retval = emit_event (canvas, &new_event);
+ }
+
+ return retval;
+}
+
+/* Button event handler for the canvas */
+static gint
+gnome_canvas_button (GtkWidget *widget, GdkEventButton *event)
+{
+ GnomeCanvas *canvas;
+ int mask;
+ int retval;
+
+ g_return_val_if_fail (GNOME_IS_CANVAS (widget), FALSE);
+ g_return_val_if_fail (event != NULL, FALSE);
+
+ retval = FALSE;
+
+ canvas = GNOME_CANVAS (widget);
+
+ /*
+ * dispatch normally regardless of the event's window if an item has
+ * has a pointer grab in effect
+ */
+ if (!canvas->grabbed_item && event->window != canvas->layout.bin_window)
+ return retval;
+
+ switch (event->button) {
+ case 1:
+ mask = GDK_BUTTON1_MASK;
+ break;
+ case 2:
+ mask = GDK_BUTTON2_MASK;
+ break;
+ case 3:
+ mask = GDK_BUTTON3_MASK;
+ break;
+ case 4:
+ mask = GDK_BUTTON4_MASK;
+ break;
+ case 5:
+ mask = GDK_BUTTON5_MASK;
+ break;
+ default:
+ mask = 0;
+ }
+
+ switch (event->type) {
+ case GDK_BUTTON_PRESS:
+ case GDK_2BUTTON_PRESS:
+ case GDK_3BUTTON_PRESS:
+ /* Pick the current item as if the button were not pressed, and
+ * then process the event.
+ */
+ canvas->state = event->state;
+ pick_current_item (canvas, (GdkEvent *) event);
+ canvas->state ^= mask;
+ retval = emit_event (canvas, (GdkEvent *) event);
+ break;
+
+ case GDK_BUTTON_RELEASE:
+ /* Process the event as if the button were pressed, then repick
+ * after the button has been released
+ */
+ canvas->state = event->state;
+ retval = emit_event (canvas, (GdkEvent *) event);
+ event->state ^= mask;
+ canvas->state = event->state;
+ pick_current_item (canvas, (GdkEvent *) event);
+ event->state ^= mask;
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+
+ return retval;
+}
+
+/* Motion event handler for the canvas */
+static gint
+gnome_canvas_motion (GtkWidget *widget, GdkEventMotion *event)
+{
+ GnomeCanvas *canvas;
+
+ g_return_val_if_fail (GNOME_IS_CANVAS (widget), FALSE);
+ g_return_val_if_fail (event != NULL, FALSE);
+
+ canvas = GNOME_CANVAS (widget);
+
+ if (event->window != canvas->layout.bin_window)
+ return FALSE;
+
+ canvas->state = event->state;
+ pick_current_item (canvas, (GdkEvent *) event);
+ return emit_event (canvas, (GdkEvent *) event);
+}
+
+/* Key event handler for the canvas */
+static gboolean
+gnome_canvas_key (GtkWidget *widget, GdkEventKey *event)
+{
+ GnomeCanvas *canvas;
+
+ g_return_val_if_fail (GNOME_IS_CANVAS (widget), FALSE);
+ g_return_val_if_fail (event != NULL, FALSE);
+
+ canvas = GNOME_CANVAS (widget);
+
+ if (!emit_event (canvas, (GdkEvent *) event)) {
+ GtkWidgetClass *widget_class;
+
+ widget_class = GTK_WIDGET_CLASS (canvas_parent_class);
+
+ if (event->type == GDK_KEY_PRESS) {
+ if (widget_class->key_press_event)
+ return (* widget_class->key_press_event) (widget, event);
+ } else if (event->type == GDK_KEY_RELEASE) {
+ if (widget_class->key_release_event)
+ return (* widget_class->key_release_event) (widget, event);
+ } else
+ g_assert_not_reached ();
+
+ return FALSE;
+ } else
+ return TRUE;
+}
+
+
+/* Crossing event handler for the canvas */
+static gint
+gnome_canvas_crossing (GtkWidget *widget, GdkEventCrossing *event)
+{
+ GnomeCanvas *canvas;
+
+ g_return_val_if_fail (GNOME_IS_CANVAS (widget), FALSE);
+ g_return_val_if_fail (event != NULL, FALSE);
+
+ canvas = GNOME_CANVAS (widget);
+
+ if (event->window != canvas->layout.bin_window)
+ return FALSE;
+
+ canvas->state = event->state;
+ return pick_current_item (canvas, (GdkEvent *) event);
+}
+
+/* Focus in handler for the canvas */
+static gint
+gnome_canvas_focus_in (GtkWidget *widget, GdkEventFocus *event)
+{
+ GnomeCanvas *canvas;
+
+ GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
+
+ canvas = GNOME_CANVAS (widget);
+
+ if (canvas->focused_item)
+ return emit_event (canvas, (GdkEvent *) event);
+ else
+ return FALSE;
+}
+
+/* Focus out handler for the canvas */
+static gint
+gnome_canvas_focus_out (GtkWidget *widget, GdkEventFocus *event)
+{
+ GnomeCanvas *canvas;
+
+ GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
+
+ canvas = GNOME_CANVAS (widget);
+
+ if (canvas->focused_item)
+ return emit_event (canvas, (GdkEvent *) event);
+ else
+ return FALSE;
+}
+
+#define IMAGE_WIDTH 512
+#define IMAGE_HEIGHT 512
+
+#define IMAGE_WIDTH_AA 256
+#define IMAGE_HEIGHT_AA 64
+
+static void
+gnome_canvas_paint_rect (GnomeCanvas *canvas, gint x0, gint y0, gint x1, gint y1)
+{
+ GtkWidget *widget;
+ gint draw_x1, draw_y1;
+ gint draw_x2, draw_y2;
+ gint xblock, yblock;
+ guchar *px;
+ GdkPixmap *pixmap;
+
+ g_return_if_fail (!canvas->need_update);
+
+ widget = GTK_WIDGET (canvas);
+
+ draw_x1 = MAX (x0, canvas->layout.hadjustment->value - canvas->zoom_xofs);
+ draw_y1 = MAX (y0, canvas->layout.vadjustment->value - canvas->zoom_yofs);
+ draw_x2 = MIN (draw_x1 + GTK_WIDGET (canvas)->allocation.width, x1);
+ draw_y2 = MIN (draw_y1 + GTK_WIDGET (canvas)->allocation.height, y1);
+
+ /* As we can come from expose, we have to tile here */
+ xblock = (canvas->aa) ? IMAGE_WIDTH_AA : IMAGE_WIDTH;
+ yblock = (canvas->aa) ? IMAGE_HEIGHT_AA : IMAGE_HEIGHT;
+
+ px = NULL;
+ pixmap = NULL;
+
+ for (y0 = draw_y1; y0 < draw_y2; y0 += yblock) {
+ y1 = MIN (y0 + yblock, draw_y2);
+ for (x0 = draw_x1; x0 < draw_x2; x0 += xblock) {
+ x1 = MIN (x0 + xblock, draw_x2);
+
+ canvas->redraw_x1 = x0;
+ canvas->redraw_y1 = y0;
+ canvas->redraw_x2 = x1;
+ canvas->redraw_y2 = y1;
+ canvas->draw_xofs = x0;
+ canvas->draw_yofs = y0;
+
+ if (canvas->aa) {
+ GnomeCanvasBuf buf;
+ GdkColor *color;
+
+ if (!px) px = g_new (guchar, IMAGE_WIDTH_AA * IMAGE_HEIGHT_AA * 3);
+
+ buf.buf = px;
+ buf.buf_rowstride = IMAGE_WIDTH_AA * 3;
+ buf.rect.x0 = x0;
+ buf.rect.y0 = y0;
+ buf.rect.x1 = x1;
+ buf.rect.y1 = y1;
+ color = &widget->style->bg[GTK_STATE_NORMAL];
+ buf.bg_color = (((color->red & 0xff00) << 8) | (color->green & 0xff00) | (color->blue >> 8));
+ buf.is_bg = 1;
+ buf.is_buf = 0;
+
+ g_signal_emit (G_OBJECT (canvas), canvas_signals[RENDER_BACKGROUND], 0, &buf);
+
+ if (canvas->root->object.flags & GNOME_CANVAS_ITEM_VISIBLE)
+ (* GNOME_CANVAS_ITEM_GET_CLASS (canvas->root)->render) (canvas->root, &buf);
+
+ if (buf.is_bg) {
+ gdk_rgb_gc_set_foreground (canvas->pixmap_gc, buf.bg_color);
+ gdk_draw_rectangle (canvas->layout.bin_window,
+ canvas->pixmap_gc,
+ TRUE,
+ (x0 + canvas->zoom_xofs),
+ (y0 + canvas->zoom_yofs),
+ x1 - x0, y1 - y0);
+ } else {
+ gdk_draw_rgb_image_dithalign (canvas->layout.bin_window,
+ canvas->pixmap_gc,
+ (x0 + canvas->zoom_xofs),
+ (y0 + canvas->zoom_yofs),
+ x1 - x0, y1 - y0,
+ canvas->dither,
+ buf.buf,
+ IMAGE_WIDTH_AA * 3,
+ x0, y0);
+ }
+ } else {
+ if (!pixmap) pixmap = gdk_pixmap_new (canvas->layout.bin_window, IMAGE_WIDTH, IMAGE_HEIGHT,
+ gtk_widget_get_visual (widget)->depth);
+
+ g_signal_emit (G_OBJECT (canvas), canvas_signals[DRAW_BACKGROUND], 0, pixmap,
+ x0, y0, x1 - x0, y1 - y0);
+
+ if (canvas->root->object.flags & GNOME_CANVAS_ITEM_VISIBLE)
+ (* GNOME_CANVAS_ITEM_GET_CLASS (
+ canvas->root)->draw) (
+ canvas->root, pixmap,
+ x0, y0,
+ x1 - x0, y1 - y0);
+ /* Copy the pixmap to the window and clean up */
+
+ gdk_draw_pixmap (canvas->layout.bin_window,
+ canvas->pixmap_gc,
+ pixmap,
+ 0, 0,
+ x0 + canvas->zoom_xofs,
+ y0 + canvas->zoom_yofs,
+ x1 - x0, y1 - y0);
+ }
+ }
+ }
+
+ if (px) g_free (px);
+ if (pixmap) gdk_pixmap_unref (pixmap);
+}
+
+/* Expose handler for the canvas */
+static gint
+gnome_canvas_expose (GtkWidget *widget, GdkEventExpose *event)
+{
+ GnomeCanvas *canvas;
+ GdkRectangle *rects;
+ gint n_rects;
+ int i;
+
+ canvas = GNOME_CANVAS (widget);
+
+ if (!GTK_WIDGET_DRAWABLE (widget) || (event->window != canvas->layout.bin_window))
+ return FALSE;
+
+#ifdef VERBOSE
+ g_print ("Expose\n");
+#endif
+
+ gdk_region_get_rectangles (event->region, &rects, &n_rects);
+
+ for (i = 0; i < n_rects; i++) {
+ ArtIRect rect;
+
+ rect.x0 = rects[i].x - canvas->zoom_xofs;
+ rect.y0 = rects[i].y - canvas->zoom_yofs;
+ rect.x1 = rects[i].x + rects[i].width - canvas->zoom_xofs;
+ rect.y1 = rects[i].y + rects[i].height - canvas->zoom_yofs;
+
+ if (canvas->need_update || canvas->need_redraw) {
+ ArtUta *uta;
+ /* Update or drawing is scheduled, so just mark exposed area as dirty */
+ uta = art_uta_from_irect (&rect);
+ gnome_canvas_request_redraw_uta (canvas, uta);
+ } else {
+ /* No pending updates, draw exposed area immediately */
+ gnome_canvas_paint_rect (canvas, rect.x0, rect.y0, rect.x1, rect.y1);
+
+ /* And call expose on parent container class */
+ if (GTK_WIDGET_CLASS (canvas_parent_class)->expose_event)
+ (* GTK_WIDGET_CLASS (canvas_parent_class)->expose_event) (
+ widget, event);
+ }
+ }
+
+ g_free (rects);
+
+ return FALSE;
+}
+
+/* Repaints the areas in the canvas that need it */
+static void
+paint (GnomeCanvas *canvas)
+{
+ ArtIRect *rects;
+ gint n_rects, i;
+
+ if (canvas->aa)
+ rects = art_rect_list_from_uta (canvas->redraw_area,
+ IMAGE_WIDTH_AA, IMAGE_HEIGHT_AA,
+ &n_rects);
+ else
+ rects = art_rect_list_from_uta (canvas->redraw_area,
+ IMAGE_WIDTH, IMAGE_HEIGHT,
+ &n_rects);
+
+ art_uta_free (canvas->redraw_area);
+ canvas->redraw_area = NULL;
+ canvas->need_redraw = FALSE;
+
+ /* Send synthetic expose events */
+ for (i = 0; i < n_rects; i++) {
+ GdkEventExpose ex;
+ gint x0, y0, x1, y1;
+
+ x0 = MAX (canvas->layout.hadjustment->value - canvas->zoom_xofs, rects[i].x0);
+ y0 = MAX (canvas->layout.vadjustment->value - canvas->zoom_yofs, rects[i].y0);
+ x1 = MIN (x0 + GTK_WIDGET (canvas)->allocation.width, rects[i].x1);
+ y1 = MIN (y0 + GTK_WIDGET (canvas)->allocation.height, rects[i].y1);
+
+ if ((x0 < x1) && (y0 < y1)) {
+ /* Here we are - whatever type is canvas, we have to send synthetic expose to layout (Lauris) */
+ ex.type = GDK_EXPOSE;
+ ex.window = canvas->layout.bin_window;
+ ex.send_event = TRUE;
+ ex.area.x = x0 + canvas->zoom_xofs;
+ ex.area.y = y0 + canvas->zoom_yofs;
+ ex.area.width = x1 - x0;
+ ex.area.height = y1 - y0;
+ ex.region = gdk_region_rectangle (&ex.area);
+ ex.count = 0;
+ gtk_widget_send_expose (GTK_WIDGET (canvas), (GdkEvent *) &ex);
+ gdk_region_destroy (ex.region);
+ }
+ }
+
+ art_free (rects);
+
+ canvas->redraw_x1 = 0;
+ canvas->redraw_y1 = 0;
+ canvas->redraw_x2 = 0;
+ canvas->redraw_y2 = 0;
+}
+
+static void
+gnome_canvas_draw_background (GnomeCanvas *canvas, GdkDrawable *drawable,
+ int x, int y, int width, int height)
+{
+ /* By default, we use the style background. */
+ gdk_gc_set_foreground (canvas->pixmap_gc,
+ &GTK_WIDGET (canvas)->style->bg[GTK_STATE_NORMAL]);
+ gdk_draw_rectangle (drawable,
+ canvas->pixmap_gc,
+ TRUE,
+ 0, 0,
+ width, height);
+}
+
+static void
+do_update (GnomeCanvas *canvas)
+{
+ /* Cause the update if necessary */
+
+update_again:
+ if (canvas->need_update) {
+ gdouble w2cpx[6];
+
+ /* We start updating root with w2cpx affine */
+ w2cpx[0] = canvas->pixels_per_unit;
+ w2cpx[1] = 0.0;
+ w2cpx[2] = 0.0;
+ w2cpx[3] = canvas->pixels_per_unit;
+ w2cpx[4] = -canvas->scroll_x1 * canvas->pixels_per_unit;
+ w2cpx[5] = -canvas->scroll_y1 * canvas->pixels_per_unit;
+
+ gnome_canvas_item_invoke_update (canvas->root, w2cpx, NULL, 0);
+
+ canvas->need_update = FALSE;
+ }
+
+ /* Pick new current item */
+
+ while (canvas->need_repick) {
+ canvas->need_repick = FALSE;
+ pick_current_item (canvas, &canvas->pick_event);
+ }
+
+ /* it is possible that during picking we emitted an event in which
+ the user then called some function which then requested update
+ of something. Without this we'd be left in a state where
+ need_update would have been left TRUE and the canvas would have
+ been left unpainted. */
+ if (canvas->need_update) {
+ goto update_again;
+ }
+
+ /* Paint if able to */
+
+ if (GTK_WIDGET_DRAWABLE (canvas) && canvas->need_redraw)
+ paint (canvas);
+}
+
+/* Idle handler for the canvas. It deals with pending updates and redraws. */
+static gboolean
+idle_handler (gpointer data)
+{
+ GnomeCanvas *canvas;
+
+ GDK_THREADS_ENTER ();
+
+ canvas = GNOME_CANVAS (data);
+ do_update (canvas);
+
+ /* Reset idle id */
+ canvas->idle_id = 0;
+
+ GDK_THREADS_LEAVE ();
+
+ return FALSE;
+}
+
+/* Convenience function to add an idle handler to a canvas */
+static void
+add_idle (GnomeCanvas *canvas)
+{
+ g_assert (canvas->need_update || canvas->need_redraw);
+
+ if (!canvas->idle_id)
+ canvas->idle_id = g_idle_add_full (CANVAS_IDLE_PRIORITY,
+ idle_handler,
+ canvas,
+ NULL);
+
+/* canvas->idle_id = gtk_idle_add (idle_handler, canvas); */
+}
+
+/**
+ * gnome_canvas_root:
+ * @canvas: A canvas.
+ *
+ * Queries the root group of a canvas.
+ *
+ * Return value: The root group of the specified canvas.
+ **/
+GnomeCanvasGroup *
+gnome_canvas_root (GnomeCanvas *canvas)
+{
+ g_return_val_if_fail (GNOME_IS_CANVAS (canvas), NULL);
+
+ return GNOME_CANVAS_GROUP (canvas->root);
+}
+
+
+/**
+ * gnome_canvas_set_scroll_region:
+ * @canvas: A canvas.
+ * @x1: Leftmost limit of the scrolling region.
+ * @y1: Upper limit of the scrolling region.
+ * @x2: Rightmost limit of the scrolling region.
+ * @y2: Lower limit of the scrolling region.
+ *
+ * Sets the scrolling region of a canvas to the specified rectangle. The canvas
+ * will then be able to scroll only within this region. The view of the canvas
+ * is adjusted as appropriate to display as much of the new region as possible.
+ **/
+void
+gnome_canvas_set_scroll_region (GnomeCanvas *canvas, double x1, double y1, double x2, double y2)
+{
+ double wxofs, wyofs;
+ int xofs, yofs;
+
+ g_return_if_fail (GNOME_IS_CANVAS (canvas));
+
+ /*
+ * Set the new scrolling region. If possible, do not move the visible contents of the
+ * canvas.
+ */
+
+ gnome_canvas_c2w (canvas,
+ GTK_LAYOUT (canvas)->hadjustment->value + canvas->zoom_xofs,
+ GTK_LAYOUT (canvas)->vadjustment->value + canvas->zoom_yofs,
+ /*canvas->zoom_xofs,
+ canvas->zoom_yofs,*/
+ &wxofs, &wyofs);
+
+ canvas->scroll_x1 = x1;
+ canvas->scroll_y1 = y1;
+ canvas->scroll_x2 = x2;
+ canvas->scroll_y2 = y2;
+
+ gnome_canvas_w2c (canvas, wxofs, wyofs, &xofs, &yofs);
+
+ scroll_to (canvas, xofs, yofs);
+
+ canvas->need_repick = TRUE;
+#if 0
+ /* todo: should be requesting update */
+ (* GNOME_CANVAS_ITEM_CLASS (canvas->root->object.klass)->update) (
+ canvas->root, NULL, NULL, 0);
+#endif
+}
+
+
+/**
+ * gnome_canvas_get_scroll_region:
+ * @canvas: A canvas.
+ * @x1: Leftmost limit of the scrolling region (return value).
+ * @y1: Upper limit of the scrolling region (return value).
+ * @x2: Rightmost limit of the scrolling region (return value).
+ * @y2: Lower limit of the scrolling region (return value).
+ *
+ * Queries the scrolling region of a canvas.
+ **/
+void
+gnome_canvas_get_scroll_region (GnomeCanvas *canvas, double *x1, double *y1, double *x2, double *y2)
+{
+ g_return_if_fail (GNOME_IS_CANVAS (canvas));
+
+ if (x1)
+ *x1 = canvas->scroll_x1;
+
+ if (y1)
+ *y1 = canvas->scroll_y1;
+
+ if (x2)
+ *x2 = canvas->scroll_x2;
+
+ if (y2)
+ *y2 = canvas->scroll_y2;
+}
+
+/**
+ * gnome_canvas_set_center_scroll_region:
+ * @canvas: A canvas.
+ * @center_scroll_region: Whether to center the scrolling region in the canvas
+ * window when it is smaller than the canvas' allocation.
+ *
+ * When the scrolling region of the canvas is smaller than the canvas window,
+ * e.g. the allocation of the canvas, it can be either centered on the window
+ * or simply made to be on the upper-left corner on the window. This function
+ * lets you configure this property.
+ **/
+void
+gnome_canvas_set_center_scroll_region (GnomeCanvas *canvas, gboolean center_scroll_region)
+{
+ g_return_if_fail (GNOME_IS_CANVAS (canvas));
+
+ canvas->center_scroll_region = center_scroll_region != 0;
+
+ scroll_to (canvas,
+ canvas->layout.hadjustment->value,
+ canvas->layout.vadjustment->value);
+}
+
+/**
+ * gnome_canvas_get_center_scroll_region:
+ * @canvas: A canvas.
+ *
+ * Returns whether the canvas is set to center the scrolling region in the window
+ * if the former is smaller than the canvas' allocation.
+ *
+ * Return value: Whether the scroll region is being centered in the canvas window.
+ **/
+gboolean
+gnome_canvas_get_center_scroll_region (GnomeCanvas *canvas)
+{
+ g_return_val_if_fail (GNOME_IS_CANVAS (canvas), FALSE);
+
+ return canvas->center_scroll_region ? TRUE : FALSE;
+}
+
+/**
+ * gnome_canvas_set_pixels_per_unit:
+ * @canvas: A canvas.
+ * @n: The number of pixels that correspond to one canvas unit.
+ *
+ * Sets the zooming factor of a canvas by specifying the number of pixels that
+ * correspond to one canvas unit.
+ *
+ * The anchor point for zooming, i.e. the point that stays fixed and all others
+ * zoom inwards or outwards from it, depends on whether the canvas is set to
+ * center the scrolling region or not. You can control this using the
+ * gnome_canvas_set_center_scroll_region() function. If the canvas is set to
+ * center the scroll region, then the center of the canvas window is used as the
+ * anchor point for zooming. Otherwise, the upper-left corner of the canvas
+ * window is used as the anchor point.
+ **/
+void
+gnome_canvas_set_pixels_per_unit (GnomeCanvas *canvas, double n)
+{
+ double ax, ay;
+ int x1, y1;
+ int anchor_x, anchor_y;
+
+ g_return_if_fail (GNOME_IS_CANVAS (canvas));
+ g_return_if_fail (n > GNOME_CANVAS_EPSILON);
+
+ if (canvas->center_scroll_region) {
+ anchor_x = GTK_WIDGET (canvas)->allocation.width / 2;
+ anchor_y = GTK_WIDGET (canvas)->allocation.height / 2;
+ } else
+ anchor_x = anchor_y = 0;
+
+ /* Find the coordinates of the anchor point in units. */
+ if(canvas->layout.hadjustment) {
+ ax = (canvas->layout.hadjustment->value + anchor_x) / canvas->pixels_per_unit + canvas->scroll_x1 + canvas->zoom_xofs;
+ } else {
+ ax = (0.0 + anchor_x) / canvas->pixels_per_unit + canvas->scroll_x1 + canvas->zoom_xofs;
+ }
+ if(canvas->layout.hadjustment) {
+ ay = (canvas->layout.vadjustment->value + anchor_y) / canvas->pixels_per_unit + canvas->scroll_y1 + canvas->zoom_yofs;
+ } else {
+ ay = (0.0 + anchor_y) / canvas->pixels_per_unit + canvas->scroll_y1 + canvas->zoom_yofs;
+ }
+
+ /* Now calculate the new offset of the upper left corner. */
+ x1 = ((ax - canvas->scroll_x1) * n) - anchor_x;
+ y1 = ((ay - canvas->scroll_y1) * n) - anchor_y;
+
+ canvas->pixels_per_unit = n;
+
+ scroll_to (canvas, x1, y1);
+
+ if (!(canvas->root->object.flags & GNOME_CANVAS_ITEM_NEED_AFFINE)) {
+ canvas->root->object.flags |= GNOME_CANVAS_ITEM_NEED_AFFINE;
+ gnome_canvas_request_update (canvas);
+ }
+
+ canvas->need_repick = TRUE;
+}
+
+/**
+ * gnome_canvas_scroll_to:
+ * @canvas: A canvas.
+ * @cx: Horizontal scrolling offset in canvas pixel units.
+ * @cy: Vertical scrolling offset in canvas pixel units.
+ *
+ * Makes a canvas scroll to the specified offsets, given in canvas pixel units.
+ * The canvas will adjust the view so that it is not outside the scrolling
+ * region. This function is typically not used, as it is better to hook
+ * scrollbars to the canvas layout's scrolling adjusments.
+ **/
+void
+gnome_canvas_scroll_to (GnomeCanvas *canvas, int cx, int cy)
+{
+ g_return_if_fail (GNOME_IS_CANVAS (canvas));
+
+ scroll_to (canvas, cx, cy);
+}
+
+/**
+ * gnome_canvas_get_scroll_offsets:
+ * @canvas: A canvas.
+ * @cx: Horizontal scrolling offset (return value).
+ * @cy: Vertical scrolling offset (return value).
+ *
+ * Queries the scrolling offsets of a canvas. The values are returned in canvas
+ * pixel units.
+ **/
+void
+gnome_canvas_get_scroll_offsets (GnomeCanvas *canvas, int *cx, int *cy)
+{
+ g_return_if_fail (GNOME_IS_CANVAS (canvas));
+
+ if (cx)
+ *cx = canvas->layout.hadjustment->value;
+
+ if (cy)
+ *cy = canvas->layout.vadjustment->value;
+}
+
+/**
+ * gnome_canvas_update_now:
+ * @canvas: A canvas.
+ *
+ * Forces an immediate update and redraw of a canvas. If the canvas does not
+ * have any pending update or redraw requests, then no action is taken. This is
+ * typically only used by applications that need explicit control of when the
+ * display is updated, like games. It is not needed by normal applications.
+ */
+void
+gnome_canvas_update_now (GnomeCanvas *canvas)
+{
+ g_return_if_fail (GNOME_IS_CANVAS (canvas));
+
+ if (!(canvas->need_update || canvas->need_redraw)) {
+ g_assert (canvas->idle_id == 0);
+ g_assert (canvas->redraw_area == NULL);
+ return;
+ }
+
+ remove_idle (canvas);
+ do_update (canvas);
+}
+
+/**
+ * gnome_canvas_get_item_at:
+ * @canvas: A canvas.
+ * @x: X position in world coordinates.
+ * @y: Y position in world coordinates.
+ *
+ * Looks for the item that is under the specified position, which must be
+ * specified in world coordinates.
+ *
+ * Return value: The sought item, or NULL if no item is at the specified
+ * coordinates.
+ **/
+GnomeCanvasItem *
+gnome_canvas_get_item_at (GnomeCanvas *canvas, double x, double y)
+{
+ GnomeCanvasItem *item;
+ double dist;
+ int cx, cy;
+
+ g_return_val_if_fail (GNOME_IS_CANVAS (canvas), NULL);
+
+ gnome_canvas_w2c (canvas, x, y, &cx, &cy);
+
+ dist = gnome_canvas_item_invoke_point (canvas->root, x, y, cx, cy, &item);
+ if ((int) (dist * canvas->pixels_per_unit + 0.5) <= canvas->close_enough)
+ return item;
+ else
+ return NULL;
+}
+
+/* Queues an update of the canvas */
+static void
+gnome_canvas_request_update (GnomeCanvas *canvas)
+{
+ GNOME_CANVAS_GET_CLASS (canvas)->request_update (canvas);
+}
+
+static void
+gnome_canvas_request_update_real (GnomeCanvas *canvas)
+{
+ if (canvas->need_update)
+ return;
+
+ canvas->need_update = TRUE;
+ if (GTK_WIDGET_MAPPED ((GtkWidget *) canvas))
+ add_idle (canvas);
+}
+
+/* Computes the union of two microtile arrays while clipping the result to the
+ * specified rectangle. Any of the specified utas can be NULL, in which case it
+ * is taken to be an empty region.
+ */
+static ArtUta *
+uta_union_clip (ArtUta *uta1, ArtUta *uta2, ArtIRect *clip)
+{
+ ArtUta *uta;
+ ArtUtaBbox *utiles;
+ int clip_x1, clip_y1, clip_x2, clip_y2;
+ int union_x1, union_y1, union_x2, union_y2;
+ int new_x1, new_y1, new_x2, new_y2;
+ int x, y;
+ int ofs, ofs1, ofs2;
+
+ g_assert (clip != NULL);
+
+ /* Compute the tile indices for the clipping rectangle */
+
+ clip_x1 = clip->x0 >> ART_UTILE_SHIFT;
+ clip_y1 = clip->y0 >> ART_UTILE_SHIFT;
+ clip_x2 = (clip->x1 >> ART_UTILE_SHIFT) + 1;
+ clip_y2 = (clip->y1 >> ART_UTILE_SHIFT) + 1;
+
+ /* Get the union of the bounds of both utas */
+
+ if (!uta1) {
+ if (!uta2)
+ return art_uta_new (clip_x1, clip_y1, clip_x1 + 1, clip_y1 + 1);
+
+ union_x1 = uta2->x0;
+ union_y1 = uta2->y0;
+ union_x2 = uta2->x0 + uta2->width;
+ union_y2 = uta2->y0 + uta2->height;
+ } else {
+ if (!uta2) {
+ union_x1 = uta1->x0;
+ union_y1 = uta1->y0;
+ union_x2 = uta1->x0 + uta1->width;
+ union_y2 = uta1->y0 + uta1->height;
+ } else {
+ union_x1 = MIN (uta1->x0, uta2->x0);
+ union_y1 = MIN (uta1->y0, uta2->y0);
+ union_x2 = MAX (uta1->x0 + uta1->width, uta2->x0 + uta2->width);
+ union_y2 = MAX (uta1->y0 + uta1->height, uta2->y0 + uta2->height);
+ }
+ }
+
+ /* Clip the union of the bounds */
+
+ new_x1 = MAX (clip_x1, union_x1);
+ new_y1 = MAX (clip_y1, union_y1);
+ new_x2 = MIN (clip_x2, union_x2);
+ new_y2 = MIN (clip_y2, union_y2);
+
+ if (new_x1 >= new_x2 || new_y1 >= new_y2)
+ return art_uta_new (clip_x1, clip_y1, clip_x1 + 1, clip_y1 + 1);
+
+ /* Make the new clipped union */
+
+ uta = art_new (ArtUta, 1);
+ uta->x0 = new_x1;
+ uta->y0 = new_y1;
+ uta->width = new_x2 - new_x1;
+ uta->height = new_y2 - new_y1;
+ uta->utiles = utiles = art_new (ArtUtaBbox, uta->width * uta->height);
+
+ ofs = 0;
+ ofs1 = ofs2 = 0;
+
+ for (y = new_y1; y < new_y2; y++) {
+ if (uta1)
+ ofs1 = (y - uta1->y0) * uta1->width + new_x1 - uta1->x0;
+
+ if (uta2)
+ ofs2 = (y - uta2->y0) * uta2->width + new_x1 - uta2->x0;
+
+ for (x = new_x1; x < new_x2; x++) {
+ ArtUtaBbox bb1, bb2, bb;
+
+ if (!uta1
+ || x < uta1->x0 || y < uta1->y0
+ || x >= uta1->x0 + uta1->width || y >= uta1->y0 + uta1->height)
+ bb1 = 0;
+ else
+ bb1 = uta1->utiles[ofs1];
+
+ if (!uta2
+ || x < uta2->x0 || y < uta2->y0
+ || x >= uta2->x0 + uta2->width || y >= uta2->y0 + uta2->height)
+ bb2 = 0;
+ else
+ bb2 = uta2->utiles[ofs2];
+
+ if (bb1 == 0)
+ bb = bb2;
+ else if (bb2 == 0)
+ bb = bb1;
+ else
+ bb = ART_UTA_BBOX_CONS (MIN (ART_UTA_BBOX_X0 (bb1),
+ ART_UTA_BBOX_X0 (bb2)),
+ MIN (ART_UTA_BBOX_Y0 (bb1),
+ ART_UTA_BBOX_Y0 (bb2)),
+ MAX (ART_UTA_BBOX_X1 (bb1),
+ ART_UTA_BBOX_X1 (bb2)),
+ MAX (ART_UTA_BBOX_Y1 (bb1),
+ ART_UTA_BBOX_Y1 (bb2)));
+
+ utiles[ofs] = bb;
+
+ ofs++;
+ ofs1++;
+ ofs2++;
+ }
+ }
+
+ return uta;
+}
+
+static inline void
+get_visible_region (GnomeCanvas *canvas, ArtIRect *visible)
+{
+ visible->x0 = canvas->layout.hadjustment->value - canvas->zoom_xofs;
+ visible->y0 = canvas->layout.vadjustment->value - canvas->zoom_yofs;
+ visible->x1 = visible->x0 + GTK_WIDGET (canvas)->allocation.width;
+ visible->y1 = visible->y0 + GTK_WIDGET (canvas)->allocation.height;
+}
+
+/**
+ * gnome_canvas_request_redraw_uta:
+ * @canvas: A canvas.
+ * @uta: Microtile array that specifies the area to be redrawn. It will
+ * be freed by this function, so the argument you pass will be invalid
+ * after you call this function.
+ *
+ * Informs a canvas that the specified area, given as a microtile array, needs
+ * to be repainted. To be used only by item implementations.
+ **/
+void
+gnome_canvas_request_redraw_uta (GnomeCanvas *canvas,
+ ArtUta *uta)
+{
+ ArtIRect visible;
+
+ g_return_if_fail (GNOME_IS_CANVAS (canvas));
+ g_return_if_fail (uta != NULL);
+
+ if (!GTK_WIDGET_DRAWABLE (canvas)) {
+ art_uta_free (uta);
+ return;
+ }
+
+ get_visible_region (canvas, &visible);
+
+ if (canvas->need_redraw) {
+ ArtUta *new_uta;
+
+ g_assert (canvas->redraw_area != NULL);
+ /* ALEX: This can fail if e.g. redraw_uta is called by an item
+ update function and we're called from update_now -> do_update
+ because update_now sets idle_id == 0. There is also some way
+ to get it from the expose handler (see bug #102811).
+ g_assert (canvas->idle_id != 0); */
+
+ new_uta = uta_union_clip (canvas->redraw_area, uta, &visible);
+ art_uta_free (canvas->redraw_area);
+ art_uta_free (uta);
+ canvas->redraw_area = new_uta;
+ if (canvas->idle_id == 0)
+ add_idle (canvas);
+ } else {
+ ArtUta *new_uta;
+
+ g_assert (canvas->redraw_area == NULL);
+
+ new_uta = uta_union_clip (uta, NULL, &visible);
+ art_uta_free (uta);
+ canvas->redraw_area = new_uta;
+
+ canvas->need_redraw = TRUE;
+ add_idle (canvas);
+ }
+}
+
+
+/**
+ * gnome_canvas_request_redraw:
+ * @canvas: A canvas.
+ * @x1: Leftmost coordinate of the rectangle to be redrawn.
+ * @y1: Upper coordinate of the rectangle to be redrawn.
+ * @x2: Rightmost coordinate of the rectangle to be redrawn, plus 1.
+ * @y2: Lower coordinate of the rectangle to be redrawn, plus 1.
+ *
+ * Convenience function that informs a canvas that the specified rectangle needs
+ * to be repainted. This function converts the rectangle to a microtile array
+ * and feeds it to gnome_canvas_request_redraw_uta(). The rectangle includes
+ * @x1 and @y1, but not @x2 and @y2. To be used only by item implementations.
+ **/
+void
+gnome_canvas_request_redraw (GnomeCanvas *canvas, int x1, int y1, int x2, int y2)
+{
+ ArtUta *uta;
+ ArtIRect bbox;
+ ArtIRect visible;
+ ArtIRect clip;
+
+ g_return_if_fail (GNOME_IS_CANVAS (canvas));
+
+ if (!GTK_WIDGET_DRAWABLE (canvas) || (x1 >= x2) || (y1 >= y2))
+ return;
+
+ bbox.x0 = x1;
+ bbox.y0 = y1;
+ bbox.x1 = x2;
+ bbox.y1 = y2;
+
+ get_visible_region (canvas, &visible);
+
+ art_irect_intersect (&clip, &bbox, &visible);
+
+ if (!art_irect_empty (&clip)) {
+ uta = art_uta_from_irect (&clip);
+ gnome_canvas_request_redraw_uta (canvas, uta);
+ }
+}
+
+
+/**
+ * gnome_canvas_w2c_affine:
+ * @canvas: A canvas.
+ * @affine: An affine transformation matrix (return value).
+ *
+ * Gets the affine transform that converts from world coordinates to canvas
+ * pixel coordinates.
+ **/
+void
+gnome_canvas_w2c_affine (GnomeCanvas *canvas, double affine[6])
+{
+ double zooom;
+
+ g_return_if_fail (GNOME_IS_CANVAS (canvas));
+ g_return_if_fail (affine != NULL);
+
+ zooom = canvas->pixels_per_unit;
+
+ affine[0] = zooom;
+ affine[1] = 0;
+ affine[2] = 0;
+ affine[3] = zooom;
+ affine[4] = -canvas->scroll_x1 * zooom;
+ affine[5] = -canvas->scroll_y1 * zooom;
+}
+
+/**
+ * gnome_canvas_w2c:
+ * @canvas: A canvas.
+ * @wx: World X coordinate.
+ * @wy: World Y coordinate.
+ * @cx: X pixel coordinate (return value).
+ * @cy: Y pixel coordinate (return value).
+ *
+ * Converts world coordinates into canvas pixel coordinates.
+ **/
+void
+gnome_canvas_w2c (GnomeCanvas *canvas, double wx, double wy, int *cx, int *cy)
+{
+ double affine[6];
+ ArtPoint w, c;
+
+ g_return_if_fail (GNOME_IS_CANVAS (canvas));
+
+ gnome_canvas_w2c_affine (canvas, affine);
+ w.x = wx;
+ w.y = wy;
+ art_affine_point (&c, &w, affine);
+ if (cx)
+ *cx = floor (c.x + 0.5);
+ if (cy)
+ *cy = floor (c.y + 0.5);
+}
+
+/**
+ * gnome_canvas_w2c_d:
+ * @canvas: A canvas.
+ * @wx: World X coordinate.
+ * @wy: World Y coordinate.
+ * @cx: X pixel coordinate (return value).
+ * @cy: Y pixel coordinate (return value).
+ *
+ * Converts world coordinates into canvas pixel coordinates. This
+ * version returns coordinates in floating point coordinates, for
+ * greater precision.
+ **/
+void
+gnome_canvas_w2c_d (GnomeCanvas *canvas, double wx, double wy, double *cx, double *cy)
+{
+ double affine[6];
+ ArtPoint w, c;
+
+ g_return_if_fail (GNOME_IS_CANVAS (canvas));
+
+ gnome_canvas_w2c_affine (canvas, affine);
+ w.x = wx;
+ w.y = wy;
+ art_affine_point (&c, &w, affine);
+ if (cx)
+ *cx = c.x;
+ if (cy)
+ *cy = c.y;
+}
+
+
+/**
+ * gnome_canvas_c2w:
+ * @canvas: A canvas.
+ * @cx: Canvas pixel X coordinate.
+ * @cy: Canvas pixel Y coordinate.
+ * @wx: X world coordinate (return value).
+ * @wy: Y world coordinate (return value).
+ *
+ * Converts canvas pixel coordinates to world coordinates.
+ **/
+void
+gnome_canvas_c2w (GnomeCanvas *canvas, int cx, int cy, double *wx, double *wy)
+{
+ double affine[6], inv[6];
+ ArtPoint w, c;
+
+ g_return_if_fail (GNOME_IS_CANVAS (canvas));
+
+ gnome_canvas_w2c_affine (canvas, affine);
+ art_affine_invert (inv, affine);
+ c.x = cx;
+ c.y = cy;
+ art_affine_point (&w, &c, inv);
+ if (wx)
+ *wx = w.x;
+ if (wy)
+ *wy = w.y;
+}
+
+
+/**
+ * gnome_canvas_window_to_world:
+ * @canvas: A canvas.
+ * @winx: Window-relative X coordinate.
+ * @winy: Window-relative Y coordinate.
+ * @worldx: X world coordinate (return value).
+ * @worldy: Y world coordinate (return value).
+ *
+ * Converts window-relative coordinates into world coordinates. You can use
+ * this when you need to convert mouse coordinates into world coordinates, for
+ * example.
+ **/
+void
+gnome_canvas_window_to_world (GnomeCanvas *canvas, double winx, double winy,
+ double *worldx, double *worldy)
+{
+ g_return_if_fail (GNOME_IS_CANVAS (canvas));
+
+ if (worldx)
+ *worldx = canvas->scroll_x1 + ((winx - canvas->zoom_xofs)
+ / canvas->pixels_per_unit);
+
+ if (worldy)
+ *worldy = canvas->scroll_y1 + ((winy - canvas->zoom_yofs)
+ / canvas->pixels_per_unit);
+}
+
+
+/**
+ * gnome_canvas_world_to_window:
+ * @canvas: A canvas.
+ * @worldx: World X coordinate.
+ * @worldy: World Y coordinate.
+ * @winx: X window-relative coordinate.
+ * @winy: Y window-relative coordinate.
+ *
+ * Converts world coordinates into window-relative coordinates.
+ **/
+void
+gnome_canvas_world_to_window (GnomeCanvas *canvas, double worldx, double worldy,
+ double *winx, double *winy)
+{
+ g_return_if_fail (GNOME_IS_CANVAS (canvas));
+
+ if (winx)
+ *winx = (canvas->pixels_per_unit)*(worldx - canvas->scroll_x1) + canvas->zoom_xofs;
+
+ if (winy)
+ *winy = (canvas->pixels_per_unit)*(worldy - canvas->scroll_y1) + canvas->zoom_yofs;
+}
+
+
+
+/**
+ * gnome_canvas_get_color:
+ * @canvas: A canvas.
+ * @spec: X color specification, or NULL for "transparent".
+ * @color: Returns the allocated color.
+ *
+ * Allocates a color based on the specified X color specification. As a
+ * convenience to item implementations, it returns TRUE if the color was
+ * allocated, or FALSE if the specification was NULL. A NULL color
+ * specification is considered as "transparent" by the canvas.
+ *
+ * Return value: TRUE if @spec is non-NULL and the color is allocated. If @spec
+ * is NULL, then returns FALSE.
+ **/
+int
+gnome_canvas_get_color (GnomeCanvas *canvas, const char *spec, GdkColor *color)
+{
+ GdkColormap *colormap;
+
+ g_return_val_if_fail (GNOME_IS_CANVAS (canvas), FALSE);
+ g_return_val_if_fail (color != NULL, FALSE);
+
+ if (!spec) {
+ color->pixel = 0;
+ color->red = 0;
+ color->green = 0;
+ color->blue = 0;
+ return FALSE;
+ }
+
+ gdk_color_parse (spec, color);
+
+ colormap = gtk_widget_get_colormap (GTK_WIDGET (canvas));
+
+ gdk_rgb_find_color (colormap, color);
+
+ return TRUE;
+}
+
+/**
+ * gnome_canvas_get_color_pixel:
+ * @canvas: A canvas.
+ * @rgba: RGBA color specification.
+ *
+ * Allocates a color from the RGBA value passed into this function. The alpha
+ * opacity value is discarded, since normal X colors do not support it.
+ *
+ * Return value: Allocated pixel value corresponding to the specified color.
+ **/
+gulong
+gnome_canvas_get_color_pixel (GnomeCanvas *canvas, guint rgba)
+{
+ GdkColormap *colormap;
+ GdkColor color;
+
+ g_return_val_if_fail (GNOME_IS_CANVAS (canvas), 0);
+
+ color.red = ((rgba & 0xff000000) >> 16) + ((rgba & 0xff000000) >> 24);
+ color.green = ((rgba & 0x00ff0000) >> 8) + ((rgba & 0x00ff0000) >> 16);
+ color.blue = (rgba & 0x0000ff00) + ((rgba & 0x0000ff00) >> 8);
+ color.pixel = 0;
+
+ colormap = gtk_widget_get_colormap (GTK_WIDGET (canvas));
+
+ gdk_rgb_find_color (colormap, &color);
+
+ return color.pixel;
+}
+
+
+/**
+ * gnome_canvas_set_stipple_origin:
+ * @canvas: A canvas.
+ * @gc: GC on which to set the stipple origin.
+ *
+ * Sets the stipple origin of the specified GC as is appropriate for the canvas,
+ * so that it will be aligned with other stipple patterns used by canvas items.
+ * This is typically only needed by item implementations.
+ **/
+void
+gnome_canvas_set_stipple_origin (GnomeCanvas *canvas, GdkGC *gc)
+{
+ g_return_if_fail (GNOME_IS_CANVAS (canvas));
+ g_return_if_fail (GDK_IS_GC (gc));
+
+ gdk_gc_set_ts_origin (gc, -canvas->draw_xofs, -canvas->draw_yofs);
+}
+
+/**
+ * gnome_canvas_set_dither:
+ * @canvas: A canvas.
+ * @dither: Type of dithering used to render an antialiased canvas.
+ *
+ * Controls dithered rendering for antialiased canvases. The value of
+ * dither should be #GDK_RGB_DITHER_NONE, #GDK_RGB_DITHER_NORMAL, or
+ * #GDK_RGB_DITHER_MAX. The default canvas setting is
+ * #GDK_RGB_DITHER_NORMAL.
+ **/
+void
+gnome_canvas_set_dither (GnomeCanvas *canvas, GdkRgbDither dither)
+{
+ g_return_if_fail (GNOME_IS_CANVAS (canvas));
+
+ canvas->dither = dither;
+}
+
+/**
+ * gnome_canvas_get_dither:
+ * @canvas: A canvas.
+ *
+ * Returns the type of dithering used to render an antialiased canvas.
+ *
+ * Return value: The dither setting.
+ **/
+GdkRgbDither
+gnome_canvas_get_dither (GnomeCanvas *canvas)
+{
+ g_return_val_if_fail (GNOME_IS_CANVAS (canvas), GDK_RGB_DITHER_NONE);
+
+ return canvas->dither;
+}
+
+static gboolean
+boolean_handled_accumulator (GSignalInvocationHint *ihint,
+ GValue *return_accu,
+ const GValue *handler_return,
+ gpointer dummy)
+{
+ gboolean continue_emission;
+ gboolean signal_handled;
+
+ signal_handled = g_value_get_boolean (handler_return);
+ g_value_set_boolean (return_accu, signal_handled);
+ continue_emission = !signal_handled;
+
+ return continue_emission;
+}
+
+/* Class initialization function for GnomeCanvasItemClass */
+static void
+gnome_canvas_item_class_init (GnomeCanvasItemClass *class)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = (GObjectClass *) class;
+
+ item_parent_class = g_type_class_peek_parent (class);
+
+ gobject_class->set_property = gnome_canvas_item_set_property;
+ gobject_class->get_property = gnome_canvas_item_get_property;
+
+ g_object_class_install_property
+ (gobject_class, ITEM_PROP_PARENT,
+ g_param_spec_object ("parent", NULL, NULL,
+ GNOME_TYPE_CANVAS_ITEM,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+
+ item_signals[ITEM_EVENT] =
+ g_signal_new ("event",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GnomeCanvasItemClass, event),
+ boolean_handled_accumulator, NULL,
+ gnome_canvas_marshal_BOOLEAN__BOXED,
+ G_TYPE_BOOLEAN, 1,
+ GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
+
+ gobject_class->dispose = gnome_canvas_item_dispose;
+
+ class->realize = gnome_canvas_item_realize;
+ class->unrealize = gnome_canvas_item_unrealize;
+ class->map = gnome_canvas_item_map;
+ class->unmap = gnome_canvas_item_unmap;
+ class->update = gnome_canvas_item_update;
+}
diff --git a/src/libgnomecanvas/gnome-canvas.h b/src/libgnomecanvas/gnome-canvas.h
new file mode 100644
index 0000000..d4f538a
--- /dev/null
+++ b/src/libgnomecanvas/gnome-canvas.h
@@ -0,0 +1,635 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: 8; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ @NOTATION@
+ */
+/* GnomeCanvas widget - Tk-like canvas widget for Gnome
+ *
+ * GnomeCanvas is basically a port of the Tk toolkit's most excellent canvas
+ * widget. Tk is copyrighted by the Regents of the University of California,
+ * Sun Microsystems, and other parties.
+ *
+ *
+ * Authors: Federico Mena <federico@nuclecu.unam.mx>
+ * Raph Levien <raph@gimp.org>
+ */
+
+#ifndef GNOME_CANVAS_H
+#define GNOME_CANVAS_H
+
+#include <gtk/gtklayout.h>
+#include <stdarg.h>
+#include <libart_lgpl/art_misc.h>
+#include <libart_lgpl/art_rect.h>
+#include <libart_lgpl/art_svp.h>
+#include <libart_lgpl/art_uta.h>
+#include <libart_lgpl/art_affine.h>
+
+G_BEGIN_DECLS
+
+
+/* "Small" value used by canvas stuff */
+#define GNOME_CANVAS_EPSILON 1e-10
+
+
+/* Macros for building colors that fit in a 32-bit integer. The values are in
+ * [0, 255].
+ */
+
+#define GNOME_CANVAS_COLOR(r, g, b) ((((unsigned int) (r) & 0xff) << 24) \
+ | (((unsigned int) (g) & 0xff) << 16) \
+ | (((unsigned int) (b) & 0xff) << 8) \
+ | 0xff)
+
+#define GNOME_CANVAS_COLOR_A(r, g, b, a) ((((unsigned int) (r) & 0xff) << 24) \
+ | (((unsigned int) (g) & 0xff) << 16) \
+ | (((unsigned int) (b) & 0xff) << 8) \
+ | ((unsigned int) (a) & 0xff))
+
+
+typedef struct _GnomeCanvas GnomeCanvas;
+typedef struct _GnomeCanvasClass GnomeCanvasClass;
+typedef struct _GnomeCanvasItem GnomeCanvasItem;
+typedef struct _GnomeCanvasItemClass GnomeCanvasItemClass;
+typedef struct _GnomeCanvasGroup GnomeCanvasGroup;
+typedef struct _GnomeCanvasGroupClass GnomeCanvasGroupClass;
+
+
+/* GnomeCanvasItem - base item class for canvas items
+ *
+ * All canvas items are derived from GnomeCanvasItem. The only information a
+ * GnomeCanvasItem contains is its parent canvas, its parent canvas item group,
+ * its bounding box in world coordinates, and its current affine transformation.
+ *
+ * Items inside a canvas are organized in a tree of GnomeCanvasItemGroup nodes
+ * and GnomeCanvasItem leaves. Each canvas has a single root group, which can
+ * be obtained with the gnome_canvas_get_root() function.
+ *
+ * The abstract GnomeCanvasItem class does not have any configurable or
+ * queryable attributes.
+ */
+
+/* Object flags for items */
+enum {
+ GNOME_CANVAS_ITEM_REALIZED = 1 << 4,
+ GNOME_CANVAS_ITEM_MAPPED = 1 << 5,
+ GNOME_CANVAS_ITEM_ALWAYS_REDRAW = 1 << 6,
+ GNOME_CANVAS_ITEM_VISIBLE = 1 << 7,
+ GNOME_CANVAS_ITEM_NEED_UPDATE = 1 << 8,
+ GNOME_CANVAS_ITEM_NEED_AFFINE = 1 << 9,
+ GNOME_CANVAS_ITEM_NEED_CLIP = 1 << 10,
+ GNOME_CANVAS_ITEM_NEED_VIS = 1 << 11,
+ GNOME_CANVAS_ITEM_AFFINE_FULL = 1 << 12
+};
+
+/* Update flags for items */
+enum {
+ GNOME_CANVAS_UPDATE_REQUESTED = 1 << 0,
+ GNOME_CANVAS_UPDATE_AFFINE = 1 << 1,
+ GNOME_CANVAS_UPDATE_CLIP = 1 << 2,
+ GNOME_CANVAS_UPDATE_VISIBILITY = 1 << 3,
+ GNOME_CANVAS_UPDATE_IS_VISIBLE = 1 << 4 /* Deprecated. FIXME: remove this */
+};
+
+/* Data for rendering in antialiased mode */
+typedef struct {
+ /* 24-bit RGB buffer for rendering */
+ guchar *buf;
+
+ /* Rectangle describing the rendering area */
+ ArtIRect rect;
+
+ /* Rowstride for the buffer */
+ int buf_rowstride;
+
+ /* Background color, given as 0xrrggbb */
+ guint32 bg_color;
+
+ /* Invariant: at least one of the following flags is true. */
+
+ /* Set when the render rectangle area is the solid color bg_color */
+ unsigned int is_bg : 1;
+
+ /* Set when the render rectangle area is represented by the buf */
+ unsigned int is_buf : 1;
+} GnomeCanvasBuf;
+
+
+#define GNOME_TYPE_CANVAS_ITEM (gnome_canvas_item_get_type ())
+#define GNOME_CANVAS_ITEM(obj) (GTK_CHECK_CAST ((obj), GNOME_TYPE_CANVAS_ITEM, GnomeCanvasItem))
+#define GNOME_CANVAS_ITEM_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GNOME_TYPE_CANVAS_ITEM, GnomeCanvasItemClass))
+#define GNOME_IS_CANVAS_ITEM(obj) (GTK_CHECK_TYPE ((obj), GNOME_TYPE_CANVAS_ITEM))
+#define GNOME_IS_CANVAS_ITEM_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_CANVAS_ITEM))
+#define GNOME_CANVAS_ITEM_GET_CLASS(obj) (GTK_CHECK_GET_CLASS ((obj), GNOME_TYPE_CANVAS_ITEM, GnomeCanvasItemClass))
+
+
+struct _GnomeCanvasItem {
+ GtkObject object;
+
+ /* Parent canvas for this item */
+ GnomeCanvas *canvas;
+
+ /* Parent canvas group for this item (a GnomeCanvasGroup) */
+ GnomeCanvasItem *parent;
+
+ /* If NULL, assumed to be the identity tranform. If flags does not have
+ * AFFINE_FULL, then a two-element array containing a translation. If
+ * flags contains AFFINE_FULL, a six-element array containing an affine
+ * transformation.
+ */
+ double *xform;
+
+ /* Bounding box for this item (in canvas coordinates) */
+ double x1, y1, x2, y2;
+};
+
+struct _GnomeCanvasItemClass {
+ GtkObjectClass parent_class;
+
+ /* Tell the item to update itself. The flags are from the update flags
+ * defined above. The item should update its internal state from its
+ * queued state, and recompute and request its repaint area. The
+ * affine, if used, is a pointer to a 6-element array of doubles. The
+ * update method also recomputes the bounding box of the item.
+ */
+ void (* update) (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags);
+
+ /* Realize an item -- create GCs, etc. */
+ void (* realize) (GnomeCanvasItem *item);
+
+ /* Unrealize an item */
+ void (* unrealize) (GnomeCanvasItem *item);
+
+ /* Map an item - normally only need by items with their own GdkWindows */
+ void (* map) (GnomeCanvasItem *item);
+
+ /* Unmap an item */
+ void (* unmap) (GnomeCanvasItem *item);
+
+ /* Return the microtile coverage of the item */
+ ArtUta *(* coverage) (GnomeCanvasItem *item);
+
+ /* Draw an item of this type. (x, y) are the upper-left canvas pixel
+ * coordinates of the drawable, a temporary pixmap, where things get
+ * drawn. (width, height) are the dimensions of the drawable.
+ */
+ void (* draw) (GnomeCanvasItem *item, GdkDrawable *drawable,
+ int x, int y, int width, int height);
+
+ /* Render the item over the buffer given. The buf data structure
+ * contains both a pointer to a packed 24-bit RGB array, and the
+ * coordinates. This method is only used for antialiased canvases.
+ *
+ * TODO: figure out where clip paths fit into the rendering framework.
+ */
+ void (* render) (GnomeCanvasItem *item, GnomeCanvasBuf *buf);
+
+ /* Calculate the distance from an item to the specified point. It also
+ * returns a canvas item which is the item itself in the case of the
+ * object being an actual leaf item, or a child in case of the object
+ * being a canvas group. (cx, cy) are the canvas pixel coordinates that
+ * correspond to the item-relative coordinates (x, y).
+ */
+ double (* point) (GnomeCanvasItem *item, double x, double y, int cx, int cy,
+ GnomeCanvasItem **actual_item);
+
+ /* Fetch the item's bounding box (need not be exactly tight). This
+ * should be in item-relative coordinates.
+ */
+ void (* bounds) (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2);
+
+ /* Signal: an event occurred for an item of this type. The (x, y)
+ * coordinates are in the canvas world coordinate system.
+ */
+ gboolean (* event) (GnomeCanvasItem *item, GdkEvent *event);
+
+ /* Reserved for future expansion */
+ gpointer spare_vmethods [4];
+};
+
+
+GType gnome_canvas_item_get_type (void) G_GNUC_CONST;
+
+/* Create a canvas item using the standard Gtk argument mechanism. The item is
+ * automatically inserted at the top of the specified canvas group. The last
+ * argument must be a NULL pointer.
+ */
+GnomeCanvasItem *gnome_canvas_item_new (GnomeCanvasGroup *parent, GType type,
+ const gchar *first_arg_name, ...);
+
+/* Constructors for use in derived classes and language wrappers */
+void gnome_canvas_item_construct (GnomeCanvasItem *item, GnomeCanvasGroup *parent,
+ const gchar *first_arg_name, va_list args);
+
+/* Configure an item using the standard Gtk argument mechanism. The last
+ * argument must be a NULL pointer.
+ */
+void gnome_canvas_item_set (GnomeCanvasItem *item, const gchar *first_arg_name, ...);
+
+/* Used only for language wrappers and the like */
+void gnome_canvas_item_set_valist (GnomeCanvasItem *item,
+ const gchar *first_arg_name, va_list args);
+
+/* Move an item by the specified amount */
+void gnome_canvas_item_move (GnomeCanvasItem *item, double dx, double dy);
+
+/* Apply a relative affine transformation to the item. */
+void gnome_canvas_item_affine_relative (GnomeCanvasItem *item, const double affine[6]);
+
+/* Apply an absolute affine transformation to the item. */
+void gnome_canvas_item_affine_absolute (GnomeCanvasItem *item, const double affine[6]);
+
+/* Raise an item in the z-order of its parent group by the specified number of
+ * positions.
+ */
+void gnome_canvas_item_raise (GnomeCanvasItem *item, int positions);
+
+/* Lower an item in the z-order of its parent group by the specified number of
+ * positions.
+ */
+void gnome_canvas_item_lower (GnomeCanvasItem *item, int positions);
+
+/* Raise an item to the top of its parent group's z-order. */
+void gnome_canvas_item_raise_to_top (GnomeCanvasItem *item);
+
+/* Lower an item to the bottom of its parent group's z-order */
+void gnome_canvas_item_lower_to_bottom (GnomeCanvasItem *item);
+
+/* Show an item (make it visible). If the item is already shown, it has no
+ * effect.
+ */
+void gnome_canvas_item_show (GnomeCanvasItem *item);
+
+/* Hide an item (make it invisible). If the item is already invisible, it has
+ * no effect.
+ */
+void gnome_canvas_item_hide (GnomeCanvasItem *item);
+
+/* Grab the mouse for the specified item. Only the events in event_mask will be
+ * reported. If cursor is non-NULL, it will be used during the duration of the
+ * grab. Time is a proper X event time parameter. Returns the same values as
+ * XGrabPointer().
+ */
+int gnome_canvas_item_grab (GnomeCanvasItem *item, unsigned int event_mask,
+ GdkCursor *cursor, guint32 etime);
+
+/* Ungrabs the mouse -- the specified item must be the same that was passed to
+ * gnome_canvas_item_grab(). Time is a proper X event time parameter.
+ */
+void gnome_canvas_item_ungrab (GnomeCanvasItem *item, guint32 etime);
+
+/* These functions convert from a coordinate system to another. "w" is world
+ * coordinates and "i" is item coordinates.
+ */
+void gnome_canvas_item_w2i (GnomeCanvasItem *item, double *x, double *y);
+void gnome_canvas_item_i2w (GnomeCanvasItem *item, double *x, double *y);
+
+/* Gets the affine transform that converts from item-relative coordinates to
+ * world coordinates.
+ */
+void gnome_canvas_item_i2w_affine (GnomeCanvasItem *item, double affine[6]);
+
+/* Gets the affine transform that converts from item-relative coordinates to
+ * canvas pixel coordinates.
+ */
+void gnome_canvas_item_i2c_affine (GnomeCanvasItem *item, double affine[6]);
+
+/* Remove the item from its parent group and make the new group its parent. The
+ * item will be put on top of all the items in the new group. The item's
+ * coordinates relative to its new parent to *not* change -- this means that the
+ * item could potentially move on the screen.
+ *
+ * The item and the group must be in the same canvas. An item cannot be
+ * reparented to a group that is the item itself or that is an inferior of the
+ * item.
+ */
+void gnome_canvas_item_reparent (GnomeCanvasItem *item, GnomeCanvasGroup *new_group);
+
+/* Used to send all of the keystroke events to a specific item as well as
+ * GDK_FOCUS_CHANGE events.
+ */
+void gnome_canvas_item_grab_focus (GnomeCanvasItem *item);
+
+/* Fetch the bounding box of the item. The bounding box may not be exactly
+ * tight, but the canvas items will do the best they can. The returned bounding
+ * box is in the coordinate system of the item's parent.
+ */
+void gnome_canvas_item_get_bounds (GnomeCanvasItem *item,
+ double *x1, double *y1, double *x2, double *y2);
+
+/* Request that the update method eventually get called. This should be used
+ * only by item implementations.
+ */
+void gnome_canvas_item_request_update (GnomeCanvasItem *item);
+
+
+/* GnomeCanvasGroup - a group of canvas items
+ *
+ * A group is a node in the hierarchical tree of groups/items inside a canvas.
+ * Groups serve to give a logical structure to the items.
+ *
+ * Consider a circuit editor application that uses the canvas for its schematic
+ * display. Hierarchically, there would be canvas groups that contain all the
+ * components needed for an "adder", for example -- this includes some logic
+ * gates as well as wires. You can move stuff around in a convenient way by
+ * doing a gnome_canvas_item_move() of the hierarchical groups -- to move an
+ * adder, simply move the group that represents the adder.
+ *
+ * The following arguments are available:
+ *
+ * name type read/write description
+ * --------------------------------------------------------------------------------
+ * x double RW X coordinate of group's origin
+ * y double RW Y coordinate of group's origin
+ */
+
+
+#define GNOME_TYPE_CANVAS_GROUP (gnome_canvas_group_get_type ())
+#define GNOME_CANVAS_GROUP(obj) (GTK_CHECK_CAST ((obj), GNOME_TYPE_CANVAS_GROUP, GnomeCanvasGroup))
+#define GNOME_CANVAS_GROUP_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GNOME_TYPE_CANVAS_GROUP, GnomeCanvasGroupClass))
+#define GNOME_IS_CANVAS_GROUP(obj) (GTK_CHECK_TYPE ((obj), GNOME_TYPE_CANVAS_GROUP))
+#define GNOME_IS_CANVAS_GROUP_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_CANVAS_GROUP))
+#define GNOME_CANVAS_GROUP_GET_CLASS(obj) (GTK_CHECK_GET_CLASS ((obj), GNOME_TYPE_CANVAS_GROUP, GnomeCanvasGroupClass))
+
+
+struct _GnomeCanvasGroup {
+ GnomeCanvasItem item;
+
+ /* Children of the group */
+ GList *item_list;
+ GList *item_list_end;
+};
+
+struct _GnomeCanvasGroupClass {
+ GnomeCanvasItemClass parent_class;
+};
+
+
+GType gnome_canvas_group_get_type (void) G_GNUC_CONST;
+
+
+/*** GnomeCanvas ***/
+
+
+#define GNOME_TYPE_CANVAS (gnome_canvas_get_type ())
+#define GNOME_CANVAS(obj) (GTK_CHECK_CAST ((obj), GNOME_TYPE_CANVAS, GnomeCanvas))
+#define GNOME_CANVAS_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GNOME_TYPE_CANVAS, GnomeCanvasClass))
+#define GNOME_IS_CANVAS(obj) (GTK_CHECK_TYPE ((obj), GNOME_TYPE_CANVAS))
+#define GNOME_IS_CANVAS_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_CANVAS))
+#define GNOME_CANVAS_GET_CLASS(obj) (GTK_CHECK_GET_CLASS ((obj), GNOME_TYPE_CANVAS, GnomeCanvasClass))
+
+
+struct _GnomeCanvas {
+ GtkLayout layout;
+
+ /* Root canvas group */
+ GnomeCanvasItem *root;
+
+ /* Area that needs redrawing, stored as a microtile array */
+ ArtUta *redraw_area;
+
+ /* The item containing the mouse pointer, or NULL if none */
+ GnomeCanvasItem *current_item;
+
+ /* Item that is about to become current (used to track deletions and such) */
+ GnomeCanvasItem *new_current_item;
+
+ /* Item that holds a pointer grab, or NULL if none */
+ GnomeCanvasItem *grabbed_item;
+
+ /* If non-NULL, the currently focused item */
+ GnomeCanvasItem *focused_item;
+
+ /* GC for temporary draw pixmap */
+ GdkGC *pixmap_gc;
+
+ /* Event on which selection of current item is based */
+ GdkEvent pick_event;
+
+ /* Scrolling region */
+ double scroll_x1, scroll_y1;
+ double scroll_x2, scroll_y2;
+
+ /* Scaling factor to be used for display */
+ double pixels_per_unit;
+
+ /* Idle handler ID */
+ guint idle_id;
+
+ /* Signal handler ID for destruction of the root item */
+ guint root_destroy_id;
+
+ /* Area that is being redrawn. Contains (x1, y1) but not (x2, y2).
+ * Specified in canvas pixel coordinates.
+ */
+ int redraw_x1, redraw_y1;
+ int redraw_x2, redraw_y2;
+
+ /* Offsets of the temprary drawing pixmap */
+ int draw_xofs, draw_yofs;
+
+ /* Internal pixel offsets when zoomed out */
+ int zoom_xofs, zoom_yofs;
+
+ /* Last known modifier state, for deferred repick when a button is down */
+ int state;
+
+ /* Event mask specified when grabbing an item */
+ guint grabbed_event_mask;
+
+ /* Tolerance distance for picking items */
+ int close_enough;
+
+ /* Whether the canvas should center the scroll region in the middle of
+ * the window if the scroll region is smaller than the window.
+ */
+ unsigned int center_scroll_region : 1;
+
+ /* Whether items need update at next idle loop iteration */
+ unsigned int need_update : 1;
+
+ /* Whether the canvas needs redrawing at the next idle loop iteration */
+ unsigned int need_redraw : 1;
+
+ /* Whether current item will be repicked at next idle loop iteration */
+ unsigned int need_repick : 1;
+
+ /* For use by internal pick_current_item() function */
+ unsigned int left_grabbed_item : 1;
+
+ /* For use by internal pick_current_item() function */
+ unsigned int in_repick : 1;
+
+ /* Whether the canvas is in antialiased mode or not */
+ unsigned int aa : 1;
+
+ /* Which dither mode to use for antialiased mode drawing */
+ GdkRgbDither dither;
+};
+
+struct _GnomeCanvasClass {
+ GtkLayoutClass parent_class;
+
+ /* Draw the background for the area given. This method is only used
+ * for non-antialiased canvases.
+ */
+ void (* draw_background) (GnomeCanvas *canvas, GdkDrawable *drawable,
+ int x, int y, int width, int height);
+
+ /* Render the background for the buffer given. The buf data structure
+ * contains both a pointer to a packed 24-bit RGB array, and the
+ * coordinates. This method is only used for antialiased canvases.
+ */
+ void (* render_background) (GnomeCanvas *canvas, GnomeCanvasBuf *buf);
+
+ /* Private Virtual methods for groping the canvas inside bonobo */
+ void (* request_update) (GnomeCanvas *canvas);
+
+ /* Reserved for future expansion */
+ gpointer spare_vmethods [4];
+};
+
+
+GType gnome_canvas_get_type (void) G_GNUC_CONST;
+
+/* Creates a new canvas. You should check that the canvas is created with the
+ * proper visual and colormap. Any visual will do unless you intend to insert
+ * gdk_imlib images into it, in which case you should use the gdk_imlib visual.
+ *
+ * You should call gnome_canvas_set_scroll_region() soon after calling this
+ * function to set the desired scrolling limits for the canvas.
+ */
+GtkWidget *gnome_canvas_new (void);
+
+/* Creates a new antialiased empty canvas. You should push the GdkRgb colormap
+ * and visual for this.
+ */
+#ifndef GNOME_EXCLUDE_EXPERIMENTAL
+GtkWidget *gnome_canvas_new_aa (void);
+#endif
+
+/* Returns the root canvas item group of the canvas */
+GnomeCanvasGroup *gnome_canvas_root (GnomeCanvas *canvas);
+
+/* Sets the limits of the scrolling region, in world coordinates */
+void gnome_canvas_set_scroll_region (GnomeCanvas *canvas,
+ double x1, double y1, double x2, double y2);
+
+/* Gets the limits of the scrolling region, in world coordinates */
+void gnome_canvas_get_scroll_region (GnomeCanvas *canvas,
+ double *x1, double *y1, double *x2, double *y2);
+
+/* Whether the canvas centers the scroll region if it is smaller than the window */
+void gnome_canvas_set_center_scroll_region (GnomeCanvas *canvas, gboolean center_scroll_region);
+
+/* Returns whether the canvas is set to center the scroll region if it is smaller than the window */
+gboolean gnome_canvas_get_center_scroll_region (GnomeCanvas *canvas);
+
+/* Sets the number of pixels that correspond to one unit in world coordinates */
+void gnome_canvas_set_pixels_per_unit (GnomeCanvas *canvas, double n);
+
+/* Scrolls the canvas to the specified offsets, given in canvas pixel coordinates */
+void gnome_canvas_scroll_to (GnomeCanvas *canvas, int cx, int cy);
+
+/* Returns the scroll offsets of the canvas in canvas pixel coordinates. You
+ * can specify NULL for any of the values, in which case that value will not be
+ * queried.
+ */
+void gnome_canvas_get_scroll_offsets (GnomeCanvas *canvas, int *cx, int *cy);
+
+/* Requests that the canvas be repainted immediately instead of in the idle
+ * loop.
+ */
+void gnome_canvas_update_now (GnomeCanvas *canvas);
+
+/* Returns the item that is at the specified position in world coordinates, or
+ * NULL if no item is there.
+ */
+GnomeCanvasItem *gnome_canvas_get_item_at (GnomeCanvas *canvas, double x, double y);
+
+/* For use only by item type implementations. Request that the canvas eventually
+ * redraw the specified region. The region is specified as a microtile
+ * array. This function takes over responsibility for freeing the uta argument.
+ */
+void gnome_canvas_request_redraw_uta (GnomeCanvas *canvas, ArtUta *uta);
+
+/* For use only by item type implementations. Request that the canvas
+ * eventually redraw the specified region, specified in canvas pixel
+ * coordinates. The region contains (x1, y1) but not (x2, y2).
+ */
+void gnome_canvas_request_redraw (GnomeCanvas *canvas, int x1, int y1, int x2, int y2);
+
+/* Gets the affine transform that converts world coordinates into canvas pixel
+ * coordinates.
+ */
+void gnome_canvas_w2c_affine (GnomeCanvas *canvas, double affine[6]);
+
+/* These functions convert from a coordinate system to another. "w" is world
+ * coordinates, "c" is canvas pixel coordinates (pixel coordinates that are
+ * (0,0) for the upper-left scrolling limit and something else for the
+ * lower-left scrolling limit).
+ */
+void gnome_canvas_w2c (GnomeCanvas *canvas, double wx, double wy, int *cx, int *cy);
+void gnome_canvas_w2c_d (GnomeCanvas *canvas, double wx, double wy, double *cx, double *cy);
+void gnome_canvas_c2w (GnomeCanvas *canvas, int cx, int cy, double *wx, double *wy);
+
+/* This function takes in coordinates relative to the GTK_LAYOUT
+ * (canvas)->bin_window and converts them to world coordinates.
+ */
+void gnome_canvas_window_to_world (GnomeCanvas *canvas,
+ double winx, double winy, double *worldx, double *worldy);
+
+/* This is the inverse of gnome_canvas_window_to_world() */
+void gnome_canvas_world_to_window (GnomeCanvas *canvas,
+ double worldx, double worldy, double *winx, double *winy);
+
+/* Takes a string specification for a color and allocates it into the specified
+ * GdkColor. If the string is null, then it returns FALSE. Otherwise, it
+ * returns TRUE.
+ */
+int gnome_canvas_get_color (GnomeCanvas *canvas, const char *spec, GdkColor *color);
+
+/* Allocates a color from the RGB value passed into this function. */
+gulong gnome_canvas_get_color_pixel (GnomeCanvas *canvas,
+ guint rgba);
+
+
+/* Sets the stipple origin of the specified gc so that it will be aligned with
+ * all the stipples used in the specified canvas. This is intended for use only
+ * by canvas item implementations.
+ */
+void gnome_canvas_set_stipple_origin (GnomeCanvas *canvas, GdkGC *gc);
+
+/* Controls the dithering used when the canvas renders.
+ * Only applicable to antialiased canvases - ignored by non-antialiased canvases.
+ */
+void gnome_canvas_set_dither (GnomeCanvas *canvas, GdkRgbDither dither);
+
+/* Returns the dither mode of an antialiased canvas.
+ * Only applicable to antialiased canvases - ignored by non-antialiased canvases.
+ */
+GdkRgbDither gnome_canvas_get_dither (GnomeCanvas *canvas);
+
+G_END_DECLS
+
+#endif
diff --git a/src/libgnomecanvas/libgnomecanvas.h b/src/libgnomecanvas/libgnomecanvas.h
new file mode 100644
index 0000000..93e21fa
--- /dev/null
+++ b/src/libgnomecanvas/libgnomecanvas.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ @NOTATION@
+ */
+
+#ifndef LIBGNOMECANVAS_H
+#define LIBGNOMECANVAS_H
+
+#include <libgnomecanvas/gnome-canvas.h>
+#include <libgnomecanvas/gnome-canvas-line.h>
+#include <libgnomecanvas/gnome-canvas-text.h>
+#include <libgnomecanvas/gnome-canvas-rich-text.h>
+#include <libgnomecanvas/gnome-canvas-polygon.h>
+#include <libgnomecanvas/gnome-canvas-pixbuf.h>
+#include <libgnomecanvas/gnome-canvas-widget.h>
+#include <libgnomecanvas/gnome-canvas-rect-ellipse.h>
+#include <libgnomecanvas/gnome-canvas-bpath.h>
+#include <libgnomecanvas/gnome-canvas-util.h>
+#include <libgnomecanvas/gnome-canvas-clipgroup.h>
+
+G_BEGIN_DECLS
+
+GType gnome_canvas_points_get_type (void);
+#define GNOME_TYPE_CANVAS_POINTS gnome_canvas_points_get_type()
+
+G_END_DECLS
+
+#endif /* LIBGNOMECANVAS_H */
diff --git a/src/libgnomecanvas/libgnomecanvastypes.c b/src/libgnomecanvas/libgnomecanvastypes.c
new file mode 100644
index 0000000..9ea5966
--- /dev/null
+++ b/src/libgnomecanvas/libgnomecanvastypes.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 1999, 2000 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ @NOTATION@
+ */
+
+#include <config.h>
+#include <glib-object.h>
+
+#include <libgnomecanvas/libgnomecanvas.h>
+
+GType
+gnome_canvas_points_get_type (void)
+{
+ static GType type_canvas_points = 0;
+
+ if (!type_canvas_points)
+ type_canvas_points = g_boxed_type_register_static
+ ("GnomeCanvasPoints",
+ (GBoxedCopyFunc) gnome_canvas_points_ref,
+ (GBoxedFreeFunc) gnome_canvas_points_unref);
+
+ return type_canvas_points;
+}