From 2679d213fe4eae9f00a496c9b5fa2a67c85e78e1 Mon Sep 17 00:00:00 2001 From: Hamish Moffatt Date: Sun, 6 Jan 2002 13:02:15 +0100 Subject: Import libstroke_0.5.1.orig.tar.gz [dgit import orig libstroke_0.5.1.orig.tar.gz] --- libgstroke/ChangeLog | 31 ++++ libgstroke/Makefile.am | 34 ++++ libgstroke/Makefile.in | 398 +++++++++++++++++++++++++++++++++++++++++ libgstroke/README | 1 + libgstroke/TODO | 11 ++ libgstroke/gnome-stroke-draw.c | 330 ++++++++++++++++++++++++++++++++++ libgstroke/gnome-stroke.c | 289 ++++++++++++++++++++++++++++++ libgstroke/gstroke-internal.h | 41 +++++ libgstroke/gstroke.h | 43 +++++ 9 files changed, 1178 insertions(+) create mode 100644 libgstroke/ChangeLog create mode 100644 libgstroke/Makefile.am create mode 100644 libgstroke/Makefile.in create mode 100644 libgstroke/README create mode 100644 libgstroke/TODO create mode 100644 libgstroke/gnome-stroke-draw.c create mode 100644 libgstroke/gnome-stroke.c create mode 100644 libgstroke/gstroke-internal.h create mode 100644 libgstroke/gstroke.h (limited to 'libgstroke') diff --git a/libgstroke/ChangeLog b/libgstroke/ChangeLog new file mode 100644 index 0000000..4c6a30f --- /dev/null +++ b/libgstroke/ChangeLog @@ -0,0 +1,31 @@ +2001-07-05 Dan Nicolaescu + + * Rename everything to be called gstroke* instead of stroke* as + the later is sometimes used to mean other things in GNOME + programs. + +2000-08-25 Dan Nicolaescu + + * gnome-stroke.c: Move global data to a structure... + * stroke-internal.h: ... defined here (struct stroke_metrics). + (STROKE_METRICS): New define. + + * gnome-stroke.c (stroke_init): + (stroke_trans): Take a stroke_metrics* parameter. + + (stroke_trans): Call stroke_init instead of freeing the + pointList. + + * stroke.h (STROKE_MOUSE_BUTTON): New define. + * gnome-stroke-wrapper.c (process_event): Use it. + (stroke_execute): Make it static. + (STROKE_SIGNALS): New define. + (stroke_signal_connect): + (stroke_execute): Use it instead of a string. + (stroke_cleanup): New function. Should be called when the widget + is destroyed. + (stroke_canonical): Move it after stroke_trans so gcc can inline + it. + + Prepend _ to all the non-static functions to keep the namespace + clean. \ No newline at end of file diff --git a/libgstroke/Makefile.am b/libgstroke/Makefile.am new file mode 100644 index 0000000..8d6f5e3 --- /dev/null +++ b/libgstroke/Makefile.am @@ -0,0 +1,34 @@ +# A brief demonstration of using Automake with Libtool. -*-Makefile-*- +# +# NOTE: Don't forget that in the libtool distribution, files in this +# directory are distributed by the demo_distfiles variable in the top +# level Makefile. +AUTOMAKE_OPTIONS = foreign + +EXTRA_DIST = + +#SEL_BIB = libgstroke.la + +lib_LTLIBRARIES = libgstroke.la +libgstroke_la_SOURCES = gnome-stroke.c gnome-stroke-draw.c gstroke.h + +libgstroke_la_LDFLAGS = -version-info 0:5:0 + +include_HEADERS = gstroke.h + +noinst_HEADERS = gstroke-internal.h + +INCLUDES = @GTK_CFLAGS@ +LDADD = @GTK_LIBS@ + +EXTRA_DIST = + +MOSTLYCLEANFILES = core *~ +CLEANFILES = core *~ +DISTCLEANFILES = core *~ +MAINTAINERCLEANFILES = core *~ + +# Unfortunately, in order to test libtool thoroughly, we need access +# to its private directory. +objdir = `sed -n -e 's/^objdir=\"\(.*\)\"$$/\1/p' ./libtool` + diff --git a/libgstroke/Makefile.in b/libgstroke/Makefile.in new file mode 100644 index 0000000..2e1b307 --- /dev/null +++ b/libgstroke/Makefile.in @@ -0,0 +1,398 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +# A brief demonstration of using Automake with Libtool. -*-Makefile-*- +# +# NOTE: Don't forget that in the libtool distribution, files in this +# directory are distributed by the demo_distfiles variable in the top +# level Makefile. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = @host_alias@ +host_triplet = @host@ +AS = @AS@ +CC = @CC@ +DLLTOOL = @DLLTOOL@ +GTK_CFLAGS = @GTK_CFLAGS@ +GTK_CONFIG = @GTK_CONFIG@ +GTK_LIBS = @GTK_LIBS@ +LD = @LD@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +NM = @NM@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +USE_SYMBOL_UNDERSCORE = @USE_SYMBOL_UNDERSCORE@ +VERSION = @VERSION@ +X_CFLAGS = @X_CFLAGS@ +X_LDFLAGS = @X_LDFLAGS@ + +AUTOMAKE_OPTIONS = foreign + +EXTRA_DIST = + +#SEL_BIB = libgstroke.la + +lib_LTLIBRARIES = libgstroke.la +libgstroke_la_SOURCES = gnome-stroke.c gnome-stroke-draw.c gstroke.h + +libgstroke_la_LDFLAGS = -version-info 0:5:0 + +include_HEADERS = gstroke.h + +noinst_HEADERS = gstroke-internal.h + +INCLUDES = @GTK_CFLAGS@ +LDADD = @GTK_LIBS@ + +MOSTLYCLEANFILES = core *~ +CLEANFILES = core *~ +DISTCLEANFILES = core *~ +MAINTAINERCLEANFILES = core *~ + +# Unfortunately, in order to test libtool thoroughly, we need access +# to its private directory. +objdir = `sed -n -e 's/^objdir=\"\(.*\)\"$$/\1/p' ./libtool` +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +LTLIBRARIES = $(lib_LTLIBRARIES) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +X_LIBS = @X_LIBS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +libgstroke_la_LIBADD = +libgstroke_la_OBJECTS = gnome-stroke.lo gnome-stroke-draw.lo +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +HEADERS = $(include_HEADERS) $(noinst_HEADERS) + +DIST_COMMON = README ChangeLog Makefile.am Makefile.in TODO + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = gtar +GZIP_ENV = --best +DEP_FILES = .deps/gnome-stroke-draw.P .deps/gnome-stroke.P +SOURCES = $(libgstroke_la_SOURCES) +OBJECTS = $(libgstroke_la_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .lo .o .s +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --foreign libgstroke/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES) + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-libLTLIBRARIES: + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + +distclean-libLTLIBRARIES: + +maintainer-clean-libLTLIBRARIES: + +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(libdir) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + echo "$(LIBTOOL) --mode=install $(INSTALL) $$p $(DESTDIR)$(libdir)/$$p"; \ + $(LIBTOOL) --mode=install $(INSTALL) $$p $(DESTDIR)$(libdir)/$$p; \ + else :; fi; \ + done + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + $(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(libdir)/$$p; \ + done + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +.s.lo: + $(LIBTOOL) --mode=compile $(COMPILE) -c $< + +.S.lo: + $(LIBTOOL) --mode=compile $(COMPILE) -c $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + +maintainer-clean-libtool: + +libgstroke.la: $(libgstroke_la_OBJECTS) $(libgstroke_la_DEPENDENCIES) + $(LINK) -rpath $(libdir) $(libgstroke_la_LDFLAGS) $(libgstroke_la_OBJECTS) $(libgstroke_la_LIBADD) $(LIBS) + +install-includeHEADERS: $(include_HEADERS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(includedir) + @list='$(include_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d= ; else d="$(srcdir)/"; fi; \ + echo " $(INSTALL_DATA) $$d$$p $(DESTDIR)$(includedir)/$$p"; \ + $(INSTALL_DATA) $$d$$p $(DESTDIR)$(includedir)/$$p; \ + done + +uninstall-includeHEADERS: + @$(NORMAL_UNINSTALL) + list='$(include_HEADERS)'; for p in $$list; do \ + rm -f $(DESTDIR)$(includedir)/$$p; \ + done + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = libgstroke + +distdir: $(DISTFILES) + here=`cd $(top_builddir) && pwd`; \ + top_distdir=`cd $(top_distdir) && pwd`; \ + distdir=`cd $(distdir) && pwd`; \ + cd $(top_srcdir) \ + && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --foreign libgstroke/Makefile + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$d/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + +DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :) + +-include $(DEP_FILES) + +mostlyclean-depend: + +clean-depend: + +distclean-depend: + -rm -rf .deps + +maintainer-clean-depend: + +%.o: %.c + @echo '$(COMPILE) -c $<'; \ + $(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $< + @-cp .deps/$(*F).pp .deps/$(*F).P; \ + tr ' ' '\012' < .deps/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*F).P; \ + rm .deps/$(*F).pp + +%.lo: %.c + @echo '$(LTCOMPILE) -c $<'; \ + $(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $< + @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \ + < .deps/$(*F).pp > .deps/$(*F).P; \ + tr ' ' '\012' < .deps/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*F).P; \ + rm -f .deps/$(*F).pp +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: install-libLTLIBRARIES +install-exec: install-exec-am + +install-data-am: install-includeHEADERS +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: uninstall-libLTLIBRARIES uninstall-includeHEADERS +uninstall: uninstall-am +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: + $(mkinstalldirs) $(DESTDIR)$(libdir) $(DESTDIR)$(includedir) + + +mostlyclean-generic: + -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES) + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) + +maintainer-clean-generic: + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +mostlyclean-am: mostlyclean-libLTLIBRARIES mostlyclean-compile \ + mostlyclean-libtool mostlyclean-tags mostlyclean-depend \ + mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-libLTLIBRARIES clean-compile clean-libtool clean-tags \ + clean-depend clean-generic mostlyclean-am + +clean: clean-am + +distclean-am: distclean-libLTLIBRARIES distclean-compile \ + distclean-libtool distclean-tags distclean-depend \ + distclean-generic clean-am + -rm -f libtool + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-libLTLIBRARIES \ + maintainer-clean-compile maintainer-clean-libtool \ + maintainer-clean-tags maintainer-clean-depend \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-libLTLIBRARIES distclean-libLTLIBRARIES \ +clean-libLTLIBRARIES maintainer-clean-libLTLIBRARIES \ +uninstall-libLTLIBRARIES install-libLTLIBRARIES mostlyclean-compile \ +distclean-compile clean-compile maintainer-clean-compile \ +mostlyclean-libtool distclean-libtool clean-libtool \ +maintainer-clean-libtool uninstall-includeHEADERS \ +install-includeHEADERS tags mostlyclean-tags distclean-tags clean-tags \ +maintainer-clean-tags distdir mostlyclean-depend distclean-depend \ +clean-depend maintainer-clean-depend info-am info dvi-am dvi check \ +check-am installcheck-am installcheck install-exec-am install-exec \ +install-data-am install-data install-am install uninstall-am uninstall \ +all-redirect all-am all installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/libgstroke/README b/libgstroke/README new file mode 100644 index 0000000..f546fc3 --- /dev/null +++ b/libgstroke/README @@ -0,0 +1 @@ +See ../README.libgstroke diff --git a/libgstroke/TODO b/libgstroke/TODO new file mode 100644 index 0000000..1427876 --- /dev/null +++ b/libgstroke/TODO @@ -0,0 +1,11 @@ +TODO +----- + +Make gnome-stroke-draw.c:gstroke_invisible_window_init (GtkWidget *widget) +use Gtk+ primitives, not X11 primitives (no idea if this is even possible). + +Should the static vars gstroke_* in gnome_stroke_draw.c be moved to +stroke_metrics structure? + +Improve the autoconf macros. They should probably use the gnome +autoconf infrastructure. Help with this would be appreciated. diff --git a/libgstroke/gnome-stroke-draw.c b/libgstroke/gnome-stroke-draw.c new file mode 100644 index 0000000..79665fe --- /dev/null +++ b/libgstroke/gnome-stroke-draw.c @@ -0,0 +1,330 @@ +/* + GNOME stroke implementation + Copyright (c) 2000, 2001 Dan Nicolaescu + See the file COPYING for distribution information. +*/ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include +#include "gstroke.h" +#include "gstroke-internal.h" + +#include +#include + + +static void gstroke_invisible_window_init (GtkWidget *widget); +/*FIXME: Maybe these should be put in a structure, and not static...*/ +static Display * gstroke_disp; +static Window gstroke_window; +static GC gstroke_gc; + +#define GSTROKE_TIMEOUT_DURATION 10 + +#define GSTROKE_SIGNALS "gstroke_signals" + +struct gstroke_func_and_data { + GtkSignalFunc func; + gpointer data; +}; + + +/*FIXME: maybe it's better to just make 2 static variables, not a + structure */ +struct mouse_position { + struct s_point last_point; + gboolean invalid; +}; + + +static struct mouse_position last_mouse_position; +static guint timer_id; + +static void gstroke_execute (GtkWidget *widget, const gchar *name); + +static void +record_stroke_segment (GtkWidget *widget) +{ + gint x, y; + struct gstroke_metrics *metrics; + + gtk_widget_get_pointer (widget, &x, &y); + + if (last_mouse_position.invalid) + last_mouse_position.invalid = FALSE; + else + { +#if 1 + XDrawLine (gstroke_disp, gstroke_window, gstroke_gc, + last_mouse_position.last_point.x, + last_mouse_position.last_point.y, + x, y); + /* XFlush (gstroke_disp); */ +#else + /* FIXME: this does not work. It will only work if we create a + corresponding GDK window for stroke_window and draw on + that... */ + gdk_draw_line (widget->window, widget->style->fg_gc[GTK_STATE_NORMAL], + last_mouse_position.last_point.x, + last_mouse_position.last_point.y, + x, + y); +#endif + } + + if (last_mouse_position.last_point.x != x + || last_mouse_position.last_point.y != y) + { + last_mouse_position.last_point.x = x; + last_mouse_position.last_point.y = y; + metrics = + (struct gstroke_metrics*)gtk_object_get_data (GTK_OBJECT (widget), + GSTROKE_METRICS); + _gstroke_record (x, y, metrics); + } +} + +static gint +gstroke_timeout (gpointer data) +{ + GtkWidget *widget = GTK_WIDGET (data); + record_stroke_segment (widget); + + return TRUE; +} + +static gint +process_event (GtkWidget *widget, GdkEvent *event, gpointer data G_GNUC_UNUSED) +{ + static GtkWidget *original_widget = NULL; + switch (event->type) { + case GDK_BUTTON_PRESS: + if (event->button.button != GSTROKE_MOUSE_BUTTON) + break; + + original_widget = widget; /* remeber the widget where + the stroke started */ + + gstroke_invisible_window_init (widget); + + record_stroke_segment (widget); + + gdk_pointer_grab (widget->window, FALSE, + GDK_BUTTON_RELEASE_MASK, NULL, NULL, + event->button.time); + timer_id = gtk_timeout_add (GSTROKE_TIMEOUT_DURATION, + gstroke_timeout, widget); + return TRUE; + + case GDK_BUTTON_RELEASE: + if ((event->button.button != GSTROKE_MOUSE_BUTTON) + || (original_widget == NULL)) + /* the stroke probably did not start here... */ + break; + + last_mouse_position.invalid = TRUE; + original_widget = NULL; + gtk_timeout_remove (timer_id); + gdk_pointer_ungrab (event->button.time); + timer_id = 0; + + { + char result[GSTROKE_MAX_SEQUENCE]; + struct gstroke_metrics *metrics + = (struct gstroke_metrics*) gtk_object_get_data (GTK_OBJECT (widget), + GSTROKE_METRICS); + /* get rid of the invisible stroke window */ + XUnmapWindow (gstroke_disp, gstroke_window); + XFlush (gstroke_disp); + + _gstroke_canonical (result, metrics); + gstroke_execute (widget, result); + return FALSE; + } + return TRUE; + default: + break; + } + + return FALSE; +} + +void +gstroke_enable (GtkWidget *widget) +{ + struct gstroke_metrics* + metrics = (struct gstroke_metrics*)gtk_object_get_data (GTK_OBJECT (widget), + GSTROKE_METRICS); + if (metrics == NULL) + { + metrics = (struct gstroke_metrics *)g_malloc (sizeof + (struct gstroke_metrics)); + metrics->pointList = NULL; + metrics->min_x = 10000; + metrics->min_y = 10000; + metrics->max_x = 0; + metrics->max_y = 0; + metrics->point_count = 0; + + gtk_object_set_data (GTK_OBJECT (widget), GSTROKE_METRICS, + metrics); + + gtk_signal_connect (GTK_OBJECT (widget), "event", + (GtkSignalFunc) process_event, + NULL); + } + else + _gstroke_init (metrics); + + last_mouse_position.invalid = TRUE; +} + +guint +gstroke_signal_connect (GtkWidget *widget, + const gchar *name, + GtkSignalFunc func, + gpointer data) +{ + struct gstroke_func_and_data *func_and_data; + GHashTable *hash_table = + (GHashTable*)gtk_object_get_data (GTK_OBJECT (widget), GSTROKE_SIGNALS); + + if (!hash_table) + { + hash_table = g_hash_table_new (g_str_hash, g_str_equal); + gtk_object_set_data (GTK_OBJECT (widget), GSTROKE_SIGNALS, + (gpointer)hash_table); + } + func_and_data = g_new (struct gstroke_func_and_data, 1); + func_and_data->func = func; + func_and_data->data = data; + g_hash_table_insert (hash_table, (gpointer)name, (gpointer)func_and_data); + return TRUE; +} + +static void +gstroke_execute (GtkWidget *widget, const gchar *name) +{ + + GHashTable *hash_table = + (GHashTable*)gtk_object_get_data (GTK_OBJECT (widget), GSTROKE_SIGNALS); + +#ifdef DEBUG + printf ("gstroke %s\n", name); + fflush (stdout); +#endif + + if (hash_table) + { + struct gstroke_func_and_data *fd = + (struct gstroke_func_and_data*)g_hash_table_lookup (hash_table, name); + if (fd) + (*fd->func)(widget, fd->data); + } +} + +void +gstroke_cleanup (GtkWidget *widget) +{ + struct gstroke_metrics *metrics; + GHashTable *hash_table = + (GHashTable*)gtk_object_get_data (GTK_OBJECT (widget), GSTROKE_SIGNALS); + if (hash_table) + /* FIXME: does this delete the elements too? */ + g_hash_table_destroy (hash_table); + + gtk_object_remove_data (GTK_OBJECT (widget), GSTROKE_SIGNALS); + + metrics = (struct gstroke_metrics*)gtk_object_get_data (GTK_OBJECT (widget), + GSTROKE_METRICS); + if (metrics) + g_free (metrics); + gtk_object_remove_data (GTK_OBJECT (widget), GSTROKE_METRICS); +} + + +/* This function should be written using Gtk+ primitives*/ +static void +gstroke_invisible_window_init (GtkWidget *widget) +{ + XSetWindowAttributes w_attr; + XWindowAttributes orig_w_attr; + unsigned long mask, col_border, col_background; + unsigned int border_width; + XSizeHints hints; + Display *disp = GDK_WINDOW_XDISPLAY(widget->window); + Window wind = GDK_WINDOW_XWINDOW (widget->window); + int screen = DefaultScreen (disp); + + gstroke_disp = disp; + + /* X server should save what's underneath */ + XGetWindowAttributes (gstroke_disp, wind, &orig_w_attr); + hints.x = orig_w_attr.x; + hints.y = orig_w_attr.y; + hints.width = orig_w_attr.width; + hints.height = orig_w_attr.height; + mask = CWSaveUnder; + w_attr.save_under = True; + + /* inhibit all the decorations */ + mask |= CWOverrideRedirect; + w_attr.override_redirect = True; + + /* Don't set a background, transparent window */ + mask |= CWBackPixmap; + w_attr.background_pixmap = None; + + /* Default input window look */ + col_background = WhitePixel (gstroke_disp, screen); + + /* no border for the window */ +#ifdef DEBUG + border_width = 5; +#else + border_width = 0; +#endif + col_border = BlackPixel (gstroke_disp, screen); + + gstroke_window = XCreateSimpleWindow (gstroke_disp, wind, + 0, 0, + hints.width - 2 * border_width, + hints.height - 2 * border_width, + border_width, + col_border, col_background); + + gstroke_gc = XCreateGC (gstroke_disp, gstroke_window, 0, NULL); + + XSetFunction (gstroke_disp, gstroke_gc, GXinvert); + + XChangeWindowAttributes (gstroke_disp, gstroke_window, mask, &w_attr); + + XSetLineAttributes (gstroke_disp, gstroke_gc, 2, LineSolid, + CapButt, JoinMiter); + XMapRaised (gstroke_disp, gstroke_window); + +#if 0 + /*FIXME: is this call really needed? If yes, does it need the real + argc and argv? */ + hints.flags = PPosition | PSize; + XSetStandardProperties (gstroke_disp, gstroke_window, "gstroke_test", NULL, + (Pixmap)NULL, NULL, 0, &hints); + + + /* Receive the close window client message */ + { + /* FIXME: is this really needed? If yes, something should be done + with wmdelete...*/ + Atom wmdelete = XInternAtom (gstroke_disp, "WM_DELETE_WINDOW", + False); + XSetWMProtocols (gstroke_disp, gstroke_window, &wmdelete, True); + } +#endif +} diff --git a/libgstroke/gnome-stroke.c b/libgstroke/gnome-stroke.c new file mode 100644 index 0000000..0907310 --- /dev/null +++ b/libgstroke/gnome-stroke.c @@ -0,0 +1,289 @@ +/* + libgstroke - a GNOME stroke interface library + Copyright (c) 1996,1997,1998,1999,2000,2001 Mark F. Willey, ETLA Technical + + See the file COPYING for distribution information. + + This file contains the stroke recognition algorithm. +*/ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include "gstroke.h" +#include "gstroke-internal.h" + + +void +_gstroke_init (struct gstroke_metrics *metrics) +{ + if (metrics->pointList != NULL) { + /* FIXME: does this free the data too?*/ + g_slist_free (metrics->pointList); + metrics->pointList = NULL; + metrics->point_count = 0; + } +} + +/* figure out which bin the point falls in */ +static gint +_gstroke_bin (p_point point_p, gint bound_x_1, gint bound_x_2, + gint bound_y_1, gint bound_y_2) +{ + + gint bin_num = 1; + + if (point_p->x > bound_x_1) bin_num += 1; + if (point_p->x > bound_x_2) bin_num += 1; + if (point_p->y > bound_y_1) bin_num += 3; + if (point_p->y > bound_y_2) bin_num += 3; + + return bin_num; +} + +gint +_gstroke_trans (gchar *sequence, struct gstroke_metrics *metrics) +{ + GSList *crt_elem; + /* number of bins recorded in the stroke */ + guint sequence_count = 0; + + /* points-->sequence translation scratch variables */ + gint prev_bin = 0; + gint current_bin = 0; + gint bin_count = 0; + + /* flag indicating the start of a stroke - always count it in the sequence */ + gint first_bin = TRUE; + + /* bin boundary and size variables */ + gint delta_x, delta_y; + gint bound_x_1, bound_x_2; + gint bound_y_1, bound_y_2; + + + /* determine size of grid */ + delta_x = metrics->max_x - metrics->min_x; + delta_y = metrics->max_y - metrics->min_y; + + /* calculate bin boundary positions */ + bound_x_1 = metrics->min_x + (delta_x / 3); + bound_x_2 = metrics->min_x + 2 * (delta_x / 3); + + bound_y_1 = metrics->min_y + (delta_y / 3); + bound_y_2 = metrics->min_y + 2 * (delta_y / 3); + + if (delta_x > GSTROKE_SCALE_RATIO * delta_y) { + bound_y_1 = (metrics->max_y + metrics->min_y - delta_x) / 2 + (delta_x / 3); + bound_y_2 = (metrics->max_y + metrics->min_y - delta_x) / 2 + 2 * (delta_x / 3); + } else if (delta_y > GSTROKE_SCALE_RATIO * delta_x) { + bound_x_1 = (metrics->max_x + metrics->min_x - delta_y) / 2 + (delta_y / 3); + bound_x_2 = (metrics->max_x + metrics->min_x - delta_y) / 2 + 2 * (delta_y / 3); + } + +#if 0 + printf ("DEBUG:: point count: %d\n", metrics->point_count); + printf ("DEBUG:: metrics->min_x: %d\n", metrics->min_x); + printf ("DEBUG:: metrics->max_x: %d\n", metrics->max_x); + printf ("DEBUG:: metrics->min_y: %d\n", metrics->min_y); + printf ("DEBUG:: metrics->max_y: %d\n", metrics->max_y); + printf ("DEBUG:: delta_x: %d\n", delta_x); + printf ("DEBUG:: delta_y: %d\n", delta_y); + printf ("DEBUG:: bound_x_1: %d\n", bound_x_1); + printf ("DEBUG:: bound_x_2: %d\n", bound_x_2); + printf ("DEBUG:: bound_y_1: %d\n", bound_y_1); + printf ("DEBUG:: bound_y_2: %d\n", bound_y_2); +#endif + + /* + build string by placing points in bins, collapsing bins and + discarding those with too few points... */ + + crt_elem = metrics->pointList; + while (crt_elem != NULL) + { + /* figure out which bin the point falls in */ + + /*printf ("X = %d Y = %d\n", ((p_point)crt_elem->data)->x, + ((p_point)crt_elem->data)->y); */ + + + current_bin = _gstroke_bin ((p_point)crt_elem->data, bound_x_1, + bound_x_2, bound_y_1, bound_y_2); + + /* if this is the first point, consider it the previous bin, too. */ + if (prev_bin == 0) + prev_bin = current_bin; + + /*printf ("DEBUG:: current bin: %d x=%d y = %d\n", current_bin, + ((p_point)crt_elem->data)->x, + ((p_point)crt_elem->data)->y); */ + + if (prev_bin == current_bin) + bin_count++; + else { + /* we are moving to a new bin -- consider adding to the sequence */ + if ((bin_count > (metrics->point_count * GSTROKE_BIN_COUNT_PERCENT)) + || (first_bin == TRUE)) { + + //gchar val = '0' + prev_bin; + //printf ("%c", val);fflush (stdout); + //g_string_append (&sequence, &val); + + first_bin = FALSE; + sequence[sequence_count++] = '0' + prev_bin; + /* printf ("DEBUG:: adding sequence: %d\n", prev_bin); */ + + } + + /* restart counting points in the new bin */ + bin_count=0; + prev_bin = current_bin; + } + + /* move to next point, freeing current point from list */ + + free (crt_elem->data); + crt_elem = g_slist_next (crt_elem); + } + /* add the last run of points to the sequence */ + sequence[sequence_count++] = '0' + current_bin; + /* printf ("DEBUG:: adding final sequence: %d\n", current_bin); */ + + _gstroke_init (metrics); + + { + // FIXME: get rid of this block + //gchar val = '0' + current_bin; + //printf ("%c\n", val);fflush (stdout); + //g_string_append (&sequence, '\0'); + sequence[sequence_count] = '\0'; + } + + return TRUE; +} + +/* my plan is to make a stroke training program where you can enter all of +the variations of slop that map to a canonical set of strokes. When the +application calls gstroke_canonical, it gets one of the recognized strokes, +or "", if it's not a recognized variation. I will probably use a hash +table. Right now, it just passes the values through to gstroke_trans */ +gint +_gstroke_canonical (gchar *sequence, struct gstroke_metrics *metrics) +{ + return _gstroke_trans (sequence, metrics); +} + + +void +_gstroke_record (gint x, gint y, struct gstroke_metrics *metrics) +{ + p_point new_point_p; + gint delx, dely; + float ix, iy; + +#if 0 + printf ("%d:%d ", x, y); fflush (stdout); +#endif + + if (metrics->point_count < GSTROKE_MAX_POINTS) { + new_point_p = (p_point) g_malloc (sizeof (struct s_point)); + + if (metrics->pointList == NULL) { + + /* first point in list - initialize metrics */ + metrics->min_x = 10000; + metrics->min_y = 10000; + metrics->max_x = -1; + metrics->max_y = -1; + + metrics->pointList = (GSList*) g_malloc (sizeof (GSList)); + + metrics->pointList->data = new_point_p; + metrics->pointList->next = NULL; + metrics->point_count = 0; + + } else { + +#define LAST_POINT ((p_point)(g_slist_last (metrics->pointList)->data)) + + /* interpolate between last and current point */ + delx = x - LAST_POINT->x; + dely = y - LAST_POINT->y; + + if (abs(delx) > abs(dely)) { /* step by the greatest delta direction */ + iy = LAST_POINT->y; + + /* go from the last point to the current, whatever direction it may be */ + for (ix = LAST_POINT->x; (delx > 0) ? (ix < x) : (ix > x); ix += (delx > 0) ? 1 : -1) { + + /* step the other axis by the correct increment */ + iy += fabs(((float) dely / (float) delx)) * (float) ((dely < 0) ? -1.0 : 1.0); + + /* add the interpolated point */ + new_point_p->x = ix; + new_point_p->y = iy; + g_slist_append (metrics->pointList, new_point_p); + + /* update metrics */ + if (((gint) ix) < metrics->min_x) metrics->min_x = (gint) ix; + if (((gint) ix) > metrics->max_x) metrics->max_x = (gint) ix; + if (((gint) iy) < metrics->min_y) metrics->min_y = (gint) iy; + if (((gint) iy) > metrics->max_y) metrics->max_y = (gint) iy; + metrics->point_count++; + + new_point_p = (p_point) malloc (sizeof(struct s_point)); + } + } else { /* same thing, but for dely larger than delx case... */ + ix = LAST_POINT->x; + + /* go from the last point to the current, whatever direction it may be + */ + for (iy = LAST_POINT->y; (dely > 0) ? (iy < y) : (iy > y); iy += (dely > 0) ? 1 : -1) { + + /* step the other axis by the correct increment */ + ix += fabs(((float) delx / (float) dely)) * (float) ((delx < 0) ? -1.0 : 1.0); + + /* add the interpolated point */ + new_point_p->y = iy; + new_point_p->x = ix; + g_slist_append(metrics->pointList, new_point_p); + + /* update metrics */ + if (((gint) ix) < metrics->min_x) metrics->min_x = (gint) ix; + if (((gint) ix) > metrics->max_x) metrics->max_x = (gint) ix; + if (((gint) iy) < metrics->min_y) metrics->min_y = (gint) iy; + if (((gint) iy) > metrics->max_y) metrics->max_y = (gint) iy; + metrics->point_count++; + + new_point_p = (p_point) malloc (sizeof(struct s_point)); + } + } + + /* add the sampled point */ + g_slist_append(metrics->pointList, new_point_p); + } + + /* record the sampled point values */ + new_point_p->x = x; + new_point_p->y = y; + +#if 0 + { + GSList *crt = metrics->pointList; + printf ("Record "); + while (crt != NULL) + { + printf ("(%d,%d)", ((p_point)crt->data)->x, ((p_point)crt->data)->y); + crt = g_slist_next (crt); + } + printf ("\n"); + } +#endif + } +} diff --git a/libgstroke/gstroke-internal.h b/libgstroke/gstroke-internal.h new file mode 100644 index 0000000..4faaa89 --- /dev/null +++ b/libgstroke/gstroke-internal.h @@ -0,0 +1,41 @@ +/* This file is to be used internally by the libgstroke implementation. + It should not be installed or used elsewhere. + + See the file COPYING for distribution information. +*/ + +#ifndef _GSTROKE_INTERNAL_H_ +#define _GSTROKE_INTERNAL_H_ + +/* metrics for stroke, they are used while processing a stroke, this + structure should be stored in local widget storage */ +struct gstroke_metrics { + GSList *pointList; /* point list */ + gint min_x; + gint min_y; + gint max_x; + gint max_y; + gint point_count; +}; + +#define GSTROKE_METRICS "gstroke_metrics" + +/* translate stroke to sequence */ +gint _gstroke_trans (gchar *sequence, struct gstroke_metrics *metrics); +gint _gstroke_canonical (gchar* sequence, struct gstroke_metrics *metrics); + +/* record point in stroke */ +void _gstroke_record (gint x, gint y, struct gstroke_metrics *metrics); + +/* initialize stroke functions */ +void _gstroke_init (struct gstroke_metrics*); + +/* structure for holding point data */ +struct s_point { + gint x; + gint y; +}; + +typedef struct s_point *p_point; + +#endif diff --git a/libgstroke/gstroke.h b/libgstroke/gstroke.h new file mode 100644 index 0000000..fc5413a --- /dev/null +++ b/libgstroke/gstroke.h @@ -0,0 +1,43 @@ +/* + libgstroke - a GNOME stroke interface library + Copyright (c) 1996,1997,1998,1999,2000,2001 Mark F. Willey, ETLA Technical + + See the file COPYING for distribution information. +*/ + +/* largest number of points allowed to be sampled */ +#ifndef _GSTROKE_H_ +#define _GSTROKE_H_ + +#define GSTROKE_MAX_POINTS 10000 + +/* number of sample points required to have a valid stroke */ +#define GSTROKE_MIN_POINTS 50 + +/* maximum number of numbers in stroke */ +#define GSTROKE_MAX_SEQUENCE 32 + +/* threshold of size of smaller axis needed for it to define its own + bin size */ +#define GSTROKE_SCALE_RATIO 4 + +/* minimum percentage of points in bin needed to add to sequence */ +#define GSTROKE_BIN_COUNT_PERCENT 0.07 + + +/* the mouse button used for strokes */ +#define GSTROKE_MOUSE_BUTTON 2 + +/* enable strokes for the widget */ +void gstroke_enable (GtkWidget *widget); + +guint gstroke_signal_connect (GtkWidget *widget, + const gchar *name, + GtkSignalFunc func, + gpointer data); + +/* frees all the memory allocated for stroke, should be called when + the widget is destroyed*/ +void gstroke_cleanup (GtkWidget *widget); + +#endif -- cgit v1.2.3