From fd51708656f04a5a9032deb05538d84348fdf7a4 Mon Sep 17 00:00:00 2001 From: Jinkun Jang Date: Wed, 13 Mar 2013 01:37:01 +0900 Subject: [PATCH 1/1] Tizen 2.1 base Change-Id: Ic920e7df104d8f3a4d40be9076cdb89988ef3ff0 --- COPYING | 21 + ChangeLog | 0 LICENSE.MIT | 20 + Makefile.am | 41 + NOTICE | 3 + autogen.sh | 13 + configure.ac | 75 + man/Makefile.am | 53 + man/gesture.man | 29 + packaging/xorg-x11-drv-gesture.spec | 54 + src/Makefile.am | 37 + src/gesture.c | 2901 +++++++++++++++++++++++++++++++++++ src/gesture.h | 394 +++++ xorg-gesture.pc.in | 6 + 14 files changed, 3647 insertions(+) create mode 100755 COPYING create mode 100644 ChangeLog create mode 100644 LICENSE.MIT create mode 100644 Makefile.am create mode 100644 NOTICE create mode 100755 autogen.sh create mode 100644 configure.ac create mode 100644 man/Makefile.am create mode 100644 man/gesture.man create mode 100644 packaging/xorg-x11-drv-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/LICENSE.MIT b/LICENSE.MIT new file mode 100644 index 0000000..1c81bdc --- /dev/null +++ b/LICENSE.MIT @@ -0,0 +1,20 @@ +Copyright (c) 2011 Samsung Electronics Co., Ltd 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, and that the name of Red Hat +not be used in advertising or publicity pertaining to distribution +of the software without specific, written prior permission. Red +Hat makes no representations about the suitability of this software +for any purpose. It is provided "as is" without express or implied +warranty. + +THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN +NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..8e655ec --- /dev/null +++ b/Makefile.am @@ -0,0 +1,41 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd 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, and that the name of Red Hat not be used in +# advertising or publicity pertaining to distribution of the software without +# specific, written prior permission. Red Hat makes no +# representations about the suitability of this software for any purpose. It +# is provided "as is" without express or implied warranty. +# +# RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO +# EVENT SHALL RED HAT BE LIABLE FOR ANY SPECIAL, INDIRECT OR +# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, +# DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +# PERFORMANCE OF THIS 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/NOTICE b/NOTICE new file mode 100644 index 0000000..c10a9c5 --- /dev/null +++ b/NOTICE @@ -0,0 +1,3 @@ +Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved. +Except as noted, this software is licensed under MIT License. +Please, see the LICENSE.MIT file for MIT License terms and conditions. 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..c36e7f8 --- /dev/null +++ b/configure.ac @@ -0,0 +1,75 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd 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, and that the name of Red Hat not be used in +# advertising or publicity pertaining to distribution of the software without +# specific, written prior permission. Red Hat makes no +# representations about the suitability of this software for any purpose. It +# is provided "as is" without express or implied warranty. +# +# RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO +# EVENT SHALL RED HAT BE LIABLE FOR ANY SPECIAL, INDIRECT OR +# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, +# DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +# PERFORMANCE OF THIS SOFTWARE. +# + +AC_PREREQ(2.57) +AC_INIT([xserver-xorg-input-gesture], + 0.1.0, + [https://bugs.freedesktop.org/enter_bug.cgi?product=xorg], + xserver-xorg-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/man/Makefile.am b/man/Makefile.am new file mode 100644 index 0000000..b91dae4 --- /dev/null +++ b/man/Makefile.am @@ -0,0 +1,53 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd 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, and that the name of Red Hat not be used in +# advertising or publicity pertaining to distribution of the software without +# specific, written prior permission. Red Hat makes no +# representations about the suitability of this software for any purpose. It +# is provided "as is" without express or implied warranty. +# +# RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO +# EVENT SHALL RED HAT BE LIABLE FOR ANY SPECIAL, INDIRECT OR +# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, +# DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +# PERFORMANCE OF THIS SOFTWARE. +# + +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-gesture.spec b/packaging/xorg-x11-drv-gesture.spec new file mode 100644 index 0000000..0787892 --- /dev/null +++ b/packaging/xorg-x11-drv-gesture.spec @@ -0,0 +1,54 @@ +#sbs-git:slp/pkgs/xorg/driver/xserver-xorg-input-gesture xorg-x11-drv-gesture 0.1.0 fb1092a8ea453d658b38d5c28e67a58462d7c931 +Name: xorg-x11-drv-gesture +Summary: X.Org X server -- Xserver gesture driver +Version: 0.1.2 +Release: 2 +Group: System/X Hardware Support +License: MIT +Source0: %{name}-%{version}.tar.gz +BuildRequires: pkgconfig(xorg-server) +BuildRequires: xorg-x11-proto-gesture +BuildRequires: pkgconfig(xproto) +BuildRequires: pkgconfig(inputproto) +BuildRequires: pkgconfig(resourceproto) +BuildRequires: pkgconfig(xorg-macros) + +%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-gesture development files + + +%prep +%setup -q + +%build + +autoreconf -vfi +./configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info CFLAGS="$CFLAGS" LDFLAGS="$LDFLAGS" +#./configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info CFLAGS="$CFLAGS -D__DETAIL_DEBUG__ -D__DEBUG_EVENT_HANDLER__ " LDFLAGS="$LDFLAGS" + +make %{?jobs:-j%jobs} + +%install +rm -rf %{buildroot} +mkdir -p %{buildroot}/usr/share/license +cp -af COPYING %{buildroot}/usr/share/license/%{name} +%make_install + +%remove_docs + +%files +%{_libdir}/xorg/modules/input/gesture_drv.so +/usr/share/license/%{name} + +%files devel +%{_libdir}/pkgconfig/xorg-gesture.pc diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..695f833 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,37 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd 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, and that the name of Red Hat not be used in +# advertising or publicity pertaining to distribution of the software without +# specific, written prior permission. Red Hat makes no +# representations about the suitability of this software for any purpose. It +# is provided "as is" without express or implied warranty. +# +# RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO +# EVENT SHALL RED HAT BE LIABLE FOR ANY SPECIAL, INDIRECT OR +# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, +# DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +# PERFORMANCE OF THIS 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..a483b7f --- /dev/null +++ b/src/gesture.c @@ -0,0 +1,2901 @@ +/************************************************************************** + +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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "gesture.h" +#include + +//Basic functions +static InputInfoPtr GesturePreInit(InputDriverPtr drv, InputInfoPtr pInfo, 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); +static double get_angle(int x1, int y1, int x2, int y2); + +//Gesture recognizer and handlers +void GestureRecognize_GroupPinchRotation(int type, InternalEvent *ev, DeviceIntPtr device, int idx, int timer_expired); +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, int kinds); +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 void +printk(const char* fmt, ...) +{ + static FILE* fp = NULL; + static char init = 0; + va_list argptr; + + if(!init && !fp) + { + fp = fopen("/dev/kmsg", "wt"); + init = 1; + } + + if(!fp) return; + + va_start(argptr, fmt); + vfprintf(fp, fmt, argptr); + fflush(fp); + va_end(argptr); +} + +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; +} + +static double +get_angle(int x1, int y1, int x2, int y2) +{ + double a, xx, yy; + xx = fabs(x2 - x1); + yy = fabs(y2 - y1); + + if (((int) xx) && ((int) yy)) + { + a = atan(yy / xx); + if (x1 < x2) + { + if (y1 < y2) + { + return (RAD_360DEG - a); + } + else + { + return (a); + } + } + else + { + if (y1 < y2) + { + return (RAD_180DEG + a); + } + else + { + return (RAD_180DEG - a); + } + } + } + + if (((int) xx)) + { /* Horizontal line */ + if (x2 < x1) + { + return (RAD_180DEG); + } + else + { + return (0.0); + } + } + + /* Vertical line */ + if (y2 < y1) + { + return (RAD_90DEG); + } + else + { + return (RAD_270DEG); + } +} + +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, int kinds) +{ + Window target_win; + WindowPtr target_pWin; + xGestureNotifyPinchRotationEvent prev; + +#ifdef __DETAIL_DEBUG__ + ErrorF("[X11][GestureHandleGesture_PinchRotation] num_fingers=%d, zoom=%.2f, angle=%.2f(deg=%.2f), distance=%d, cx=%d, cy=%d\n", + num_of_fingers, zoom, angle, rad2degree(angle), distance, cx, cy); +#endif//__DETAIL_DEBUG__ + + g_pGesture->recognized_gesture |= PinchRotationFilterMask; + memset(&prev, 0, sizeof(xGestureNotifyPinchRotationEvent)); + prev.type = GestureNotifyPinchRotation; + prev.kind = kinds; + 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", (unsigned int)prev.window, (unsigned int)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, int timer_expired) +{ + static int cx, cy; + + static int num_pressed = 0; + static int state = GestureEnd; + static int event_type = GestureNotifyPinchRotation; + static OsTimerPtr pinchrotation_event_timer = NULL; + + static pixman_region16_t base_area; + static pixman_region16_t cur_area; + + static double base_distance = 0.0f; + static double base_angle = 0.0f; + + static double prev_distance = 0.0f; + static double prev_angle = 0.0f; + + static double cur_distance = 0.0f; + static double cur_angle = 0.0f; + + double diff_distance = 0.0f; + double diff_angle = 0.0f; + + static int has_event_mask = 0; + + static Time base_time = 0; + Time current_time; + + if( timer_expired ) + { + if( state == GestureEnd ) + { + current_time = GetTimeInMillis(); + if( (current_time - base_time) >= PINCHROTATION_TIME_THRESHOLD ) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupPinchRotation][Timer] You must move farther than dist threshold(=%.2f) or angle threshold(=%2f) within time threshold(=%d) !\n", PINCHROTATION_DIST_THRESHOLD, PINCHROTATION_ANGLE_THRESHOLD, PINCHROTATION_TIME_THRESHOLD); +#endif//__DETAIL_DEBUG__ + goto cleanup_pinchrotation; + } + } + + return; + } + + switch( type ) + { + case ET_ButtonPress: + g_pGesture->fingers[idx].flags |= PressFlagPinchRotation; + + if( g_pGesture->num_pressed < 2 ) + return; + + if( g_pGesture->num_pressed < num_pressed && state != GestureEnd ) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupPinchRotation][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_pinchrotation; + } + + if( base_distance == 0.0f && g_pGesture->num_pressed == 2 ) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupPinchRotation][First Time !!!] num_pressed=%d, g_pGesture->num_pressed=%d\n", num_pressed, g_pGesture->num_pressed); +#endif//__DETAIL_DEBUG__ + + base_time = GetTimeInMillis(); + pixman_region_init(&base_area); + pixman_region_union(&base_area, &g_pGesture->finger_rects[0], &g_pGesture->finger_rects[1]); + + prev_distance = base_distance = AREA_DIAG_LEN(&base_area.extents); + +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupPinchRotation][P] x1=%d, x2=%d, y1=%d, y2=%d\n", g_pGesture->fingers[0].px, g_pGesture->fingers[1].px, + g_pGesture->fingers[0].py, g_pGesture->fingers[1].py); +#endif//__DETAIL_DEBUG__ + + prev_angle = base_angle = get_angle(g_pGesture->fingers[0].px, g_pGesture->fingers[0].py, g_pGesture->fingers[1].px, g_pGesture->fingers[1].py); +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupPinchRotation][P] base_angle=%.2f(deg=%.2f)\n", base_angle, rad2degree(base_angle)); +#endif//__DETAIL_DEBUG__ + event_type = GestureNotifyPinchRotation; + pinchrotation_event_timer = TimerSet(pinchrotation_event_timer, 0, PINCHROTATION_TIME_THRESHOLD, GestureEventTimerHandler, (int *)&event_type); + } + num_pressed = g_pGesture->num_pressed; + +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupPinchRotation][P][num_pressed=%d] AREA_SIZE(base_area.extents)=%d\n", num_pressed, AREA_SIZE(&base_area.extents)); + ErrorF("[GroupPinchRotation][P][num_pressed=%d] base_distance=%.2f, base_angle=%.2f(deg=%.2f)\n", num_pressed, base_distance, base_angle, rad2degree(base_angle)); +#endif//__DETAIL_DEBUG__ + break; + + case ET_Motion: + if( !(g_pGesture->fingers[idx].flags & PressFlagPinchRotation) ) + break; + + if( (num_pressed != g_pGesture->num_pressed) && (state != GestureEnd) ) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupPinchRotation][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_pinchrotation; + } + + if( num_pressed < 2 ) + return; + + if( g_pGesture->fingers[0].mx && g_pGesture->fingers[0].my && g_pGesture->fingers[1].mx && g_pGesture->fingers[1].my ) + { + pixman_region_init(&cur_area); + pixman_region_union(&cur_area, &g_pGesture->finger_rects[0], &g_pGesture->finger_rects[1]); + + cur_distance = AREA_DIAG_LEN(&cur_area.extents); + +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupPinchRotation][M] x1=%d, x2=%d, y1=%d, y2=%d\n", g_pGesture->fingers[0].mx, g_pGesture->fingers[1].mx, + g_pGesture->fingers[0].my, g_pGesture->fingers[1].my); +#endif//__DETAIL_DEBUG__ + + cur_angle = get_angle(g_pGesture->fingers[0].mx, g_pGesture->fingers[0].my, g_pGesture->fingers[1].mx, g_pGesture->fingers[1].my); +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupPinchRotation][M] cur_angle=%.2f(deg=%.2f)\n", cur_angle, rad2degree(cur_angle)); +#endif//__DETAIL_DEBUG__ + + diff_distance = prev_distance - cur_distance; + diff_angle = prev_angle - cur_angle; + + cx = AREA_CENTER_X(&cur_area.extents); + cy = AREA_CENTER_Y(&cur_area.extents); + +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupPinchRotation][M][state=%d] cx=%d, cy=%d\n", state, cx, cy); +#endif//__DETAIL_DEBUG__ + +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupPinchRotation][M][num_pressed=%d] prev_distance=%.2f, cur_distance=%.2f, diff=%.2f\n", num_pressed, prev_distance, cur_distance, diff_distance); + ErrorF("[GroupPinchRotation][M][num_pressed=%d] prev_angle=%.2f(deg=%.2f), cur_angle=%.2f(deg=%.2f), diff=%.2f(deg=%.2f)\n", num_pressed, prev_angle, rad2degree(prev_angle), cur_angle, rad2degree(cur_angle), diff_angle, rad2degree(diff_angle)); +#endif//__DETAIL_DEBUG__ + + switch( state ) + { + case GestureEnd: + if( (ABS(diff_distance) >= PINCHROTATION_DIST_THRESHOLD) || (ABS(diff_angle) >= PINCHROTATION_ANGLE_THRESHOLD) ) + { +#ifdef __DETAIL_DEBUG__ + if( ABS(diff_distance) >= PINCHROTATION_DIST_THRESHOLD ) + ErrorF("[GroupPinchRotation][M] zoom changed !\n"); + + if( ABS(diff_angle) >= PINCHROTATION_ANGLE_THRESHOLD ) + ErrorF("[GroupPinchRotation][M] angle changed !\n"); +#endif//__DETAIL_DEBUG__ + + TimerCancel(pinchrotation_event_timer); + state = GestureBegin; + goto gesture_begin_handle; + } + break; + + case GestureBegin: +gesture_begin_handle: +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupPinchRotation] PINCHROTATION Begin !cx=%d, cy=%d, state=%d\n", cx, cy, state); +#endif//__DETAIL_DEBUG__ + if( GestureHasFingerEventMask(GestureNotifyPinchRotation, num_pressed) ) + { + GestureHandleGesture_PinchRotation(num_pressed, cur_distance / base_distance, (cur_angle > base_angle) ? (cur_angle-base_angle) : (RAD_360DEG + cur_angle - base_angle), cur_distance, cx, cy, GestureBegin); + prev_distance = cur_distance; + prev_angle = cur_angle; + state = GestureUpdate; + has_event_mask = 1; + } + else + { + has_event_mask = 0; + goto cleanup_pinchrotation; + } + break; + + case GestureUpdate: + //if( ABS(diff_distance) < PINCHROTATION_DIST_THRESHOLD && ABS(diff_angle) < PINCHROTATION_ANGLE_THRESHOLD ) + // break; + +#ifdef __DETAIL_DEBUG__ + if( ABS(diff_distance) >= PINCHROTATION_DIST_THRESHOLD ) + ErrorF("[GroupPinchRotation][M] zoom changed !\n"); + + if( ABS(diff_angle) >= PINCHROTATION_ANGLE_THRESHOLD ) + ErrorF("[GroupPinchRotation][M] angle changed !\n"); +#endif//__DETAIL_DEBUG__ + +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupPinchRotation] PINCHROTATION Update ! cx=%d, cy=%d, state=%d\n", cx, cy, state); +#endif//__DETAIL_DEBUG__ + GestureHandleGesture_PinchRotation(num_pressed, cur_distance / base_distance, (cur_angle > base_angle) ? (cur_angle-base_angle) : (RAD_360DEG + cur_angle - base_angle), cur_distance, cx, cy, GestureUpdate); + prev_distance = cur_distance; + prev_angle = cur_angle; + break; + + case GestureDone: + default: + break; + } + } + break; + + case ET_ButtonRelease: + if( state != GestureEnd && num_pressed >= 2) + { +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupPinchRotation][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_pinchrotation; + } + + if( g_pGesture->num_pressed ) + break; + + goto cleanup_pinchrotation; + break; + } + + return; + +cleanup_pinchrotation: + + if( has_event_mask && (state == GestureBegin || state == GestureUpdate) ) + { + state = GestureEnd; +#ifdef __DETAIL_DEBUG__ + ErrorF("[GroupPinchRotation] PINCHROTATION End ! cx=%d, cy=%d, state=%d\n", cx, cy, state); +#endif//__DETAIL_DEBUG__ + GestureHandleGesture_PinchRotation(num_pressed, cur_distance / base_distance, (cur_angle > base_angle) ? (cur_angle-base_angle) : (RAD_360DEG + cur_angle - base_angle), cur_distance, cx, cy, GestureEnd); + } + else + { + g_pGesture->recognized_gesture &= ~PinchRotationFilterMask; + } + + g_pGesture->filter_mask |= PinchRotationFilterMask; + + if( g_pGesture->filter_mask == GESTURE_FILTER_MASK_ALL ) + { +#if 1//def __DETAIL_DEBUG__ + ErrorF("[GroupPinchRotation][cleanup] GestureFlushOrDrop() !\n"); +#endif//__DETAIL_DEBUG__ + + if( ERROR_INVALPTR == GestureFlushOrDrop() ) + { + GestureControl(g_pGesture->this_device, DEVICE_OFF); + } + } + + prev_distance = base_distance = 0.0f; + prev_angle = base_angle = 0.0f; + has_event_mask = num_pressed = 0; + state = GestureEnd; + cx = cy = 0; + TimerCancel(pinchrotation_event_timer); + 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( state <= GestureBegin ) + { + if( !INBOX(&base_box_ext, cx, cy) ) + { + TimerCancel(pan_event_timer); + pan_event_timer = NULL; + + 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; + 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; + if( pan_event_timer ) + { + TimerCancel(pan_event_timer); + pan_event_timer = NULL; + } + 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; + + case GestureNotifyPinchRotation: +#ifdef __DETAIL_DEBUG__ + ErrorF("[GestureEventTimerHandler] GestureNotifyPinchRotation (event_type = %d)\n", event_type); +#endif//__DETAIL_DEBUG__ + GestureRecognize_GroupPinchRotation(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; + static OsTimerPtr single_finger_timer = NULL; + int idx = -1; + + if( PROPAGATE_EVENTS == g_pGesture->ehtype || + device->id < g_pGesture->first_fingerid ) + return; + + for( i = 0 ; i < g_pGesture->num_mt_devices ; i++ ) + { + if( device->id == g_pGesture->mt_devices[i]->id ) + { + idx = i; + break; + } + } + + if( idx < 0 ) + 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, 0); + } + 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, 5000, GestureTimerHandler, pInfo); + + if( !pGesture->device_setting_timer ) + { + ErrorF("[X11][GestureEnableEventHandler] Failed to allocate memory for timer !\n"); + goto failed; + } + + 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(); + + 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->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; + pGesture->first_fingerid = -1; + return 0; + } + + pGesture->first_fingerid = pGesture->mt_devices[0]->id; + 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; + + 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 0; + +failed: + + GestureUninstallResourceStateHooks(); + GestureUnsetMaxNumberOfFingers(); + + 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"); + i--; + while(i >= 0 && tmpEQ[i].event) + { + free(tmpEQ[i].event); + tmpEQ[i].event = NULL; + } + free (tmpEQ); + tmpEQ = NULL; + 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"); + printk("[X11][GestureEnqueueEvent] Gesture EQ is full...Force Gesture Flush !\n"); + GestureEventsFlush(); + 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, InputInfoPtr pInfo, int flags) +{ + int rc = BadAlloc; + GestureDevicePtr pGesture; + + pGesture = calloc(1, sizeof(GestureDeviceRec)); + + if (!pGesture) { + pInfo->private = NULL; + //xf86DeleteInput(pInfo, 0); + goto error; + } + + g_pGesture = pGesture; + pInfo->private = pGesture; + pInfo->flags = 0; + 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(pInfo->options, "Device", "/dev/null"); + pGesture->is_active = xf86SetIntOption(pInfo->options, "Activate", 0); + pGesture->gestureWin = None; + + xf86Msg(X_INFO, "%s: Using device %s.\n", pInfo->name, pGesture->device); + + /* process generic options */ + xf86CollectInputOptions(pInfo, NULL); + xf86ProcessCommonOptions(pInfo, pInfo->options); + + pInfo->fd = -1; + + return Success; + +error: + if (pInfo->fd >= 0) + close(pInfo->fd); + return rc; +} + +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..7d59dae --- /dev/null +++ b/src/gesture.h @@ -0,0 +1,394 @@ +/************************************************************************** + +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) ) +#define AREA_HEIGHT(extents) (((extents)->y2)-((extents)->y1)) +#define AREA_WIDTH(extents) (((extents)->x2)-((extents)->x1)) +#define AREA_DIAG_LEN(extents) sqrt((AREA_WIDTH(extents)*AREA_WIDTH(extents))+(AREA_HEIGHT(extents)*AREA_HEIGHT(extents))) + +//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 PINCHROTATION_TIME_THRESHOLD 500//ms +#define PINCHROTATION_INIT_DIST_THRESHOLD 25.0f +#define PINCHROTATION_INIT_ANGLE_THRESHOLD 0.2f +#define PINCHROTATION_DIST_THRESHOLD 25.0f +#define PINCHROTATION_ANGLE_THRESHOLD 0.2f + +#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 + +#define RAD_90DEG M_PI_2 +#define RAD_180DEG M_PI +#define RAD_270DEG (M_PI_2 * 3) +#define RAD_360DEG (M_PI * 2) +#define rad2degree(r) ((r) * 180/M_PI) + +typedef enum _MTSyncType +{ + MTOUCH_FRAME_SYNC_END, + MTOUCH_FRAME_SYNC_BEGIN +} MTSyncType; + +typedef enum _EventHandleType +{ + PROPAGATE_EVENTS, + KEEP_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 (also used in pointer emulating + touch events) */ + uint32_t key; /**< Key code */ + } detail; + uint32_t touchid; /**< Touch ID (client_id) */ + 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)*/ + double data[MAX_VALUATORS]; /**< Valuator 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 */ + uint32_t flags; /**< Flags to be copied into the generated 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} -- 2.7.4