From 83340c17f7430b6edeb4c285517934e94a2f56e9 Mon Sep 17 00:00:00 2001 From: Kibum Kim Date: Sat, 7 Jan 2012 01:10:16 +0900 Subject: Git init --- COPYING | 21 + ChangeLog | 0 Makefile.am | 40 + autogen.sh | 13 + configure.ac | 77 + debian/changelog | 37 + debian/compat | 1 + debian/control | 21 + debian/rules | 105 ++ debian/xserver-xorg-input-gesture.install | 2 + debian/xsfbs/repack.sh | 32 + debian/xsfbs/xsfbs.mk | 293 ++++ debian/xsfbs/xsfbs.sh | 853 ++++++++++ man/Makefile.am | 57 + man/gesture.man | 29 + packaging/xorg-x11-drv-input-gesture.spec | 48 + src/Makefile.am | 37 + src/gesture.c | 2560 +++++++++++++++++++++++++++++ src/gesture.h | 378 +++++ xorg-gesture.pc.in | 6 + 20 files changed, 4610 insertions(+) create mode 100755 COPYING create mode 100644 ChangeLog create mode 100644 Makefile.am create mode 100755 autogen.sh create mode 100644 configure.ac create mode 100755 debian/changelog create mode 100644 debian/compat create mode 100644 debian/control create mode 100755 debian/rules create mode 100644 debian/xserver-xorg-input-gesture.install create mode 100644 debian/xsfbs/repack.sh create mode 100644 debian/xsfbs/xsfbs.mk create mode 100644 debian/xsfbs/xsfbs.sh create mode 100644 man/Makefile.am create mode 100644 man/gesture.man create mode 100644 packaging/xorg-x11-drv-input-gesture.spec create mode 100644 src/Makefile.am create mode 100755 src/gesture.c create mode 100755 src/gesture.h create mode 100644 xorg-gesture.pc.in diff --git a/COPYING b/COPYING new file mode 100755 index 0000000..8f6ba4b --- /dev/null +++ b/COPYING @@ -0,0 +1,21 @@ +Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is fur- +nished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- +NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON- +NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + + diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..e69de29 diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..50ddc5b --- /dev/null +++ b/Makefile.am @@ -0,0 +1,40 @@ +# Copyright 2007 Peter Hutterer +# Copyright 2009 Przemysław Firszt +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# on the rights to use, copy, modify, merge, publish, distribute, sub +# license, and/or sell copies of the Software, and to permit persons to whom +# the Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice (including the next +# paragraph) shall be included in all copies or substantial portions of the +# Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +# ADAM JACKSON BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +AUTOMAKE_OPTIONS = foreign + +# Ensure headers are installed below $(prefix) for distcheck +DISTCHECK_CONFIGURE_FLAGS = --with-sdkdir='$${includedir}/xorg' + +SUBDIRS = src man + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = xorg-gesture.pc + +EXTRA_DIST = ChangeLog + +MAINTAINERCLEANFILES=ChangeLog + +.PHONY: ChangeLog + +ChangeLog: + $(CHANGELOG_CMD) + +dist-hook: ChangeLog diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..0aad669 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,13 @@ +#! /bin/sh + +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +ORIGDIR=`pwd` +cd $srcdir + +autoreconf -v --install || exit 1 +cd $ORIGDIR || exit $? + +#$srcdir/configure --enable-maintainer-mode "$@" +#$srcdir/configure --prefix=/usr --enable-maintainer-mode "$@" diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..2aff572 --- /dev/null +++ b/configure.ac @@ -0,0 +1,77 @@ +# Copyright 2007 Peter Hutterer +# Copyright 2009 Przemysław Firszt +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# on the rights to use, copy, modify, merge, publish, distribute, sub +# license, and/or sell copies of the Software, and to permit persons to whom +# the Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice (including the next +# paragraph) shall be included in all copies or substantial portions of the +# Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +# AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Process this file with autoconf to produce a configure script + +AC_PREREQ(2.57) +AC_INIT([xf86-input-gesture], + 0.0.1, + [https://bugs.freedesktop.org/enter_bug.cgi?product=xorg], + xf86-input-gesture) + +AC_CONFIG_SRCDIR([Makefile.am]) +AC_CONFIG_AUX_DIR(.) +AM_INIT_AUTOMAKE([dist-bzip2]) + +AM_MAINTAINER_MODE + +# Require xorg-macros: XORG_DEFAULT_OPTIONS +m4_ifndef([XORG_MACROS_VERSION], [AC_FATAL([must install xorg-macros 1.3 or later before running autoconf/autogen])]) +XORG_MACROS_VERSION(1.3) +AM_CONFIG_HEADER([config.h]) + +# Checks for programs. +AC_DISABLE_STATIC +AC_PROG_LIBTOOL +AC_PROG_CC +XORG_DEFAULT_OPTIONS + +AH_TOP([#include "xorg-server.h"]) + +AC_ARG_WITH(xorg-module-dir, + AC_HELP_STRING([--with-xorg-module-dir=DIR], + [Default xorg module directory [[default=$libdir/xorg/modules]]]), + [moduledir="$withval"], + [moduledir="$libdir/xorg/modules"]) +inputdir=${moduledir}/input +AC_SUBST(inputdir) + +# Checks for pkg-config packages. We need to be able to override sdkdir +# to satisfy silly distcheck requirements. +PKG_CHECK_MODULES(XORG, xorg-server xproto $REQUIRED_MODULES) +XORG_CFLAGS="$CWARNFLAGS $XORG_CFLAGS" +AC_ARG_WITH([sdkdir], [], + [sdkdir="$withval"], + [sdkdir=`$PKG_CONFIG --variable=sdkdir xorg-server`]) +AC_SUBST([sdkdir]) + +# Checks for libraries. + +# Checks for header files. +AC_HEADER_STDC + +DRIVER_NAME=gesture +AC_SUBST([DRIVER_NAME]) + +AC_OUTPUT([Makefile + src/Makefile + man/Makefile + xorg-gesture.pc]) diff --git a/debian/changelog b/debian/changelog new file mode 100755 index 0000000..f45efac --- /dev/null +++ b/debian/changelog @@ -0,0 +1,37 @@ +xserver-xorg-input-gesture (0.1.0-4) unstable; urgency=low + + * Exception handling routine added. This commit is to fix Xorg BS problem at booting time. + * Git: 165.213.180.234:slp/pkgs/xorg/driver/xserver-xorg-input-gesture + * Tag: xserver-xorg-input-gesture_0.1.0-4 + + -- Sung-Jin Park Mon, 28 Nov 2011 15:20:14 +0900 + +xserver-xorg-input-gesture (0.1.0-3) unstable; urgency=low + + * Define ErrorStatus and check up error status at important check points + Fix GestureEventsFlush() not to modify timestamp of each event + Remove unnecessary modification and remove unused code + Remove unused macro from gesture.h + Remove whitespace and fix indentation + Replace GestureEventsFree() with GestureEventsDrop() + * Git: 165.213.180.234:slp/pkgs/xorg/driver/xserver-xorg-input-gesture + * Tag: xserver-xorg-input-gesture_0.1.0-3 + + -- Sung-Jin Park Mon, 21 Nov 2011 22:51:22 +0900 + +xserver-xorg-input-gesture (0.1.0-2) unstable; urgency=low + + * add null check + * Git: 165.213.180.234:slp/pkgs/xorg/driver/xserver-xorg-input-gesture + * Tag: xserver-xorg-input-gesture_0.1.0-2 + + -- SooChan Lim Tue, 08 Nov 2011 12:44:49 +0900 + +xserver-xorg-input-gesture (0.1.0-1) unstable; urgency=low + + * Initial version + * Git: 165.213.180.234:slp/pkgs/xorg/driver/xserver-xorg-input-gesture + * Tag: xserver-xorg-input-gesture_0.1.0-1 + + -- Sung-Jin Park Wed, 19 Oct 2011 17:13:15 +0900 + diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..7ed6ff8 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +5 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..aeced7a --- /dev/null +++ b/debian/control @@ -0,0 +1,21 @@ +Source: xserver-xorg-input-gesture +Section: x11 +Priority: optional +Maintainer: Sung-Jin Park , Sangjin Lee +Uploaders: Sung-Jin Park +Build-Depends: debhelper (>= 5.0.0), pkg-config, quilt, xserver-xorg-dev (>= 1.9.3-19slp2), x11proto-core-dev, dpkg-dev (>= 1.14.17), automake, libtool, xutils-dev (>= 1:7.3~1), libpixman-1-dev, x11proto-gesture-dev (>= 0.1.0-1) +#Build-Depends: debhelper (>= 5.0.0), pkg-config, quilt, xserver-xorg-dev (>= 1.6.99.900), x11proto-core-dev, x11proto-randr-dev, x11proto-input-dev, x11proto-kb-dev, libxkbfile-dev, dpkg-dev (>= 1.14.17), automake, libtool, xutils-dev (>= 1:7.3~1) +Standards-Version: 3.8.3 + +Package: xserver-xorg-input-gesture +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, ${xserver} +Provides: ${xinpdriver:Provides} +Description: X.Org X server -- Xserver gesture driver + This package provides the driver for recognizing gesture(s) using button + and motion events inside X server. + +Package: xserver-xorg-input-gesture-dbg +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, ${xserver}, xserver-xorg-input-gesture (=${Source-Version}) +Description: Debug package of xserver-xorg-input-gesture diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..dd236a7 --- /dev/null +++ b/debian/rules @@ -0,0 +1,105 @@ +#!/usr/bin/make -f +# debian/rules for the Debian xserver-xorg-input-gesture package. +# Copyright © 2004 Scott James Remnant +# Copyright © 2005 Daniel Stone +# Copyright © 2005 David Nusinow + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +include debian/xsfbs/xsfbs.mk + +CFLAGS = -Wall -g +LDFLAGS += -Wl,--hash-style=both -Wl,--as-needed +ifneq (,$(filter noopt,$(DEB_BUILD_OPTIONS))) + CFLAGS += -O0 +else + CFLAGS += -O2 +endif +ifneq (,$(filter parallel=%,$(DEB_BUILD_OPTIONS))) + NUMJOBS = $(patsubst parallel=%,%,$(filter parallel=%,$(DEB_BUILD_OPTIONS))) + MAKEFLAGS += -j$(NUMJOBS) +endif + +DEB_HOST_ARCH ?= $(shell dpkg-architecture -qDEB_HOST_ARCH) +DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) +DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) +ifeq ($(DEB_BUILD_GNU_TYPE), $(DEB_HOST_GNU_TYPE)) + confflags += --build=$(DEB_HOST_GNU_TYPE) +else + confflags += --build=$(DEB_HOST_GNU_TYPE) --host=$(DEB_HOST_GNU_TYPE) +# confflags += --build=$(DEB_BUILD_GNU_TYPE) --host=$(DEB_HOST_GNU_TYPE) +endif + +# kbd_drv.a isn't phenomenally useful; kbd_drv.so more so +confflags += --disable-static + +#configure: $(STAMP_DIR)/patch +configure: + autoreconf -vfi + #./autogen.sh + +obj-$(DEB_BUILD_GNU_TYPE)/config.status: configure + mkdir -p obj-$(DEB_BUILD_GNU_TYPE) + cd obj-$(DEB_BUILD_GNU_TYPE) && \ + ../configure --prefix=/usr --mandir=\$${prefix}/share/man \ + --infodir=\$${prefix}/share/info $(confflags) \ + CFLAGS="$(CFLAGS)" \ + LDFLAGS="$(LDFLAGS)" + +build: build-stamp +build-stamp: obj-$(DEB_BUILD_GNU_TYPE)/config.status + dh_testdir + cd obj-$(DEB_BUILD_GNU_TYPE) && $(MAKE) + >$@ + +clean: xsfclean + dh_testdir + dh_testroot + rm -f build-stamp + + rm -f config.cache config.log config.status + rm -f */config.cache */config.log */config.status + rm -f conftest* */conftest* + rm -rf autom4te.cache */autom4te.cache + rm -rf obj-* + rm -f $$(find -name Makefile.in) + rm -f compile config.guess config.sub configure depcomp install-sh + rm -f ltmain.sh missing INSTALL aclocal.m4 ylwrap mkinstalldirs config.h.in + + dh_clean + +install: build + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs + + cd obj-$(DEB_BUILD_GNU_TYPE) && $(MAKE) DESTDIR=$(CURDIR)/debian/tmp install + +# Build architecture-dependent files here. +binary-arch: build install serverabi + dh_testdir + dh_testroot + + dh_installdocs + dh_installchangelogs ChangeLog + dh_install --sourcedir=debian/tmp --list-missing --exclude=usr/share/man/man4 + dh_installman + dh_link + dh_strip --dbg-package=xserver-xorg-input-gesture-dbg + dh_compress + dh_fixperms + dh_installdeb +# dh_shlibdeps -- --warnings=6 + dh_shlibdeps -- + dh_gencontrol + dh_md5sums + dh_builddeb + +# Build architecture-independent files here. +binary-indep: build install +# Nothing to do + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install diff --git a/debian/xserver-xorg-input-gesture.install b/debian/xserver-xorg-input-gesture.install new file mode 100644 index 0000000..1002d70 --- /dev/null +++ b/debian/xserver-xorg-input-gesture.install @@ -0,0 +1,2 @@ +usr/lib/xorg/modules/input/*.so +usr/lib/xorg/modules/input/*.la diff --git a/debian/xsfbs/repack.sh b/debian/xsfbs/repack.sh new file mode 100644 index 0000000..5935cc9 --- /dev/null +++ b/debian/xsfbs/repack.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +set -e + +if ! [ -d debian/prune ]; then + exit 0 +fi + +if [ "x$1" != x--upstream-version ]; then + exit 1 +fi + +version="$2" +filename="$3" + +if [ -z "$version" ] || ! [ -f "$filename" ]; then + exit 1 +fi + +dir="$(pwd)" +tempdir="$(mktemp -d)" + +cd "$tempdir" +tar xf "$dir/$filename" +cat "$dir"/debian/prune/* | while read file; do rm -f */$file; done + +tar czf "$dir/$filename" * +cd "$dir" +rm -rf "$tempdir" +echo "Done pruning upstream tarball" + +exit 0 diff --git a/debian/xsfbs/xsfbs.mk b/debian/xsfbs/xsfbs.mk new file mode 100644 index 0000000..f0f8953 --- /dev/null +++ b/debian/xsfbs/xsfbs.mk @@ -0,0 +1,293 @@ +#!/usr/bin/make -f + +# Debian X Strike Force Build System (XSFBS): Make portion + +# Copyright 1996 Stephen Early +# Copyright 1997 Mark Eichin +# Copyright 1998-2005, 2007 Branden Robinson +# Copyright 2005 David Nusinow +# +# Licensed under the GNU General Public License, version 2. See the file +# /usr/share/common-licenses/GPL or . + +# Originally by Stephen Early +# Modified by Mark W. Eichin +# Modified by Adam Heath +# Modified by Branden Robinson +# Modified by Fabio Massimo Di Nitto +# Modified by David Nusinow +# Acknowledgements to Manoj Srivastava. + +# Pass $(DH_OPTIONS) into the environment for debhelper's benefit. +export DH_OPTIONS + +# force quilt to not use ~/.quiltrc and to use debian/patches +QUILT = QUILT_PATCHES=debian/patches quilt --quiltrc /dev/null + +# Set up parameters for the upstream build environment. + +# Determine (source) package name from Debian changelog. +SOURCE_NAME:=$(shell dpkg-parsechangelog -ldebian/changelog \ + | grep '^Source:' | awk '{print $$2}') + +# Determine package version from Debian changelog. +SOURCE_VERSION:=$(shell dpkg-parsechangelog -ldebian/changelog \ + | grep '^Version:' | awk '{print $$2}') + +# Determine upstream version number. +UPSTREAM_VERSION:=$(shell echo $(SOURCE_VERSION) | sed 's/-.*//') + +# Determine the source version without the epoch for make-orig-tar-gz +NO_EPOCH_VER:=$(shell echo $(UPSTREAM_VERSION) | sed 's/^.://') + +# Figure out who's building this package. +BUILDER:=$(shell echo $${DEBEMAIL:-$${EMAIL:-$$(echo $$LOGNAME@$$(cat /etc/mailname 2>/dev/null))}}) + +# Find out if this is an official build; an official build has nothing but +# digits, dots, and/or the codename of a release in the Debian part of the +# version number. Anything else indicates an unofficial build. +OFFICIAL_BUILD:=$(shell VERSION=$(SOURCE_VERSION); if ! expr "$$(echo $${VERSION\#\#*-} | sed 's/\(woody\|sarge\|etch\|lenny\)//g')" : ".*[^0-9.].*" >/dev/null 2>&1; then echo yes; fi) + +# Set up parameters for the Debian build environment. + +# Determine our architecture. +BUILD_ARCH:=$(shell dpkg-architecture -qDEB_BUILD_ARCH) +# Work around some old-time dpkg braindamage. +BUILD_ARCH:=$(subst i486,i386,$(BUILD_ARCH)) +# The DEB_HOST_ARCH variable may be set per the Debian cross-compilation policy. +ifdef DEB_HOST_ARCH + ARCH:=$(DEB_HOST_ARCH) +else + # dpkg-cross sets the ARCH environment variable; if set, use it. + ifdef ARCH + ARCH:=$(ARCH) + else + ARCH:=$(BUILD_ARCH) + endif +endif + +# $(STAMP_DIR) houses stamp files for complex targets. +STAMP_DIR:=stampdir + +# $(DEBTREEDIR) is where all install rules are told (via $(DESTDIR)) to place +# their files. +DEBTREEDIR:=$(CURDIR)/debian/tmp + +# All "important" targets have four lines: +# 1) A target name that is invoked by a package-building tool or the user. +# This consists of a dependency on a "$(STAMP_DIR)/"-prefixed counterpart. +# 2) A line delcaring 1) as a phony target (".PHONY:"). +# 3) A "$(STAMP_DIR)/"-prefixed target which does the actual work, and may +# depend on other targets. +# 4) A line declaring 3) as a member of the $(stampdir_targets) variable; the +# "$(STAMP_DIR)/" prefix is omitted. +# +# This indirection is needed so that the "stamp" files that signify when a rule +# is done can be located in a separate "stampdir". Recall that make has no way +# to know when a goal has been met for a phony target (like "build" or +# "install"). +# +# At the end of each "$(STAMP_DIR)/" target, be sure to run the command ">$@" +# so that the target will not be run again. Removing the file will make Make +# run the target over. + +# All phony targets should be declared as dependencies of .PHONY, even if they +# do not have "($STAMP_DIR)/"-prefixed counterparts. + +# Define a harmless default rule to keep things from going nuts by accident. +.PHONY: default +default: + +# Set up the $(STAMP_DIR) directory. +.PHONY: stampdir +stampdir_targets+=stampdir +stampdir: $(STAMP_DIR)/stampdir +$(STAMP_DIR)/stampdir: + mkdir $(STAMP_DIR) + >$@ + +# Set up the package build directory as quilt expects to find it. +.PHONY: prepare +stampdir_targets+=prepare +prepare: $(STAMP_DIR)/prepare +$(STAMP_DIR)/prepare: $(STAMP_DIR)/log $(STAMP_DIR)/genscripts + >$@ + +.PHONY: log +stampdir_targets+=log +log: $(STAMP_DIR)/log +$(STAMP_DIR)/log: $(STAMP_DIR)/stampdir + mkdir -p $(STAMP_DIR)/log + +# Apply all patches to the upstream source. +.PHONY: patch +stampdir_targets+=patch +patch: $(STAMP_DIR)/patch +$(STAMP_DIR)/patch: $(STAMP_DIR)/prepare + if ! [ `which quilt` ]; then \ + echo "Couldn't find quilt. Please install it or add it to the build-depends for this package."; \ + exit 1; \ + fi; \ + if $(QUILT) next >/dev/null 2>&1; then \ + echo -n "Applying patches..."; \ + if $(QUILT) push -a -v >$(STAMP_DIR)/log/patch 2>&1; then \ + cat $(STAMP_DIR)/log/patch; \ + echo "successful."; \ + else \ + cat $(STAMP_DIR)/log/patch; \ + echo "failed! (check $(STAMP_DIR)/log/patch for details)"; \ + exit 1; \ + fi; \ + else \ + echo "No patches to apply"; \ + fi; \ + >$@ + +# Revert all patches to the upstream source. +.PHONY: unpatch +unpatch: $(STAMP_DIR)/log + rm -f $(STAMP_DIR)/patch + @echo -n "Unapplying patches..."; \ + if $(QUILT) applied >/dev/null 2>/dev/null; then \ + if $(QUILT) pop -a -v >$(STAMP_DIR)/log/unpatch 2>&1; then \ + cat $(STAMP_DIR)/log/unpatch; \ + echo "successful."; \ + else \ + cat $(STAMP_DIR)/log/unpatch; \ + echo "failed! (check $(STAMP_DIR)/log/unpatch for details)"; \ + exit 1; \ + fi; \ + else \ + echo "nothing to do."; \ + fi + +# Clean the generated maintainer scripts. +.PHONY: cleanscripts +cleanscripts: + rm -f $(STAMP_DIR)/genscripts + rm -f debian/*.config \ + debian/*.postinst \ + debian/*.postrm \ + debian/*.preinst \ + debian/*.prerm + +# Clean the package build tree. +.PHONY: xsfclean +xsfclean: cleanscripts unpatch + dh_testdir + rm -rf .pc + rm -rf $(STAMP_DIR) $(SOURCE_DIR) + rm -rf imports + dh_clean debian/shlibs.local \ + debian/po/pothead + +# Generate the debconf templates POT file header. +debian/po/pothead: debian/po/pothead.in + sed -e 's/SOURCE_VERSION/$(SOURCE_VERSION)/' \ + -e 's/DATE/$(shell date "+%F %X%z"/)' <$< >$@ + +# Update POT and PO files. +.PHONY: updatepo +updatepo: debian/po/pothead + debian/scripts/debconf-updatepo --pot-header=pothead --verbose + +# Remove files from the upstream source tree that we don't need, or which have +# licensing problems. It must be run before creating the .orig.tar.gz. +# +# Note: This rule is for Debian package maintainers' convenience, and is not +# needed for conventional build scenarios. +.PHONY: prune-upstream-tree +prune-upstream-tree: + # Ensure we're in the correct directory. + dh_testdir + grep -rvh '^#' debian/prune/ | xargs --no-run-if-empty rm -rf + +# Verify that there are no offsets or fuzz in the patches we apply. +# +# Note: This rule is for Debian package maintainers' convenience, and is not +# needed for conventional build scenarios. +.PHONY: patch-audit +patch-audit: prepare unpatch + @echo -n "Auditing patches..."; \ + >$(STAMP_DIR)/log/patch; \ + FUZZY=; \ + while [ -n "$$($(QUILT) next)" ]; do \ + RESULT=$$($(QUILT) push -v | tee -a $(STAMP_DIR)/log/patch | grep ^Hunk | sed 's/^Hunk.*\(succeeded\|FAILED\).*/\1/');\ + case "$$RESULT" in \ + succeeded) \ + echo "fuzzy patch: $$($(QUILT) top)" \ + | tee -a $(STAMP_DIR)/log/$$($(QUILT) top); \ + FUZZY=yes; \ + ;; \ + FAILED) \ + echo "broken patch: $$($(QUILT) next)" \ + | tee -a $(STAMP_DIR)/log/$$($(QUILT) next); \ + exit 1; \ + ;; \ + esac; \ + done; \ + if [ -n "$$FUZZY" ]; then \ + echo "there were fuzzy patches; please fix."; \ + exit 1; \ + else \ + echo "done."; \ + fi + +# Generate the maintainer scripts. +.PHONY: genscripts +stampdir_targets+=genscripts +genscripts: $(STAMP_DIR)/genscripts +$(STAMP_DIR)/genscripts: $(STAMP_DIR)/stampdir + for FILE in debian/*.config.in \ + debian/*.postinst.in \ + debian/*.postrm.in \ + debian/*.preinst.in \ + debian/*.prerm.in; do \ + if [ -e "$$FILE" ]; then \ + MAINTSCRIPT=$$(echo $$FILE | sed 's/.in$$//'); \ + sed -n '1,/^#INCLUDE_SHELL_LIB#$$/p' <$$FILE \ + | sed -e '/^#INCLUDE_SHELL_LIB#$$/d' >$$MAINTSCRIPT.tmp; \ + cat debian/xsfbs/xsfbs.sh >>$$MAINTSCRIPT.tmp; \ + sed -n '/^#INCLUDE_SHELL_LIB#$$/,$$p' <$$FILE \ + | sed -e '/^#INCLUDE_SHELL_LIB#$$/d' >>$$MAINTSCRIPT.tmp; \ + sed -e 's/@SOURCE_VERSION@/$(SOURCE_VERSION)/' \ + -e 's/@OFFICIAL_BUILD@/$(OFFICIAL_BUILD)/' \ + -e 's/@DEFAULT_DCRESOLUTIONS@/$(DEFAULT_DCRESOLUTIONS)/' \ + <$$MAINTSCRIPT.tmp >$$MAINTSCRIPT; \ + rm $$MAINTSCRIPT.tmp; \ + fi; \ + done + # Validate syntax of generated shell scripts. + #sh debian/scripts/validate-posix-sh debian/*.config \ + # debian/*.postinst \ + # debian/*.postrm \ + # debian/*.preinst \ + # debian/*.prerm + >$@ + +# Generate the shlibs.local file. +debian/shlibs.local: + cat debian/*.shlibs >$@ + +SERVERMINVERS = $(shell cat /usr/share/xserver-xorg/serverminver 2>/dev/null) +VIDEOABI = $(shell cat /usr/share/xserver-xorg/videoabiver 2>/dev/null) +INPUTABI = $(shell cat /usr/share/xserver-xorg/inputabiver 2>/dev/null) +SERVER_DEPENDS = xserver-xorg-core (>= $(SERVERMINVERS)) +VIDDRIVER_PROVIDES = xserver-xorg-video-$(VIDEOABI) +INPDRIVER_PROVIDES = xserver-xorg-input-$(INPUTABI) +ifeq ($(PACKAGE),) +PACKAGE=$(shell awk '/^Package:/ { print $$2; exit }' < debian/control) +endif + +.PHONY: serverabi +serverabi: install +ifeq ($(SERVERMINVERS),) + @echo error: xserver-xorg-dev needs to be installed + @exit 1 +else + echo "xserver:Depends=$(SERVER_DEPENDS)" >> debian/$(PACKAGE).substvars + echo "xviddriver:Provides=$(VIDDRIVER_PROVIDES)" >> debian/$(PACKAGE).substvars + echo "xinpdriver:Provides=$(INPDRIVER_PROVIDES)" >> debian/$(PACKAGE).substvars +endif + +# vim:set noet ai sts=8 sw=8 tw=0: diff --git a/debian/xsfbs/xsfbs.sh b/debian/xsfbs/xsfbs.sh new file mode 100644 index 0000000..781826f --- /dev/null +++ b/debian/xsfbs/xsfbs.sh @@ -0,0 +1,853 @@ +# $Id$ + +# This is the X Strike Force shell library for X Window System package +# maintainer scripts. It serves to define shell functions commonly used by +# such packages, and performs some error checking necessary for proper operation +# of those functions. By itself, it does not "do" much; the maintainer scripts +# invoke the functions defined here to accomplish package installation and +# removal tasks. + +# If you are reading this within a Debian package maintainer script (e.g., +# /var/lib/dpkg)info/PACKAGE.{config,preinst,postinst,prerm,postrm}), you can +# skip past this library by scanning forward in this file to the string +# "GOBSTOPPER". + +SOURCE_VERSION=@SOURCE_VERSION@ +OFFICIAL_BUILD=@OFFICIAL_BUILD@ + +# Use special abnormal exit codes so that problems with this library are more +# easily tracked down. +SHELL_LIB_INTERNAL_ERROR=86 +SHELL_LIB_THROWN_ERROR=74 +SHELL_LIB_USAGE_ERROR=99 + +# old -> new variable names +if [ -z "$DEBUG_XORG_PACKAGE" ] && [ -n "$DEBUG_XFREE86_PACKAGE" ]; then + DEBUG_XORG_PACKAGE="$DEBUG_XFREE86_PACKAGE" +fi +if [ -z "$DEBUG_XORG_DEBCONF" ] && [ -n "$DEBUG_XFREE86_DEBCONF" ]; then + DEBUG_XORG_DEBCONF="$DEBUG_XFREE86_DEBCONF" +fi + +# initial sanity checks +if [ -z "$THIS_PACKAGE" ]; then + cat >&2 < on the World Wide Web for +instructions, read the file /usr/share/doc/debian/bug-reporting.txt from the +"doc-debian" package, or install the "reportbug" package and use the command of +the same name to file a report against version $SOURCE_VERSION of this package. +EOF + exit $SHELL_LIB_USAGE_ERROR +fi + +if [ -z "$THIS_SCRIPT" ]; then + cat >&2 < on the World Wide Web for +instructions, read the file /usr/share/doc/debian/bug-reporting.txt from the +"doc-debian" package, or install the "reportbug" package and use the command of +the same name to file a report against version $SOURCE_VERSION of the +"$THIS_PACKAGE" package. +EOF + exit $SHELL_LIB_USAGE_ERROR +fi + +if [ "$1" = "reconfigure" ] || [ -n "$DEBCONF_RECONFIGURE" ]; then + RECONFIGURE="true" +else + RECONFIGURE= +fi + +if ([ "$1" = "install" ] || [ "$1" = "configure" ]) && [ -z "$2" ]; then + FIRSTINST="yes" +fi + +if [ -z "$RECONFIGURE" ] && [ -z "$FIRSTINST" ]; then + UPGRADE="yes" +fi + +trap "message;\ + message \"Received signal. Aborting $THIS_PACKAGE package $THIS_SCRIPT script.\";\ + message;\ + exit 1" HUP INT QUIT TERM + +reject_nondigits () { + # syntax: reject_nondigits [ operand ... ] + # + # scan operands (typically shell variables whose values cannot be trusted) for + # characters other than decimal digits and barf if any are found + while [ -n "$1" ]; do + # does the operand contain anything but digits? + if ! expr "$1" : "[[:digit:]]\+$" > /dev/null 2>&1; then + # can't use die(), because it wraps message() which wraps this function + echo "$THIS_PACKAGE $THIS_SCRIPT error: reject_nondigits() encountered" \ + "possibly malicious garbage \"$1\"" >&2 + exit $SHELL_LIB_THROWN_ERROR + fi + shift + done +} + +reject_whitespace () { + # syntax: reject_whitespace [ operand ] + # + # scan operand (typically a shell variable whose value cannot be trusted) for + # whitespace characters and barf if any are found + if [ -n "$1" ]; then + # does the operand contain any whitespace? + if expr "$1" : "[[:space:]]" > /dev/null 2>&1; then + # can't use die(), because I want to avoid forward references + echo "$THIS_PACKAGE $THIS_SCRIPT error: reject_whitespace() encountered" \ + "possibly malicious garbage \"$1\"" >&2 + exit $SHELL_LIB_THROWN_ERROR + fi + fi +} + +reject_unlikely_path_chars () { + # syntax: reject_unlikely_path_chars [ operand ... ] + # + # scan operands (typically shell variables whose values cannot be trusted) for + # characters unlikely to be seen in a path and which the shell might + # interpret and barf if any are found + while [ -n "$1" ]; do + # does the operand contain any funny characters? + if expr "$1" : '.*[!$&()*;<>?|].*' > /dev/null 2>&1; then + # can't use die(), because I want to avoid forward references + echo "$THIS_PACKAGE $THIS_SCRIPT error: reject_unlikely_path_chars()" \ + "encountered possibly malicious garbage \"$1\"" >&2 + exit $SHELL_LIB_THROWN_ERROR + fi + shift + done +} + +# Query the terminal to establish a default number of columns to use for +# displaying messages to the user. This is used only as a fallback in the +# event the COLUMNS variable is not set. ($COLUMNS can react to SIGWINCH while +# the script is running, and this cannot, only being calculated once.) +DEFCOLUMNS=$(stty size 2> /dev/null | awk '{print $2}') || true +if ! expr "$DEFCOLUMNS" : "[[:digit:]]\+$" > /dev/null 2>&1; then + DEFCOLUMNS=80 +fi + +message () { + # pretty-print messages of arbitrary length + reject_nondigits "$COLUMNS" + echo "$*" | fmt -t -w ${COLUMNS:-$DEFCOLUMNS} >&2 +} + +observe () { + # syntax: observe message ... + # + # issue observational message suitable for logging someday when support for + # it exists in dpkg + if [ -n "$DEBUG_XORG_PACKAGE" ]; then + message "$THIS_PACKAGE $THIS_SCRIPT note: $*" + fi +} + +warn () { + # syntax: warn message ... + # + # issue warning message suitable for logging someday when support for + # it exists in dpkg; also send to standard error + message "$THIS_PACKAGE $THIS_SCRIPT warning: $*" +} + +die () { + # syntax: die message ... + # + # exit script with error message + message "$THIS_PACKAGE $THIS_SCRIPT error: $*" + exit $SHELL_LIB_THROWN_ERROR +} + +internal_error () { + # exit script with error; essentially a "THIS SHOULD NEVER HAPPEN" message + message "internal error: $*" + if [ -n "$OFFICIAL_BUILD" ]; then + message "Please report a bug in the $THIS_SCRIPT script of the" \ + "$THIS_PACKAGE package, version $SOURCE_VERSION to the Debian Bug" \ + "Tracking System. Include all messages above that mention the" \ + "$THIS_PACKAGE package. Visit " \ + " on the World Wide Web for" \ + "instructions, read the file" \ + "/usr/share/doc/debian/bug-reporting.txt from the doc-debian" \ + "package, or install the reportbug package and use the command of" \ + "the same name to file a report." + fi + exit $SHELL_LIB_INTERNAL_ERROR +} + +usage_error () { + message "usage error: $*" + message "Please report a bug in the $THIS_SCRIPT script of the" \ + "$THIS_PACKAGE package, version $SOURCE_VERSION to the Debian Bug" \ + "Tracking System. Include all messages above that mention the" \ + "$THIS_PACKAGE package. Visit " \ + " on the World Wide Web for" \ + "instructions, read the file" \ + "/usr/share/doc/debian/bug-reporting.txt from the doc-debian" \ + "package, or install the reportbug package and use the command of" \ + "the same name to file a report." + exit $SHELL_LIB_USAGE_ERROR +} + + +maplink () { + # returns what symlink should point to; i.e., what the "sane" answer is + # Keep this in sync with the debian/*.links files. + # This is only needed for symlinks to directories. + # + # XXX: Most of these look wrong in the X11R7 world and need to be fixed. + # If we've stopped using this function, fixing it might enable us to re-enable + # it again and catch more errors. + case "$1" in + /etc/X11/xkb/compiled) echo /var/lib/xkb ;; + /etc/X11/xkb/xkbcomp) echo /usr/X11R6/bin/xkbcomp ;; + /usr/X11R6/lib/X11/app-defaults) echo /etc/X11/app-defaults ;; + /usr/X11R6/lib/X11/fs) echo /etc/X11/fs ;; + /usr/X11R6/lib/X11/lbxproxy) echo /etc/X11/lbxproxy ;; + /usr/X11R6/lib/X11/proxymngr) echo /etc/X11/proxymngr ;; + /usr/X11R6/lib/X11/rstart) echo /etc/X11/rstart ;; + /usr/X11R6/lib/X11/twm) echo /etc/X11/twm ;; + /usr/X11R6/lib/X11/xdm) echo /etc/X11/xdm ;; + /usr/X11R6/lib/X11/xinit) echo /etc/X11/xinit ;; + /usr/X11R6/lib/X11/xkb) echo /etc/X11/xkb ;; + /usr/X11R6/lib/X11/xserver) echo /etc/X11/xserver ;; + /usr/X11R6/lib/X11/xsm) echo /etc/X11/xsm ;; + /usr/bin/X11) echo ../X11R6/bin ;; + /usr/bin/rstartd) echo ../X11R6/bin/rstartd ;; + /usr/include/X11) echo ../X11R6/include/X11 ;; + /usr/lib/X11) echo ../X11R6/lib/X11 ;; + *) internal_error "maplink() called with unknown path \"$1\"" ;; + esac +} + +analyze_path () { + # given a supplied set of pathnames, break each one up by directory and do an + # ls -dl on each component, cumulatively; i.e. + # analyze_path /usr/X11R6/bin -> ls -dl /usr /usr/X11R6 /usr/X11R6/bin + # Thanks to Randolph Chung for this clever hack. + + local f g + + while [ -n "$1" ]; do + reject_whitespace "$1" + g= + message "Analyzing $1:" + for f in $(echo "$1" | tr / \ ); do + if [ -e /$g$f ]; then + ls -dl /$g$f /$g$f.dpkg-* 2> /dev/null || true + g=$g$f/ + else + message "/$g$f: nonexistent; directory contents of /$g:" + ls -l /$g + break + fi + done + shift + done +} + +find_culprits () { + local f p dpkg_info_dir possible_culprits smoking_guns bad_packages package \ + msg + + reject_whitespace "$1" + message "Searching for overlapping packages..." + dpkg_info_dir=/var/lib/dpkg/info + if [ -d $dpkg_info_dir ]; then + if [ "$(echo $dpkg_info_dir/*.list)" != "$dpkg_info_dir/*.list" ]; then + possible_culprits=$(ls -1 $dpkg_info_dir/*.list | egrep -v \ + "(xbase-clients|x11-common|xfs|xlibs)") + if [ -n "$possible_culprits" ]; then + smoking_guns=$(grep -l "$1" $possible_culprits || true) + if [ -n "$smoking_guns" ]; then + bad_packages=$(printf "\\n") + for f in $smoking_guns; do + # too bad you can't nest parameter expansion voodoo + p=${f%*.list} # strip off the trailing ".list" + package=${p##*/} # strip off the directories + bad_packages=$(printf "%s\n%s" "$bad_packages" "$package") + done + msg=$(cat < /dev/null 2>&1; then + shortcmd=${cmd##*/} + observe "running $shortcmd in $dir font directory" + cmd_opts= + if [ "$shortcmd" = "update-fonts-alias" ]; then + cmd_opts=--x11r7-layout + fi + if [ "$shortcmd" = "update-fonts-dir" ]; then + cmd_opts=--x11r7-layout + fi + if [ "$shortcmd" = "update-fonts-scale" ]; then + cmd_opts=--x11r7-layout + fi + $cmd $cmd_opts $dir || warn "$cmd $cmd_opts $dir" \ + "failed; font directory data may not" \ + "be up to date" + else + warn "$cmd not found; not updating corresponding $dir font" \ + "directory data" + fi + done + else + warn "$dir is not a directory; not updating font directory data" + fi + done +} + +remove_conffile_prepare () { + # syntax: remove_conffile_prepare filename official_md5sum ... + # + # Check a conffile "filename" against a list of canonical MD5 checksums. + # If the file's current MD5 checksum matches one of the "official_md5sum" + # operands provided, then prepare the conffile for removal from the system. + # We defer actual deletion until the package is configured so that we can + # roll this operation back if package installation fails. + # + # Call this function from a preinst script in the event $1 is "upgrade" or + # "install" and verify $2 to ensure the package is being upgraded from a + # version (or installed over a version removed-but-not-purged) prior to the + # one in which the conffile was obsoleted. + + local conffile current_checksum + + # validate arguments + if [ $# -lt 2 ]; then + usage_error "remove_conffile_prepare() called with wrong number of" \ + "arguments; expected at least 2, got $#" + exit $SHELL_LIB_USAGE_ERROR + fi + + conffile="$1" + shift + + # does the conffile even exist? + if [ -e "$conffile" ]; then + # calculate its checksum + current_checksum=$(md5sum < "$conffile" | sed 's/[[:space:]].*//') + # compare it to each supplied checksum + while [ -n "$1" ]; do + if [ "$current_checksum" = "$1" ]; then + # we found a match; move the confffile and stop looking + observe "preparing obsolete conffile $conffile for removal" + mv "$conffile" "$conffile.$THIS_PACKAGE-tmp" + break + fi + shift + done + fi +} + +remove_conffile_lookup () { + # syntax: remove_conffile_lookup package filename + # + # Lookup the md5sum of a conffile in dpkg's database, and prepare for removal + # if it matches the actual file's md5sum. + # + # Call this function when you would call remove_conffile_prepare but only + # want to check against dpkg's status database instead of known checksums. + + local package conffile old_md5sum + + # validate arguments + if [ $# -ne 2 ]; then + usage_error "remove_conffile_lookup() called with wrong number of" \ + "arguments; expected 1, got $#" + exit $SHELL_LIB_USAGE_ERROR + fi + + package="$1" + conffile="$2" + + if ! [ -e "$conffile" ]; then + return + fi + old_md5sum="$(dpkg-query -W -f='${Conffiles}' "$package" | \ + awk '{ if (match($0, "^ '"$conffile"' ")) print $2}')" + if [ -n "$old_md5sum" ]; then + remove_conffile_prepare "$conffile" "$old_md5sum" + fi +} + +remove_conffile_commit () { + # syntax: remove_conffile_commit filename + # + # Complete the removal of a conffile "filename" that has become obsolete. + # + # Call this function from a postinst script after having used + # remove_conffile_prepare() in the preinst. + + local conffile + + # validate arguments + if [ $# -ne 1 ]; then + usage_error "remove_conffile_commit() called with wrong number of" \ + "arguments; expected 1, got $#" + exit $SHELL_LIB_USAGE_ERROR + fi + + conffile="$1" + + # if the temporary file created by remove_conffile_prepare() exists, remove it + if [ -e "$conffile.$THIS_PACKAGE-tmp" ]; then + observe "committing removal of obsolete conffile $conffile" + rm "$conffile.$THIS_PACKAGE-tmp" + fi +} + +remove_conffile_rollback () { + # syntax: remove_conffile_rollback filename + # + # Roll back the removal of a conffile "filename". + # + # Call this function from a postrm script in the event $1 is "abort-upgrade" + # or "abort-install" is after having used remove_conffile_prepare() in the + # preinst. + + local conffile + + # validate arguments + if [ $# -ne 1 ]; then + usage_error "remove_conffile_rollback() called with wrong number of" \ + "arguments; expected 1, got $#" + exit $SHELL_LIB_USAGE_ERROR + fi + + conffile="$1" + + # if the temporary file created by remove_conffile_prepare() exists, move it + # back + if [ -e "$conffile.$THIS_PACKAGE-tmp" ]; then + observe "rolling back removal of obsolete conffile $conffile" + mv "$conffile.$THIS_PACKAGE-tmp" "$conffile" + fi +} + +replace_conffile_with_symlink_prepare () { + # syntax: replace_conffile_with_symlink_prepare oldfilename newfilename \ + # official_md5sum ... + # + # Check a conffile "oldfilename" against a list of canonical MD5 checksums. + # If the file's current MD5 checksum matches one of the "official_md5sum" + # operands provided, then prepare the conffile for removal from the system. + # We defer actual deletion until the package is configured so that we can + # roll this operation back if package installation fails. Otherwise copy it + # to newfilename and let dpkg handle it through conffiles mechanism. + # + # Call this function from a preinst script in the event $1 is "upgrade" or + # "install" and verify $2 to ensure the package is being upgraded from a + # version (or installed over a version removed-but-not-purged) prior to the + # one in which the conffile was obsoleted. + + local conffile current_checksum + + # validate arguments + if [ $# -lt 3 ]; then + usage_error "replace_conffile_with_symlink_prepare() called with wrong" \ + " number of arguments; expected at least 3, got $#" + exit $SHELL_LIB_USAGE_ERROR + fi + + oldconffile="$1" + shift + newconffile="$1" + shift + + remove_conffile_prepare "$_oldconffile" "$@" + # If $oldconffile still exists, then md5sums didn't match. + # Copy it to new one. + if [ -f "$oldconffile" ]; then + cp "$oldconffile" "$newconffile" + fi + +} + +replace_conffile_with_symlink_commit () { + # syntax: replace_conffile_with_symlink_commit oldfilename + # + # Complete the removal of a conffile "oldfilename" that has been + # replaced by a symlink. + # + # Call this function from a postinst script after having used + # replace_conffile_with_symlink_prepare() in the preinst. + + local conffile + + # validate arguments + if [ $# -ne 1 ]; then + usage_error "replace_conffile_with_symlink_commit() called with wrong" \ + "number of arguments; expected 1, got $#" + exit $SHELL_LIB_USAGE_ERROR + fi + + conffile="$1" + + remove_conffile_commit "$conffile" +} + +replace_conffile_with_symlink_rollback () { + # syntax: replace_conffile_with_symlink_rollback oldfilename newfilename + # + # Roll back the replacing of a conffile "oldfilename" with symlink to + # "newfilename". + # + # Call this function from a postrm script in the event $1 is "abort-upgrade" + # or "abort-install" and verify $2 to ensure the package failed to upgrade + # from a version (or install over a version removed-but-not-purged) prior + # to the one in which the conffile was obsoleted. + # You should have used replace_conffile_with_symlink_prepare() in the + # preinst. + + local conffile + + # validate arguments + if [ $# -ne 2 ]; then + usage_error "replace_conffile_with_symlink_rollback() called with wrong" \ + "number of arguments; expected 2, got $#" + exit $SHELL_LIB_USAGE_ERROR + fi + + oldconffile="$1" + newconffile="$2" + + remove_conffile_rollback "$_oldconffile" + if [ -f "$newconffile" ]; then + rm "$newconffile" + fi +} + +run () { + # syntax: run command [ argument ... ] + # + # Run specified command with optional arguments and report its exit status. + # Useful for commands whose exit status may be nonzero, but still acceptable, + # or commands whose failure is not fatal to us. + # + # NOTE: Do *not* use this function with db_get or db_metaget commands; in + # those cases the return value of the debconf command *must* be checked + # before the string returned by debconf is used for anything. + + local retval + + # validate arguments + if [ $# -lt 1 ]; then + usage_error "run() called with wrong number of arguments; expected at" \ + "least 1, got $#" + exit $SHELL_LIB_USAGE_ERROR + fi + + "$@" || retval=$? + + if [ ${retval:-0} -ne 0 ]; then + observe "command \"$*\" exited with status $retval" + fi +} + +make_symlink_sane () { + # syntax: make_symlink_sane symlink target + # + # Ensure that the symbolic link symlink exists, and points to target. + # + # If symlink does not exist, create it and point it at target. + # + # If symlink exists but is not a symbolic link, back it up. + # + # If symlink exists, is a symbolic link, but points to the wrong location, fix + # it. + # + # If symlink exists, is a symbolic link, and already points to target, do + # nothing. + # + # This function wouldn't be needed if ln had an -I, --idempotent option. + + # Validate arguments. + if [ $# -ne 2 ]; then + usage_error "make_symlink_sane() called with wrong number of arguments;" \ + "expected 2, got $#" + exit $SHELL_LIB_USAGE_ERROR + fi + + # We could just use the positional parameters as-is, but that makes things + # harder to follow. + local symlink target + + symlink="$1" + target="$2" + + if [ -L "$symlink" ] && [ "$(readlink "$symlink")" = "$target" ]; then + observe "link from $symlink to $target already exists" + else + observe "creating symbolic link from $symlink to $target" + mkdir -p "${target%/*}" "${symlink%/*}" + ln -s -b -S ".dpkg-old" "$target" "$symlink" + fi +} + +migrate_dir_to_symlink () { + # syntax: migrate_dir_to_symlink old_location new_location + # + # Per Debian Policy section 6.5.4, "A directory will never be replaced by a + # symbolic link to a directory or vice versa; instead, the existing state + # (symlink or not) will be left alone and dpkg will follow the symlink if + # there is one." + # + # We have to do it ourselves. + # + # This function moves the contents of old_location, a directory, into + # new_location, a directory, then makes old_location a symbolic link to + # new_location. + # + # old_location need not exist, but if it does, it must be a directory (or a + # symlink to a directory). If it is not, it is backed up. If new_location + # exists already and is not a directory, it is backed up. + # + # This function should be called from a package's preinst so that other + # packages unpacked after this one --- but before this package's postinst runs + # --- are unpacked into new_location even if their payloads contain + # old_location filespecs. + + # Validate arguments. + if [ $# -ne 2 ]; then + usage_error "migrate_dir_to_symlink() called with wrong number of" + "arguments; expected 2, got $#" + exit $SHELL_LIB_USAGE_ERROR + fi + + # We could just use the positional parameters as-is, but that makes things + # harder to follow. + local new old + + old="$1" + new="$2" + + # Is old location a symlink? + if [ -L "$old" ]; then + # Does it already point to new location? + if [ "$(readlink "$old")" = "$new" ]; then + # Nothing to do; migration has already been done. + observe "migration of $old to $new already done" + return 0 + else + # Back it up. + warn "backing up symbolic link $old as $old.dpkg-old" + mv -b "$old" "$old.dpkg-old" + fi + fi + + # Does old location exist, but is not a directory? + if [ -e "$old" ] && ! [ -d "$old" ]; then + # Back it up. + warn "backing up non-directory $old as $old.dpkg-old" + mv -b "$old" "$old.dpkg-old" + fi + + observe "migrating $old to $new" + + # Is new location a symlink? + if [ -L "$new" ]; then + # Does it point the wrong way, i.e., back to where we're migrating from? + if [ "$(readlink "$new")" = "$old" ]; then + # Get rid of it. + observe "removing symbolic link $new which points to $old" + rm "$new" + else + # Back it up. + warn "backing up symbolic link $new as $new.dpkg-old" + mv -b "$new" "$new.dpkg-old" + fi + fi + + # Does new location exist, but is not a directory? + if [ -e "$new" ] && ! [ -d "$new" ]; then + warn "backing up non-directory $new as $new.dpkg-old" + mv -b "$new" "$new.dpkg-old" + fi + + # Create new directory if it does not yet exist. + if ! [ -e "$new" ]; then + observe "creating $new" + mkdir -p "$new" + fi + + # Copy files in old location to new location. Back up any filenames that + # already exist in the new location with the extension ".dpkg-old". + observe "copying files from $old to $new" + if ! (cd "$old" && cp -a -b -S ".dpkg-old" . "$new"); then + die "error(s) encountered while copying files from $old to $new" + fi + + # Remove files at old location. + observe "removing $old" + rm -r "$old" + + # Create symlink from old location to new location. + make_symlink_sane "$old" "$new" +} + +# vim:set ai et sw=2 ts=2 tw=80: + +# GOBSTOPPER: The X Strike Force shell library ends here. diff --git a/man/Makefile.am b/man/Makefile.am new file mode 100644 index 0000000..276f2f0 --- /dev/null +++ b/man/Makefile.am @@ -0,0 +1,57 @@ +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, provided that +# the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation. +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the copyright holders shall +# not be used in advertising or otherwise to promote the sale, use or +# other dealings in this Software without prior written authorization +# from the copyright holders. +# + +drivermandir = $(DRIVER_MAN_DIR) + +driverman_PRE = @DRIVER_NAME@.man + +driverman_DATA = $(driverman_PRE:man=@DRIVER_MAN_SUFFIX@) + +EXTRA_DIST = @DRIVER_NAME@.man + +CLEANFILES = $(driverman_DATA) + +SED = sed + +# Strings to replace in man pages +XORGRELSTRING = @PACKAGE_STRING@ + XORGMANNAME = X Version 11 + +MAN_SUBSTS = \ + -e 's|__vendorversion__|"$(XORGRELSTRING)" "$(XORGMANNAME)"|' \ + -e 's|__xorgversion__|"$(XORGRELSTRING)" "$(XORGMANNAME)"|' \ + -e 's|__xservername__|Xorg|g' \ + -e 's|__xconfigfile__|xorg.conf|g' \ + -e 's|__projectroot__|$(prefix)|g' \ + -e 's|__appmansuffix__|$(APP_MAN_SUFFIX)|g' \ + -e 's|__drivermansuffix__|$(DRIVER_MAN_SUFFIX)|g' \ + -e 's|__adminmansuffix__|$(ADMIN_MAN_SUFFIX)|g' \ + -e 's|__miscmansuffix__|$(MISC_MAN_SUFFIX)|g' \ + -e 's|__filemansuffix__|$(FILE_MAN_SUFFIX)|g' + +SUFFIXES = .$(DRIVER_MAN_SUFFIX) .man + +.man.$(DRIVER_MAN_SUFFIX): + sed $(MAN_SUBSTS) < $< > $@ diff --git a/man/gesture.man b/man/gesture.man new file mode 100644 index 0000000..f3e0eeb --- /dev/null +++ b/man/gesture.man @@ -0,0 +1,29 @@ +.ds q \N'34' +.TH GESUTRE __drivermansuffix__ __vendorversion__ +.SH NAME +gesture \- Example X.Org input driver +.SH SYNOPSIS +.nf +.B "Section \*qInputDevice\*q" +.BI " Identifier \*q" devname \*q +.B " Driver \*qgesture\*q" +.BI " Option \*qDevice\*q \*q" devpath \*q +\ \ ... +.B EndSection +.fi +.SH DESCRIPTION +.B gesture +is an example __xservername__ input driver It reads from /dev/ugesture and +moves the pointer along the X axis by a gesture number of pixels. +.PP +.SH EMPTY MANPAGE +This is an example driver, hence the man page is not particularly useful. +For a better structure of the man page, including which sections to use in a +new man page see the +.B evdev(4) +man page. + + +.SH "SEE ALSO" +__xservername__(__appmansuffix__), __xconfigfile__(__filemansuffix__), Xserver(__appmansuffix__), X(__miscmansuffix__), +README.mouse. diff --git a/packaging/xorg-x11-drv-input-gesture.spec b/packaging/xorg-x11-drv-input-gesture.spec new file mode 100644 index 0000000..81cdee0 --- /dev/null +++ b/packaging/xorg-x11-drv-input-gesture.spec @@ -0,0 +1,48 @@ +Name: xorg-x11-drv-input-gesture +Summary: X.Org X server -- Xserver gesture driver +Version: 0.1.0 +Release: 4 +Group: System/X Hardware Support +License: MIT +Source0: %{name}-%{version}.tar.gz +Requires: xorg-x11-server +BuildRequires: pkgconfig(xorg-server) +BuildRequires: pkgconfig(gestureproto) +BuildRequires: pkgconfig(xproto) +BuildRequires: pkgconfig(inputproto) +%description + This package provides the driver for recognizing gesture(s) using button +and motion events inside X server. + + +%package devel +Summary: Development files for xorg gesture driver +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} + +%description devel +xorg-x11-drv-input-gesture development files + + +%prep +%setup -q + +%build + +autoreconf -vfi +./configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info CFLAGS="$CFLAGS" LDFLAGS="$LDFLAGS" + +make %{?jobs:-j%jobs} + +%install +rm -rf %{buildroot} +%make_install + +%remove_docs + +%files +%{_libdir}/xorg/modules/input/gesture_drv.so + +%files devel +%{_libdir}/pkgconfig/xorg-gesture.pc + diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..902f7ad --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,37 @@ +# Copyright 2005 Adam Jackson. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# on the rights to use, copy, modify, merge, publish, distribute, sub +# license, and/or sell copies of the Software, and to permit persons to whom +# the Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice (including the next +# paragraph) shall be included in all copies or substantial portions of the +# Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL +# ADAM JACKSON BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +# this is obnoxious: +# -module lets us name the module exactly how we want +# -avoid-version prevents gratuitous .0.0.0 version numbers on the end +# _ladir passes a dummy rpath to libtool so the thing will actually link +# TODO: -nostdlib/-Bstatic/-lgcc platform magic, not installing the .a, etc. +AM_CFLAGS = $(XORG_CFLAGS) + +@DRIVER_NAME@_drv_la_LTLIBRARIES = @DRIVER_NAME@_drv.la +@DRIVER_NAME@_drv_la_LDFLAGS = -module -avoid-version +@DRIVER_NAME@_drv_ladir = @inputdir@ + +INCLUDES=-I$(top_srcdir)/include/ + +@DRIVER_NAME@_drv_la_SOURCES = @DRIVER_NAME@.c \ + @DRIVER_NAME@.h + diff --git a/src/gesture.c b/src/gesture.c new file mode 100755 index 0000000..cf1c32d --- /dev/null +++ b/src/gesture.c @@ -0,0 +1,2560 @@ +/************************************************************************** + +xserver-xorg-input-gesture + +Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + +Contact: Sung-Jin Park + Sangjin LEE + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include + +#ifdef HAVE_PROPERTIES +#include +#include +/* 1.6 has properties, but no labels */ +#ifdef AXIS_LABEL_PROP +#define HAVE_LABELS +#else +#undef HAVE_LABELS +#endif + +#endif + +#define __DEBUG__ +//#define __DETAIL_DEBUG__ +//#define __DEBUG_EVENT_HANDLER__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "gesture.h" +#include + +//Basic functions +static InputInfoPtr GesturePreInit(InputDriverPtr drv, IDevPtr dev, int flags); +static void GestureUnInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags); +static pointer GesturePlug(pointer module, pointer options, int *errmaj, int *errmin); +static void GestureUnplug(pointer p); +static int GestureControl(DeviceIntPtr device,int what); +static int GestureInit(DeviceIntPtr device); +static void GestureFini(DeviceIntPtr device); +static void GestureReadInput(InputInfoPtr pInfo); + +//other initializers +ErrorStatus GestureRegionsInit(void); + +//event queue handling functions +ErrorStatus GestureInitEQ(void); +ErrorStatus GestureFiniEQ(void); +ErrorStatus GestureEnqueueEvent(int screen_num, InternalEvent *ev, DeviceIntPtr device); +ErrorStatus GestureEventsFlush(void); +void GestureEventsDrop(void); + +//utility functions +ErrorStatus GestureRegionsReinit(void); +void GestureSetDisable(InputInfoPtr pInfo, int enable); +WindowPtr GestureGetEventsWindow(void); + +//Enqueued event handlers and enabler/disabler +static ErrorStatus GestureEnableEventHandler(InputInfoPtr pInfo); +static ErrorStatus GestureDisableEventHandler(void); +static CARD32 GestureTimerHandler(OsTimerPtr timer, CARD32 time, pointer arg); +static CARD32 GestureEventTimerHandler(OsTimerPtr timer, CARD32 time, pointer arg); +void GestureHandleMTSyncEvent(int screen_num, InternalEvent *ev, DeviceIntPtr device); +void GestureHandleButtonPressEvent(int screen_num, InternalEvent *ev, DeviceIntPtr device); +void GestureHandleButtonReleaseEvent(int screen_num, InternalEvent *ev, DeviceIntPtr device); +void GestureHandleMotionEvent(int screen_num, InternalEvent *ev, DeviceIntPtr device); + +//Gesture recognizer helper +static Bool PointInBorderSize(WindowPtr pWin, int x, int y); +static WindowPtr GestureWindowOnXY(int x, int y); +Bool GestureHasFingerEventMask(int eventType, int num_finger); + +//Gesture recognizer and handlers +void GestureRecognize_GroupPinchRotation(int type, InternalEvent *ev, DeviceIntPtr device, int idx); +void GestureRecognize_GroupFlick(int type, InternalEvent *ev, DeviceIntPtr device, int idx); +void GestureRecognize_GroupPan(int type, InternalEvent *ev, DeviceIntPtr device, int idx, int timer_expired); +void GestureRecognize_GroupTap(int type, InternalEvent *ev, DeviceIntPtr device, int idx, int timer_expired); +void GestureRecognize_GroupTapNHold(int type, InternalEvent *ev, DeviceIntPtr device, int idx, int timer_expired); +void GestureRecognize_GroupHold(int type, InternalEvent *ev, DeviceIntPtr device, int idx, int timer_expired); +void GestureHandleGesture_Flick(int num_of_fingers, int distance, Time duration, int direction); +void GestureHandleGesture_Tap(int num_finger, int tap_repeat, int cx, int cy); +void GestureHandleGesture_PinchRotation(int num_of_fingers, double zoom, double angle, int distance, int cx, int cy); +void GestureHandleGesture_Hold(int num_fingers, int cx, int cy, Time holdtime, int kinds); +void GestureHandleGesture_TapNHold(int num_fingers, int cx, int cy, Time interval, Time holdtime, int kinds); +void GestureHandleGesture_Pan(int num_fingers, short int dx, short int dy, int direction, int distance, Time duration, int kinds); +void GestureRecognize(int type, InternalEvent *ev, DeviceIntPtr device); +ErrorStatus GestureFlushOrDrop(void); + +#ifdef HAVE_PROPERTIES +//function related property handling +static void GestureInitProperty(DeviceIntPtr dev); +static int GestureSetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val, BOOL checkonly); +#endif + +static Atom prop_gesture_recognizer_onoff = None; + +GestureDevicePtr g_pGesture = NULL; +_X_EXPORT InputDriverRec GESTURE = { + 1, + "gesture", + NULL, + GesturePreInit, + GestureUnInit, + NULL, + 0 +}; + +static XF86ModuleVersionInfo GestureVersionRec = +{ + "gesture", + MODULEVENDORSTRING, + MODINFOSTRING1, + MODINFOSTRING2, + XORG_VERSION_CURRENT, + PACKAGE_VERSION_MAJOR, PACKAGE_VERSION_MINOR, + PACKAGE_VERSION_PATCHLEVEL, + ABI_CLASS_XINPUT, + ABI_XINPUT_VERSION, + MOD_CLASS_XINPUT, + {0, 0, 0, 0} +}; + +_X_EXPORT XF86ModuleData gestureModuleData = +{ + &GestureVersionRec, + &GesturePlug, + &GestureUnplug +}; + +static Bool +PointInBorderSize(WindowPtr pWin, int x, int y) +{ + BoxRec box; + if( pixman_region_contains_point (&pWin->borderSize, x, y, &box) ) + return TRUE; + + return FALSE; +} + +static WindowPtr +GestureWindowOnXY(int x, int y) +{ + WindowPtr pWin; + BoxRec box; + SpritePtr pSprite; + DeviceIntPtr pDev = g_pGesture->master_pointer; + + pSprite = pDev->spriteInfo->sprite; + pSprite->spriteTraceGood = 1; /* root window still there */ + pWin = RootWindow(pDev)->firstChild; + + while (pWin) + { + if ((pWin->mapped) && + (x >= pWin->drawable.x - wBorderWidth (pWin)) && + (x < pWin->drawable.x + (int)pWin->drawable.width + + wBorderWidth(pWin)) && + (y >= pWin->drawable.y - wBorderWidth (pWin)) && + (y < pWin->drawable.y + (int)pWin->drawable.height + + wBorderWidth (pWin)) + /* When a window is shaped, a further check + * is made to see if the point is inside + * borderSize + */ + && (!wBoundingShape(pWin) || PointInBorderSize(pWin, x, y)) + && (!wInputShape(pWin) || + RegionContainsPoint(wInputShape(pWin), + x - pWin->drawable.x, + y - pWin->drawable.y, &box)) +#ifdef ROOTLESS + /* In rootless mode windows may be offscreen, even when + * they're in X's stack. (E.g. if the native window system + * implements some form of virtual desktop system). + */ + && !pWin->rootlessUnhittable +#endif + ) + { + if (pSprite->spriteTraceGood >= pSprite->spriteTraceSize) + { + pSprite->spriteTraceSize += 10; + pSprite->spriteTrace = realloc(pSprite->spriteTrace, + pSprite->spriteTraceSize*sizeof(WindowPtr)); + } + pSprite->spriteTrace[pSprite->spriteTraceGood++] = pWin; + pWin = pWin->firstChild; + } + else + pWin = pWin->nextSib; + } + return pSprite->spriteTrace[pSprite->spriteTraceGood-1]; +} + +Bool +GestureHasFingerEventMask(int eventType, int num_finger) +{ + Bool ret = FALSE; + Mask eventmask = (1L << eventType); + + if( (g_pGesture->grabMask & eventmask) && + (g_pGesture->GrabEvents[eventType].pGestureGrabWinInfo[num_finger].window != None) ) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[X11][GestureHasFingerEventMask] TRUE !! Has grabMask\n"); +#endif//__DETAIL_DEBUG__ + return TRUE; + } + + if( g_pGesture->eventMask & eventmask ) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[X11][GestureHasFingerEventMask] TRUE !! Has eventMask\n"); +#endif//__DETAIL_DEBUG__ + return TRUE; + } + +#ifdef __DETAIL_DEBUG__ + ErrorF("[X11][GestureHasFingerEventMask] FALSE !! eventType=%d, num_finger=%d\n", eventType, num_finger); +#endif//__DETAIL_DEBUG__ + + return ret; +} + +void +GestureHandleGesture_Flick(int num_of_fingers, int distance, Time duration, int direction) +{ + Window target_win; + WindowPtr target_pWin; + xGestureNotifyFlickEvent fev; + +#ifdef __DETAIL_DEBUG__ + ErrorF("[X11][GestureHandleGesture_Flick] num_fingers=%d, distance=%d, duration=%d, direction=%d\n", + num_of_fingers, distance, duration, direction); +#endif//__DETAIL_DEBUG__ + + g_pGesture->recognized_gesture |= FlickFilterMask; + memset(&fev, 0, sizeof(xGestureNotifyFlickEvent)); + fev.type = GestureNotifyFlick; + fev.kind = GestureDone; + fev.num_finger = num_of_fingers; + fev.distance = distance; + fev.duration = duration; + fev.direction = direction; + + target_win = g_pGesture->GrabEvents[GestureNotifyFlick].pGestureGrabWinInfo[num_of_fingers].window; + target_pWin = g_pGesture->GrabEvents[GestureNotifyFlick].pGestureGrabWinInfo[num_of_fingers].pWin; + + if( g_pGesture->grabMask && (target_win != None) ) + { + fev.window = target_win; + } + else + { + fev.window = g_pGesture->gestureWin; + } + +#ifdef __DETAIL_DEBUG__ + ErrorF("[X11][GestureHandleGesture_Flick] fev.window=0x%x, g_pGesture->grabMask=0x%x\n", fev.window, g_pGesture->grabMask); +#endif//__DETAIL_DEBUG__ + + GestureSendEvent(target_pWin, GestureNotifyFlick, GestureFlickMask, (xGestureCommonEvent *)&fev); +} + +void +GestureHandleGesture_Tap(int num_finger, int tap_repeat, int cx, int cy) +{ + Window target_win; + WindowPtr target_pWin; + xGestureNotifyTapEvent tev; + + //skip non-tap events and single finger tap + if( !tap_repeat || num_finger <= 1 ) + return; + +#ifdef __DETAIL_DEBUG__ + ErrorF("[X11][GestureHandleGesture_Tap] num_finger=%d, tap_repeat=%d, cx=%d, cy=%d\n", + num_finger, tap_repeat, cx, cy); +#endif//__DETAIL_DEBUG__ + + g_pGesture->recognized_gesture |= TapFilterMask; + memset(&tev, 0, sizeof(xGestureNotifyTapEvent)); + tev.type = GestureNotifyTap; + tev.kind = GestureDone; + tev.num_finger = num_finger; + tev.tap_repeat = tap_repeat; + tev.interval = 0; + tev.cx = cx; + tev.cy = cy; + + target_win = g_pGesture->GrabEvents[GestureNotifyTap].pGestureGrabWinInfo[num_finger].window; + target_pWin = g_pGesture->GrabEvents[GestureNotifyTap].pGestureGrabWinInfo[num_finger].pWin; + + if( g_pGesture->grabMask && (target_win != None) ) + { + tev.window = target_win; + } + else + { + tev.window = g_pGesture->gestureWin; + } + +#ifdef __DETAIL_DEBUG__ + ErrorF("[X11][GestureHandleGesture_Tap] tev.window=0x%x, g_pGesture->grabMask=0x%x\n", tev.window, g_pGesture->grabMask); +#endif//__DETAIL_DEBUG__ + + GestureSendEvent(target_pWin, GestureNotifyTap, GestureTapMask, (xGestureCommonEvent *)&tev); +} + +void GestureHandleGesture_PinchRotation(int num_of_fingers, double zoom, double angle, int distance, int cx, int cy) +{ + Window target_win; + WindowPtr target_pWin; + xGestureNotifyPinchRotationEvent prev; + +#ifdef __DETAIL_DEBUG__ + ErrorF("[X11][GestureHandleGesture_PinchRotation] num_fingers=%d, zoom=%.2f, angle=%.2f, distance=%d\n", + num_of_fingers, zoom, angle, distance, cx, cy); +#endif//__DETAIL_DEBUG__ + + g_pGesture->recognized_gesture |= PinchRotationFilterMask; + memset(&prev, 0, sizeof(xGestureNotifyPinchRotationEvent)); + prev.type = GestureNotifyPinchRotation; + prev.kind = GestureDone; + prev.num_finger = num_of_fingers; + prev.zoom = XDoubleToFixed(zoom); + prev.angle = XDoubleToFixed(angle); + prev.distance = distance; + prev.cx = cx; + prev.cy = cy; + + target_win = g_pGesture->GrabEvents[GestureNotifyPinchRotation].pGestureGrabWinInfo[num_of_fingers].window; + target_pWin = g_pGesture->GrabEvents[GestureNotifyPinchRotation].pGestureGrabWinInfo[num_of_fingers].pWin; + + if( g_pGesture->grabMask && (target_win != None) ) + { + prev.window = target_win; + } + else + { + prev.window = g_pGesture->gestureWin; + } + +#ifdef __DETAIL_DEBUG__ + ErrorF("[X11][GestureHandleGesture_PinchRotation] prev.window=0x%x, g_pGesture->grabMask=0x%x\n", prev.window, g_pGesture->grabMask); +#endif//__DETAIL_DEBUG__ + + GestureSendEvent(target_pWin, GestureNotifyPinchRotation, GesturePinchRotationMask, (xGestureCommonEvent *)&prev); +} + +void GestureHandleGesture_Hold(int num_fingers, int cx, int cy, Time holdtime, int kinds) +{ + Window target_win; + WindowPtr target_pWin; + xGestureNotifyHoldEvent hev; + +#ifdef __DETAIL_DEBUG__ + ErrorF("[X11][GestureHandleGesture_Hold] num_fingers=%d, cx=%d, cy=%d, holdtime=%d, kinds=%d\n", + num_fingers, cx, cy, holdtime, kinds); +#endif//__DETAIL_DEBUG__ + + g_pGesture->recognized_gesture |= HoldFilterMask; + memset(&hev, 0, sizeof(xGestureNotifyHoldEvent)); + hev.type = GestureNotifyHold; + hev.kind = kinds; + hev.num_finger = num_fingers; + hev.holdtime = holdtime; + hev.cx = cx; + hev.cy = cy; + + target_win = g_pGesture->GrabEvents[GestureNotifyHold].pGestureGrabWinInfo[num_fingers].window; + target_pWin = g_pGesture->GrabEvents[GestureNotifyHold].pGestureGrabWinInfo[num_fingers].pWin; + + if( g_pGesture->grabMask && (target_win != None) ) + { + hev.window = target_win; + } + else + { + hev.window = g_pGesture->gestureWin; + } + +#ifdef __DETAIL_DEBUG__ + ErrorF("[X11][GestureHandleGesture_Hold] hev.window=0x%x, g_pGesture->grabMask=0x%x\n", hev.window, g_pGesture->grabMask); +#endif//__DETAIL_DEBUG__ + + GestureSendEvent(target_pWin, GestureNotifyHold, GestureHoldMask, (xGestureCommonEvent *)&hev); +} + +void GestureHandleGesture_TapNHold(int num_fingers, int cx, int cy, Time interval, Time holdtime, int kinds) +{ + Window target_win; + WindowPtr target_pWin; + xGestureNotifyTapNHoldEvent thev; + +#ifdef __DETAIL_DEBUG__ + ErrorF("[X11][GestureHandleGesture_TapNHold] num_fingers=%d, cx=%d, cy=%d, interval=%d, holdtime=%d, kinds=%d\n", + num_fingers, cx, cy, interval, holdtime, kinds); +#endif//__DETAIL_DEBUG__ + + g_pGesture->recognized_gesture |= TapNHoldFilterMask; + memset(&thev, 0, sizeof(xGestureNotifyTapNHoldEvent)); + thev.type = GestureNotifyTapNHold; + thev.kind = kinds; + thev.num_finger = num_fingers; + thev.holdtime = holdtime; + thev.cx = cx; + thev.cy = cy; + thev.interval = interval; + + target_win = g_pGesture->GrabEvents[GestureNotifyTapNHold].pGestureGrabWinInfo[num_fingers].window; + target_pWin = g_pGesture->GrabEvents[GestureNotifyTapNHold].pGestureGrabWinInfo[num_fingers].pWin; + + if( g_pGesture->grabMask && (target_win != None) ) + { + thev.window = target_win; + } + else + { + thev.window = g_pGesture->gestureWin; + } + +#ifdef __DETAIL_DEBUG__ + ErrorF("[X11][GestureHandleGesture_TapNHold] thev.window=0x%x, g_pGesture->grabMask=0x%x\n", thev.window, g_pGesture->grabMask); +#endif//__DETAIL_DEBUG__ + + GestureSendEvent(target_pWin, GestureNotifyTapNHold, GestureTapNHoldMask, (xGestureCommonEvent *)&thev); +} + +void GestureHandleGesture_Pan(int num_fingers, short int dx, short int dy, int direction, int distance, Time duration, int kinds) +{ + Window target_win; + WindowPtr target_pWin; + xGestureNotifyPanEvent pev; + +#ifdef __DETAIL_DEBUG__ + ErrorF("[X11][GestureHandleGesture_Pan] num_fingers=%d, dx=%d, dy=%d, direction=%d, distance=%d, duration=%d, kinds=%d\n", + num_fingers, dx, dy, direction, distance, duration, kinds); +#endif//__DETAIL_DEBUG__ + + g_pGesture->recognized_gesture |= PanFilterMask; + memset(&pev, 0, sizeof(xGestureNotifyPanEvent)); + pev.type = GestureNotifyPan; + pev.kind = kinds; + pev.num_finger = num_fingers; + pev.direction = direction; + pev.distance = distance; + pev.duration = duration; + pev.dx = dx; + pev.dy = dy; + + target_win = g_pGesture->GrabEvents[GestureNotifyPan].pGestureGrabWinInfo[num_fingers].window; + target_pWin = g_pGesture->GrabEvents[GestureNotifyPan].pGestureGrabWinInfo[num_fingers].pWin; + + if( g_pGesture->grabMask && (target_win != None) ) + { + pev.window = target_win; + } + else + { + pev.window = g_pGesture->gestureWin; + } + +#ifdef __DETAIL_DEBUG__ + ErrorF("[X11][GestureHandleGesture_Pan] pev.window=0x%x, g_pGesture->grabMask=0x%x\n", pev.window, g_pGesture->grabMask); +#endif//__DETAIL_DEBUG__ + + GestureSendEvent(target_pWin, GestureNotifyPan, GesturePanMask, (xGestureCommonEvent *)&pev); +} + +void +GestureRecognize_GroupPinchRotation(int type, InternalEvent *ev, DeviceIntPtr device, int idx) +{ + + g_pGesture->recognized_gesture &= ~PinchRotationFilterMask; + g_pGesture->filter_mask |= PinchRotationFilterMask; + return; +} + +void +GestureRecognize_GroupFlick(int type, InternalEvent *ev, DeviceIntPtr device, int idx) +{ + static int num_pressed = 0; + static int mbits = 0; + static int base_area_size = 0; + static Time base_time = 0; + static int base_x, base_y; + Time current_time; + Time duration; + int distx, disty; + int distance, direction; + int area_size; + int flicked = 0; + + switch( type ) + { + case ET_ButtonPress: + g_pGesture->fingers[idx].flags |= PressFlagFlick; + + if( g_pGesture->num_pressed < 2 ) + return; + + if( !base_area_size || g_pGesture->num_pressed > num_pressed ) + { + base_area_size = AREA_SIZE(&g_pGesture->area.extents); + base_x = g_pGesture->area.extents.x1; + base_y = g_pGesture->area.extents.y1; + base_time = GetTimeInMillis(); + } + num_pressed = g_pGesture->num_pressed; + +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupFlick][P]][num_pressed=%d] AREA_SIZE(area.extents)=%d\n", num_pressed, base_area_size); +#endif//__DETAIL_DEBUG__ + break; + + case ET_Motion: + if( !(g_pGesture->fingers[idx].flags & PressFlagFlick ) ) + break; + +#ifdef __DETAIL_DEBUG__ + if( num_pressed > g_pGesture->num_pressed ) + { + ErrorF("[GroupFlick][M][cleanup] num_pressed=%d, g_pGesture->num_pressed=%d\n", num_pressed, g_pGesture->num_pressed); + //goto cleanup_flick; + } +#endif//__DETAIL_DEBUG__ + + if( num_pressed < 2 ) + return; + + mbits |= (1 << idx); + if( mbits == (pow(2, num_pressed)-1) ) + { + area_size = AREA_SIZE(&g_pGesture->area.extents); +#ifdef __DETAIL_DEBUG__ + ErrorF("[M][num_pressed=%d] AREA_SIZE(area.extents)=%d\n", num_pressed, area_size); +#endif//__DETAIL_DEBUG__ + if( ABS(base_area_size - area_size) >= FLICK_AREA_THRESHOLD ) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupFlick][M] diff between Area size(=%d) and base area size(=%d) is bigger than threshold(=%d)!\n", area_size, base_area_size, FLICK_AREA_THRESHOLD); +#endif//__DETAIL_DEBUG__ + goto cleanup_flick; + } + + current_time = GetTimeInMillis(); + if( (current_time - base_time) >= FLICK_AREA_TIMEOUT ) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupFlick][M] diff between current time(=%d) and base time(=%d) is bigger than threashold(=%d) !\n", current_time, base_time, FLICK_AREA_TIMEOUT); +#endif//__DETAIL_DEBUG__ + goto cleanup_flick; + } + mbits = 0; + } + break; + + case ET_ButtonRelease: + if( g_pGesture->num_pressed ) + break; + + duration = GetTimeInMillis() - base_time; + distx = g_pGesture->area.extents.x1 - base_x; + disty = g_pGesture->area.extents.y1 - base_y; + +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupFlick] duration=%d, distx=%d, disty=%d\n", duration, distx, disty); +#endif//__DETAIL_DEBUG__ + + if( duration <= 0 || duration >= FLICK_AREA_TIMEOUT ) + goto cleanup_flick; + + if( ABS(distx) >= FLICK_MOVE_THRESHOLD ) + { + direction = (distx > 0) ? FLICK_EASTWARD : FLICK_WESTWARD; + distance = ABS(distx); + flicked++; + } + else if( ABS(disty) >= FLICK_MOVE_THRESHOLD ) + { + direction = (disty > 0) ? FLICK_SOUTHWARD : FLICK_NORTHWARD; + distance = ABS(disty); + flicked++; + } + + if( !flicked ) + goto cleanup_flick; + + if( GestureHasFingerEventMask(GestureNotifyFlick, num_pressed) ) + GestureHandleGesture_Flick(num_pressed, distance, duration, direction); + goto cleanup_flick_recognized; + break; + } + + return; + +cleanup_flick: + + g_pGesture->recognized_gesture &= ~FlickFilterMask; + +cleanup_flick_recognized: + + g_pGesture->filter_mask |= FlickFilterMask; + num_pressed = 0; + base_area_size = 0; + base_time = 0; + mbits = 0; + return; +} + +void +GestureRecognize_GroupPan(int type, InternalEvent *ev, DeviceIntPtr device, int idx, int timer_expired) +{ + static int num_pressed = 0; + static int mbits = 0; + static int base_area_size = 0; + static Time base_time = 0; + static pixman_box16_t base_box_ext; + static int base_cx; + static int base_cy; + static int prev_cx; + static int prev_cy; + static int cx = 0; + static int cy = 0; + int dx, dy; + static Time prev_time = 0; + Time current_time = 0; + int distance = 0; + int direction = 0; + int area_size; + static int time_checked = 0; + static int state = GestureEnd; + + static OsTimerPtr pan_event_timer = NULL; + static int event_type = GestureNotifyPan; + + if( timer_expired ) + { + if( !time_checked ) + { + current_time = GetTimeInMillis(); + if( (current_time - base_time) >= PAN_TIME_THRESHOLD ) + { + if( (!cx && !cy) || INBOX(&base_box_ext, cx, cy) ) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupPan][Timer] You must move farther than move threshold(=%d) within time threshold(=%d) !\n", PAN_MOVE_THRESHOLD*2, PAN_TIME_THRESHOLD); +#endif//__DETAIL_DEBUG__ + goto cleanup_pan; + } + time_checked = 1; + } + } + return; + } + + switch( type ) + { + case ET_ButtonPress: + g_pGesture->fingers[idx].flags |= PressFlagPan; + + if( g_pGesture->num_pressed < 2 ) + return; + + if( !base_area_size || g_pGesture->num_pressed > num_pressed ) + { + if( state != GestureEnd ) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupPan][P][cleanup] num_finger changed ! num_pressed=%d, g_pGesture->num_pressed=%d\n", num_pressed, g_pGesture->num_pressed); +#endif//__DETAIL_DEBUG__ + goto cleanup_pan; + } + base_area_size = AREA_SIZE(&g_pGesture->area.extents); + prev_cx = base_cx = AREA_CENTER_X(&g_pGesture->area.extents); + prev_cy = base_cy = AREA_CENTER_Y(&g_pGesture->area.extents); + prev_time = base_time = GetTimeInMillis(); + base_box_ext.x1 = base_cx-PAN_MOVE_THRESHOLD; + base_box_ext.y1 = base_cy-PAN_MOVE_THRESHOLD; + base_box_ext.x2 = base_cx+PAN_MOVE_THRESHOLD; + base_box_ext.y2 = base_cy+PAN_MOVE_THRESHOLD; + event_type = GestureNotifyPan; + pan_event_timer = TimerSet(pan_event_timer, 0, PAN_TIME_THRESHOLD, GestureEventTimerHandler, (int *)&event_type); + } + num_pressed = g_pGesture->num_pressed; + +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupPan][P][num_pressed=%d] AREA_SIZE(area.extents)=%d, base_cx=%d, base_cy=%d\n", num_pressed, base_area_size, base_cx, base_cy); +#endif//__DETAIL_DEBUG__ + break; + + case ET_Motion: + if( !(g_pGesture->fingers[idx].flags & PressFlagPan ) ) + break; + + if( num_pressed != g_pGesture->num_pressed ) + { + if( state != GestureEnd ) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupPan][M][cleanup] num_finger changed ! num_pressed=%d, g_pGesture->num_pressed=%d\n", num_pressed, g_pGesture->num_pressed); +#endif//__DETAIL_DEBUG__ + goto cleanup_pan; + } + } + + if( num_pressed < 2 ) + return; + + mbits |= (1 << idx); + if( mbits == (pow(2, num_pressed)-1) ) + { + area_size = AREA_SIZE(&g_pGesture->area.extents); +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupPan][M][num_pressed=%d] area_size=%d, base_area_size=%d, diff=%d\n", num_pressed, area_size, base_area_size, ABS(base_area_size - area_size)); +#endif//__DETAIL_DEBUG__ + + if( (state != GestureUpdate) && (ABS(base_area_size - area_size) >= PAN_AREA_THRESHOLD) ) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupPan][M] diff between area size(=%d) and base area size(=%d) is bigger than threshold(=%d)!\n", area_size, base_area_size, PAN_AREA_THRESHOLD); +#endif//__DETAIL_DEBUG__ + goto cleanup_pan; + } + + cx = AREA_CENTER_X(&g_pGesture->area.extents); + cy = AREA_CENTER_Y(&g_pGesture->area.extents); + +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupPan][M] cx=%d, prev_cx=%d, diff=%d\n", cx, prev_cx, ABS(cx-prev_cx)); + ErrorF("[GroupPan][M] cy=%d, prev_cy=%d, diff=%d\n", cy, prev_cy, ABS(cy-prev_cy)); +#endif//__DETAIL_DEBUG__ + + if( !time_checked ) + { + current_time = GetTimeInMillis(); + if( (current_time - base_time) >= PAN_TIME_THRESHOLD ) + { + if( INBOX(&base_box_ext, cx, cy) ) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupPan][M] You must move farther than move threshold(=%d) within time threshold(=%d) !\n", PAN_MOVE_THRESHOLD*2, PAN_TIME_THRESHOLD); +#endif//__DETAIL_DEBUG__ + goto cleanup_pan; + } + time_checked = 1; + } + } + + if( time_checked ) + { + if( state <= GestureBegin ) + { + base_box_ext.x1 = prev_cx-PAN_MOVE_THRESHOLD; + base_box_ext.y1 = prev_cy-PAN_MOVE_THRESHOLD; + base_box_ext.x2 = prev_cx+PAN_MOVE_THRESHOLD; + base_box_ext.y2 = prev_cy+PAN_MOVE_THRESHOLD; + + if( !INBOX(&base_box_ext, cx, cy) ) + { + current_time = GetTimeInMillis(); +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupPan] PAN Begin !dx=%d, dy=%d, state=%d\n", prev_cx, prev_cy, state); +#endif//__DETAIL_DEBUG__ + if( GestureHasFingerEventMask(GestureNotifyPan, num_pressed) ) + { + GestureHandleGesture_Pan(num_pressed, prev_cx, prev_cy, direction, distance, current_time-prev_time, GestureBegin); + state = GestureUpdate; + } + else + goto cleanup_pan; + } + } + else + { + dx = cx-prev_cx; + dy = cy-prev_cy; + //if( ABS(dx) >= PAN_UPDATE_MOVE_THRESHOLD || ABS(dy) >= PAN_UPDATE_MOVE_THRESHOLD ) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupPan] PAN Update !dx=%d, dy=%d, state=%d\n", dx, dy, state); +#endif//__DETAIL_DEBUG__ + + GestureHandleGesture_Pan(num_pressed, dx, dy, direction, distance, current_time-prev_time, GestureUpdate); + } + } + prev_cx = cx; + prev_cy = cy; + prev_time = current_time; + } + mbits = 0; + } + break; + + case ET_ButtonRelease: + if( state != GestureEnd && num_pressed >= 2) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupPan][R][cleanup] num_finger changed ! num_pressed=%d, g_pGesture->num_pressed=%d\n", num_pressed, g_pGesture->num_pressed); +#endif//__DETAIL_DEBUG__ + goto cleanup_pan; + } + + if( g_pGesture->num_pressed ) + break; + + goto cleanup_pan; + break; + } + + return; + +cleanup_pan: + + if( state == GestureBegin || state == GestureUpdate ) + { + state = GestureEnd; + if( GestureHasFingerEventMask(GestureNotifyPan, num_pressed) ) + { + GestureHandleGesture_Pan(num_pressed, (short int)(cx-prev_cx), (short int)(cy-prev_cy), direction, distance, GetTimeInMillis()-prev_time, GestureEnd); + } + } + else + { + g_pGesture->recognized_gesture &= ~PanFilterMask; + } + + g_pGesture->filter_mask |= PanFilterMask; + num_pressed = 0; + base_area_size = 0; + base_time = 0; + mbits = 0; + time_checked = 0; + state = GestureEnd; + cx = cy = 0; + prev_time = 0; + base_box_ext.x1 = base_box_ext.x2 = base_box_ext.y1 = base_box_ext.y2 = 0; + TimerCancel(pan_event_timer); + return; +} + +void +GestureRecognize_GroupTap(int type, InternalEvent *ev, DeviceIntPtr device, int idx, int timer_expired) +{ + static int num_pressed = 0; + static int base_area_size = 0; + + static Time base_time = 0; + Time current_time; + + int cx, cy; + int area_size; + + static int state = 0; + static int mbits = 0; + static int base_cx; + static int base_cy; + static pixman_box16_t base_box_ext; + + static int tap_repeat = 0; + static int prev_tap_repeat = 0; + static int prev_num_pressed = 0; + + static OsTimerPtr tap_event_timer = NULL; + static int event_type = GestureNotifyTap; + + if( timer_expired ) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupTap][Timer] state=%d\n", state); +#endif//__DETAIL_DEBUG__ + + switch( state ) + { + case 1://first tap initiation check + if( num_pressed ) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupTap][Timer][state=1] Tap time expired !(num_pressed=%d, tap_repeat=%d)\n", tap_repeat, num_pressed, tap_repeat); +#endif//__DETAIL_DEBUG__ + state = 0; + goto cleanup_tap; + } + break; + + case 2: + if( tap_repeat <= 1 ) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupTap][Timer][state=2] %d finger SINGLE TAP !(ignored)\n", prev_num_pressed); +#endif//__DETAIL_DEBUG__ + state = 0; + goto cleanup_tap; + } + +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupTap][Timer][state=2] tap_repeat=%d, prev_tap_repeat=%d, num_pressed=%d\n", tap_repeat, prev_tap_repeat, num_pressed); +#endif//__DETAIL_DEBUG__ + if( GestureHasFingerEventMask(GestureNotifyTap, prev_num_pressed) ) + GestureHandleGesture_Tap(prev_num_pressed, tap_repeat, base_cx, base_cy); + goto cleanup_tap; + break; + } + + return; + } + + switch( type ) + { + case ET_ButtonPress: + g_pGesture->fingers[idx].flags |= PressFlagTap; + + if( g_pGesture->num_pressed < 2 ) + return; + + if( !prev_num_pressed && (!base_area_size || g_pGesture->num_pressed > num_pressed) ) + { + base_area_size = AREA_SIZE(&g_pGesture->area.extents); + base_cx = AREA_CENTER_X(&g_pGesture->area.extents); + base_cy = AREA_CENTER_Y(&g_pGesture->area.extents); + base_time = GetTimeInMillis(); + base_box_ext.x1 = base_cx-TAP_MOVE_THRESHOLD; + base_box_ext.y1 = base_cy-TAP_MOVE_THRESHOLD; + base_box_ext.x2 = base_cx+TAP_MOVE_THRESHOLD; + base_box_ext.y2 = base_cy+TAP_MOVE_THRESHOLD; + state = 1; + TimerCancel(tap_event_timer); + tap_event_timer = TimerSet(tap_event_timer, 0, SGL_TAP_TIME_THRESHOLD, GestureEventTimerHandler, (int *)&event_type); + } + + num_pressed = g_pGesture->num_pressed; + + current_time = GetTimeInMillis(); + +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupTap][P][num_pressed=%d] AREA_SIZE(area.extents)=%d, base_cx=%d, base_cy=%d, base_time=%d, current_time=%d\n", num_pressed, base_area_size, base_cx, base_cy, base_time, current_time); +#endif//__DETAIL_DEBUG__ + break; + + case ET_Motion: + if( !(g_pGesture->fingers[idx].flags & PressFlagTap ) ) + break; + + if( num_pressed < 2 ) + return; + + if( num_pressed != g_pGesture->num_pressed ) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupTap][M][cleanup] num_pressed=%d, g_pGesture->num_pressed=%d\n", num_pressed, g_pGesture->num_pressed); +#endif//__DETAIL_DEBUG__ + //goto cleanup_tap; + } + + mbits |= (1 << idx); + if( mbits == (pow(2, num_pressed)-1) ) + { + area_size = AREA_SIZE(&g_pGesture->area.extents); + cx = AREA_CENTER_X(&g_pGesture->area.extents); + cy = AREA_CENTER_Y(&g_pGesture->area.extents); +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupTap][M][num_pressed=%d] area_size=%d, base_area_size=%d, diff=%d\n", num_pressed, area_size, base_area_size, ABS(base_area_size - area_size)); + ErrorF("[GroupTap][M] cx=%d, base_cx=%d, diff=%d\n", cx, base_cx, ABS(cx-base_cx)); + ErrorF("[GroupTap][M] cy=%d, base_cy=%d, diff=%d\n", cy, base_cy, ABS(cy-base_cy)); +#endif//__DETAIL_DEBUG__ + + if( ABS(base_area_size-area_size) >= TAP_AREA_THRESHOLD ) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupTap][M] diff between area size(=%d) and base area size(=%d) is bigger than threshold(=%d)!\n", area_size, base_area_size, ABS(base_area_size-area_size)); +#endif//__DETAIL_DEBUG__ + goto cleanup_tap; + } + + if( !INBOX(&base_box_ext, cx, cy) ) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupTap][M] current center coordinates is not in base coordinates box !\n"); +#endif//__DETAIL_DEBUG__ + goto cleanup_tap; + } + } + break; + + case ET_ButtonRelease: + if( g_pGesture->num_pressed ) + break; + + if( !tap_repeat ) + { + prev_num_pressed = num_pressed; + } + + prev_tap_repeat = tap_repeat; + tap_repeat++; + +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupTap][R] tap_repeat=%d, prev_tap_repeat=%d, num_pressed=%d, prev_num_pressed=%d\n", tap_repeat, prev_tap_repeat, num_pressed, prev_num_pressed); +#endif//__DETAIL_DEBUG__ + + if( num_pressed != prev_num_pressed || !GestureHasFingerEventMask(GestureNotifyTap, num_pressed) ) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupTap][R] num_pressed(=%d) != prev_num_pressed(=%d) OR %d finger tap event was not grabbed/selected !\n", + num_pressed, prev_num_pressed, num_pressed); +#endif//__DETAIL_DEBUG__ + goto cleanup_tap; + } + + if( tap_repeat < MAX_TAP_REPEATS ) + { + state = 2; + TimerCancel(tap_event_timer); + tap_event_timer = TimerSet(tap_event_timer, 0, DBL_TAP_TIME_THRESHOLD, GestureEventTimerHandler, (int *)&event_type); + num_pressed = 0; + break; + } + +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupTap][R] %d finger %s\n", num_pressed, (tap_repeat==2) ? "DBL_TAP" : "TRIPLE_TAP"); +#endif//__DETAIL_DEBUG__ + + if( GestureHasFingerEventMask(GestureNotifyTap, num_pressed) ) + GestureHandleGesture_Tap(num_pressed, tap_repeat, base_cx, base_cy); + + if( tap_repeat >= MAX_TAP_REPEATS ) + { + goto cleanup_tap; + } + + prev_num_pressed = num_pressed; + num_pressed = 0; + break; + } + + return; + +cleanup_tap: + + if( 0 == state ) + g_pGesture->recognized_gesture &= ~TapFilterMask; + g_pGesture->filter_mask |= TapFilterMask; + + if( g_pGesture->filter_mask == GESTURE_FILTER_MASK_ALL ) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupTap][cleanup] GestureFlushOrDrop() !\n"); +#endif//__DETAIL_DEBUG__ + + if( ERROR_INVALPTR == GestureFlushOrDrop() ) + { + GestureControl(g_pGesture->this_device, DEVICE_OFF); + } + } + + num_pressed = 0; + tap_repeat = 0; + prev_num_pressed = 0; + mbits = 0; + base_time = 0; + state = 0; + TimerCancel(tap_event_timer); + return; +} + +void +GestureRecognize_GroupTapNHold(int type, InternalEvent *ev, DeviceIntPtr device, int idx, int timer_expired) +{ + static int num_pressed = 0; + static int base_area_size = 0; + static Time base_time = 0; + static int base_cx; + static int base_cy; + int cx, cy; + static pixman_box16_t base_box_ext; + int area_size; + static int mbits = 0; + + static int tap_repeat = 0; + static int prev_num_pressed = 0; + + static OsTimerPtr tapnhold_event_timer = NULL; + static int event_type = GestureNotifyTapNHold; + static int state = GestureEnd; + + Time interval = 0; + Time holdtime = 0; + + if( timer_expired ) + { + if( (state == GestureEnd) && num_pressed ) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupTapNHold][Timer][state=%d] Tap time expired !(num_pressed=%d, tap_repeat=%d)\n", GestureEnd, tap_repeat, num_pressed, tap_repeat); +#endif//__DETAIL_DEBUG__ + state = 0; + goto cleanup_tapnhold; + } + + if( state == GestureDone ) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupTapNHold][Timer][state=%d] Interval between Tap and Hold is too long !\n"); +#endif//__DETAIL_DEBUG__ + goto cleanup_tapnhold; + } + +#ifdef __DETAIL_DEBUG__ + switch( state ) + { + case GestureBegin: + ErrorF("[GroupTapNHold][Timer] TapNHold Begin !\n"); + break; + + case GestureUpdate: + ErrorF("[GroupTapNHold][Timer] TapNHold Update !\n"); + break; + } +#endif//__DETAIL_DEBUG__ + + if( GestureHasFingerEventMask(GestureNotifyTapNHold, prev_num_pressed) ) + { + GestureHandleGesture_TapNHold(prev_num_pressed, base_cx, base_cy, interval, holdtime, state); + tapnhold_event_timer = TimerSet(tapnhold_event_timer, 0, TAPNHOLD_HOLD_TIME_THRESHOLD, GestureEventTimerHandler, (int *)&event_type); + } + else + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupTapNHold][Timer] %d finger TapNHold event was not grabbed/selected !\n", prev_num_pressed); +#endif//__DETAIL_DEBUG__ + goto cleanup_tapnhold; + } + + if( state <= GestureBegin ) + state++; + return; + } + + switch( type ) + { + case ET_ButtonPress: + g_pGesture->fingers[idx].flags |= PressFlagTapNHold; + + if( g_pGesture->num_pressed < 2 ) + return; + + //if( !prev_num_pressed && (!base_area_size || g_pGesture->num_pressed > num_pressed) ) + if( !base_area_size || g_pGesture->num_pressed > num_pressed ) + { + + if( state == GestureUpdate ) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupTapNHold][P][cleanup] num_finger changed ! num_pressed=%d, g_pGesture->num_pressed=%d\n", num_pressed, g_pGesture->num_pressed); +#endif//__DETAIL_DEBUG__ + goto cleanup_tapnhold; + } + + if( state == GestureDone ) + state = GestureBegin; + + base_area_size = AREA_SIZE(&g_pGesture->area.extents); + base_cx = AREA_CENTER_X(&g_pGesture->area.extents); + base_cy = AREA_CENTER_Y(&g_pGesture->area.extents); + base_time = GetTimeInMillis(); + base_box_ext.x1 = base_cx-TAPNHOLD_MOVE_THRESHOLD; + base_box_ext.y1 = base_cy-TAPNHOLD_MOVE_THRESHOLD; + base_box_ext.x2 = base_cx+TAPNHOLD_MOVE_THRESHOLD; + base_box_ext.y2 = base_cy+TAPNHOLD_MOVE_THRESHOLD; + if( state == GestureEnd ) + tapnhold_event_timer = TimerSet(tapnhold_event_timer, 0, TAPNHOLD_TAP_TIME_THRESHOLD, GestureEventTimerHandler, (int *)&event_type); + else + { + TimerCancel(tapnhold_event_timer); + tapnhold_event_timer = TimerSet(tapnhold_event_timer, 0, TAPNHOLD_HOLD_TIME_THRESHOLD, GestureEventTimerHandler, (int *)&event_type); + } +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupTapNHold][P] Create Timer !(state=%d)\n", state); +#endif//__DETAIL_DEBUG__ + } + + num_pressed = g_pGesture->num_pressed; + +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupTapNHold][P][num_pressed=%d] AREA_SIZE(area.extents)=%d, base_cx=%d, base_cy=%d, base_time=%d\n", num_pressed, base_area_size, base_cx, base_cy, base_time); +#endif//__DETAIL_DEBUG__ + break; + + case ET_Motion: + if( !(g_pGesture->fingers[idx].flags & PressFlagTapNHold ) ) + break; + + if( num_pressed < 2 ) + return; + + if( num_pressed != g_pGesture->num_pressed ) + { + if( state != GestureEnd ) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupTapNHold][M][cleanup] num_finger changed ! num_pressed=%d, g_pGesture->num_pressed=%d\n", num_pressed, g_pGesture->num_pressed); +#endif//__DETAIL_DEBUG__ + goto cleanup_tapnhold; + } +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupTapNHold][M][cleanup] num_pressed=%d, g_pGesture->num_pressed=%d\n", num_pressed, g_pGesture->num_pressed); +#endif//__DETAIL_DEBUG__ + //goto cleanup_tapnhold; + } + + mbits |= (1 << idx); + if( mbits == (pow(2, num_pressed)-1) ) + { + area_size = AREA_SIZE(&g_pGesture->area.extents); + cx = AREA_CENTER_X(&g_pGesture->area.extents); + cy = AREA_CENTER_Y(&g_pGesture->area.extents); +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupTapNHold][M][num_pressed=%d] area_size=%d, base_area_size=%d, diff=%d\n", num_pressed, area_size, base_area_size, ABS(base_area_size - area_size)); + ErrorF("[GroupTapNHold][M] cx=%d, base_cx=%d, diff=%d\n", cx, base_cx, ABS(cx-base_cx)); + ErrorF("[GroupTapNHold][M] cy=%d, base_cy=%d, diff=%d\n", cy, base_cy, ABS(cy-base_cy)); +#endif//__DETAIL_DEBUG__ + + if( ABS(base_area_size-area_size) >= TAPNHOLD_AREA_THRESHOLD ) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupTapNHold][M] diff between area size(=%d) and base area size(=%d) is bigger than threshold(=%d)!\n", area_size, base_area_size, ABS(base_area_size-area_size)); +#endif//__DETAIL_DEBUG__ + goto cleanup_tapnhold; + } + + if( !INBOX(&base_box_ext, cx, cy) ) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupTapNHold][M] current center coordinates is not in base coordinates box !\n"); +#endif//__DETAIL_DEBUG__ + goto cleanup_tapnhold; + } + } + break; + + case ET_ButtonRelease: + if( state != GestureEnd && num_pressed >= 2) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupTapNHold][R][cleanup] num_finger changed ! num_pressed=%d, g_pGesture->num_pressed=%d\n", num_pressed, g_pGesture->num_pressed); +#endif//__DETAIL_DEBUG__ + goto cleanup_tapnhold; + } + + if( g_pGesture->num_pressed ) + break; + + if( !tap_repeat ) + { + prev_num_pressed = num_pressed; + } + + tap_repeat++; + +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupTapNHold][R] tap_repeat=%d, num_pressed=%d, prev_num_pressed=%d\n", tap_repeat, num_pressed, prev_num_pressed); +#endif//__DETAIL_DEBUG__ + + if( num_pressed != prev_num_pressed || !GestureHasFingerEventMask(GestureNotifyTapNHold, num_pressed) ) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupTapNHold][R] num_pressed(=%d) != prev_num_pressed(=%d) OR %d finger tap event was not grabbed/selected !\n", + num_pressed, prev_num_pressed, num_pressed); +#endif//__DETAIL_DEBUG__ + goto cleanup_tapnhold; + } + + if( tap_repeat > 1 ) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupTapNHold][R] Tap events(tap_repeat=%d) were put twice or more !(ignored)\n", tap_repeat); +#endif//__DETAIL_DEBUG__ + goto cleanup_tapnhold; + } + + prev_num_pressed = num_pressed; + num_pressed = 0; + state = GestureDone; + + TimerCancel(tapnhold_event_timer); + tapnhold_event_timer = TimerSet(tapnhold_event_timer, 0, TAPNHOLD_INTV_TIME_THRESHOLD, GestureEventTimerHandler, (int *)&event_type); + +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupTapNHold][R][Last] state=%d, tap_repeat=%d, num_pressed=%d, prev_num_pressed=%d\n", state, tap_repeat, num_pressed, prev_num_pressed); +#endif//__DETAIL_DEBUG__ + break; + } + + return; + +cleanup_tapnhold: + + if( state == GestureUpdate ) + { + state = GestureEnd; + if( GestureHasFingerEventMask(GestureNotifyTapNHold, prev_num_pressed) ) + { + GestureHandleGesture_TapNHold(prev_num_pressed, base_cx, base_cy, interval, holdtime, state); + } + } + else + { + g_pGesture->recognized_gesture &= ~TapNHoldFilterMask; + } + + g_pGesture->filter_mask |= TapNHoldFilterMask; + if( g_pGesture->filter_mask == GESTURE_FILTER_MASK_ALL ) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupTapNHold][cleanup] GestureFlushOrDrop() !\n"); +#endif//__DETAIL_DEBUG__ + + if( ERROR_INVALPTR == GestureFlushOrDrop() ) + { + GestureControl(g_pGesture->this_device, DEVICE_OFF); + } + } + + TimerCancel(tapnhold_event_timer); + num_pressed = 0; + tap_repeat = 0; + prev_num_pressed = 0; + mbits = 0; + base_time = 0; + state = 0; + + return; +} + +void GestureRecognize_GroupHold(int type, InternalEvent *ev, DeviceIntPtr device, int idx, int timer_expired) +{ + static int num_pressed = 0; + static int base_area_size = 0; + static Time base_time = 0; + static int base_cx; + static int base_cy; + int cx, cy; + static pixman_box16_t base_box_ext; + int area_size; + static int state = GestureEnd; + + static OsTimerPtr hold_event_timer = NULL; + static int event_type = GestureNotifyHold; + + if( timer_expired ) + { + if( state <= GestureBegin ) + state++; + +#ifdef __DETAIL_DEBUG__ + switch( state ) + { + case GestureBegin: + ErrorF("[GroupHold] HOLD Begin !\n"); + break; + + case GestureUpdate: + ErrorF("[GroupHold] HOLD Update !\n"); + break; + } +#endif//__DETAIL_DEBUG__ + + if( GestureHasFingerEventMask(GestureNotifyHold, num_pressed) ) + { + GestureHandleGesture_Hold(num_pressed, base_cx, base_cy, GetTimeInMillis()-base_time, state); + hold_event_timer = TimerSet(hold_event_timer, 0, HOLD_TIME_THRESHOLD, GestureEventTimerHandler, (int *)&event_type); + } + return; + } + + switch( type ) + { + case ET_ButtonPress: + g_pGesture->fingers[idx].flags |= PressFlagHold; + + if( g_pGesture->num_pressed < 2 ) + return; + + if( !base_area_size || g_pGesture->num_pressed > num_pressed ) + { + if( state != GestureEnd ) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupHold][P][cleanup] num_finger changed ! num_pressed=%d, g_pGesture->num_pressed=%d\n", num_pressed, g_pGesture->num_pressed); +#endif//__DETAIL_DEBUG__ + goto cleanup_hold; + } + + base_area_size = AREA_SIZE(&g_pGesture->area.extents); + base_cx = AREA_CENTER_X(&g_pGesture->area.extents); + base_cy = AREA_CENTER_Y(&g_pGesture->area.extents); + base_time = GetTimeInMillis(); + base_box_ext.x1 = base_cx-HOLD_MOVE_THRESHOLD; + base_box_ext.y1 = base_cy-HOLD_MOVE_THRESHOLD; + base_box_ext.x2 = base_cx+HOLD_MOVE_THRESHOLD; + base_box_ext.y2 = base_cy+HOLD_MOVE_THRESHOLD; + event_type = GestureNotifyHold; + hold_event_timer = TimerSet(hold_event_timer, 0, HOLD_TIME_THRESHOLD, GestureEventTimerHandler, (int *)&event_type); + } + num_pressed = g_pGesture->num_pressed; + +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupHold][P]][num_pressed=%d] AREA_SIZE(area.extents)=%d, base_cx=%d, base_cy=%d\n", num_pressed, base_area_size, base_cx, base_cy); +#endif//__DETAIL_DEBUG__ + break; + + case ET_Motion: + if( !(g_pGesture->fingers[idx].flags & PressFlagHold ) ) + break; + + if( num_pressed < 2 ) + return; + + if( num_pressed != g_pGesture->num_pressed ) + { + if( state != GestureEnd ) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupHold][M][cleanup] num_finger changed ! num_pressed=%d, g_pGesture->num_pressed=%d\n", num_pressed, g_pGesture->num_pressed); +#endif//__DETAIL_DEBUG__ + goto cleanup_hold; + } +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupHold][M][cleanup] num_pressed=%d, g_pGesture->num_pressed=%d\n", num_pressed, g_pGesture->num_pressed); +#endif//__DETAIL_DEBUG__ + //goto cleanup_hold; + } + + area_size = AREA_SIZE(&g_pGesture->area.extents); + cx = AREA_CENTER_X(&g_pGesture->area.extents); + cy = AREA_CENTER_Y(&g_pGesture->area.extents); +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupHold][M][num_pressed=%d] area_size=%d, base_area_size=%d, diff=%d\n", num_pressed, area_size, base_area_size, ABS(base_area_size - area_size)); + ErrorF("[GroupHold][M] cx=%d, base_cx=%d, diff=%d\n", cx, base_cx, ABS(cx-base_cx)); + ErrorF("[GroupHold][M] cy=%d, base_cy=%d, diff=%d\n", cy, base_cy, ABS(cy-base_cy)); +#endif//__DETAIL_DEBUG__ + + if( ABS(base_area_size-area_size) >= HOLD_AREA_THRESHOLD ) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupHold][M] diff between area size(=%d) and base area size(=%d) is bigger than threshold(=%d)!\n", area_size, base_area_size, ABS(base_area_size-area_size)); +#endif//__DETAIL_DEBUG__ + goto cleanup_hold; + } + + if( !INBOX(&base_box_ext, cx, cy) ) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupHold][M] current center coordinates is not in base coordinates box !\n"); +#endif//__DETAIL_DEBUG__ + goto cleanup_hold; + } + break; + + case ET_ButtonRelease: + if( state != GestureEnd && num_pressed >= 2) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupHold][R][cleanup] num_finger changed ! num_pressed=%d, g_pGesture->num_pressed=%d\n", num_pressed, g_pGesture->num_pressed); +#endif//__DETAIL_DEBUG__ + goto cleanup_hold; + } + + //ErrorF("[GroupHold][R] num_pressed=%d, g_pGesture->num_pressed=%d\n", num_pressed, g_pGesture->num_pressed); + if( g_pGesture->num_pressed ) + break; + + goto cleanup_hold; + break; + } + + return; + +cleanup_hold: + + if( state == GestureBegin || state == GestureUpdate ) + { + state = GestureEnd; + if( GestureHasFingerEventMask(GestureNotifyHold, num_pressed) ) + { + GestureHandleGesture_Hold(num_pressed, base_cx, base_cy, GetTimeInMillis()-base_time, state); + } + } + else + { + g_pGesture->recognized_gesture &= ~HoldFilterMask; + } + + g_pGesture->filter_mask |= HoldFilterMask; + num_pressed = 0; + base_area_size = 0; + base_time = 0; + base_cx = base_cy = 0; + state = GestureEnd; + base_box_ext.x1 = base_box_ext.x2 = base_box_ext.y1 = base_box_ext.y2 = 0; + TimerCancel(hold_event_timer); + return; +} + +WindowPtr +GestureGetEventsWindow(void) +{ + Mask mask; + WindowPtr pWin; + + //check grabbed event(s) + if( !GestureHasGrabbedEvents(&g_pGesture->grabMask, &g_pGesture->GrabEvents) ) + g_pGesture->grabMask = 0; + + pWin = GestureWindowOnXY(g_pGesture->fingers[0].px, g_pGesture->fingers[0].py); + + if( pWin ) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[X11][GestureGetEventsWindow] pWin->drawable.id=0x%x\n", pWin->drawable.id); +#endif//__DETAIL_DEBUG__ + g_pGesture->gestureWin = pWin->drawable.id; + } + else + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[X11][GestureGetEventsWindow] GestureWindowOnXY returns NULL !\n"); +#endif//__DETAIL_DEBUG__ + return NULL; + } + + //check selected event(s) + if( !GestureHasSelectedEvents(pWin, &g_pGesture->eventMask) ) + g_pGesture->eventMask = 0; + + if( !g_pGesture->grabMask && !g_pGesture->eventMask ) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[X11][GestureGetEventsWindow] No events were grabbed/selected for window(0x%x) !\n", pWin->drawable.id); +#endif//__DETAIL_DEBUG__ + return NULL; + } + +#ifdef __DETAIL_DEBUG__ + ErrorF("[X11][GestureGetEventsWindow] g_pGesture->grabMask=0x%x, g_pGesture->eventMask=0x%x\n", + g_pGesture->grabMask, g_pGesture->eventMask); +#endif//__DETAIL_DEBUG__ + + mask = (GESTURE_FILTER_MASK_ALL & ~(g_pGesture->grabMask | g_pGesture->eventMask)); + +#ifdef __DETAIL_DEBUG__ + ErrorF("[X11][GestureGetEventsWindow] g_pGesture->filter_mask=0x%x, mask=0x%x\n", g_pGesture->filter_mask, mask); +#endif//__DETAIL_DEBUG__ + + g_pGesture->filter_mask = mask; + +#ifdef __DETAIL_DEBUG__ + ErrorF("[X11][GestureGetEventsWindow] g_pGesture->filter_mask=0x%x\n", g_pGesture->filter_mask); +#endif//__DETAIL_DEBUG__ + + return pWin; +} + +static CARD32 +GestureEventTimerHandler(OsTimerPtr timer, CARD32 time, pointer arg) +{ + int event_type = *(int *)arg; + + switch( event_type ) + { + case GestureNotifyHold: +#ifdef __DETAIL_DEBUG__ + ErrorF("[GestureEventTimerHandler] GestureNotifyHold (event_type = %d)\n", event_type); +#endif//__DETAIL_DEBUG__ + GestureRecognize_GroupHold(event_type, NULL, NULL, 0, 1); + break; + + case GestureNotifyPan: +#ifdef __DETAIL_DEBUG__ + ErrorF("[GestureEventTimerHandler] GestureNotifyPan (event_type = %d)\n", event_type); +#endif//__DETAIL_DEBUG__ + GestureRecognize_GroupPan(event_type, NULL, NULL, 0, 1); + break; + + case GestureNotifyTap: +#ifdef __DETAIL_DEBUG__ + ErrorF("[GestureEventTimerHandler] GestureNotifyTap (event_type = %d)\n", event_type); +#endif//__DETAIL_DEBUG__ + GestureRecognize_GroupTap(event_type, NULL, NULL, 0, 1); + break; + + case GestureNotifyTapNHold: +#ifdef __DETAIL_DEBUG__ + ErrorF("[GestureEventTimerHandler] GestureNotifyTapNHold (event_type = %d)\n", event_type); +#endif//__DETAIL_DEBUG__ + GestureRecognize_GroupTapNHold(event_type, NULL, NULL, 0, 1); + break; + + default: +#ifdef __DETAIL_DEBUG__ + ErrorF("[GestureEventTimerHandler] unknown event_type (=%d)\n", event_type); +#endif//__DETAIL_DEBUG__ + if(timer) + ErrorF("[GestureEventTimerHandler] timer=%x\n", (unsigned int)timer); + } + + return 0; +} + +static CARD32 +GestureSingleFingerTimerHandler(OsTimerPtr timer, CARD32 time, pointer arg) +{ + g_pGesture->filter_mask = GESTURE_FILTER_MASK_ALL; + g_pGesture->recognized_gesture = 0; + + if( ERROR_INVALPTR == GestureFlushOrDrop() ) + { + GestureControl(g_pGesture->this_device, DEVICE_OFF); + } + +#ifdef __DETAIL_DEBUG__ + ErrorF("[X11][Single] expired !\n"); +#endif//__DETAIL_DEBUG__ + + return 0; +} + +void +GestureRecognize(int type, InternalEvent *ev, DeviceIntPtr device) +{ + int i; + int idx = device->id - g_pGesture->first_fingerid; + static OsTimerPtr single_finger_timer = NULL; + + if( PROPAGATE_EVENTS == g_pGesture->ehtype ) + return; + + if( device->id < g_pGesture->first_fingerid )//filtering device id : 2 + return; + + switch( type ) + { + case ET_ButtonPress: + if( idx == 0 ) + g_pGesture->event_sum[0] = BTN_PRESSED; + g_pGesture->fingers[idx].ptime = ev->any.time; + g_pGesture->fingers[idx].px = ev->device_event.root_x; + g_pGesture->fingers[idx].py = ev->device_event.root_y; + + g_pGesture->num_pressed++; + if( g_pGesture->num_pressed == 1 ) + { + single_finger_timer = TimerSet(single_finger_timer, 0, 50, GestureSingleFingerTimerHandler, NULL); + } + else + { + TimerCancel(single_finger_timer); + } + + if( g_pGesture->num_pressed > g_pGesture->num_mt_devices ) + g_pGesture->num_pressed = g_pGesture->num_mt_devices; + + if( !g_pGesture->pTempWin || g_pGesture->num_pressed != g_pGesture->inc_num_pressed ) + { + g_pGesture->pTempWin = GestureGetEventsWindow(); + + if( NULL == g_pGesture->pTempWin ) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[X11][GestureRecognize][g_pGesture->num_pressed=%d] No grabbed events and no event masks !\n", g_pGesture->num_pressed); +#endif//__DETAIL_DEBUG__ + g_pGesture->filter_mask = GESTURE_FILTER_MASK_ALL; + goto flush_or_drop; + } + } + + g_pGesture->inc_num_pressed = g_pGesture->num_pressed; + + g_pGesture->finger_rects[idx].extents.x1 = ev->device_event.root_x - FINGER_WIDTH; + g_pGesture->finger_rects[idx].extents.x2 = ev->device_event.root_x + FINGER_WIDTH; + g_pGesture->finger_rects[idx].extents.y1 = ev->device_event.root_y - FINGER_HEIGHT; + g_pGesture->finger_rects[idx].extents.y2 = ev->device_event.root_y + FINGER_HEIGHT; + + if( g_pGesture->inc_num_pressed == 1 ) + { + pixman_region_union(&g_pGesture->area, &g_pGesture->finger_rects[0], &g_pGesture->finger_rects[0]); +#ifdef __DETAIL_DEBUG__ + ErrorF("[P][g_pGesture->inc_num_pressed=1] AREA_SIZE(area.extents)=%d\n", AREA_SIZE(&g_pGesture->area.extents)); +#endif//__DETAIL_DEBUG__ + } + else + { + pixman_region_union(&g_pGesture->area, &g_pGesture->finger_rects[0], &g_pGesture->finger_rects[0]); + for( i = 1 ; i < g_pGesture->inc_num_pressed ; i++ ) + { + pixman_region_union(&g_pGesture->area, &g_pGesture->area, &g_pGesture->finger_rects[i]); + } +#ifdef __DETAIL_DEBUG__ + ErrorF("[P][g_pGesture->inc_num_pressed=%d] AREA_SIZE(area.extents)=%d\n", g_pGesture->inc_num_pressed, AREA_SIZE(&g_pGesture->area.extents)); +#endif//__DETAIL_DEBUG__ + } + break; + + case ET_Motion: + if( !g_pGesture->fingers[idx].ptime ) + return; + + g_pGesture->fingers[idx].mx = ev->device_event.root_x; + g_pGesture->fingers[idx].my = ev->device_event.root_y; + + if( idx == 0 && g_pGesture->event_sum[0] ) + { + g_pGesture->event_sum[0] += BTN_MOVING; +#ifdef __DETAIL_DEBUG__ + ErrorF("[X11][GestureRecognize] moving !\n"); +#endif//__DETAIL_DEBUG__ + if( g_pGesture->event_sum[0] >= 7 ) + { + if( (g_pGesture->event_sum[0] >= 7) && (g_pGesture->inc_num_pressed < 2) ) + { + #ifdef __DETAIL_DEBUG__ + ErrorF("[X11][GestureRecognize] moving limit!\n"); + #endif//__DETAIL_DEBUG__ + g_pGesture->filter_mask = GESTURE_FILTER_MASK_ALL; + goto flush_or_drop; + } + } + } + + g_pGesture->finger_rects[idx].extents.x1 = ev->device_event.root_x - FINGER_WIDTH; + g_pGesture->finger_rects[idx].extents.x2 = ev->device_event.root_x + FINGER_WIDTH; + g_pGesture->finger_rects[idx].extents.y1 = ev->device_event.root_y - FINGER_HEIGHT; + g_pGesture->finger_rects[idx].extents.y2 = ev->device_event.root_y + FINGER_HEIGHT; + + if( g_pGesture->inc_num_pressed == 1 ) + { + pixman_region_union(&g_pGesture->area, &g_pGesture->finger_rects[0], &g_pGesture->finger_rects[0]); +#ifdef __DETAIL_DEBUG__ + ErrorF("[M][g_pGesture->inc_num_pressed=1] AREA_SIZE(area)=%d\n", AREA_SIZE(&g_pGesture->area.extents)); +#endif//__DETAIL_DEBUG__ + } + else + { + pixman_region_union(&g_pGesture->area, &g_pGesture->finger_rects[0], &g_pGesture->finger_rects[0]); + for( i = 1 ; i < g_pGesture->inc_num_pressed ; i++ ) + { + pixman_region_union(&g_pGesture->area, &g_pGesture->area, &g_pGesture->finger_rects[i]); + } +#ifdef __DETAIL_DEBUG__ + ErrorF("[M][g_pGesture->inc_num_pressed=%d] AREA_SIZE(area)=%d\n", g_pGesture->inc_num_pressed, AREA_SIZE(&g_pGesture->area.extents)); +#endif//__DETAIL_DEBUG__ + } + break; + + case ET_ButtonRelease: + g_pGesture->fingers[idx].rtime = ev->any.time; + g_pGesture->fingers[idx].rx = ev->device_event.root_x; + g_pGesture->fingers[idx].ry = ev->device_event.root_y; + + g_pGesture->num_pressed--; + if( g_pGesture->num_pressed <= 0 ) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[X11][GestureRecognize] All fingers were released !\n"); +#endif//__DETAIL_DEBUG__ + if( g_pGesture->inc_num_pressed == 1 ) + goto flush_or_drop; + } + break; + } + + if( g_pGesture->filter_mask != GESTURE_FILTER_MASK_ALL ) + { + if( !(g_pGesture->filter_mask & FlickFilterMask) ) + { + GestureRecognize_GroupFlick(type, ev, device, idx); + } + if( !(g_pGesture->filter_mask & PanFilterMask) ) + { + GestureRecognize_GroupPan(type, ev, device, idx, 0); + } + if( !(g_pGesture->filter_mask & PinchRotationFilterMask) ) + { + GestureRecognize_GroupPinchRotation(type, ev, device, idx); + } + if( !(g_pGesture->filter_mask & TapFilterMask) ) + { + GestureRecognize_GroupTap(type, ev, device, idx, 0); + } + if( !(g_pGesture->filter_mask & TapNHoldFilterMask) ) + { + GestureRecognize_GroupTapNHold(type, ev, device, idx, 0); + } + if( !(g_pGesture->filter_mask & HoldFilterMask) ) + { + GestureRecognize_GroupHold(type, ev, device, idx, 0); + } + } + +#ifdef __DETAIL_DEBUG__ + ErrorF("[X11][GestureRecognize][N] g_pGesture->filter_mask = 0x%x\n", g_pGesture->filter_mask); + ErrorF("[X11][GestureRecognize][N] g_pGesture->GESTURE_FILTER_MASK_ALL = 0x%x\n", GESTURE_FILTER_MASK_ALL); + ErrorF("[X11][GestureRecognize][N] g_pGesture->recognized_gesture=0x%x\n", g_pGesture->recognized_gesture); +#endif//__DETAIL_DEBUG__ + + if( g_pGesture->filter_mask == GESTURE_FILTER_MASK_ALL ) + { + if( !g_pGesture->recognized_gesture ) + goto flush_or_drop; + else if( !g_pGesture->num_pressed ) + goto flush_or_drop; + } + + if( g_pGesture->recognized_gesture ) + { + if( g_pGesture->ehtype == KEEP_EVENTS ) + GestureEventsDrop(); + g_pGesture->ehtype = IGNORE_EVENTS; + } + + return; + +flush_or_drop: + +#ifdef __DETAIL_DEBUG__ + ErrorF("[GestureRecognize] GestureFlushOrDrop() !\n"); +#endif//__DETAIL_DEBUG__ + if( ERROR_INVALPTR == GestureFlushOrDrop() ) + { + GestureControl(g_pGesture->this_device, DEVICE_OFF); + } +} + + +ErrorStatus GestureFlushOrDrop(void) +{ + ErrorStatus err; + + if( g_pGesture->recognized_gesture ) + { + GestureEventsDrop(); + } + else + { + g_pGesture->ehtype = PROPAGATE_EVENTS; + + err = GestureEventsFlush(); + if( ERROR_NONE != err ) + return err; + +#ifdef __DETAIL_DEBUG__ + ErrorF("[X11][GestureFlushOrDrop][F] g_pGesture->filter_mask = 0x%x\n", g_pGesture->filter_mask); + ErrorF("[X11][GestureFlushOrDrop][F] g_pGesture->GESTURE_FILTER_MASK_ALL = 0x%x\n", GESTURE_FILTER_MASK_ALL); + ErrorF("[X11][GestureFlushOrDrop][F] g_pGesture->recognized_gesture=0x%x\n", g_pGesture->recognized_gesture); +#endif//__DETAIL_DEBUG__ + } + + err = GestureRegionsReinit(); + if( ERROR_NONE != err ) + return err; + + g_pGesture->pTempWin = NULL; + g_pGesture->inc_num_pressed = g_pGesture->num_pressed = 0; + g_pGesture->event_sum[0] = 0; + + return ERROR_NONE; +} + +void +GestureHandleMTSyncEvent(int screen_num, InternalEvent *ev, DeviceIntPtr device) +{ + int i; + +#ifdef __DEBUG_EVENT_HANDLER__ + ErrorF("\n[X11][GestureHandleMTSyncEvent] (%d:%d) time:%d cur:%d\n", + ev->any_event.deviceid, ev->any_event.sync, (int)ev->any.time, (int)GetTimeInMillis()); +#endif//__DEBUG_EVENT_HANDLER__ + + if( MTOUCH_FRAME_SYNC_BEGIN == ev->any_event.sync ) + { + g_pGesture->ehtype = KEEP_EVENTS; + g_pGesture->filter_mask = 0; + g_pGesture->recognized_gesture = 0; + g_pGesture->num_pressed = 0; + + for( i=0 ; i < g_pGesture->num_mt_devices ; i++ ) + g_pGesture->fingers[i].ptime = 0; + } + else if( MTOUCH_FRAME_SYNC_END == ev->any_event.sync ) + { + g_pGesture->ehtype = PROPAGATE_EVENTS; + } +} + +void +GestureHandleButtonPressEvent(int screen_num, InternalEvent *ev, DeviceIntPtr device) +{ +#ifdef __DEBUG_EVENT_HANDLER__ + ErrorF("[X11][GestureHandleButtonPEvent] devid=%d time:%d cur:%d\n", device->id, ev->any.time, GetTimeInMillis()); +#endif//__DEBUG_EVENT_HANDLER__ + + switch( g_pGesture->ehtype ) + { + case KEEP_EVENTS: + if( ERROR_INVALPTR == GestureEnqueueEvent(screen_num, ev, device) ) + { + GestureControl(g_pGesture->this_device, DEVICE_OFF); + return; + } + + if( g_pGesture->num_mt_devices ) + GestureRecognize(ET_ButtonPress, ev, device); + else + device->public.processInputProc(ev, device); + break; + + case PROPAGATE_EVENTS: + device->public.processInputProc(ev, device); + break; + + case IGNORE_EVENTS: + GestureRecognize(ET_ButtonPress, ev, device); + break; + + default: + break; + } +} + +void +GestureHandleMotionEvent(int screen_num, InternalEvent *ev, DeviceIntPtr device) +{ +#ifdef __DEBUG_EVENT_HANDLER__ + ErrorF("[X11][GestureHandleMotionEvent] devid=%d time:%d cur:%d\n", device->id, ev->any.time, GetTimeInMillis()); +#endif//__DEBUG_EVENT_HANDLER__ + + switch( g_pGesture->ehtype ) + { + case KEEP_EVENTS: + if( ERROR_INVALPTR == GestureEnqueueEvent(screen_num, ev, device) ) + { + GestureControl(g_pGesture->this_device, DEVICE_OFF); + return; + } + + if( g_pGesture->num_mt_devices ) + GestureRecognize(ET_Motion, ev, device); + else + device->public.processInputProc(ev, device); + break; + + case PROPAGATE_EVENTS: + device->public.processInputProc(ev, device); + break; + + case IGNORE_EVENTS: + GestureRecognize(ET_Motion, ev, device); + break; + + default: + break; + } + +} + +void +GestureHandleButtonReleaseEvent(int screen_num, InternalEvent *ev, DeviceIntPtr device) +{ +#ifdef __DEBUG_EVENT_HANDLER__ + ErrorF("[X11][GestureHandleButtonREvent] devid=%d time:%d cur:%d\n", device->id, ev->any.time, GetTimeInMillis()); +#endif//__DEBUG_EVENT_HANDLER__ + + switch( g_pGesture->ehtype ) + { + case KEEP_EVENTS: + if( ERROR_INVALPTR == GestureEnqueueEvent(screen_num, ev, device) ) + { + GestureControl(g_pGesture->this_device, DEVICE_OFF); + return; + } + + if( g_pGesture->num_mt_devices ) + GestureRecognize(ET_ButtonRelease, ev, device); + else + device->public.processInputProc(ev, device); + break; + + case PROPAGATE_EVENTS: + device->public.processInputProc(ev, device); + break; + + case IGNORE_EVENTS: + GestureRecognize(ET_ButtonRelease, ev, device); + break; + + default: + break; + } +} + +static ErrorStatus +GestureEnableEventHandler(InputInfoPtr pInfo) + { + Bool res; + GestureDevicePtr pGesture = pInfo->private; + + res = GestureInstallResourceStateHooks(); + + if( !res ) + { + ErrorF("[X11][GestureEnableEventHandler] Failed on GestureInstallResourceStateHooks() !\n"); + return ERROR_ABNORMAL; + } + + res = GestureSetMaxNumberOfFingers((int)MAX_MT_DEVICES); + + if( !res ) + { + ErrorF("[X11][GestureEnableEventHandler] Failed on GestureSetMaxNumberOfFingers(%d) !\n", (int)MAX_MT_DEVICES); + goto failed; + } + + pGesture->device_setting_timer = TimerSet(pGesture->device_setting_timer, 0, 500, GestureTimerHandler, pInfo); + + if( !pGesture->device_setting_timer ) + { + ErrorF("[X11][GestureEnableEventHandler] Failed to allocate memory for timer !\n"); + goto failed; + } + + if( ERROR_NONE != GestureRegionsInit() || ERROR_NONE != GestureInitEQ() ) + { + goto failed; + } + + mieqSetHandler(ET_ButtonPress, GestureHandleButtonPressEvent); + mieqSetHandler(ET_ButtonRelease, GestureHandleButtonReleaseEvent); + mieqSetHandler(ET_Motion, GestureHandleMotionEvent); + if( pGesture->is_active ) + mieqSetHandler(ET_MTSync, GestureHandleMTSyncEvent); + + return ERROR_NONE; + +failed: + GestureUninstallResourceStateHooks(); + GestureUnsetMaxNumberOfFingers(); + + return ERROR_ABNORMAL; +} + +static ErrorStatus +GestureDisableEventHandler(void) +{ + ErrorStatus err = ERROR_NONE; + + mieqSetHandler(ET_ButtonPress, NULL); + mieqSetHandler(ET_ButtonRelease, NULL); + mieqSetHandler(ET_Motion, NULL); + mieqSetHandler(ET_MTSync, NULL); + + err = GestureFiniEQ(); + + if( ERROR_INVALPTR == err ) + { + ErrorF("[X11][GestureDisableEventHandler] EQ is invalid or was freed already !\n"); + } + + GestureUninstallResourceStateHooks(); + GestureUnsetMaxNumberOfFingers(); + + return err; +} + +static CARD32 +GestureTimerHandler(OsTimerPtr timer, CARD32 time, pointer arg) +{ + InputInfoPtr pInfo = (InputInfoPtr)arg; + GestureDevicePtr pGesture = pInfo->private; + + int idx = 0; + DeviceIntPtr dev; + for( dev = inputInfo.pointer ; dev; dev = dev->next ) + { + if(IsMaster(dev) && IsPointerDevice(dev)) + { + pGesture->master_pointer = dev; + ErrorF("[X11][GestureTimerHandler][id:%d] Master Pointer=%s\n", dev->id, pGesture->master_pointer->name); + continue; + } + + if(IsXTestDevice(dev, NULL) && IsPointerDevice(dev)) + { + pGesture->xtest_pointer = dev; + ErrorF("[X11][GestureTimerHandler][id:%d] XTest Pointer=%s\n", dev->id, pGesture->xtest_pointer->name); + continue; + } + + if(IsPointerDevice(dev)) + { + if( idx >= MAX_MT_DEVICES ) + { + ErrorF("[X11][GestureTimerHandler] Number of mt device is over MAX_MT_DEVICES(%d) !\n", + MAX_MT_DEVICES); + continue; + } + pGesture->mt_devices[idx] = dev; + ErrorF("[X11][GestureTimerHandler][id:%d] MT device[%d] name=%s\n", dev->id, idx, pGesture->mt_devices[idx]->name); + idx++; + } + } + + if( !pGesture->master_pointer || !pGesture->xtest_pointer ) + { + ErrorF("[X11][GestureTimerHandler] Failed to get info of master pointer or XTest pointer !\n"); + pGesture->device_setting_timer = TimerSet(pGesture->device_setting_timer, 0, 0, NULL, NULL); + pGesture->num_mt_devices = 0; + + return 0; + } + + pGesture->device_setting_timer = TimerSet(pGesture->device_setting_timer, 0, 0, NULL, NULL); + pGesture->first_fingerid = pGesture->mt_devices[0]->id; + pGesture->num_mt_devices = idx; + + if( !pGesture->num_mt_devices ) + { + ErrorF("[X11][GestureTimerHandler] Failed to mt device information !\n"); + pGesture->device_setting_timer = TimerSet(pGesture->device_setting_timer, 0, 0, NULL, NULL); + pGesture->num_mt_devices = 0; + + return 0; + } + + memset(pGesture->fingers, 0, sizeof(TouchStatus)*pGesture->num_mt_devices); + pGesture->pRootWin = RootWindow(pGesture->master_pointer); + g_pGesture->grabMask = g_pGesture->eventMask = 0; + g_pGesture->pTempWin = NULL; + g_pGesture->inc_num_pressed = 0; + + return 0; +} + +BOOL +IsXTestDevice(DeviceIntPtr dev, DeviceIntPtr master) +{ + if (IsMaster(dev)) + return FALSE; + + if (master) + return (dev->xtest_master_id == master->id); + + return (dev->xtest_master_id != 0); +} + +void +GestureSetDisable(InputInfoPtr pInfo, int enable) +{ + if( !enable ) + { + g_pGesture->ehtype = PROPAGATE_EVENTS; + mieqSetHandler(ET_MTSync, NULL); + g_pGesture->is_active = 0; + ErrorF("[X11][GestureSetDisable] Disabled !\n"); + } + else + { + g_pGesture->ehtype = KEEP_EVENTS; + mieqSetHandler(ET_MTSync, GestureHandleMTSyncEvent); + g_pGesture->is_active = 1; + ErrorF("[X11][GestureSetDisable] Enabled !\n"); + } +} + +ErrorStatus +GestureRegionsInit(void) +{ + int i; + + if( !g_pGesture ) + return ERROR_INVALPTR; + + pixman_region_init(&g_pGesture->area); + + for( i = 0 ; i < MAX_MT_DEVICES ; i++ ) + { + pixman_region_init_rect (&g_pGesture->finger_rects[i], 0, 0, FINGER_WIDTH_2T, FINGER_HEIGHT_2T); + } + + return ERROR_NONE; +} + +ErrorStatus +GestureRegionsReinit(void) +{ + if( !g_pGesture ) + { + ErrorF("[X11][GestureRegionsReinit] Invalid pointer access !\n"); + return ERROR_INVALPTR; + } + + pixman_region_init(&g_pGesture->area); + + return ERROR_NONE; +} + +ErrorStatus +GestureInitEQ(void) +{ + int i; + IEventPtr tmpEQ; + + tmpEQ = (IEventRec *)calloc(GESTURE_EQ_SIZE, sizeof(IEventRec)); + + if( !tmpEQ ) + { + ErrorF("[X11][GestureInitEQ] Failed to allocate memory for EQ !\n"); + return ERROR_ALLOCFAIL; + } + + for( i = 0 ; i < GESTURE_EQ_SIZE ; i++ ) + { + tmpEQ[i].event = (InternalEvent *)malloc(sizeof(InternalEvent)); + if( !tmpEQ[i].event ) + { + ErrorF("[X11][GestureInitEQ] Failed to allocation memory for each event buffer in EQ !\n"); + return ERROR_ALLOCFAIL; + } + } + + g_pGesture->EQ = tmpEQ; + g_pGesture->headEQ = g_pGesture->tailEQ = 0; + + return ERROR_NONE; +} + +ErrorStatus +GestureFiniEQ(void) +{ + int i; + + if( !g_pGesture || !g_pGesture->EQ ) + return ERROR_INVALPTR; + + for( i = 0 ; i < GESTURE_EQ_SIZE ; i++ ) + { + if( g_pGesture->EQ[i].event ) + { + free(g_pGesture->EQ[i].event); + g_pGesture->EQ[i].event = NULL; + } + } + + free(g_pGesture->EQ); + g_pGesture->EQ = NULL; + + return ERROR_NONE; +} + +ErrorStatus +GestureEnqueueEvent(int screen_num, InternalEvent *ev, DeviceIntPtr device) +{ + int tail; + + if( !g_pGesture || !g_pGesture->EQ ) + { + ErrorF("[X11][GestureEnqueueEvent] Invalid pointer access !\n"); + return ERROR_INVALPTR; + } + + tail = g_pGesture->tailEQ; + + if( tail >= GESTURE_EQ_SIZE ) + { + ErrorF("[X11][GestureEnqueueEvent] Gesture EQ is full !\n"); + return ERROR_EQFULL; + } + +#ifdef __DETAIL_DEBUG__ + switch( ev->any.type ) + { + case ET_ButtonPress: + ErrorF("[X11][GestureEnqueueEvent] ET_ButtonPress (id:%d)\n", device->id); + break; + + case ET_ButtonRelease: + ErrorF("[X11][GestureEnqueueEvent] ET_ButtonRelease (id:%d)\n", device->id); + break; + + case ET_Motion: + ErrorF("[X11][GestureEnqueueEvent] ET_Motion (id:%d)\n", device->id); + break; + } +#endif//__DETAIL_DEBUG__ + + g_pGesture->EQ[tail].device = device; + g_pGesture->EQ[tail].screen_num = screen_num; + memcpy(g_pGesture->EQ[tail].event, ev, sizeof(InternalEvent));//need to be optimized + g_pGesture->tailEQ++; + + return ERROR_NONE; +} + +ErrorStatus +GestureEventsFlush(void) +{ + int i; + DeviceIntPtr device; + + if( !g_pGesture->EQ ) + { + ErrorF("[X11][GestureEventsFlush] Invalid pointer access !\n"); + return ERROR_INVALPTR; + } + +#ifdef __DETAIL_DEBUG__ + ErrorF("[X11][GestureEventsFlush]\n"); +#endif//__DETAIL_DEBUG__ + + for( i = g_pGesture->headEQ ; i < g_pGesture->tailEQ ; i++) + { + device = g_pGesture->EQ[i].device; + device->public.processInputProc(g_pGesture->EQ[i].event, device); + } + + for( i = 0 ; i < MAX_MT_DEVICES ; i++ ) + g_pGesture->event_sum[i] = 0; + + g_pGesture->headEQ = g_pGesture->tailEQ = 0;//Free EQ + + return ERROR_NONE; +} + +void +GestureEventsDrop(void) +{ + g_pGesture->headEQ = g_pGesture->tailEQ = 0;//Free EQ +} + +#ifdef HAVE_PROPERTIES +static void +GestureInitProperty(DeviceIntPtr dev) +{ + int rc; + + prop_gesture_recognizer_onoff = MakeAtom(GESTURE_RECOGNIZER_ONOFF, strlen(GESTURE_RECOGNIZER_ONOFF), TRUE); + rc = XIChangeDeviceProperty(dev, prop_gesture_recognizer_onoff, XA_INTEGER, 32, PropModeReplace, 1, &g_pGesture->is_active, FALSE); + + if (rc != Success) + return; + + XISetDevicePropertyDeletable(dev, prop_gesture_recognizer_onoff, FALSE); +} + +static int +GestureSetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val, + BOOL checkonly) +{ + InputInfoPtr pInfo = dev->public.devicePrivate; + + if( prop_gesture_recognizer_onoff == atom ) + { + int data; + if( val->format != 32 || val->type != XA_INTEGER || val->size != 1 ) + return BadMatch; + + if( !checkonly ) + { + data = *((int *)val->data); + GestureSetDisable(pInfo, data); + } + } + + return Success; +} +#endif//HAVE_PROPERTIES + +static int +GestureInit(DeviceIntPtr device) +{ + InputInfoPtr pInfo; + pInfo = device->public.devicePrivate; + +#ifdef HAVE_PROPERTIES + GestureInitProperty(device); + XIRegisterPropertyHandler(device, GestureSetProperty, NULL, NULL); +#endif + + return Success; +} + +static void +GestureFini(DeviceIntPtr device) +{ + XIRegisterPropertyHandler(device, NULL, NULL, NULL); +} + +static pointer +GesturePlug(pointer module, pointer options, int *errmaj, int *errmin) +{ + xf86AddInputDriver(&GESTURE, module, 0); + return module; +} + +static void +GestureUnplug(pointer p) +{ +} + +static InputInfoPtr +GesturePreInit(InputDriverPtr drv, IDevPtr dev, int flags) +{ + InputInfoPtr pInfo; + GestureDevicePtr pGesture; + + if (!(pInfo = xf86AllocateInput(drv, 0))) + return NULL; + + pGesture = calloc(1, sizeof(GestureDeviceRec)); + if (!pGesture) { + pInfo->private = NULL; + xf86DeleteInput(pInfo, 0); + return NULL; + } + + g_pGesture = pGesture; + pInfo->private = pGesture; + pInfo->name = xstrdup(dev->identifier); + pInfo->flags = 0; + pInfo->type_name = XI_MOUSE; /* see XI.h */ + pInfo->conf_idev = dev; + pInfo->read_input = GestureReadInput; /* new data avl */ + pInfo->switch_mode = NULL; /* toggle absolute/relative mode */ + pInfo->device_control = GestureControl; /* enable/disable dev */ + /* process driver specific options */ + pGesture->device = xf86SetStrOption(dev->commonOptions, "Device", "/dev/null"); + pGesture->is_active = xf86SetIntOption(dev->commonOptions, "Activate", 0); + pGesture->gestureWin = None; + + xf86Msg(X_INFO, "%s: Using device %s.\n", pInfo->name, pGesture->device); + + /* process generic options */ + xf86CollectInputOptions(pInfo, NULL, NULL); + xf86ProcessCommonOptions(pInfo, pInfo->options); + + pInfo->fd = -1; + pInfo->flags |= XI86_POINTER_CAPABLE; + pInfo->flags |= XI86_OPEN_ON_INIT; + pInfo->flags |= XI86_CONFIGURED; + return pInfo; +} + +static void +GestureUnInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags) +{ + GestureDevicePtr pGesture = pInfo->private; + + g_pGesture = pGesture = NULL; + pInfo->private = NULL; + + xf86DeleteInput(pInfo, 0); +} + +static int +GestureControl(DeviceIntPtr device, int what) +{ + InputInfoPtr pInfo = device->public.devicePrivate; + GestureDevicePtr pGesture = pInfo->private; + + switch(what) + { + case DEVICE_INIT: + GestureInit(device); + break; + + /* Switch device on. Establish socket, start event delivery. */ + case DEVICE_ON: + xf86Msg(X_INFO, "%s: On.\n", pInfo->name); + + if (device->public.on) + break; + + device->public.on = TRUE; + pGesture->this_device = device; + pGesture->num_mt_devices = 0; + if( ERROR_ABNORMAL == GestureEnableEventHandler(pInfo) ) + goto device_off; + break; + + case DEVICE_OFF: +device_off: + GestureDisableEventHandler(); + GestureFini(device); + pGesture->this_device = NULL; + xf86Msg(X_INFO, "%s: Off.\n", pInfo->name); + + if (!device->public.on) + break; + + pInfo->fd = -1; + device->public.on = FALSE; + break; + + case DEVICE_CLOSE: + /* free what we have to free */ + break; + } + return Success; +} + +static void +GestureReadInput(InputInfoPtr pInfo) +{ +} + diff --git a/src/gesture.h b/src/gesture.h new file mode 100755 index 0000000..e9e17ff --- /dev/null +++ b/src/gesture.h @@ -0,0 +1,378 @@ +/************************************************************************** + +xserver-xorg-input-gesture + +Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + +Contact: Sung-Jin Park + Sangjin LEE + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice (including the +next paragraph) shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**************************************************************************/ + +#ifndef _GESTURE_H_ +#define _GESTURE_H_ + +#include +#include +#include +#include + +#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 3 +#define HAVE_PROPERTIES 1 +#endif + +#define SYSCALL(call) while (((call) == -1) && (errno == EINTR)) +#define RootWindow(dev) dev->spriteInfo->sprite->spriteTrace[0] +#define CLIENT_BITS(id) ((id) & RESOURCE_CLIENT_MASK) +#define CLIENT_ID(id) ((int)(CLIENT_BITS(id) >> CLIENTOFFSET)) + +#define MAX_MT_DEVICES 3 +#define GESTURE_EQ_SIZE 256 + +#define GESTURE_RECOGNIZER_ONOFF "GESTURE_RECOGNIZER_ONOFF" + +#define FINGER_WIDTH 10 +#define FINGER_HEIGHT 10 +#define FINGER_WIDTH_2T 20 +#define FINGER_HEIGHT_2T 20 +#define AREA_CENTER_X(extents) ((extents)->x1 + (((extents)->x2-(extents)->x1)/2)) +#define AREA_CENTER_Y(extents) ((extents)->y1 + (((extents)->y2-(extents)->y1)/2)) +#define AREA_SIZE(extents) (ABS((extents)->x2-(extents)->x1)*ABS((extents)->y2-(extents)->y1)) +#define INBOX(r,x,y) ( ((r)->x2 > x) && ((r)->x1 <= x) && ((r)->y2 > y) && ((r)->y1 <= y) ) + +//tap +#define TAP_THRESHOLD 100//in pixel +#define SINGLE_TAP_TIMEOUT 100//in msec +#define DOUBLE_TAP_TIMEOUT 250//in msec + +//pinch rotation +#define ZOOM_THRESHOLD 0.05f +#define ANGLE_THRESHOLD 0.1f + +typedef int XFixed; +typedef double XDouble; +#define XDoubleToFixed(f) ((XFixed) ((f) * 65536)) +#define XFixedToDouble(f) (((XDouble) (f)) / 65536) + +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) +#define MAX(x, y) (((x) > (y)) ? (x) : (y)) +#define ABS(x) (((x) < 0) ? -(x) : (x)) + +enum +{ + FLICK_NORTHWARD = 0, + FLICK_NORTHEASTWARD, + FLICK_EASTWARD, + FLICK_SOUTHEASTWARD, + FLICK_SOUTHWARD, + FLICK_SOUTHWESTWARD, + FLICK_WESTWARD, + FLICK_NORTHWESTWARD +}; + +#define PAN_AREA_THRESHOLD 10000//=100pixel * 100pixel +#define PAN_MOVE_THRESHOLD 5//pixel +#define PAN_UPDATE_MOVE_THRESHOLD 3//pixel +#define PAN_TIME_THRESHOLD 300//ms + +#define HOLD_AREA_THRESHOLD 2500//=50pixel * 50pixel +#define HOLD_MOVE_THRESHOLD 10//pixel +#define HOLD_TIME_THRESHOLD 500//ms + +#define TAP_AREA_THRESHOLD 10000//= 100pixel * 100pixel +#define TAP_MOVE_THRESHOLD 70//pixel +#define SGL_TAP_TIME_THRESHOLD 200//ms +#define DBL_TAP_TIME_THRESHOLD 200//ms +#define MAX_TAP_REPEATS 3 + +#define TAPNHOLD_AREA_THRESHOLD 4900//= 70pixel * 70pixel +#define TAPNHOLD_MOVE_THRESHOLD 50//pixel +#define TAPNHOLD_TAP_TIME_THRESHOLD 200//ms +#define TAPNHOLD_INTV_TIME_THRESHOLD 200//ms +#define TAPNHOLD_HOLD_TIME_THRESHOLD 500//ms + +#define FLICK_AREA_THRESHOLD 22500//=150pixel * 150pixel +#define FLICK_AREA_TIMEOUT 700//ms +#define FLICK_MOVE_THRESHOLD 100//pixel +#define FLICK_MOVE_TIMEOUT 1000//ms + +typedef enum _MTSyncType +{ + MTOUCH_FRAME_SYNC_END, + MTOUCH_FRAME_SYNC_BEGIN +} MTSyncType; + +typedef enum _EventHandleType +{ + KEEP_EVENTS, + PROPAGATE_EVENTS, + IGNORE_EVENTS +} EventHandleType; + +typedef enum _ErrorStatus +{ + ERROR_NONE, + ERROR_ABNORMAL, + ERROR_INVALPTR, + ERROR_EQFULL, + ERROR_ALLOCFAIL +} ErrorStatus; + +enum EventType +{ + ET_KeyPress = 2, + ET_KeyRelease, + ET_ButtonPress, + ET_ButtonRelease, + ET_Motion, + /* + ... + */ + ET_MTSync = 0x7E, + ET_Internal = 0xFF /* First byte */ +}; + +struct _DeviceEvent +{ + unsigned char header; /**< Always ET_Internal */ + enum EventType type; /**< One of EventType */ + int length; /**< Length in bytes */ + Time time; /**< Time in ms */ + int deviceid; /**< Device to post this event for */ + int sourceid; /**< The physical source device */ + union { + uint32_t button; /**< Button number */ + uint32_t key; /**< Key code */ + } detail; + int16_t root_x; /**< Pos relative to root window in integral data */ + float root_x_frac; /**< Pos relative to root window in frac part */ + int16_t root_y; /**< Pos relative to root window in integral part */ + float root_y_frac; /**< Pos relative to root window in frac part */ + uint8_t buttons[(MAX_BUTTONS + 7)/8]; /**< Button mask */ + struct { + uint8_t mask[(MAX_VALUATORS + 7)/8]; /**< Valuator mask */ + uint8_t mode[(MAX_VALUATORS + 7)/8]; /**< Valuator mode (Abs or Rel)*/ + int32_t data[MAX_VALUATORS]; /**< Valuator data */ + int32_t data_frac[MAX_VALUATORS]; /**< Fractional part for data */ + } valuators; + struct { + uint32_t base; /**< XKB base modifiers */ + uint32_t latched; /**< XKB latched modifiers */ + uint32_t locked; /**< XKB locked modifiers */ + uint32_t effective;/**< XKB effective modifiers */ + } mods; + struct { + uint8_t base; /**< XKB base group */ + uint8_t latched; /**< XKB latched group */ + uint8_t locked; /**< XKB locked group */ + uint8_t effective;/**< XKB effective group */ + } group; + Window root; /**< Root window of the event */ + int corestate; /**< Core key/button state BEFORE the event */ + int key_repeat; /**< Internally-generated key repeat event */ +}; + +typedef struct _AnyEvent AnyEvent; +struct _AnyEvent +{ + unsigned char header; /**< Always ET_Internal */ + enum EventType type; /**< One of EventType */ + int length; /**< Length in bytes */ + Time time; /**< Time in ms */ + int deviceid; + MTSyncType sync; + int x; + int y; +}; + +union _InternalEvent { + struct { + unsigned char header; /**< Always ET_Internal */ + enum EventType type; /**< One of ET_* */ + int length; /**< Length in bytes */ + Time time; /**< Time in ms. */ + } any; + AnyEvent any_event; + DeviceEvent device_event; +}; + +#define wUseDefault(w,field,def) ((w)->optional ? (w)->optional->field : def) +#define wBoundingShape(w) wUseDefault(w, boundingShape, NULL) +#define wInputShape(w) wUseDefault(w, inputShape, NULL) +#define wBorderWidth(w) ((int) (w)->borderWidth) + +/* used as NULL-terminated list */ +typedef struct _DevCursorNode { + CursorPtr cursor; + DeviceIntPtr dev; + struct _DevCursorNode* next; +} DevCursNodeRec, *DevCursNodePtr, *DevCursorList; + +typedef struct _WindowOpt { + VisualID visual; /* default: same as parent */ + CursorPtr cursor; /* default: window.cursorNone */ + Colormap colormap; /* default: same as parent */ + Mask dontPropagateMask; /* default: window.dontPropagate */ + Mask otherEventMasks; /* default: 0 */ + struct _OtherClients *otherClients; /* default: NULL */ + struct _GrabRec *passiveGrabs; /* default: NULL */ + PropertyPtr userProps; /* default: NULL */ + unsigned long backingBitPlanes; /* default: ~0L */ + unsigned long backingPixel; /* default: 0 */ + RegionPtr boundingShape; /* default: NULL */ + RegionPtr clipShape; /* default: NULL */ + RegionPtr inputShape; /* default: NULL */ + struct _OtherInputMasks *inputMasks; /* default: NULL */ + DevCursorList deviceCursors; /* default: NULL */ +} WindowOptRec, *WindowOptPtr; + +typedef struct _Window { + DrawableRec drawable; + PrivateRec *devPrivates; + WindowPtr parent; /* ancestor chain */ + WindowPtr nextSib; /* next lower sibling */ + WindowPtr prevSib; /* next higher sibling */ + WindowPtr firstChild; /* top-most child */ + WindowPtr lastChild; /* bottom-most child */ + RegionRec clipList; /* clipping rectangle for output */ + RegionRec borderClip; /* NotClippedByChildren + border */ + union _Validate *valdata; + RegionRec winSize; + RegionRec borderSize; + DDXPointRec origin; /* position relative to parent */ + unsigned short borderWidth; + unsigned short deliverableEvents; /* all masks from all clients */ + Mask eventMask; /* mask from the creating client */ + PixUnion background; + PixUnion border; + pointer backStorage; /* null when BS disabled */ + WindowOptPtr optional; + unsigned backgroundState:2; /* None, Relative, Pixel, Pixmap */ + unsigned borderIsPixel:1; + unsigned cursorIsNone:1; /* else real cursor (might inherit) */ + unsigned backingStore:2; + unsigned saveUnder:1; + unsigned DIXsaveUnder:1; + unsigned bitGravity:4; + unsigned winGravity:4; + unsigned overrideRedirect:1; + unsigned visibility:2; + unsigned mapped:1; + unsigned realized:1; /* ancestors are all mapped */ + unsigned viewable:1; /* realized && InputOutput */ + unsigned dontPropagate:3;/* index into DontPropagateMasks */ + unsigned forcedBS:1; /* system-supplied backingStore */ + unsigned redirectDraw:2; /* COMPOSITE rendering redirect */ + unsigned forcedBG:1; /* must have an opaque background */ +#ifdef ROOTLESS + unsigned rootlessUnhittable:1; /* doesn't hit-test */ +#endif +} WindowRec; + +typedef struct _IEvent { + InternalEvent *event; + int screen_num; + DeviceIntPtr device; +} IEventRec, *IEventPtr; + +enum +{ + BTN_RELEASED, + BTN_PRESSED, + BTN_MOVING +}; + +#define PressFlagFlick 0x01//(1 << 0) +#define PressFlagPan 0x02//(1 << 1) +#define PressFlagPinchRotation 0x04//(1 << 2) +#define PressFlagTap 0x08//(1 << 3) +#define PressFlagTapNHold 0x10//(1 << 4) +#define PressFlagHold 0x20//(1 << 5) + +#define FlickFilterMask 0x01//(1 << 0) +#define PanFilterMask 0x02//(1 << 1) +#define PinchRotationFilterMask 0x04//(1 << 2) +#define TapFilterMask 0x08//(1 << 3) +#define TapNHoldFilterMask 0x10//(1 << 4) +#define HoldFilterMask 0x20//(1 << 5) + +#define GESTURE_FILTER_MASK_ALL 0x3f//(FlickFilterMask | PanFilterMask | PinchRotationFilterMask | TapFilterMask |TapNHoldFilterMask | HoldFilterMask) + +typedef struct _tagTouchStatus +{ + int status;//One of BTN_RELEASED, BTN_PRESSED and BTN_MOVING + uint32_t flags; + + int px; //press x + int py; //press y + int mx; //motion x + int my; //motion y + int rx; //release x + int ry; //release y + Time ptime; //press time + Time mtime; //motion time + Time rtime; //current/previous release time +} TouchStatus; + +typedef struct _GestureDeviceRec +{ + char *device; + int version; /* Driver version */ + OsTimerPtr device_setting_timer; + + int is_active; + + WindowPtr pRootWin; + Window gestureWin; + int num_mt_devices; + + Mask grabMask; + Mask eventMask; + GestureGrabEventPtr GrabEvents; + + EventHandleType ehtype; + IEventPtr EQ; + int headEQ; + int tailEQ; + + pixman_region16_t area; + pixman_region16_t finger_rects[MAX_MT_DEVICES]; + + WindowPtr pTempWin; + int inc_num_pressed; + + int first_fingerid; + int num_pressed; + TouchStatus fingers[MAX_MT_DEVICES]; + + int event_sum[MAX_MT_DEVICES]; + uint32_t recognized_gesture; + uint32_t filter_mask; + + DeviceIntPtr this_device; + DeviceIntPtr mt_devices[MAX_MT_DEVICES]; + DeviceIntPtr master_pointer; + DeviceIntPtr xtest_pointer; +} GestureDeviceRec, *GestureDevicePtr ; + +#endif//_GESTURE_H_ diff --git a/xorg-gesture.pc.in b/xorg-gesture.pc.in new file mode 100644 index 0000000..320b0be --- /dev/null +++ b/xorg-gesture.pc.in @@ -0,0 +1,6 @@ +sdkdir=@sdkdir@ + +Name: xorg-evdev +Description: X.Org gesture input driver. +Version: @PACKAGE_VERSION@ +Cflags: -I${sdkdir} -- cgit v1.2.3