From: Jinkun Jang Date: Tue, 12 Mar 2013 16:37:01 +0000 (+0900) Subject: Tizen 2.1 base X-Git-Tag: accepted/tizen/20130910.110909~2 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fadaptation%2Fxf86-input-gesture.git;a=commitdiff_plain;h=fd51708656f04a5a9032deb05538d84348fdf7a4 Tizen 2.1 base Change-Id: Ic920e7df104d8f3a4d40be9076cdb89988ef3ff0 --- 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}