--- /dev/null
+# $Id$
+
+# This is the X Strike Force shell library for X Window System package
+# maintainer scripts. It serves to define shell functions commonly used by
+# such packages, and performs some error checking necessary for proper operation
+# of those functions. By itself, it does not "do" much; the maintainer scripts
+# invoke the functions defined here to accomplish package installation and
+# removal tasks.
+
+# If you are reading this within a Debian package maintainer script (e.g.,
+# /var/lib/dpkg)info/PACKAGE.{config,preinst,postinst,prerm,postrm}), you can
+# skip past this library by scanning forward in this file to the string
+# "GOBSTOPPER".
+
+SOURCE_VERSION=@SOURCE_VERSION@
+OFFICIAL_BUILD=@OFFICIAL_BUILD@
+
+# Use special abnormal exit codes so that problems with this library are more
+# easily tracked down.
+SHELL_LIB_INTERNAL_ERROR=86
+SHELL_LIB_THROWN_ERROR=74
+SHELL_LIB_USAGE_ERROR=99
+
+# old -> new variable names
+if [ -z "$DEBUG_XORG_PACKAGE" ] && [ -n "$DEBUG_XFREE86_PACKAGE" ]; then
+ DEBUG_XORG_PACKAGE="$DEBUG_XFREE86_PACKAGE"
+fi
+if [ -z "$DEBUG_XORG_DEBCONF" ] && [ -n "$DEBUG_XFREE86_DEBCONF" ]; then
+ DEBUG_XORG_DEBCONF="$DEBUG_XFREE86_DEBCONF"
+fi
+
+# initial sanity checks
+if [ -z "$THIS_PACKAGE" ]; then
+ cat >&2 <<EOF
+Error: package maintainer script attempted to use shell library without
+definining \$THIS_PACKAGE shell variable. Please report the package name,
+version, and the text of this error message to the Debian Bug Tracking System.
+Visit <http://www.debian.org/Bugs/Reporting> on the World Wide Web for
+instructions, read the file /usr/share/doc/debian/bug-reporting.txt from the
+"doc-debian" package, or install the "reportbug" package and use the command of
+the same name to file a report against version $SOURCE_VERSION of this package.
+EOF
+ exit $SHELL_LIB_USAGE_ERROR
+fi
+
+if [ -z "$THIS_SCRIPT" ]; then
+ cat >&2 <<EOF
+Error: package maintainer script attempted to use shell library without
+definining \$THIS_SCRIPT shell variable. Please report the package name,
+version, and the text of this error message to the Debian Bug Tracking System.
+Visit <http://www.debian.org/Bugs/Reporting> on the World Wide Web for
+instructions, read the file /usr/share/doc/debian/bug-reporting.txt from the
+"doc-debian" package, or install the "reportbug" package and use the command of
+the same name to file a report against version $SOURCE_VERSION of the
+"$THIS_PACKAGE" package.
+EOF
+ exit $SHELL_LIB_USAGE_ERROR
+fi
+
+if [ "$1" = "reconfigure" ] || [ -n "$DEBCONF_RECONFIGURE" ]; then
+ RECONFIGURE="true"
+else
+ RECONFIGURE=
+fi
+
+if ([ "$1" = "install" ] || [ "$1" = "configure" ]) && [ -z "$2" ]; then
+ FIRSTINST="yes"
+fi
+
+if [ -z "$RECONFIGURE" ] && [ -z "$FIRSTINST" ]; then
+ UPGRADE="yes"
+fi
+
+trap "message;\
+ message \"Received signal. Aborting $THIS_PACKAGE package $THIS_SCRIPT script.\";\
+ message;\
+ exit 1" HUP INT QUIT TERM
+
+reject_nondigits () {
+ # syntax: reject_nondigits [ operand ... ]
+ #
+ # scan operands (typically shell variables whose values cannot be trusted) for
+ # characters other than decimal digits and barf if any are found
+ while [ -n "$1" ]; do
+ # does the operand contain anything but digits?
+ if ! expr "$1" : "[[:digit:]]\+$" > /dev/null 2>&1; then
+ # can't use die(), because it wraps message() which wraps this function
+ echo "$THIS_PACKAGE $THIS_SCRIPT error: reject_nondigits() encountered" \
+ "possibly malicious garbage \"$1\"" >&2
+ exit $SHELL_LIB_THROWN_ERROR
+ fi
+ shift
+ done
+}
+
+reject_whitespace () {
+ # syntax: reject_whitespace [ operand ]
+ #
+ # scan operand (typically a shell variable whose value cannot be trusted) for
+ # whitespace characters and barf if any are found
+ if [ -n "$1" ]; then
+ # does the operand contain any whitespace?
+ if expr "$1" : "[[:space:]]" > /dev/null 2>&1; then
+ # can't use die(), because I want to avoid forward references
+ echo "$THIS_PACKAGE $THIS_SCRIPT error: reject_whitespace() encountered" \
+ "possibly malicious garbage \"$1\"" >&2
+ exit $SHELL_LIB_THROWN_ERROR
+ fi
+ fi
+}
+
+reject_unlikely_path_chars () {
+ # syntax: reject_unlikely_path_chars [ operand ... ]
+ #
+ # scan operands (typically shell variables whose values cannot be trusted) for
+ # characters unlikely to be seen in a path and which the shell might
+ # interpret and barf if any are found
+ while [ -n "$1" ]; do
+ # does the operand contain any funny characters?
+ if expr "$1" : '.*[!$&()*;<>?|].*' > /dev/null 2>&1; then
+ # can't use die(), because I want to avoid forward references
+ echo "$THIS_PACKAGE $THIS_SCRIPT error: reject_unlikely_path_chars()" \
+ "encountered possibly malicious garbage \"$1\"" >&2
+ exit $SHELL_LIB_THROWN_ERROR
+ fi
+ shift
+ done
+}
+
+# Query the terminal to establish a default number of columns to use for
+# displaying messages to the user. This is used only as a fallback in the
+# event the COLUMNS variable is not set. ($COLUMNS can react to SIGWINCH while
+# the script is running, and this cannot, only being calculated once.)
+DEFCOLUMNS=$(stty size 2> /dev/null | awk '{print $2}') || true
+if ! expr "$DEFCOLUMNS" : "[[:digit:]]\+$" > /dev/null 2>&1; then
+ DEFCOLUMNS=80
+fi
+
+message () {
+ # pretty-print messages of arbitrary length
+ reject_nondigits "$COLUMNS"
+ echo "$*" | fmt -t -w ${COLUMNS:-$DEFCOLUMNS} >&2
+}
+
+observe () {
+ # syntax: observe message ...
+ #
+ # issue observational message suitable for logging someday when support for
+ # it exists in dpkg
+ if [ -n "$DEBUG_XORG_PACKAGE" ]; then
+ message "$THIS_PACKAGE $THIS_SCRIPT note: $*"
+ fi
+}
+
+warn () {
+ # syntax: warn message ...
+ #
+ # issue warning message suitable for logging someday when support for
+ # it exists in dpkg; also send to standard error
+ message "$THIS_PACKAGE $THIS_SCRIPT warning: $*"
+}
+
+die () {
+ # syntax: die message ...
+ #
+ # exit script with error message
+ message "$THIS_PACKAGE $THIS_SCRIPT error: $*"
+ exit $SHELL_LIB_THROWN_ERROR
+}
+
+internal_error () {
+ # exit script with error; essentially a "THIS SHOULD NEVER HAPPEN" message
+ message "internal error: $*"
+ if [ -n "$OFFICIAL_BUILD" ]; then
+ message "Please report a bug in the $THIS_SCRIPT script of the" \
+ "$THIS_PACKAGE package, version $SOURCE_VERSION to the Debian Bug" \
+ "Tracking System. Include all messages above that mention the" \
+ "$THIS_PACKAGE package. Visit " \
+ "<http://www.debian.org/Bugs/Reporting> on the World Wide Web for" \
+ "instructions, read the file" \
+ "/usr/share/doc/debian/bug-reporting.txt from the doc-debian" \
+ "package, or install the reportbug package and use the command of" \
+ "the same name to file a report."
+ fi
+ exit $SHELL_LIB_INTERNAL_ERROR
+}
+
+usage_error () {
+ message "usage error: $*"
+ message "Please report a bug in the $THIS_SCRIPT script of the" \
+ "$THIS_PACKAGE package, version $SOURCE_VERSION to the Debian Bug" \
+ "Tracking System. Include all messages above that mention the" \
+ "$THIS_PACKAGE package. Visit " \
+ "<http://www.debian.org/Bugs/Reporting> on the World Wide Web for" \
+ "instructions, read the file" \
+ "/usr/share/doc/debian/bug-reporting.txt from the doc-debian" \
+ "package, or install the reportbug package and use the command of" \
+ "the same name to file a report."
+ exit $SHELL_LIB_USAGE_ERROR
+}
+
+
+maplink () {
+ # returns what symlink should point to; i.e., what the "sane" answer is
+ # Keep this in sync with the debian/*.links files.
+ # This is only needed for symlinks to directories.
+ #
+ # XXX: Most of these look wrong in the X11R7 world and need to be fixed.
+ # If we've stopped using this function, fixing it might enable us to re-enable
+ # it again and catch more errors.
+ case "$1" in
+ /etc/X11/xkb/compiled) echo /var/lib/xkb ;;
+ /etc/X11/xkb/xkbcomp) echo /usr/X11R6/bin/xkbcomp ;;
+ /usr/X11R6/lib/X11/app-defaults) echo /etc/X11/app-defaults ;;
+ /usr/X11R6/lib/X11/fs) echo /etc/X11/fs ;;
+ /usr/X11R6/lib/X11/lbxproxy) echo /etc/X11/lbxproxy ;;
+ /usr/X11R6/lib/X11/proxymngr) echo /etc/X11/proxymngr ;;
+ /usr/X11R6/lib/X11/rstart) echo /etc/X11/rstart ;;
+ /usr/X11R6/lib/X11/twm) echo /etc/X11/twm ;;
+ /usr/X11R6/lib/X11/xdm) echo /etc/X11/xdm ;;
+ /usr/X11R6/lib/X11/xinit) echo /etc/X11/xinit ;;
+ /usr/X11R6/lib/X11/xkb) echo /etc/X11/xkb ;;
+ /usr/X11R6/lib/X11/xserver) echo /etc/X11/xserver ;;
+ /usr/X11R6/lib/X11/xsm) echo /etc/X11/xsm ;;
+ /usr/bin/X11) echo ../X11R6/bin ;;
+ /usr/bin/rstartd) echo ../X11R6/bin/rstartd ;;
+ /usr/include/X11) echo ../X11R6/include/X11 ;;
+ /usr/lib/X11) echo ../X11R6/lib/X11 ;;
+ *) internal_error "maplink() called with unknown path \"$1\"" ;;
+ esac
+}
+
+analyze_path () {
+ # given a supplied set of pathnames, break each one up by directory and do an
+ # ls -dl on each component, cumulatively; i.e.
+ # analyze_path /usr/X11R6/bin -> ls -dl /usr /usr/X11R6 /usr/X11R6/bin
+ # Thanks to Randolph Chung for this clever hack.
+
+ local f g
+
+ while [ -n "$1" ]; do
+ reject_whitespace "$1"
+ g=
+ message "Analyzing $1:"
+ for f in $(echo "$1" | tr / \ ); do
+ if [ -e /$g$f ]; then
+ ls -dl /$g$f /$g$f.dpkg-* 2> /dev/null || true
+ g=$g$f/
+ else
+ message "/$g$f: nonexistent; directory contents of /$g:"
+ ls -l /$g
+ break
+ fi
+ done
+ shift
+ done
+}
+
+find_culprits () {
+ local f p dpkg_info_dir possible_culprits smoking_guns bad_packages package \
+ msg
+
+ reject_whitespace "$1"
+ message "Searching for overlapping packages..."
+ dpkg_info_dir=/var/lib/dpkg/info
+ if [ -d $dpkg_info_dir ]; then
+ if [ "$(echo $dpkg_info_dir/*.list)" != "$dpkg_info_dir/*.list" ]; then
+ possible_culprits=$(ls -1 $dpkg_info_dir/*.list | egrep -v \
+ "(xbase-clients|x11-common|xfs|xlibs)")
+ if [ -n "$possible_culprits" ]; then
+ smoking_guns=$(grep -l "$1" $possible_culprits || true)
+ if [ -n "$smoking_guns" ]; then
+ bad_packages=$(printf "\\n")
+ for f in $smoking_guns; do
+ # too bad you can't nest parameter expansion voodoo
+ p=${f%*.list} # strip off the trailing ".list"
+ package=${p##*/} # strip off the directories
+ bad_packages=$(printf "%s\n%s" "$bad_packages" "$package")
+ done
+ msg=$(cat <<EOF
+The following packages appear to have file overlaps with the X.Org packages;
+these packages are either very old, or in violation of Debian Policy. Try
+upgrading each of these packages to the latest available version if possible:
+for example, with the command "apt-get install". If no newer version of a
+package is available, you will have to remove it; for example, with the command
+"apt-get remove". If even the latest available version of the package has
+this file overlap, please file a bug against that package with the Debian Bug
+Tracking System. You may want to refer the package maintainer to section 12.8
+of the Debian Policy manual.
+EOF
+)
+ message "$msg"
+ message "The overlapping packages are: $bad_packages"
+ else
+ message "no overlaps found."
+ fi
+ fi
+ else
+ message "cannot search; no matches for $dpkg_info_dir/*.list."
+ fi
+ else
+ message "cannot search; $dpkg_info_dir does not exist."
+ fi
+}
+
+check_symlink () {
+ # syntax: check_symlink symlink
+ #
+ # See if specified symlink points where it is supposed to. Return 0 if it
+ # does, and 1 if it does not.
+ #
+ # Primarily used by check_symlinks_and_warn() and check_symlinks_and_bomb().
+
+ local symlink
+
+ # validate arguments
+ if [ $# -ne 1 ]; then
+ usage_error "check_symlink() called with wrong number of arguments;" \
+ "expected 1, got $#"
+ exit $SHELL_LIB_USAGE_ERROR
+ fi
+
+ symlink="$1"
+
+ if [ "$(maplink "$symlink")" = "$(readlink "$symlink")" ]; then
+ return 0
+ else
+ return 1
+ fi
+}
+
+check_symlinks_and_warn () {
+ # syntax: check_symlinks_and_warn symlink ...
+ #
+ # For each argument, check for symlink sanity, and warn if it isn't sane.
+ #
+ # Call this function from a preinst script in the event $1 is "upgrade" or
+ # "install".
+
+ local errmsg symlink
+
+ # validate arguments
+ if [ $# -lt 1 ]; then
+ usage_error "check_symlinks_and_warn() called with wrong number of" \
+ "arguments; expected at least 1, got $#"
+ exit $SHELL_LIB_USAGE_ERROR
+ fi
+
+ while [ -n "$1" ]; do
+ symlink="$1"
+ if [ -L "$symlink" ]; then
+ if ! check_symlink "$symlink"; then
+ observe "$symlink symbolic link points to wrong location" \
+ "$(readlink "$symlink"); removing"
+ rm "$symlink"
+ fi
+ elif [ -e "$symlink" ]; then
+ errmsg="$symlink exists and is not a symbolic link; this package cannot"
+ errmsg="$errmsg be installed until this"
+ if [ -f "$symlink" ]; then
+ errmsg="$errmsg file"
+ elif [ -d "$symlink" ]; then
+ errmsg="$errmsg directory"
+ else
+ errmsg="$errmsg thing"
+ fi
+ errmsg="$errmsg is removed"
+ die "$errmsg"
+ fi
+ shift
+ done
+}
+
+check_symlinks_and_bomb () {
+ # syntax: check_symlinks_and_bomb symlink ...
+ #
+ # For each argument, check for symlink sanity, and bomb if it isn't sane.
+ #
+ # Call this function from a postinst script.
+
+ local problem symlink
+
+ # validate arguments
+ if [ $# -lt 1 ]; then
+ usage_error "check_symlinks_and_bomb() called with wrong number of"
+ "arguments; expected at least 1, got $#"
+ exit $SHELL_LIB_USAGE_ERROR
+ fi
+
+ while [ -n "$1" ]; do
+ problem=
+ symlink="$1"
+ if [ -L "$symlink" ]; then
+ if ! check_symlink "$symlink"; then
+ problem=yes
+ warn "$symlink symbolic link points to wrong location" \
+ "$(readlink "$symlink")"
+ fi
+ elif [ -e "$symlink" ]; then
+ problem=yes
+ warn "$symlink is not a symbolic link"
+ else
+ problem=yes
+ warn "$symlink symbolic link does not exist"
+ fi
+ if [ -n "$problem" ]; then
+ analyze_path "$symlink" "$(readlink "$symlink")"
+ find_culprits "$symlink"
+ die "bad symbolic links on system"
+ fi
+ shift
+ done
+}
+
+font_update () {
+ # run $UPDATECMDS in $FONTDIRS
+
+ local dir cmd shortcmd x_font_dir_prefix
+
+ x_font_dir_prefix="/usr/share/fonts/X11"
+
+ if [ -z "$UPDATECMDS" ]; then
+ usage_error "font_update() called but \$UPDATECMDS not set"
+ fi
+ if [ -z "$FONTDIRS" ]; then
+ usage_error "font_update() called but \$FONTDIRS not set"
+ fi
+
+ reject_unlikely_path_chars "$UPDATECMDS"
+ reject_unlikely_path_chars "$FONTDIRS"
+
+ for dir in $FONTDIRS; do
+ if [ -d "$x_font_dir_prefix/$dir" ]; then
+ for cmd in $UPDATECMDS; do
+ if which "$cmd" > /dev/null 2>&1; then
+ shortcmd=${cmd##*/}
+ observe "running $shortcmd in $dir font directory"
+ cmd_opts=
+ if [ "$shortcmd" = "update-fonts-alias" ]; then
+ cmd_opts=--x11r7-layout
+ fi
+ if [ "$shortcmd" = "update-fonts-dir" ]; then
+ cmd_opts=--x11r7-layout
+ fi
+ if [ "$shortcmd" = "update-fonts-scale" ]; then
+ cmd_opts=--x11r7-layout
+ fi
+ $cmd $cmd_opts $dir || warn "$cmd $cmd_opts $dir" \
+ "failed; font directory data may not" \
+ "be up to date"
+ else
+ warn "$cmd not found; not updating corresponding $dir font" \
+ "directory data"
+ fi
+ done
+ else
+ warn "$dir is not a directory; not updating font directory data"
+ fi
+ done
+}
+
+remove_conffile_prepare () {
+ # syntax: remove_conffile_prepare filename official_md5sum ...
+ #
+ # Check a conffile "filename" against a list of canonical MD5 checksums.
+ # If the file's current MD5 checksum matches one of the "official_md5sum"
+ # operands provided, then prepare the conffile for removal from the system.
+ # We defer actual deletion until the package is configured so that we can
+ # roll this operation back if package installation fails.
+ #
+ # Call this function from a preinst script in the event $1 is "upgrade" or
+ # "install" and verify $2 to ensure the package is being upgraded from a
+ # version (or installed over a version removed-but-not-purged) prior to the
+ # one in which the conffile was obsoleted.
+
+ local conffile current_checksum
+
+ # validate arguments
+ if [ $# -lt 2 ]; then
+ usage_error "remove_conffile_prepare() called with wrong number of" \
+ "arguments; expected at least 2, got $#"
+ exit $SHELL_LIB_USAGE_ERROR
+ fi
+
+ conffile="$1"
+ shift
+
+ # does the conffile even exist?
+ if [ -e "$conffile" ]; then
+ # calculate its checksum
+ current_checksum=$(md5sum < "$conffile" | sed 's/[[:space:]].*//')
+ # compare it to each supplied checksum
+ while [ -n "$1" ]; do
+ if [ "$current_checksum" = "$1" ]; then
+ # we found a match; move the confffile and stop looking
+ observe "preparing obsolete conffile $conffile for removal"
+ mv "$conffile" "$conffile.$THIS_PACKAGE-tmp"
+ break
+ fi
+ shift
+ done
+ fi
+}
+
+remove_conffile_lookup () {
+ # syntax: remove_conffile_lookup package filename
+ #
+ # Lookup the md5sum of a conffile in dpkg's database, and prepare for removal
+ # if it matches the actual file's md5sum.
+ #
+ # Call this function when you would call remove_conffile_prepare but only
+ # want to check against dpkg's status database instead of known checksums.
+
+ local package conffile old_md5sum
+
+ # validate arguments
+ if [ $# -ne 2 ]; then
+ usage_error "remove_conffile_lookup() called with wrong number of" \
+ "arguments; expected 1, got $#"
+ exit $SHELL_LIB_USAGE_ERROR
+ fi
+
+ package="$1"
+ conffile="$2"
+
+ if ! [ -e "$conffile" ]; then
+ return
+ fi
+ old_md5sum="$(dpkg-query -W -f='${Conffiles}' "$package" | \
+ awk '{ if (match($0, "^ '"$conffile"' ")) print $2}')"
+ if [ -n "$old_md5sum" ]; then
+ remove_conffile_prepare "$conffile" "$old_md5sum"
+ fi
+}
+
+remove_conffile_commit () {
+ # syntax: remove_conffile_commit filename
+ #
+ # Complete the removal of a conffile "filename" that has become obsolete.
+ #
+ # Call this function from a postinst script after having used
+ # remove_conffile_prepare() in the preinst.
+
+ local conffile
+
+ # validate arguments
+ if [ $# -ne 1 ]; then
+ usage_error "remove_conffile_commit() called with wrong number of" \
+ "arguments; expected 1, got $#"
+ exit $SHELL_LIB_USAGE_ERROR
+ fi
+
+ conffile="$1"
+
+ # if the temporary file created by remove_conffile_prepare() exists, remove it
+ if [ -e "$conffile.$THIS_PACKAGE-tmp" ]; then
+ observe "committing removal of obsolete conffile $conffile"
+ rm "$conffile.$THIS_PACKAGE-tmp"
+ fi
+}
+
+remove_conffile_rollback () {
+ # syntax: remove_conffile_rollback filename
+ #
+ # Roll back the removal of a conffile "filename".
+ #
+ # Call this function from a postrm script in the event $1 is "abort-upgrade"
+ # or "abort-install" is after having used remove_conffile_prepare() in the
+ # preinst.
+
+ local conffile
+
+ # validate arguments
+ if [ $# -ne 1 ]; then
+ usage_error "remove_conffile_rollback() called with wrong number of" \
+ "arguments; expected 1, got $#"
+ exit $SHELL_LIB_USAGE_ERROR
+ fi
+
+ conffile="$1"
+
+ # if the temporary file created by remove_conffile_prepare() exists, move it
+ # back
+ if [ -e "$conffile.$THIS_PACKAGE-tmp" ]; then
+ observe "rolling back removal of obsolete conffile $conffile"
+ mv "$conffile.$THIS_PACKAGE-tmp" "$conffile"
+ fi
+}
+
+replace_conffile_with_symlink_prepare () {
+ # syntax: replace_conffile_with_symlink_prepare oldfilename newfilename \
+ # official_md5sum ...
+ #
+ # Check a conffile "oldfilename" against a list of canonical MD5 checksums.
+ # If the file's current MD5 checksum matches one of the "official_md5sum"
+ # operands provided, then prepare the conffile for removal from the system.
+ # We defer actual deletion until the package is configured so that we can
+ # roll this operation back if package installation fails. Otherwise copy it
+ # to newfilename and let dpkg handle it through conffiles mechanism.
+ #
+ # Call this function from a preinst script in the event $1 is "upgrade" or
+ # "install" and verify $2 to ensure the package is being upgraded from a
+ # version (or installed over a version removed-but-not-purged) prior to the
+ # one in which the conffile was obsoleted.
+
+ local conffile current_checksum
+
+ # validate arguments
+ if [ $# -lt 3 ]; then
+ usage_error "replace_conffile_with_symlink_prepare() called with wrong" \
+ " number of arguments; expected at least 3, got $#"
+ exit $SHELL_LIB_USAGE_ERROR
+ fi
+
+ oldconffile="$1"
+ shift
+ newconffile="$1"
+ shift
+
+ remove_conffile_prepare "$_oldconffile" "$@"
+ # If $oldconffile still exists, then md5sums didn't match.
+ # Copy it to new one.
+ if [ -f "$oldconffile" ]; then
+ cp "$oldconffile" "$newconffile"
+ fi
+
+}
+
+replace_conffile_with_symlink_commit () {
+ # syntax: replace_conffile_with_symlink_commit oldfilename
+ #
+ # Complete the removal of a conffile "oldfilename" that has been
+ # replaced by a symlink.
+ #
+ # Call this function from a postinst script after having used
+ # replace_conffile_with_symlink_prepare() in the preinst.
+
+ local conffile
+
+ # validate arguments
+ if [ $# -ne 1 ]; then
+ usage_error "replace_conffile_with_symlink_commit() called with wrong" \
+ "number of arguments; expected 1, got $#"
+ exit $SHELL_LIB_USAGE_ERROR
+ fi
+
+ conffile="$1"
+
+ remove_conffile_commit "$conffile"
+}
+
+replace_conffile_with_symlink_rollback () {
+ # syntax: replace_conffile_with_symlink_rollback oldfilename newfilename
+ #
+ # Roll back the replacing of a conffile "oldfilename" with symlink to
+ # "newfilename".
+ #
+ # Call this function from a postrm script in the event $1 is "abort-upgrade"
+ # or "abort-install" and verify $2 to ensure the package failed to upgrade
+ # from a version (or install over a version removed-but-not-purged) prior
+ # to the one in which the conffile was obsoleted.
+ # You should have used replace_conffile_with_symlink_prepare() in the
+ # preinst.
+
+ local conffile
+
+ # validate arguments
+ if [ $# -ne 2 ]; then
+ usage_error "replace_conffile_with_symlink_rollback() called with wrong" \
+ "number of arguments; expected 2, got $#"
+ exit $SHELL_LIB_USAGE_ERROR
+ fi
+
+ oldconffile="$1"
+ newconffile="$2"
+
+ remove_conffile_rollback "$_oldconffile"
+ if [ -f "$newconffile" ]; then
+ rm "$newconffile"
+ fi
+}
+
+run () {
+ # syntax: run command [ argument ... ]
+ #
+ # Run specified command with optional arguments and report its exit status.
+ # Useful for commands whose exit status may be nonzero, but still acceptable,
+ # or commands whose failure is not fatal to us.
+ #
+ # NOTE: Do *not* use this function with db_get or db_metaget commands; in
+ # those cases the return value of the debconf command *must* be checked
+ # before the string returned by debconf is used for anything.
+
+ local retval
+
+ # validate arguments
+ if [ $# -lt 1 ]; then
+ usage_error "run() called with wrong number of arguments; expected at" \
+ "least 1, got $#"
+ exit $SHELL_LIB_USAGE_ERROR
+ fi
+
+ "$@" || retval=$?
+
+ if [ ${retval:-0} -ne 0 ]; then
+ observe "command \"$*\" exited with status $retval"
+ fi
+}
+
+make_symlink_sane () {
+ # syntax: make_symlink_sane symlink target
+ #
+ # Ensure that the symbolic link symlink exists, and points to target.
+ #
+ # If symlink does not exist, create it and point it at target.
+ #
+ # If symlink exists but is not a symbolic link, back it up.
+ #
+ # If symlink exists, is a symbolic link, but points to the wrong location, fix
+ # it.
+ #
+ # If symlink exists, is a symbolic link, and already points to target, do
+ # nothing.
+ #
+ # This function wouldn't be needed if ln had an -I, --idempotent option.
+
+ # Validate arguments.
+ if [ $# -ne 2 ]; then
+ usage_error "make_symlink_sane() called with wrong number of arguments;" \
+ "expected 2, got $#"
+ exit $SHELL_LIB_USAGE_ERROR
+ fi
+
+ # We could just use the positional parameters as-is, but that makes things
+ # harder to follow.
+ local symlink target
+
+ symlink="$1"
+ target="$2"
+
+ if [ -L "$symlink" ] && [ "$(readlink "$symlink")" = "$target" ]; then
+ observe "link from $symlink to $target already exists"
+ else
+ observe "creating symbolic link from $symlink to $target"
+ mkdir -p "${target%/*}" "${symlink%/*}"
+ ln -s -b -S ".dpkg-old" "$target" "$symlink"
+ fi
+}
+
+migrate_dir_to_symlink () {
+ # syntax: migrate_dir_to_symlink old_location new_location
+ #
+ # Per Debian Policy section 6.5.4, "A directory will never be replaced by a
+ # symbolic link to a directory or vice versa; instead, the existing state
+ # (symlink or not) will be left alone and dpkg will follow the symlink if
+ # there is one."
+ #
+ # We have to do it ourselves.
+ #
+ # This function moves the contents of old_location, a directory, into
+ # new_location, a directory, then makes old_location a symbolic link to
+ # new_location.
+ #
+ # old_location need not exist, but if it does, it must be a directory (or a
+ # symlink to a directory). If it is not, it is backed up. If new_location
+ # exists already and is not a directory, it is backed up.
+ #
+ # This function should be called from a package's preinst so that other
+ # packages unpacked after this one --- but before this package's postinst runs
+ # --- are unpacked into new_location even if their payloads contain
+ # old_location filespecs.
+
+ # Validate arguments.
+ if [ $# -ne 2 ]; then
+ usage_error "migrate_dir_to_symlink() called with wrong number of"
+ "arguments; expected 2, got $#"
+ exit $SHELL_LIB_USAGE_ERROR
+ fi
+
+ # We could just use the positional parameters as-is, but that makes things
+ # harder to follow.
+ local new old
+
+ old="$1"
+ new="$2"
+
+ # Is old location a symlink?
+ if [ -L "$old" ]; then
+ # Does it already point to new location?
+ if [ "$(readlink "$old")" = "$new" ]; then
+ # Nothing to do; migration has already been done.
+ observe "migration of $old to $new already done"
+ return 0
+ else
+ # Back it up.
+ warn "backing up symbolic link $old as $old.dpkg-old"
+ mv -b "$old" "$old.dpkg-old"
+ fi
+ fi
+
+ # Does old location exist, but is not a directory?
+ if [ -e "$old" ] && ! [ -d "$old" ]; then
+ # Back it up.
+ warn "backing up non-directory $old as $old.dpkg-old"
+ mv -b "$old" "$old.dpkg-old"
+ fi
+
+ observe "migrating $old to $new"
+
+ # Is new location a symlink?
+ if [ -L "$new" ]; then
+ # Does it point the wrong way, i.e., back to where we're migrating from?
+ if [ "$(readlink "$new")" = "$old" ]; then
+ # Get rid of it.
+ observe "removing symbolic link $new which points to $old"
+ rm "$new"
+ else
+ # Back it up.
+ warn "backing up symbolic link $new as $new.dpkg-old"
+ mv -b "$new" "$new.dpkg-old"
+ fi
+ fi
+
+ # Does new location exist, but is not a directory?
+ if [ -e "$new" ] && ! [ -d "$new" ]; then
+ warn "backing up non-directory $new as $new.dpkg-old"
+ mv -b "$new" "$new.dpkg-old"
+ fi
+
+ # Create new directory if it does not yet exist.
+ if ! [ -e "$new" ]; then
+ observe "creating $new"
+ mkdir -p "$new"
+ fi
+
+ # Copy files in old location to new location. Back up any filenames that
+ # already exist in the new location with the extension ".dpkg-old".
+ observe "copying files from $old to $new"
+ if ! (cd "$old" && cp -a -b -S ".dpkg-old" . "$new"); then
+ die "error(s) encountered while copying files from $old to $new"
+ fi
+
+ # Remove files at old location.
+ observe "removing $old"
+ rm -r "$old"
+
+ # Create symlink from old location to new location.
+ make_symlink_sane "$old" "$new"
+}
+
+# vim:set ai et sw=2 ts=2 tw=80:
+
+# GOBSTOPPER: The X Strike Force shell library ends here.
--- /dev/null
+/**************************************************************************
+
+xserver-xorg-input-gesture
+
+Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+
+Contact: Sung-Jin Park <sj76.park@samsung.com>
+ Sangjin LEE <lsj119@samsung.com>
+
+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 <linux/input.h>
+#include <linux/types.h>
+
+#include <xf86_OSproc.h>
+
+#include <unistd.h>
+
+#include <xf86.h>
+#include <xf86Xinput.h>
+#include <exevents.h>
+#include <xorgVersion.h>
+#include <xkbsrv.h>
+
+#ifdef HAVE_PROPERTIES
+#include <X11/Xatom.h>
+#include <xserver-properties.h>
+/* 1.6 has properties, but no labels */
+#ifdef AXIS_LABEL_PROP
+#define HAVE_LABELS
+#else
+#undef HAVE_LABELS
+#endif
+
+#endif
+
+#define __DEBUG__
+//#define __DETAIL_DEBUG__
+//#define __DEBUG_EVENT_HANDLER__
+
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <xorg-server.h>
+#include <xorgVersion.h>
+#include <xf86Module.h>
+#include <X11/Xatom.h>
+#include "gesture.h"
+#include <xorg/mi.h>
+
+//Basic functions
+static InputInfoPtr GesturePreInit(InputDriverPtr drv, IDevPtr dev, int flags);
+static void GestureUnInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags);
+static pointer GesturePlug(pointer module, pointer options, int *errmaj, int *errmin);
+static void GestureUnplug(pointer p);
+static int GestureControl(DeviceIntPtr device,int what);
+static int GestureInit(DeviceIntPtr device);
+static void GestureFini(DeviceIntPtr device);
+static void GestureReadInput(InputInfoPtr pInfo);
+
+//other initializers
+ErrorStatus GestureRegionsInit(void);
+
+//event queue handling functions
+ErrorStatus GestureInitEQ(void);
+ErrorStatus GestureFiniEQ(void);
+ErrorStatus GestureEnqueueEvent(int screen_num, InternalEvent *ev, DeviceIntPtr device);
+ErrorStatus GestureEventsFlush(void);
+void GestureEventsDrop(void);
+
+//utility functions
+ErrorStatus GestureRegionsReinit(void);
+void GestureSetDisable(InputInfoPtr pInfo, int enable);
+WindowPtr GestureGetEventsWindow(void);
+
+//Enqueued event handlers and enabler/disabler
+static ErrorStatus GestureEnableEventHandler(InputInfoPtr pInfo);
+static ErrorStatus GestureDisableEventHandler(void);
+static CARD32 GestureTimerHandler(OsTimerPtr timer, CARD32 time, pointer arg);
+static CARD32 GestureEventTimerHandler(OsTimerPtr timer, CARD32 time, pointer arg);
+void GestureHandleMTSyncEvent(int screen_num, InternalEvent *ev, DeviceIntPtr device);
+void GestureHandleButtonPressEvent(int screen_num, InternalEvent *ev, DeviceIntPtr device);
+void GestureHandleButtonReleaseEvent(int screen_num, InternalEvent *ev, DeviceIntPtr device);
+void GestureHandleMotionEvent(int screen_num, InternalEvent *ev, DeviceIntPtr device);
+
+//Gesture recognizer helper
+static Bool PointInBorderSize(WindowPtr pWin, int x, int y);
+static WindowPtr GestureWindowOnXY(int x, int y);
+Bool GestureHasFingerEventMask(int eventType, int num_finger);
+
+//Gesture recognizer and handlers
+void GestureRecognize_GroupPinchRotation(int type, InternalEvent *ev, DeviceIntPtr device, int idx);
+void GestureRecognize_GroupFlick(int type, InternalEvent *ev, DeviceIntPtr device, int idx);
+void GestureRecognize_GroupPan(int type, InternalEvent *ev, DeviceIntPtr device, int idx, int timer_expired);
+void GestureRecognize_GroupTap(int type, InternalEvent *ev, DeviceIntPtr device, int idx, int timer_expired);
+void GestureRecognize_GroupTapNHold(int type, InternalEvent *ev, DeviceIntPtr device, int idx, int timer_expired);
+void GestureRecognize_GroupHold(int type, InternalEvent *ev, DeviceIntPtr device, int idx, int timer_expired);
+void GestureHandleGesture_Flick(int num_of_fingers, int distance, Time duration, int direction);
+void GestureHandleGesture_Tap(int num_finger, int tap_repeat, int cx, int cy);
+void GestureHandleGesture_PinchRotation(int num_of_fingers, double zoom, double angle, int distance, int cx, int cy);
+void GestureHandleGesture_Hold(int num_fingers, int cx, int cy, Time holdtime, int kinds);
+void GestureHandleGesture_TapNHold(int num_fingers, int cx, int cy, Time interval, Time holdtime, int kinds);
+void GestureHandleGesture_Pan(int num_fingers, short int dx, short int dy, int direction, int distance, Time duration, int kinds);
+void GestureRecognize(int type, InternalEvent *ev, DeviceIntPtr device);
+ErrorStatus GestureFlushOrDrop(void);
+
+#ifdef HAVE_PROPERTIES
+//function related property handling
+static void GestureInitProperty(DeviceIntPtr dev);
+static int GestureSetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val, BOOL checkonly);
+#endif
+
+static Atom prop_gesture_recognizer_onoff = None;
+
+GestureDevicePtr g_pGesture = NULL;
+_X_EXPORT InputDriverRec GESTURE = {
+ 1,
+ "gesture",
+ NULL,
+ GesturePreInit,
+ GestureUnInit,
+ NULL,
+ 0
+};
+
+static XF86ModuleVersionInfo GestureVersionRec =
+{
+ "gesture",
+ MODULEVENDORSTRING,
+ MODINFOSTRING1,
+ MODINFOSTRING2,
+ XORG_VERSION_CURRENT,
+ PACKAGE_VERSION_MAJOR, PACKAGE_VERSION_MINOR,
+ PACKAGE_VERSION_PATCHLEVEL,
+ ABI_CLASS_XINPUT,
+ ABI_XINPUT_VERSION,
+ MOD_CLASS_XINPUT,
+ {0, 0, 0, 0}
+};
+
+_X_EXPORT XF86ModuleData gestureModuleData =
+{
+ &GestureVersionRec,
+ &GesturePlug,
+ &GestureUnplug
+};
+
+static Bool
+PointInBorderSize(WindowPtr pWin, int x, int y)
+{
+ BoxRec box;
+ if( pixman_region_contains_point (&pWin->borderSize, x, y, &box) )
+ return TRUE;
+
+ return FALSE;
+}
+
+static WindowPtr
+GestureWindowOnXY(int x, int y)
+{
+ WindowPtr pWin;
+ BoxRec box;
+ SpritePtr pSprite;
+ DeviceIntPtr pDev = g_pGesture->master_pointer;
+
+ pSprite = pDev->spriteInfo->sprite;
+ pSprite->spriteTraceGood = 1; /* root window still there */
+ pWin = RootWindow(pDev)->firstChild;
+
+ while (pWin)
+ {
+ if ((pWin->mapped) &&
+ (x >= pWin->drawable.x - wBorderWidth (pWin)) &&
+ (x < pWin->drawable.x + (int)pWin->drawable.width +
+ wBorderWidth(pWin)) &&
+ (y >= pWin->drawable.y - wBorderWidth (pWin)) &&
+ (y < pWin->drawable.y + (int)pWin->drawable.height +
+ wBorderWidth (pWin))
+ /* When a window is shaped, a further check
+ * is made to see if the point is inside
+ * borderSize
+ */
+ && (!wBoundingShape(pWin) || PointInBorderSize(pWin, x, y))
+ && (!wInputShape(pWin) ||
+ RegionContainsPoint(wInputShape(pWin),
+ x - pWin->drawable.x,
+ y - pWin->drawable.y, &box))
+#ifdef ROOTLESS
+ /* In rootless mode windows may be offscreen, even when
+ * they're in X's stack. (E.g. if the native window system
+ * implements some form of virtual desktop system).
+ */
+ && !pWin->rootlessUnhittable
+#endif
+ )
+ {
+ if (pSprite->spriteTraceGood >= pSprite->spriteTraceSize)
+ {
+ pSprite->spriteTraceSize += 10;
+ pSprite->spriteTrace = realloc(pSprite->spriteTrace,
+ pSprite->spriteTraceSize*sizeof(WindowPtr));
+ }
+ pSprite->spriteTrace[pSprite->spriteTraceGood++] = pWin;
+ pWin = pWin->firstChild;
+ }
+ else
+ pWin = pWin->nextSib;
+ }
+ return pSprite->spriteTrace[pSprite->spriteTraceGood-1];
+}
+
+Bool
+GestureHasFingerEventMask(int eventType, int num_finger)
+{
+ Bool ret = FALSE;
+ Mask eventmask = (1L << eventType);
+
+ if( (g_pGesture->grabMask & eventmask) &&
+ (g_pGesture->GrabEvents[eventType].pGestureGrabWinInfo[num_finger].window != None) )
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[X11][GestureHasFingerEventMask] TRUE !! Has grabMask\n");
+#endif//__DETAIL_DEBUG__
+ return TRUE;
+ }
+
+ if( g_pGesture->eventMask & eventmask )
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[X11][GestureHasFingerEventMask] TRUE !! Has eventMask\n");
+#endif//__DETAIL_DEBUG__
+ return TRUE;
+ }
+
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[X11][GestureHasFingerEventMask] FALSE !! eventType=%d, num_finger=%d\n", eventType, num_finger);
+#endif//__DETAIL_DEBUG__
+
+ return ret;
+}
+
+void
+GestureHandleGesture_Flick(int num_of_fingers, int distance, Time duration, int direction)
+{
+ Window target_win;
+ WindowPtr target_pWin;
+ xGestureNotifyFlickEvent fev;
+
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[X11][GestureHandleGesture_Flick] num_fingers=%d, distance=%d, duration=%d, direction=%d\n",
+ num_of_fingers, distance, duration, direction);
+#endif//__DETAIL_DEBUG__
+
+ g_pGesture->recognized_gesture |= FlickFilterMask;
+ memset(&fev, 0, sizeof(xGestureNotifyFlickEvent));
+ fev.type = GestureNotifyFlick;
+ fev.kind = GestureDone;
+ fev.num_finger = num_of_fingers;
+ fev.distance = distance;
+ fev.duration = duration;
+ fev.direction = direction;
+
+ target_win = g_pGesture->GrabEvents[GestureNotifyFlick].pGestureGrabWinInfo[num_of_fingers].window;
+ target_pWin = g_pGesture->GrabEvents[GestureNotifyFlick].pGestureGrabWinInfo[num_of_fingers].pWin;
+
+ if( g_pGesture->grabMask && (target_win != None) )
+ {
+ fev.window = target_win;
+ }
+ else
+ {
+ fev.window = g_pGesture->gestureWin;
+ }
+
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[X11][GestureHandleGesture_Flick] fev.window=0x%x, g_pGesture->grabMask=0x%x\n", fev.window, g_pGesture->grabMask);
+#endif//__DETAIL_DEBUG__
+
+ GestureSendEvent(target_pWin, GestureNotifyFlick, GestureFlickMask, (xGestureCommonEvent *)&fev);
+}
+
+void
+GestureHandleGesture_Tap(int num_finger, int tap_repeat, int cx, int cy)
+{
+ Window target_win;
+ WindowPtr target_pWin;
+ xGestureNotifyTapEvent tev;
+
+ //skip non-tap events and single finger tap
+ if( !tap_repeat || num_finger <= 1 )
+ return;
+
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[X11][GestureHandleGesture_Tap] num_finger=%d, tap_repeat=%d, cx=%d, cy=%d\n",
+ num_finger, tap_repeat, cx, cy);
+#endif//__DETAIL_DEBUG__
+
+ g_pGesture->recognized_gesture |= TapFilterMask;
+ memset(&tev, 0, sizeof(xGestureNotifyTapEvent));
+ tev.type = GestureNotifyTap;
+ tev.kind = GestureDone;
+ tev.num_finger = num_finger;
+ tev.tap_repeat = tap_repeat;
+ tev.interval = 0;
+ tev.cx = cx;
+ tev.cy = cy;
+
+ target_win = g_pGesture->GrabEvents[GestureNotifyTap].pGestureGrabWinInfo[num_finger].window;
+ target_pWin = g_pGesture->GrabEvents[GestureNotifyTap].pGestureGrabWinInfo[num_finger].pWin;
+
+ if( g_pGesture->grabMask && (target_win != None) )
+ {
+ tev.window = target_win;
+ }
+ else
+ {
+ tev.window = g_pGesture->gestureWin;
+ }
+
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[X11][GestureHandleGesture_Tap] tev.window=0x%x, g_pGesture->grabMask=0x%x\n", tev.window, g_pGesture->grabMask);
+#endif//__DETAIL_DEBUG__
+
+ GestureSendEvent(target_pWin, GestureNotifyTap, GestureTapMask, (xGestureCommonEvent *)&tev);
+}
+
+void GestureHandleGesture_PinchRotation(int num_of_fingers, double zoom, double angle, int distance, int cx, int cy)
+{
+ Window target_win;
+ WindowPtr target_pWin;
+ xGestureNotifyPinchRotationEvent prev;
+
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[X11][GestureHandleGesture_PinchRotation] num_fingers=%d, zoom=%.2f, angle=%.2f, distance=%d\n",
+ num_of_fingers, zoom, angle, distance, cx, cy);
+#endif//__DETAIL_DEBUG__
+
+ g_pGesture->recognized_gesture |= PinchRotationFilterMask;
+ memset(&prev, 0, sizeof(xGestureNotifyPinchRotationEvent));
+ prev.type = GestureNotifyPinchRotation;
+ prev.kind = GestureDone;
+ prev.num_finger = num_of_fingers;
+ prev.zoom = XDoubleToFixed(zoom);
+ prev.angle = XDoubleToFixed(angle);
+ prev.distance = distance;
+ prev.cx = cx;
+ prev.cy = cy;
+
+ target_win = g_pGesture->GrabEvents[GestureNotifyPinchRotation].pGestureGrabWinInfo[num_of_fingers].window;
+ target_pWin = g_pGesture->GrabEvents[GestureNotifyPinchRotation].pGestureGrabWinInfo[num_of_fingers].pWin;
+
+ if( g_pGesture->grabMask && (target_win != None) )
+ {
+ prev.window = target_win;
+ }
+ else
+ {
+ prev.window = g_pGesture->gestureWin;
+ }
+
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[X11][GestureHandleGesture_PinchRotation] prev.window=0x%x, g_pGesture->grabMask=0x%x\n", prev.window, g_pGesture->grabMask);
+#endif//__DETAIL_DEBUG__
+
+ GestureSendEvent(target_pWin, GestureNotifyPinchRotation, GesturePinchRotationMask, (xGestureCommonEvent *)&prev);
+}
+
+void GestureHandleGesture_Hold(int num_fingers, int cx, int cy, Time holdtime, int kinds)
+{
+ Window target_win;
+ WindowPtr target_pWin;
+ xGestureNotifyHoldEvent hev;
+
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[X11][GestureHandleGesture_Hold] num_fingers=%d, cx=%d, cy=%d, holdtime=%d, kinds=%d\n",
+ num_fingers, cx, cy, holdtime, kinds);
+#endif//__DETAIL_DEBUG__
+
+ g_pGesture->recognized_gesture |= HoldFilterMask;
+ memset(&hev, 0, sizeof(xGestureNotifyHoldEvent));
+ hev.type = GestureNotifyHold;
+ hev.kind = kinds;
+ hev.num_finger = num_fingers;
+ hev.holdtime = holdtime;
+ hev.cx = cx;
+ hev.cy = cy;
+
+ target_win = g_pGesture->GrabEvents[GestureNotifyHold].pGestureGrabWinInfo[num_fingers].window;
+ target_pWin = g_pGesture->GrabEvents[GestureNotifyHold].pGestureGrabWinInfo[num_fingers].pWin;
+
+ if( g_pGesture->grabMask && (target_win != None) )
+ {
+ hev.window = target_win;
+ }
+ else
+ {
+ hev.window = g_pGesture->gestureWin;
+ }
+
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[X11][GestureHandleGesture_Hold] hev.window=0x%x, g_pGesture->grabMask=0x%x\n", hev.window, g_pGesture->grabMask);
+#endif//__DETAIL_DEBUG__
+
+ GestureSendEvent(target_pWin, GestureNotifyHold, GestureHoldMask, (xGestureCommonEvent *)&hev);
+}
+
+void GestureHandleGesture_TapNHold(int num_fingers, int cx, int cy, Time interval, Time holdtime, int kinds)
+{
+ Window target_win;
+ WindowPtr target_pWin;
+ xGestureNotifyTapNHoldEvent thev;
+
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[X11][GestureHandleGesture_TapNHold] num_fingers=%d, cx=%d, cy=%d, interval=%d, holdtime=%d, kinds=%d\n",
+ num_fingers, cx, cy, interval, holdtime, kinds);
+#endif//__DETAIL_DEBUG__
+
+ g_pGesture->recognized_gesture |= TapNHoldFilterMask;
+ memset(&thev, 0, sizeof(xGestureNotifyTapNHoldEvent));
+ thev.type = GestureNotifyTapNHold;
+ thev.kind = kinds;
+ thev.num_finger = num_fingers;
+ thev.holdtime = holdtime;
+ thev.cx = cx;
+ thev.cy = cy;
+ thev.interval = interval;
+
+ target_win = g_pGesture->GrabEvents[GestureNotifyTapNHold].pGestureGrabWinInfo[num_fingers].window;
+ target_pWin = g_pGesture->GrabEvents[GestureNotifyTapNHold].pGestureGrabWinInfo[num_fingers].pWin;
+
+ if( g_pGesture->grabMask && (target_win != None) )
+ {
+ thev.window = target_win;
+ }
+ else
+ {
+ thev.window = g_pGesture->gestureWin;
+ }
+
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[X11][GestureHandleGesture_TapNHold] thev.window=0x%x, g_pGesture->grabMask=0x%x\n", thev.window, g_pGesture->grabMask);
+#endif//__DETAIL_DEBUG__
+
+ GestureSendEvent(target_pWin, GestureNotifyTapNHold, GestureTapNHoldMask, (xGestureCommonEvent *)&thev);
+}
+
+void GestureHandleGesture_Pan(int num_fingers, short int dx, short int dy, int direction, int distance, Time duration, int kinds)
+{
+ Window target_win;
+ WindowPtr target_pWin;
+ xGestureNotifyPanEvent pev;
+
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[X11][GestureHandleGesture_Pan] num_fingers=%d, dx=%d, dy=%d, direction=%d, distance=%d, duration=%d, kinds=%d\n",
+ num_fingers, dx, dy, direction, distance, duration, kinds);
+#endif//__DETAIL_DEBUG__
+
+ g_pGesture->recognized_gesture |= PanFilterMask;
+ memset(&pev, 0, sizeof(xGestureNotifyPanEvent));
+ pev.type = GestureNotifyPan;
+ pev.kind = kinds;
+ pev.num_finger = num_fingers;
+ pev.direction = direction;
+ pev.distance = distance;
+ pev.duration = duration;
+ pev.dx = dx;
+ pev.dy = dy;
+
+ target_win = g_pGesture->GrabEvents[GestureNotifyPan].pGestureGrabWinInfo[num_fingers].window;
+ target_pWin = g_pGesture->GrabEvents[GestureNotifyPan].pGestureGrabWinInfo[num_fingers].pWin;
+
+ if( g_pGesture->grabMask && (target_win != None) )
+ {
+ pev.window = target_win;
+ }
+ else
+ {
+ pev.window = g_pGesture->gestureWin;
+ }
+
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[X11][GestureHandleGesture_Pan] pev.window=0x%x, g_pGesture->grabMask=0x%x\n", pev.window, g_pGesture->grabMask);
+#endif//__DETAIL_DEBUG__
+
+ GestureSendEvent(target_pWin, GestureNotifyPan, GesturePanMask, (xGestureCommonEvent *)&pev);
+}
+
+void
+GestureRecognize_GroupPinchRotation(int type, InternalEvent *ev, DeviceIntPtr device, int idx)
+{
+
+ g_pGesture->recognized_gesture &= ~PinchRotationFilterMask;
+ g_pGesture->filter_mask |= PinchRotationFilterMask;
+ return;
+}
+
+void
+GestureRecognize_GroupFlick(int type, InternalEvent *ev, DeviceIntPtr device, int idx)
+{
+ static int num_pressed = 0;
+ static int mbits = 0;
+ static int base_area_size = 0;
+ static Time base_time = 0;
+ static int base_x, base_y;
+ Time current_time;
+ Time duration;
+ int distx, disty;
+ int distance, direction;
+ int area_size;
+ int flicked = 0;
+
+ switch( type )
+ {
+ case ET_ButtonPress:
+ g_pGesture->fingers[idx].flags |= PressFlagFlick;
+
+ if( g_pGesture->num_pressed < 2 )
+ return;
+
+ if( !base_area_size || g_pGesture->num_pressed > num_pressed )
+ {
+ base_area_size = AREA_SIZE(&g_pGesture->area.extents);
+ base_x = g_pGesture->area.extents.x1;
+ base_y = g_pGesture->area.extents.y1;
+ base_time = GetTimeInMillis();
+ }
+ num_pressed = g_pGesture->num_pressed;
+
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupFlick][P]][num_pressed=%d] AREA_SIZE(area.extents)=%d\n", num_pressed, base_area_size);
+#endif//__DETAIL_DEBUG__
+ break;
+
+ case ET_Motion:
+ if( !(g_pGesture->fingers[idx].flags & PressFlagFlick ) )
+ break;
+
+#ifdef __DETAIL_DEBUG__
+ if( num_pressed > g_pGesture->num_pressed )
+ {
+ ErrorF("[GroupFlick][M][cleanup] num_pressed=%d, g_pGesture->num_pressed=%d\n", num_pressed, g_pGesture->num_pressed);
+ //goto cleanup_flick;
+ }
+#endif//__DETAIL_DEBUG__
+
+ if( num_pressed < 2 )
+ return;
+
+ mbits |= (1 << idx);
+ if( mbits == (pow(2, num_pressed)-1) )
+ {
+ area_size = AREA_SIZE(&g_pGesture->area.extents);
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[M][num_pressed=%d] AREA_SIZE(area.extents)=%d\n", num_pressed, area_size);
+#endif//__DETAIL_DEBUG__
+ if( ABS(base_area_size - area_size) >= FLICK_AREA_THRESHOLD )
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupFlick][M] diff between Area size(=%d) and base area size(=%d) is bigger than threshold(=%d)!\n", area_size, base_area_size, FLICK_AREA_THRESHOLD);
+#endif//__DETAIL_DEBUG__
+ goto cleanup_flick;
+ }
+
+ current_time = GetTimeInMillis();
+ if( (current_time - base_time) >= FLICK_AREA_TIMEOUT )
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupFlick][M] diff between current time(=%d) and base time(=%d) is bigger than threashold(=%d) !\n", current_time, base_time, FLICK_AREA_TIMEOUT);
+#endif//__DETAIL_DEBUG__
+ goto cleanup_flick;
+ }
+ mbits = 0;
+ }
+ break;
+
+ case ET_ButtonRelease:
+ if( g_pGesture->num_pressed )
+ break;
+
+ duration = GetTimeInMillis() - base_time;
+ distx = g_pGesture->area.extents.x1 - base_x;
+ disty = g_pGesture->area.extents.y1 - base_y;
+
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupFlick] duration=%d, distx=%d, disty=%d\n", duration, distx, disty);
+#endif//__DETAIL_DEBUG__
+
+ if( duration <= 0 || duration >= FLICK_AREA_TIMEOUT )
+ goto cleanup_flick;
+
+ if( ABS(distx) >= FLICK_MOVE_THRESHOLD )
+ {
+ direction = (distx > 0) ? FLICK_EASTWARD : FLICK_WESTWARD;
+ distance = ABS(distx);
+ flicked++;
+ }
+ else if( ABS(disty) >= FLICK_MOVE_THRESHOLD )
+ {
+ direction = (disty > 0) ? FLICK_SOUTHWARD : FLICK_NORTHWARD;
+ distance = ABS(disty);
+ flicked++;
+ }
+
+ if( !flicked )
+ goto cleanup_flick;
+
+ if( GestureHasFingerEventMask(GestureNotifyFlick, num_pressed) )
+ GestureHandleGesture_Flick(num_pressed, distance, duration, direction);
+ goto cleanup_flick_recognized;
+ break;
+ }
+
+ return;
+
+cleanup_flick:
+
+ g_pGesture->recognized_gesture &= ~FlickFilterMask;
+
+cleanup_flick_recognized:
+
+ g_pGesture->filter_mask |= FlickFilterMask;
+ num_pressed = 0;
+ base_area_size = 0;
+ base_time = 0;
+ mbits = 0;
+ return;
+}
+
+void
+GestureRecognize_GroupPan(int type, InternalEvent *ev, DeviceIntPtr device, int idx, int timer_expired)
+{
+ static int num_pressed = 0;
+ static int mbits = 0;
+ static int base_area_size = 0;
+ static Time base_time = 0;
+ static pixman_box16_t base_box_ext;
+ static int base_cx;
+ static int base_cy;
+ static int prev_cx;
+ static int prev_cy;
+ static int cx = 0;
+ static int cy = 0;
+ int dx, dy;
+ static Time prev_time = 0;
+ Time current_time = 0;
+ int distance = 0;
+ int direction = 0;
+ int area_size;
+ static int time_checked = 0;
+ static int state = GestureEnd;
+
+ static OsTimerPtr pan_event_timer = NULL;
+ static int event_type = GestureNotifyPan;
+
+ if( timer_expired )
+ {
+ if( !time_checked )
+ {
+ current_time = GetTimeInMillis();
+ if( (current_time - base_time) >= PAN_TIME_THRESHOLD )
+ {
+ if( (!cx && !cy) || INBOX(&base_box_ext, cx, cy) )
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupPan][Timer] You must move farther than move threshold(=%d) within time threshold(=%d) !\n", PAN_MOVE_THRESHOLD*2, PAN_TIME_THRESHOLD);
+#endif//__DETAIL_DEBUG__
+ goto cleanup_pan;
+ }
+ time_checked = 1;
+ }
+ }
+ return;
+ }
+
+ switch( type )
+ {
+ case ET_ButtonPress:
+ g_pGesture->fingers[idx].flags |= PressFlagPan;
+
+ if( g_pGesture->num_pressed < 2 )
+ return;
+
+ if( !base_area_size || g_pGesture->num_pressed > num_pressed )
+ {
+ if( state != GestureEnd )
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupPan][P][cleanup] num_finger changed ! num_pressed=%d, g_pGesture->num_pressed=%d\n", num_pressed, g_pGesture->num_pressed);
+#endif//__DETAIL_DEBUG__
+ goto cleanup_pan;
+ }
+ base_area_size = AREA_SIZE(&g_pGesture->area.extents);
+ prev_cx = base_cx = AREA_CENTER_X(&g_pGesture->area.extents);
+ prev_cy = base_cy = AREA_CENTER_Y(&g_pGesture->area.extents);
+ prev_time = base_time = GetTimeInMillis();
+ base_box_ext.x1 = base_cx-PAN_MOVE_THRESHOLD;
+ base_box_ext.y1 = base_cy-PAN_MOVE_THRESHOLD;
+ base_box_ext.x2 = base_cx+PAN_MOVE_THRESHOLD;
+ base_box_ext.y2 = base_cy+PAN_MOVE_THRESHOLD;
+ event_type = GestureNotifyPan;
+ pan_event_timer = TimerSet(pan_event_timer, 0, PAN_TIME_THRESHOLD, GestureEventTimerHandler, (int *)&event_type);
+ }
+ num_pressed = g_pGesture->num_pressed;
+
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupPan][P][num_pressed=%d] AREA_SIZE(area.extents)=%d, base_cx=%d, base_cy=%d\n", num_pressed, base_area_size, base_cx, base_cy);
+#endif//__DETAIL_DEBUG__
+ break;
+
+ case ET_Motion:
+ if( !(g_pGesture->fingers[idx].flags & PressFlagPan ) )
+ break;
+
+ if( num_pressed != g_pGesture->num_pressed )
+ {
+ if( state != GestureEnd )
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupPan][M][cleanup] num_finger changed ! num_pressed=%d, g_pGesture->num_pressed=%d\n", num_pressed, g_pGesture->num_pressed);
+#endif//__DETAIL_DEBUG__
+ goto cleanup_pan;
+ }
+ }
+
+ if( num_pressed < 2 )
+ return;
+
+ mbits |= (1 << idx);
+ if( mbits == (pow(2, num_pressed)-1) )
+ {
+ area_size = AREA_SIZE(&g_pGesture->area.extents);
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupPan][M][num_pressed=%d] area_size=%d, base_area_size=%d, diff=%d\n", num_pressed, area_size, base_area_size, ABS(base_area_size - area_size));
+#endif//__DETAIL_DEBUG__
+
+ if( (state != GestureUpdate) && (ABS(base_area_size - area_size) >= PAN_AREA_THRESHOLD) )
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupPan][M] diff between area size(=%d) and base area size(=%d) is bigger than threshold(=%d)!\n", area_size, base_area_size, PAN_AREA_THRESHOLD);
+#endif//__DETAIL_DEBUG__
+ goto cleanup_pan;
+ }
+
+ cx = AREA_CENTER_X(&g_pGesture->area.extents);
+ cy = AREA_CENTER_Y(&g_pGesture->area.extents);
+
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupPan][M] cx=%d, prev_cx=%d, diff=%d\n", cx, prev_cx, ABS(cx-prev_cx));
+ ErrorF("[GroupPan][M] cy=%d, prev_cy=%d, diff=%d\n", cy, prev_cy, ABS(cy-prev_cy));
+#endif//__DETAIL_DEBUG__
+
+ if( !time_checked )
+ {
+ current_time = GetTimeInMillis();
+ if( (current_time - base_time) >= PAN_TIME_THRESHOLD )
+ {
+ if( INBOX(&base_box_ext, cx, cy) )
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupPan][M] You must move farther than move threshold(=%d) within time threshold(=%d) !\n", PAN_MOVE_THRESHOLD*2, PAN_TIME_THRESHOLD);
+#endif//__DETAIL_DEBUG__
+ goto cleanup_pan;
+ }
+ time_checked = 1;
+ }
+ }
+
+ if( time_checked )
+ {
+ if( state <= GestureBegin )
+ {
+ base_box_ext.x1 = prev_cx-PAN_MOVE_THRESHOLD;
+ base_box_ext.y1 = prev_cy-PAN_MOVE_THRESHOLD;
+ base_box_ext.x2 = prev_cx+PAN_MOVE_THRESHOLD;
+ base_box_ext.y2 = prev_cy+PAN_MOVE_THRESHOLD;
+
+ if( !INBOX(&base_box_ext, cx, cy) )
+ {
+ current_time = GetTimeInMillis();
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupPan] PAN Begin !dx=%d, dy=%d, state=%d\n", prev_cx, prev_cy, state);
+#endif//__DETAIL_DEBUG__
+ if( GestureHasFingerEventMask(GestureNotifyPan, num_pressed) )
+ {
+ GestureHandleGesture_Pan(num_pressed, prev_cx, prev_cy, direction, distance, current_time-prev_time, GestureBegin);
+ state = GestureUpdate;
+ }
+ else
+ goto cleanup_pan;
+ }
+ }
+ else
+ {
+ dx = cx-prev_cx;
+ dy = cy-prev_cy;
+ //if( ABS(dx) >= PAN_UPDATE_MOVE_THRESHOLD || ABS(dy) >= PAN_UPDATE_MOVE_THRESHOLD )
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupPan] PAN Update !dx=%d, dy=%d, state=%d\n", dx, dy, state);
+#endif//__DETAIL_DEBUG__
+
+ GestureHandleGesture_Pan(num_pressed, dx, dy, direction, distance, current_time-prev_time, GestureUpdate);
+ }
+ }
+ prev_cx = cx;
+ prev_cy = cy;
+ prev_time = current_time;
+ }
+ mbits = 0;
+ }
+ break;
+
+ case ET_ButtonRelease:
+ if( state != GestureEnd && num_pressed >= 2)
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupPan][R][cleanup] num_finger changed ! num_pressed=%d, g_pGesture->num_pressed=%d\n", num_pressed, g_pGesture->num_pressed);
+#endif//__DETAIL_DEBUG__
+ goto cleanup_pan;
+ }
+
+ if( g_pGesture->num_pressed )
+ break;
+
+ goto cleanup_pan;
+ break;
+ }
+
+ return;
+
+cleanup_pan:
+
+ if( state == GestureBegin || state == GestureUpdate )
+ {
+ state = GestureEnd;
+ if( GestureHasFingerEventMask(GestureNotifyPan, num_pressed) )
+ {
+ GestureHandleGesture_Pan(num_pressed, (short int)(cx-prev_cx), (short int)(cy-prev_cy), direction, distance, GetTimeInMillis()-prev_time, GestureEnd);
+ }
+ }
+ else
+ {
+ g_pGesture->recognized_gesture &= ~PanFilterMask;
+ }
+
+ g_pGesture->filter_mask |= PanFilterMask;
+ num_pressed = 0;
+ base_area_size = 0;
+ base_time = 0;
+ mbits = 0;
+ time_checked = 0;
+ state = GestureEnd;
+ cx = cy = 0;
+ prev_time = 0;
+ base_box_ext.x1 = base_box_ext.x2 = base_box_ext.y1 = base_box_ext.y2 = 0;
+ TimerCancel(pan_event_timer);
+ return;
+}
+
+void
+GestureRecognize_GroupTap(int type, InternalEvent *ev, DeviceIntPtr device, int idx, int timer_expired)
+{
+ static int num_pressed = 0;
+ static int base_area_size = 0;
+
+ static Time base_time = 0;
+ Time current_time;
+
+ int cx, cy;
+ int area_size;
+
+ static int state = 0;
+ static int mbits = 0;
+ static int base_cx;
+ static int base_cy;
+ static pixman_box16_t base_box_ext;
+
+ static int tap_repeat = 0;
+ static int prev_tap_repeat = 0;
+ static int prev_num_pressed = 0;
+
+ static OsTimerPtr tap_event_timer = NULL;
+ static int event_type = GestureNotifyTap;
+
+ if( timer_expired )
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupTap][Timer] state=%d\n", state);
+#endif//__DETAIL_DEBUG__
+
+ switch( state )
+ {
+ case 1://first tap initiation check
+ if( num_pressed )
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupTap][Timer][state=1] Tap time expired !(num_pressed=%d, tap_repeat=%d)\n", tap_repeat, num_pressed, tap_repeat);
+#endif//__DETAIL_DEBUG__
+ state = 0;
+ goto cleanup_tap;
+ }
+ break;
+
+ case 2:
+ if( tap_repeat <= 1 )
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupTap][Timer][state=2] %d finger SINGLE TAP !(ignored)\n", prev_num_pressed);
+#endif//__DETAIL_DEBUG__
+ state = 0;
+ goto cleanup_tap;
+ }
+
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupTap][Timer][state=2] tap_repeat=%d, prev_tap_repeat=%d, num_pressed=%d\n", tap_repeat, prev_tap_repeat, num_pressed);
+#endif//__DETAIL_DEBUG__
+ if( GestureHasFingerEventMask(GestureNotifyTap, prev_num_pressed) )
+ GestureHandleGesture_Tap(prev_num_pressed, tap_repeat, base_cx, base_cy);
+ goto cleanup_tap;
+ break;
+ }
+
+ return;
+ }
+
+ switch( type )
+ {
+ case ET_ButtonPress:
+ g_pGesture->fingers[idx].flags |= PressFlagTap;
+
+ if( g_pGesture->num_pressed < 2 )
+ return;
+
+ if( !prev_num_pressed && (!base_area_size || g_pGesture->num_pressed > num_pressed) )
+ {
+ base_area_size = AREA_SIZE(&g_pGesture->area.extents);
+ base_cx = AREA_CENTER_X(&g_pGesture->area.extents);
+ base_cy = AREA_CENTER_Y(&g_pGesture->area.extents);
+ base_time = GetTimeInMillis();
+ base_box_ext.x1 = base_cx-TAP_MOVE_THRESHOLD;
+ base_box_ext.y1 = base_cy-TAP_MOVE_THRESHOLD;
+ base_box_ext.x2 = base_cx+TAP_MOVE_THRESHOLD;
+ base_box_ext.y2 = base_cy+TAP_MOVE_THRESHOLD;
+ state = 1;
+ TimerCancel(tap_event_timer);
+ tap_event_timer = TimerSet(tap_event_timer, 0, SGL_TAP_TIME_THRESHOLD, GestureEventTimerHandler, (int *)&event_type);
+ }
+
+ num_pressed = g_pGesture->num_pressed;
+
+ current_time = GetTimeInMillis();
+
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupTap][P][num_pressed=%d] AREA_SIZE(area.extents)=%d, base_cx=%d, base_cy=%d, base_time=%d, current_time=%d\n", num_pressed, base_area_size, base_cx, base_cy, base_time, current_time);
+#endif//__DETAIL_DEBUG__
+ break;
+
+ case ET_Motion:
+ if( !(g_pGesture->fingers[idx].flags & PressFlagTap ) )
+ break;
+
+ if( num_pressed < 2 )
+ return;
+
+ if( num_pressed != g_pGesture->num_pressed )
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupTap][M][cleanup] num_pressed=%d, g_pGesture->num_pressed=%d\n", num_pressed, g_pGesture->num_pressed);
+#endif//__DETAIL_DEBUG__
+ //goto cleanup_tap;
+ }
+
+ mbits |= (1 << idx);
+ if( mbits == (pow(2, num_pressed)-1) )
+ {
+ area_size = AREA_SIZE(&g_pGesture->area.extents);
+ cx = AREA_CENTER_X(&g_pGesture->area.extents);
+ cy = AREA_CENTER_Y(&g_pGesture->area.extents);
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupTap][M][num_pressed=%d] area_size=%d, base_area_size=%d, diff=%d\n", num_pressed, area_size, base_area_size, ABS(base_area_size - area_size));
+ ErrorF("[GroupTap][M] cx=%d, base_cx=%d, diff=%d\n", cx, base_cx, ABS(cx-base_cx));
+ ErrorF("[GroupTap][M] cy=%d, base_cy=%d, diff=%d\n", cy, base_cy, ABS(cy-base_cy));
+#endif//__DETAIL_DEBUG__
+
+ if( ABS(base_area_size-area_size) >= TAP_AREA_THRESHOLD )
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupTap][M] diff between area size(=%d) and base area size(=%d) is bigger than threshold(=%d)!\n", area_size, base_area_size, ABS(base_area_size-area_size));
+#endif//__DETAIL_DEBUG__
+ goto cleanup_tap;
+ }
+
+ if( !INBOX(&base_box_ext, cx, cy) )
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupTap][M] current center coordinates is not in base coordinates box !\n");
+#endif//__DETAIL_DEBUG__
+ goto cleanup_tap;
+ }
+ }
+ break;
+
+ case ET_ButtonRelease:
+ if( g_pGesture->num_pressed )
+ break;
+
+ if( !tap_repeat )
+ {
+ prev_num_pressed = num_pressed;
+ }
+
+ prev_tap_repeat = tap_repeat;
+ tap_repeat++;
+
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupTap][R] tap_repeat=%d, prev_tap_repeat=%d, num_pressed=%d, prev_num_pressed=%d\n", tap_repeat, prev_tap_repeat, num_pressed, prev_num_pressed);
+#endif//__DETAIL_DEBUG__
+
+ if( num_pressed != prev_num_pressed || !GestureHasFingerEventMask(GestureNotifyTap, num_pressed) )
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupTap][R] num_pressed(=%d) != prev_num_pressed(=%d) OR %d finger tap event was not grabbed/selected !\n",
+ num_pressed, prev_num_pressed, num_pressed);
+#endif//__DETAIL_DEBUG__
+ goto cleanup_tap;
+ }
+
+ if( tap_repeat < MAX_TAP_REPEATS )
+ {
+ state = 2;
+ TimerCancel(tap_event_timer);
+ tap_event_timer = TimerSet(tap_event_timer, 0, DBL_TAP_TIME_THRESHOLD, GestureEventTimerHandler, (int *)&event_type);
+ num_pressed = 0;
+ break;
+ }
+
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupTap][R] %d finger %s\n", num_pressed, (tap_repeat==2) ? "DBL_TAP" : "TRIPLE_TAP");
+#endif//__DETAIL_DEBUG__
+
+ if( GestureHasFingerEventMask(GestureNotifyTap, num_pressed) )
+ GestureHandleGesture_Tap(num_pressed, tap_repeat, base_cx, base_cy);
+
+ if( tap_repeat >= MAX_TAP_REPEATS )
+ {
+ goto cleanup_tap;
+ }
+
+ prev_num_pressed = num_pressed;
+ num_pressed = 0;
+ break;
+ }
+
+ return;
+
+cleanup_tap:
+
+ if( 0 == state )
+ g_pGesture->recognized_gesture &= ~TapFilterMask;
+ g_pGesture->filter_mask |= TapFilterMask;
+
+ if( g_pGesture->filter_mask == GESTURE_FILTER_MASK_ALL )
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupTap][cleanup] GestureFlushOrDrop() !\n");
+#endif//__DETAIL_DEBUG__
+
+ if( ERROR_INVALPTR == GestureFlushOrDrop() )
+ {
+ GestureControl(g_pGesture->this_device, DEVICE_OFF);
+ }
+ }
+
+ num_pressed = 0;
+ tap_repeat = 0;
+ prev_num_pressed = 0;
+ mbits = 0;
+ base_time = 0;
+ state = 0;
+ TimerCancel(tap_event_timer);
+ return;
+}
+
+void
+GestureRecognize_GroupTapNHold(int type, InternalEvent *ev, DeviceIntPtr device, int idx, int timer_expired)
+{
+ static int num_pressed = 0;
+ static int base_area_size = 0;
+ static Time base_time = 0;
+ static int base_cx;
+ static int base_cy;
+ int cx, cy;
+ static pixman_box16_t base_box_ext;
+ int area_size;
+ static int mbits = 0;
+
+ static int tap_repeat = 0;
+ static int prev_num_pressed = 0;
+
+ static OsTimerPtr tapnhold_event_timer = NULL;
+ static int event_type = GestureNotifyTapNHold;
+ static int state = GestureEnd;
+
+ Time interval = 0;
+ Time holdtime = 0;
+
+ if( timer_expired )
+ {
+ if( (state == GestureEnd) && num_pressed )
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupTapNHold][Timer][state=%d] Tap time expired !(num_pressed=%d, tap_repeat=%d)\n", GestureEnd, tap_repeat, num_pressed, tap_repeat);
+#endif//__DETAIL_DEBUG__
+ state = 0;
+ goto cleanup_tapnhold;
+ }
+
+ if( state == GestureDone )
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupTapNHold][Timer][state=%d] Interval between Tap and Hold is too long !\n");
+#endif//__DETAIL_DEBUG__
+ goto cleanup_tapnhold;
+ }
+
+#ifdef __DETAIL_DEBUG__
+ switch( state )
+ {
+ case GestureBegin:
+ ErrorF("[GroupTapNHold][Timer] TapNHold Begin !\n");
+ break;
+
+ case GestureUpdate:
+ ErrorF("[GroupTapNHold][Timer] TapNHold Update !\n");
+ break;
+ }
+#endif//__DETAIL_DEBUG__
+
+ if( GestureHasFingerEventMask(GestureNotifyTapNHold, prev_num_pressed) )
+ {
+ GestureHandleGesture_TapNHold(prev_num_pressed, base_cx, base_cy, interval, holdtime, state);
+ tapnhold_event_timer = TimerSet(tapnhold_event_timer, 0, TAPNHOLD_HOLD_TIME_THRESHOLD, GestureEventTimerHandler, (int *)&event_type);
+ }
+ else
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupTapNHold][Timer] %d finger TapNHold event was not grabbed/selected !\n", prev_num_pressed);
+#endif//__DETAIL_DEBUG__
+ goto cleanup_tapnhold;
+ }
+
+ if( state <= GestureBegin )
+ state++;
+ return;
+ }
+
+ switch( type )
+ {
+ case ET_ButtonPress:
+ g_pGesture->fingers[idx].flags |= PressFlagTapNHold;
+
+ if( g_pGesture->num_pressed < 2 )
+ return;
+
+ //if( !prev_num_pressed && (!base_area_size || g_pGesture->num_pressed > num_pressed) )
+ if( !base_area_size || g_pGesture->num_pressed > num_pressed )
+ {
+
+ if( state == GestureUpdate )
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupTapNHold][P][cleanup] num_finger changed ! num_pressed=%d, g_pGesture->num_pressed=%d\n", num_pressed, g_pGesture->num_pressed);
+#endif//__DETAIL_DEBUG__
+ goto cleanup_tapnhold;
+ }
+
+ if( state == GestureDone )
+ state = GestureBegin;
+
+ base_area_size = AREA_SIZE(&g_pGesture->area.extents);
+ base_cx = AREA_CENTER_X(&g_pGesture->area.extents);
+ base_cy = AREA_CENTER_Y(&g_pGesture->area.extents);
+ base_time = GetTimeInMillis();
+ base_box_ext.x1 = base_cx-TAPNHOLD_MOVE_THRESHOLD;
+ base_box_ext.y1 = base_cy-TAPNHOLD_MOVE_THRESHOLD;
+ base_box_ext.x2 = base_cx+TAPNHOLD_MOVE_THRESHOLD;
+ base_box_ext.y2 = base_cy+TAPNHOLD_MOVE_THRESHOLD;
+ if( state == GestureEnd )
+ tapnhold_event_timer = TimerSet(tapnhold_event_timer, 0, TAPNHOLD_TAP_TIME_THRESHOLD, GestureEventTimerHandler, (int *)&event_type);
+ else
+ {
+ TimerCancel(tapnhold_event_timer);
+ tapnhold_event_timer = TimerSet(tapnhold_event_timer, 0, TAPNHOLD_HOLD_TIME_THRESHOLD, GestureEventTimerHandler, (int *)&event_type);
+ }
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupTapNHold][P] Create Timer !(state=%d)\n", state);
+#endif//__DETAIL_DEBUG__
+ }
+
+ num_pressed = g_pGesture->num_pressed;
+
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupTapNHold][P][num_pressed=%d] AREA_SIZE(area.extents)=%d, base_cx=%d, base_cy=%d, base_time=%d\n", num_pressed, base_area_size, base_cx, base_cy, base_time);
+#endif//__DETAIL_DEBUG__
+ break;
+
+ case ET_Motion:
+ if( !(g_pGesture->fingers[idx].flags & PressFlagTapNHold ) )
+ break;
+
+ if( num_pressed < 2 )
+ return;
+
+ if( num_pressed != g_pGesture->num_pressed )
+ {
+ if( state != GestureEnd )
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupTapNHold][M][cleanup] num_finger changed ! num_pressed=%d, g_pGesture->num_pressed=%d\n", num_pressed, g_pGesture->num_pressed);
+#endif//__DETAIL_DEBUG__
+ goto cleanup_tapnhold;
+ }
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupTapNHold][M][cleanup] num_pressed=%d, g_pGesture->num_pressed=%d\n", num_pressed, g_pGesture->num_pressed);
+#endif//__DETAIL_DEBUG__
+ //goto cleanup_tapnhold;
+ }
+
+ mbits |= (1 << idx);
+ if( mbits == (pow(2, num_pressed)-1) )
+ {
+ area_size = AREA_SIZE(&g_pGesture->area.extents);
+ cx = AREA_CENTER_X(&g_pGesture->area.extents);
+ cy = AREA_CENTER_Y(&g_pGesture->area.extents);
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupTapNHold][M][num_pressed=%d] area_size=%d, base_area_size=%d, diff=%d\n", num_pressed, area_size, base_area_size, ABS(base_area_size - area_size));
+ ErrorF("[GroupTapNHold][M] cx=%d, base_cx=%d, diff=%d\n", cx, base_cx, ABS(cx-base_cx));
+ ErrorF("[GroupTapNHold][M] cy=%d, base_cy=%d, diff=%d\n", cy, base_cy, ABS(cy-base_cy));
+#endif//__DETAIL_DEBUG__
+
+ if( ABS(base_area_size-area_size) >= TAPNHOLD_AREA_THRESHOLD )
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupTapNHold][M] diff between area size(=%d) and base area size(=%d) is bigger than threshold(=%d)!\n", area_size, base_area_size, ABS(base_area_size-area_size));
+#endif//__DETAIL_DEBUG__
+ goto cleanup_tapnhold;
+ }
+
+ if( !INBOX(&base_box_ext, cx, cy) )
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupTapNHold][M] current center coordinates is not in base coordinates box !\n");
+#endif//__DETAIL_DEBUG__
+ goto cleanup_tapnhold;
+ }
+ }
+ break;
+
+ case ET_ButtonRelease:
+ if( state != GestureEnd && num_pressed >= 2)
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupTapNHold][R][cleanup] num_finger changed ! num_pressed=%d, g_pGesture->num_pressed=%d\n", num_pressed, g_pGesture->num_pressed);
+#endif//__DETAIL_DEBUG__
+ goto cleanup_tapnhold;
+ }
+
+ if( g_pGesture->num_pressed )
+ break;
+
+ if( !tap_repeat )
+ {
+ prev_num_pressed = num_pressed;
+ }
+
+ tap_repeat++;
+
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupTapNHold][R] tap_repeat=%d, num_pressed=%d, prev_num_pressed=%d\n", tap_repeat, num_pressed, prev_num_pressed);
+#endif//__DETAIL_DEBUG__
+
+ if( num_pressed != prev_num_pressed || !GestureHasFingerEventMask(GestureNotifyTapNHold, num_pressed) )
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupTapNHold][R] num_pressed(=%d) != prev_num_pressed(=%d) OR %d finger tap event was not grabbed/selected !\n",
+ num_pressed, prev_num_pressed, num_pressed);
+#endif//__DETAIL_DEBUG__
+ goto cleanup_tapnhold;
+ }
+
+ if( tap_repeat > 1 )
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupTapNHold][R] Tap events(tap_repeat=%d) were put twice or more !(ignored)\n", tap_repeat);
+#endif//__DETAIL_DEBUG__
+ goto cleanup_tapnhold;
+ }
+
+ prev_num_pressed = num_pressed;
+ num_pressed = 0;
+ state = GestureDone;
+
+ TimerCancel(tapnhold_event_timer);
+ tapnhold_event_timer = TimerSet(tapnhold_event_timer, 0, TAPNHOLD_INTV_TIME_THRESHOLD, GestureEventTimerHandler, (int *)&event_type);
+
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupTapNHold][R][Last] state=%d, tap_repeat=%d, num_pressed=%d, prev_num_pressed=%d\n", state, tap_repeat, num_pressed, prev_num_pressed);
+#endif//__DETAIL_DEBUG__
+ break;
+ }
+
+ return;
+
+cleanup_tapnhold:
+
+ if( state == GestureUpdate )
+ {
+ state = GestureEnd;
+ if( GestureHasFingerEventMask(GestureNotifyTapNHold, prev_num_pressed) )
+ {
+ GestureHandleGesture_TapNHold(prev_num_pressed, base_cx, base_cy, interval, holdtime, state);
+ }
+ }
+ else
+ {
+ g_pGesture->recognized_gesture &= ~TapNHoldFilterMask;
+ }
+
+ g_pGesture->filter_mask |= TapNHoldFilterMask;
+ if( g_pGesture->filter_mask == GESTURE_FILTER_MASK_ALL )
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupTapNHold][cleanup] GestureFlushOrDrop() !\n");
+#endif//__DETAIL_DEBUG__
+
+ if( ERROR_INVALPTR == GestureFlushOrDrop() )
+ {
+ GestureControl(g_pGesture->this_device, DEVICE_OFF);
+ }
+ }
+
+ TimerCancel(tapnhold_event_timer);
+ num_pressed = 0;
+ tap_repeat = 0;
+ prev_num_pressed = 0;
+ mbits = 0;
+ base_time = 0;
+ state = 0;
+
+ return;
+}
+
+void GestureRecognize_GroupHold(int type, InternalEvent *ev, DeviceIntPtr device, int idx, int timer_expired)
+{
+ static int num_pressed = 0;
+ static int base_area_size = 0;
+ static Time base_time = 0;
+ static int base_cx;
+ static int base_cy;
+ int cx, cy;
+ static pixman_box16_t base_box_ext;
+ int area_size;
+ static int state = GestureEnd;
+
+ static OsTimerPtr hold_event_timer = NULL;
+ static int event_type = GestureNotifyHold;
+
+ if( timer_expired )
+ {
+ if( state <= GestureBegin )
+ state++;
+
+#ifdef __DETAIL_DEBUG__
+ switch( state )
+ {
+ case GestureBegin:
+ ErrorF("[GroupHold] HOLD Begin !\n");
+ break;
+
+ case GestureUpdate:
+ ErrorF("[GroupHold] HOLD Update !\n");
+ break;
+ }
+#endif//__DETAIL_DEBUG__
+
+ if( GestureHasFingerEventMask(GestureNotifyHold, num_pressed) )
+ {
+ GestureHandleGesture_Hold(num_pressed, base_cx, base_cy, GetTimeInMillis()-base_time, state);
+ hold_event_timer = TimerSet(hold_event_timer, 0, HOLD_TIME_THRESHOLD, GestureEventTimerHandler, (int *)&event_type);
+ }
+ return;
+ }
+
+ switch( type )
+ {
+ case ET_ButtonPress:
+ g_pGesture->fingers[idx].flags |= PressFlagHold;
+
+ if( g_pGesture->num_pressed < 2 )
+ return;
+
+ if( !base_area_size || g_pGesture->num_pressed > num_pressed )
+ {
+ if( state != GestureEnd )
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupHold][P][cleanup] num_finger changed ! num_pressed=%d, g_pGesture->num_pressed=%d\n", num_pressed, g_pGesture->num_pressed);
+#endif//__DETAIL_DEBUG__
+ goto cleanup_hold;
+ }
+
+ base_area_size = AREA_SIZE(&g_pGesture->area.extents);
+ base_cx = AREA_CENTER_X(&g_pGesture->area.extents);
+ base_cy = AREA_CENTER_Y(&g_pGesture->area.extents);
+ base_time = GetTimeInMillis();
+ base_box_ext.x1 = base_cx-HOLD_MOVE_THRESHOLD;
+ base_box_ext.y1 = base_cy-HOLD_MOVE_THRESHOLD;
+ base_box_ext.x2 = base_cx+HOLD_MOVE_THRESHOLD;
+ base_box_ext.y2 = base_cy+HOLD_MOVE_THRESHOLD;
+ event_type = GestureNotifyHold;
+ hold_event_timer = TimerSet(hold_event_timer, 0, HOLD_TIME_THRESHOLD, GestureEventTimerHandler, (int *)&event_type);
+ }
+ num_pressed = g_pGesture->num_pressed;
+
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupHold][P]][num_pressed=%d] AREA_SIZE(area.extents)=%d, base_cx=%d, base_cy=%d\n", num_pressed, base_area_size, base_cx, base_cy);
+#endif//__DETAIL_DEBUG__
+ break;
+
+ case ET_Motion:
+ if( !(g_pGesture->fingers[idx].flags & PressFlagHold ) )
+ break;
+
+ if( num_pressed < 2 )
+ return;
+
+ if( num_pressed != g_pGesture->num_pressed )
+ {
+ if( state != GestureEnd )
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupHold][M][cleanup] num_finger changed ! num_pressed=%d, g_pGesture->num_pressed=%d\n", num_pressed, g_pGesture->num_pressed);
+#endif//__DETAIL_DEBUG__
+ goto cleanup_hold;
+ }
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupHold][M][cleanup] num_pressed=%d, g_pGesture->num_pressed=%d\n", num_pressed, g_pGesture->num_pressed);
+#endif//__DETAIL_DEBUG__
+ //goto cleanup_hold;
+ }
+
+ area_size = AREA_SIZE(&g_pGesture->area.extents);
+ cx = AREA_CENTER_X(&g_pGesture->area.extents);
+ cy = AREA_CENTER_Y(&g_pGesture->area.extents);
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupHold][M][num_pressed=%d] area_size=%d, base_area_size=%d, diff=%d\n", num_pressed, area_size, base_area_size, ABS(base_area_size - area_size));
+ ErrorF("[GroupHold][M] cx=%d, base_cx=%d, diff=%d\n", cx, base_cx, ABS(cx-base_cx));
+ ErrorF("[GroupHold][M] cy=%d, base_cy=%d, diff=%d\n", cy, base_cy, ABS(cy-base_cy));
+#endif//__DETAIL_DEBUG__
+
+ if( ABS(base_area_size-area_size) >= HOLD_AREA_THRESHOLD )
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupHold][M] diff between area size(=%d) and base area size(=%d) is bigger than threshold(=%d)!\n", area_size, base_area_size, ABS(base_area_size-area_size));
+#endif//__DETAIL_DEBUG__
+ goto cleanup_hold;
+ }
+
+ if( !INBOX(&base_box_ext, cx, cy) )
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupHold][M] current center coordinates is not in base coordinates box !\n");
+#endif//__DETAIL_DEBUG__
+ goto cleanup_hold;
+ }
+ break;
+
+ case ET_ButtonRelease:
+ if( state != GestureEnd && num_pressed >= 2)
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GroupHold][R][cleanup] num_finger changed ! num_pressed=%d, g_pGesture->num_pressed=%d\n", num_pressed, g_pGesture->num_pressed);
+#endif//__DETAIL_DEBUG__
+ goto cleanup_hold;
+ }
+
+ //ErrorF("[GroupHold][R] num_pressed=%d, g_pGesture->num_pressed=%d\n", num_pressed, g_pGesture->num_pressed);
+ if( g_pGesture->num_pressed )
+ break;
+
+ goto cleanup_hold;
+ break;
+ }
+
+ return;
+
+cleanup_hold:
+
+ if( state == GestureBegin || state == GestureUpdate )
+ {
+ state = GestureEnd;
+ if( GestureHasFingerEventMask(GestureNotifyHold, num_pressed) )
+ {
+ GestureHandleGesture_Hold(num_pressed, base_cx, base_cy, GetTimeInMillis()-base_time, state);
+ }
+ }
+ else
+ {
+ g_pGesture->recognized_gesture &= ~HoldFilterMask;
+ }
+
+ g_pGesture->filter_mask |= HoldFilterMask;
+ num_pressed = 0;
+ base_area_size = 0;
+ base_time = 0;
+ base_cx = base_cy = 0;
+ state = GestureEnd;
+ base_box_ext.x1 = base_box_ext.x2 = base_box_ext.y1 = base_box_ext.y2 = 0;
+ TimerCancel(hold_event_timer);
+ return;
+}
+
+WindowPtr
+GestureGetEventsWindow(void)
+{
+ Mask mask;
+ WindowPtr pWin;
+
+ //check grabbed event(s)
+ if( !GestureHasGrabbedEvents(&g_pGesture->grabMask, &g_pGesture->GrabEvents) )
+ g_pGesture->grabMask = 0;
+
+ pWin = GestureWindowOnXY(g_pGesture->fingers[0].px, g_pGesture->fingers[0].py);
+
+ if( pWin )
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[X11][GestureGetEventsWindow] pWin->drawable.id=0x%x\n", pWin->drawable.id);
+#endif//__DETAIL_DEBUG__
+ g_pGesture->gestureWin = pWin->drawable.id;
+ }
+ else
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[X11][GestureGetEventsWindow] GestureWindowOnXY returns NULL !\n");
+#endif//__DETAIL_DEBUG__
+ return NULL;
+ }
+
+ //check selected event(s)
+ if( !GestureHasSelectedEvents(pWin, &g_pGesture->eventMask) )
+ g_pGesture->eventMask = 0;
+
+ if( !g_pGesture->grabMask && !g_pGesture->eventMask )
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[X11][GestureGetEventsWindow] No events were grabbed/selected for window(0x%x) !\n", pWin->drawable.id);
+#endif//__DETAIL_DEBUG__
+ return NULL;
+ }
+
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[X11][GestureGetEventsWindow] g_pGesture->grabMask=0x%x, g_pGesture->eventMask=0x%x\n",
+ g_pGesture->grabMask, g_pGesture->eventMask);
+#endif//__DETAIL_DEBUG__
+
+ mask = (GESTURE_FILTER_MASK_ALL & ~(g_pGesture->grabMask | g_pGesture->eventMask));
+
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[X11][GestureGetEventsWindow] g_pGesture->filter_mask=0x%x, mask=0x%x\n", g_pGesture->filter_mask, mask);
+#endif//__DETAIL_DEBUG__
+
+ g_pGesture->filter_mask = mask;
+
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[X11][GestureGetEventsWindow] g_pGesture->filter_mask=0x%x\n", g_pGesture->filter_mask);
+#endif//__DETAIL_DEBUG__
+
+ return pWin;
+}
+
+static CARD32
+GestureEventTimerHandler(OsTimerPtr timer, CARD32 time, pointer arg)
+{
+ int event_type = *(int *)arg;
+
+ switch( event_type )
+ {
+ case GestureNotifyHold:
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GestureEventTimerHandler] GestureNotifyHold (event_type = %d)\n", event_type);
+#endif//__DETAIL_DEBUG__
+ GestureRecognize_GroupHold(event_type, NULL, NULL, 0, 1);
+ break;
+
+ case GestureNotifyPan:
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GestureEventTimerHandler] GestureNotifyPan (event_type = %d)\n", event_type);
+#endif//__DETAIL_DEBUG__
+ GestureRecognize_GroupPan(event_type, NULL, NULL, 0, 1);
+ break;
+
+ case GestureNotifyTap:
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GestureEventTimerHandler] GestureNotifyTap (event_type = %d)\n", event_type);
+#endif//__DETAIL_DEBUG__
+ GestureRecognize_GroupTap(event_type, NULL, NULL, 0, 1);
+ break;
+
+ case GestureNotifyTapNHold:
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GestureEventTimerHandler] GestureNotifyTapNHold (event_type = %d)\n", event_type);
+#endif//__DETAIL_DEBUG__
+ GestureRecognize_GroupTapNHold(event_type, NULL, NULL, 0, 1);
+ break;
+
+ default:
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GestureEventTimerHandler] unknown event_type (=%d)\n", event_type);
+#endif//__DETAIL_DEBUG__
+ if(timer)
+ ErrorF("[GestureEventTimerHandler] timer=%x\n", (unsigned int)timer);
+ }
+
+ return 0;
+}
+
+static CARD32
+GestureSingleFingerTimerHandler(OsTimerPtr timer, CARD32 time, pointer arg)
+{
+ g_pGesture->filter_mask = GESTURE_FILTER_MASK_ALL;
+ g_pGesture->recognized_gesture = 0;
+
+ if( ERROR_INVALPTR == GestureFlushOrDrop() )
+ {
+ GestureControl(g_pGesture->this_device, DEVICE_OFF);
+ }
+
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[X11][Single] expired !\n");
+#endif//__DETAIL_DEBUG__
+
+ return 0;
+}
+
+void
+GestureRecognize(int type, InternalEvent *ev, DeviceIntPtr device)
+{
+ int i;
+ int idx = device->id - g_pGesture->first_fingerid;
+ static OsTimerPtr single_finger_timer = NULL;
+
+ if( PROPAGATE_EVENTS == g_pGesture->ehtype )
+ return;
+
+ if( device->id < g_pGesture->first_fingerid )//filtering device id : 2
+ return;
+
+ switch( type )
+ {
+ case ET_ButtonPress:
+ if( idx == 0 )
+ g_pGesture->event_sum[0] = BTN_PRESSED;
+ g_pGesture->fingers[idx].ptime = ev->any.time;
+ g_pGesture->fingers[idx].px = ev->device_event.root_x;
+ g_pGesture->fingers[idx].py = ev->device_event.root_y;
+
+ g_pGesture->num_pressed++;
+ if( g_pGesture->num_pressed == 1 )
+ {
+ single_finger_timer = TimerSet(single_finger_timer, 0, 50, GestureSingleFingerTimerHandler, NULL);
+ }
+ else
+ {
+ TimerCancel(single_finger_timer);
+ }
+
+ if( g_pGesture->num_pressed > g_pGesture->num_mt_devices )
+ g_pGesture->num_pressed = g_pGesture->num_mt_devices;
+
+ if( !g_pGesture->pTempWin || g_pGesture->num_pressed != g_pGesture->inc_num_pressed )
+ {
+ g_pGesture->pTempWin = GestureGetEventsWindow();
+
+ if( NULL == g_pGesture->pTempWin )
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[X11][GestureRecognize][g_pGesture->num_pressed=%d] No grabbed events and no event masks !\n", g_pGesture->num_pressed);
+#endif//__DETAIL_DEBUG__
+ g_pGesture->filter_mask = GESTURE_FILTER_MASK_ALL;
+ goto flush_or_drop;
+ }
+ }
+
+ g_pGesture->inc_num_pressed = g_pGesture->num_pressed;
+
+ g_pGesture->finger_rects[idx].extents.x1 = ev->device_event.root_x - FINGER_WIDTH;
+ g_pGesture->finger_rects[idx].extents.x2 = ev->device_event.root_x + FINGER_WIDTH;
+ g_pGesture->finger_rects[idx].extents.y1 = ev->device_event.root_y - FINGER_HEIGHT;
+ g_pGesture->finger_rects[idx].extents.y2 = ev->device_event.root_y + FINGER_HEIGHT;
+
+ if( g_pGesture->inc_num_pressed == 1 )
+ {
+ pixman_region_union(&g_pGesture->area, &g_pGesture->finger_rects[0], &g_pGesture->finger_rects[0]);
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[P][g_pGesture->inc_num_pressed=1] AREA_SIZE(area.extents)=%d\n", AREA_SIZE(&g_pGesture->area.extents));
+#endif//__DETAIL_DEBUG__
+ }
+ else
+ {
+ pixman_region_union(&g_pGesture->area, &g_pGesture->finger_rects[0], &g_pGesture->finger_rects[0]);
+ for( i = 1 ; i < g_pGesture->inc_num_pressed ; i++ )
+ {
+ pixman_region_union(&g_pGesture->area, &g_pGesture->area, &g_pGesture->finger_rects[i]);
+ }
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[P][g_pGesture->inc_num_pressed=%d] AREA_SIZE(area.extents)=%d\n", g_pGesture->inc_num_pressed, AREA_SIZE(&g_pGesture->area.extents));
+#endif//__DETAIL_DEBUG__
+ }
+ break;
+
+ case ET_Motion:
+ if( !g_pGesture->fingers[idx].ptime )
+ return;
+
+ g_pGesture->fingers[idx].mx = ev->device_event.root_x;
+ g_pGesture->fingers[idx].my = ev->device_event.root_y;
+
+ if( idx == 0 && g_pGesture->event_sum[0] )
+ {
+ g_pGesture->event_sum[0] += BTN_MOVING;
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[X11][GestureRecognize] moving !\n");
+#endif//__DETAIL_DEBUG__
+ if( g_pGesture->event_sum[0] >= 7 )
+ {
+ if( (g_pGesture->event_sum[0] >= 7) && (g_pGesture->inc_num_pressed < 2) )
+ {
+ #ifdef __DETAIL_DEBUG__
+ ErrorF("[X11][GestureRecognize] moving limit!\n");
+ #endif//__DETAIL_DEBUG__
+ g_pGesture->filter_mask = GESTURE_FILTER_MASK_ALL;
+ goto flush_or_drop;
+ }
+ }
+ }
+
+ g_pGesture->finger_rects[idx].extents.x1 = ev->device_event.root_x - FINGER_WIDTH;
+ g_pGesture->finger_rects[idx].extents.x2 = ev->device_event.root_x + FINGER_WIDTH;
+ g_pGesture->finger_rects[idx].extents.y1 = ev->device_event.root_y - FINGER_HEIGHT;
+ g_pGesture->finger_rects[idx].extents.y2 = ev->device_event.root_y + FINGER_HEIGHT;
+
+ if( g_pGesture->inc_num_pressed == 1 )
+ {
+ pixman_region_union(&g_pGesture->area, &g_pGesture->finger_rects[0], &g_pGesture->finger_rects[0]);
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[M][g_pGesture->inc_num_pressed=1] AREA_SIZE(area)=%d\n", AREA_SIZE(&g_pGesture->area.extents));
+#endif//__DETAIL_DEBUG__
+ }
+ else
+ {
+ pixman_region_union(&g_pGesture->area, &g_pGesture->finger_rects[0], &g_pGesture->finger_rects[0]);
+ for( i = 1 ; i < g_pGesture->inc_num_pressed ; i++ )
+ {
+ pixman_region_union(&g_pGesture->area, &g_pGesture->area, &g_pGesture->finger_rects[i]);
+ }
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[M][g_pGesture->inc_num_pressed=%d] AREA_SIZE(area)=%d\n", g_pGesture->inc_num_pressed, AREA_SIZE(&g_pGesture->area.extents));
+#endif//__DETAIL_DEBUG__
+ }
+ break;
+
+ case ET_ButtonRelease:
+ g_pGesture->fingers[idx].rtime = ev->any.time;
+ g_pGesture->fingers[idx].rx = ev->device_event.root_x;
+ g_pGesture->fingers[idx].ry = ev->device_event.root_y;
+
+ g_pGesture->num_pressed--;
+ if( g_pGesture->num_pressed <= 0 )
+ {
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[X11][GestureRecognize] All fingers were released !\n");
+#endif//__DETAIL_DEBUG__
+ if( g_pGesture->inc_num_pressed == 1 )
+ goto flush_or_drop;
+ }
+ break;
+ }
+
+ if( g_pGesture->filter_mask != GESTURE_FILTER_MASK_ALL )
+ {
+ if( !(g_pGesture->filter_mask & FlickFilterMask) )
+ {
+ GestureRecognize_GroupFlick(type, ev, device, idx);
+ }
+ if( !(g_pGesture->filter_mask & PanFilterMask) )
+ {
+ GestureRecognize_GroupPan(type, ev, device, idx, 0);
+ }
+ if( !(g_pGesture->filter_mask & PinchRotationFilterMask) )
+ {
+ GestureRecognize_GroupPinchRotation(type, ev, device, idx);
+ }
+ if( !(g_pGesture->filter_mask & TapFilterMask) )
+ {
+ GestureRecognize_GroupTap(type, ev, device, idx, 0);
+ }
+ if( !(g_pGesture->filter_mask & TapNHoldFilterMask) )
+ {
+ GestureRecognize_GroupTapNHold(type, ev, device, idx, 0);
+ }
+ if( !(g_pGesture->filter_mask & HoldFilterMask) )
+ {
+ GestureRecognize_GroupHold(type, ev, device, idx, 0);
+ }
+ }
+
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[X11][GestureRecognize][N] g_pGesture->filter_mask = 0x%x\n", g_pGesture->filter_mask);
+ ErrorF("[X11][GestureRecognize][N] g_pGesture->GESTURE_FILTER_MASK_ALL = 0x%x\n", GESTURE_FILTER_MASK_ALL);
+ ErrorF("[X11][GestureRecognize][N] g_pGesture->recognized_gesture=0x%x\n", g_pGesture->recognized_gesture);
+#endif//__DETAIL_DEBUG__
+
+ if( g_pGesture->filter_mask == GESTURE_FILTER_MASK_ALL )
+ {
+ if( !g_pGesture->recognized_gesture )
+ goto flush_or_drop;
+ else if( !g_pGesture->num_pressed )
+ goto flush_or_drop;
+ }
+
+ if( g_pGesture->recognized_gesture )
+ {
+ if( g_pGesture->ehtype == KEEP_EVENTS )
+ GestureEventsDrop();
+ g_pGesture->ehtype = IGNORE_EVENTS;
+ }
+
+ return;
+
+flush_or_drop:
+
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[GestureRecognize] GestureFlushOrDrop() !\n");
+#endif//__DETAIL_DEBUG__
+ if( ERROR_INVALPTR == GestureFlushOrDrop() )
+ {
+ GestureControl(g_pGesture->this_device, DEVICE_OFF);
+ }
+}
+
+
+ErrorStatus GestureFlushOrDrop(void)
+{
+ ErrorStatus err;
+
+ if( g_pGesture->recognized_gesture )
+ {
+ GestureEventsDrop();
+ }
+ else
+ {
+ g_pGesture->ehtype = PROPAGATE_EVENTS;
+
+ err = GestureEventsFlush();
+ if( ERROR_NONE != err )
+ return err;
+
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[X11][GestureFlushOrDrop][F] g_pGesture->filter_mask = 0x%x\n", g_pGesture->filter_mask);
+ ErrorF("[X11][GestureFlushOrDrop][F] g_pGesture->GESTURE_FILTER_MASK_ALL = 0x%x\n", GESTURE_FILTER_MASK_ALL);
+ ErrorF("[X11][GestureFlushOrDrop][F] g_pGesture->recognized_gesture=0x%x\n", g_pGesture->recognized_gesture);
+#endif//__DETAIL_DEBUG__
+ }
+
+ err = GestureRegionsReinit();
+ if( ERROR_NONE != err )
+ return err;
+
+ g_pGesture->pTempWin = NULL;
+ g_pGesture->inc_num_pressed = g_pGesture->num_pressed = 0;
+ g_pGesture->event_sum[0] = 0;
+
+ return ERROR_NONE;
+}
+
+void
+GestureHandleMTSyncEvent(int screen_num, InternalEvent *ev, DeviceIntPtr device)
+{
+ int i;
+
+#ifdef __DEBUG_EVENT_HANDLER__
+ ErrorF("\n[X11][GestureHandleMTSyncEvent] (%d:%d) time:%d cur:%d\n",
+ ev->any_event.deviceid, ev->any_event.sync, (int)ev->any.time, (int)GetTimeInMillis());
+#endif//__DEBUG_EVENT_HANDLER__
+
+ if( MTOUCH_FRAME_SYNC_BEGIN == ev->any_event.sync )
+ {
+ g_pGesture->ehtype = KEEP_EVENTS;
+ g_pGesture->filter_mask = 0;
+ g_pGesture->recognized_gesture = 0;
+ g_pGesture->num_pressed = 0;
+
+ for( i=0 ; i < g_pGesture->num_mt_devices ; i++ )
+ g_pGesture->fingers[i].ptime = 0;
+ }
+ else if( MTOUCH_FRAME_SYNC_END == ev->any_event.sync )
+ {
+ g_pGesture->ehtype = PROPAGATE_EVENTS;
+ }
+}
+
+void
+GestureHandleButtonPressEvent(int screen_num, InternalEvent *ev, DeviceIntPtr device)
+{
+#ifdef __DEBUG_EVENT_HANDLER__
+ ErrorF("[X11][GestureHandleButtonPEvent] devid=%d time:%d cur:%d\n", device->id, ev->any.time, GetTimeInMillis());
+#endif//__DEBUG_EVENT_HANDLER__
+
+ switch( g_pGesture->ehtype )
+ {
+ case KEEP_EVENTS:
+ if( ERROR_INVALPTR == GestureEnqueueEvent(screen_num, ev, device) )
+ {
+ GestureControl(g_pGesture->this_device, DEVICE_OFF);
+ return;
+ }
+
+ if( g_pGesture->num_mt_devices )
+ GestureRecognize(ET_ButtonPress, ev, device);
+ else
+ device->public.processInputProc(ev, device);
+ break;
+
+ case PROPAGATE_EVENTS:
+ device->public.processInputProc(ev, device);
+ break;
+
+ case IGNORE_EVENTS:
+ GestureRecognize(ET_ButtonPress, ev, device);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void
+GestureHandleMotionEvent(int screen_num, InternalEvent *ev, DeviceIntPtr device)
+{
+#ifdef __DEBUG_EVENT_HANDLER__
+ ErrorF("[X11][GestureHandleMotionEvent] devid=%d time:%d cur:%d\n", device->id, ev->any.time, GetTimeInMillis());
+#endif//__DEBUG_EVENT_HANDLER__
+
+ switch( g_pGesture->ehtype )
+ {
+ case KEEP_EVENTS:
+ if( ERROR_INVALPTR == GestureEnqueueEvent(screen_num, ev, device) )
+ {
+ GestureControl(g_pGesture->this_device, DEVICE_OFF);
+ return;
+ }
+
+ if( g_pGesture->num_mt_devices )
+ GestureRecognize(ET_Motion, ev, device);
+ else
+ device->public.processInputProc(ev, device);
+ break;
+
+ case PROPAGATE_EVENTS:
+ device->public.processInputProc(ev, device);
+ break;
+
+ case IGNORE_EVENTS:
+ GestureRecognize(ET_Motion, ev, device);
+ break;
+
+ default:
+ break;
+ }
+
+}
+
+void
+GestureHandleButtonReleaseEvent(int screen_num, InternalEvent *ev, DeviceIntPtr device)
+{
+#ifdef __DEBUG_EVENT_HANDLER__
+ ErrorF("[X11][GestureHandleButtonREvent] devid=%d time:%d cur:%d\n", device->id, ev->any.time, GetTimeInMillis());
+#endif//__DEBUG_EVENT_HANDLER__
+
+ switch( g_pGesture->ehtype )
+ {
+ case KEEP_EVENTS:
+ if( ERROR_INVALPTR == GestureEnqueueEvent(screen_num, ev, device) )
+ {
+ GestureControl(g_pGesture->this_device, DEVICE_OFF);
+ return;
+ }
+
+ if( g_pGesture->num_mt_devices )
+ GestureRecognize(ET_ButtonRelease, ev, device);
+ else
+ device->public.processInputProc(ev, device);
+ break;
+
+ case PROPAGATE_EVENTS:
+ device->public.processInputProc(ev, device);
+ break;
+
+ case IGNORE_EVENTS:
+ GestureRecognize(ET_ButtonRelease, ev, device);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static ErrorStatus
+GestureEnableEventHandler(InputInfoPtr pInfo)
+ {
+ Bool res;
+ GestureDevicePtr pGesture = pInfo->private;
+
+ res = GestureInstallResourceStateHooks();
+
+ if( !res )
+ {
+ ErrorF("[X11][GestureEnableEventHandler] Failed on GestureInstallResourceStateHooks() !\n");
+ return ERROR_ABNORMAL;
+ }
+
+ res = GestureSetMaxNumberOfFingers((int)MAX_MT_DEVICES);
+
+ if( !res )
+ {
+ ErrorF("[X11][GestureEnableEventHandler] Failed on GestureSetMaxNumberOfFingers(%d) !\n", (int)MAX_MT_DEVICES);
+ goto failed;
+ }
+
+ pGesture->device_setting_timer = TimerSet(pGesture->device_setting_timer, 0, 500, GestureTimerHandler, pInfo);
+
+ if( !pGesture->device_setting_timer )
+ {
+ ErrorF("[X11][GestureEnableEventHandler] Failed to allocate memory for timer !\n");
+ goto failed;
+ }
+
+ if( ERROR_NONE != GestureRegionsInit() || ERROR_NONE != GestureInitEQ() )
+ {
+ goto failed;
+ }
+
+ mieqSetHandler(ET_ButtonPress, GestureHandleButtonPressEvent);
+ mieqSetHandler(ET_ButtonRelease, GestureHandleButtonReleaseEvent);
+ mieqSetHandler(ET_Motion, GestureHandleMotionEvent);
+ if( pGesture->is_active )
+ mieqSetHandler(ET_MTSync, GestureHandleMTSyncEvent);
+
+ return ERROR_NONE;
+
+failed:
+ GestureUninstallResourceStateHooks();
+ GestureUnsetMaxNumberOfFingers();
+
+ return ERROR_ABNORMAL;
+}
+
+static ErrorStatus
+GestureDisableEventHandler(void)
+{
+ ErrorStatus err = ERROR_NONE;
+
+ mieqSetHandler(ET_ButtonPress, NULL);
+ mieqSetHandler(ET_ButtonRelease, NULL);
+ mieqSetHandler(ET_Motion, NULL);
+ mieqSetHandler(ET_MTSync, NULL);
+
+ err = GestureFiniEQ();
+
+ if( ERROR_INVALPTR == err )
+ {
+ ErrorF("[X11][GestureDisableEventHandler] EQ is invalid or was freed already !\n");
+ }
+
+ GestureUninstallResourceStateHooks();
+ GestureUnsetMaxNumberOfFingers();
+
+ return err;
+}
+
+static CARD32
+GestureTimerHandler(OsTimerPtr timer, CARD32 time, pointer arg)
+{
+ InputInfoPtr pInfo = (InputInfoPtr)arg;
+ GestureDevicePtr pGesture = pInfo->private;
+
+ int idx = 0;
+ DeviceIntPtr dev;
+ for( dev = inputInfo.pointer ; dev; dev = dev->next )
+ {
+ if(IsMaster(dev) && IsPointerDevice(dev))
+ {
+ pGesture->master_pointer = dev;
+ ErrorF("[X11][GestureTimerHandler][id:%d] Master Pointer=%s\n", dev->id, pGesture->master_pointer->name);
+ continue;
+ }
+
+ if(IsXTestDevice(dev, NULL) && IsPointerDevice(dev))
+ {
+ pGesture->xtest_pointer = dev;
+ ErrorF("[X11][GestureTimerHandler][id:%d] XTest Pointer=%s\n", dev->id, pGesture->xtest_pointer->name);
+ continue;
+ }
+
+ if(IsPointerDevice(dev))
+ {
+ if( idx >= MAX_MT_DEVICES )
+ {
+ ErrorF("[X11][GestureTimerHandler] Number of mt device is over MAX_MT_DEVICES(%d) !\n",
+ MAX_MT_DEVICES);
+ continue;
+ }
+ pGesture->mt_devices[idx] = dev;
+ ErrorF("[X11][GestureTimerHandler][id:%d] MT device[%d] name=%s\n", dev->id, idx, pGesture->mt_devices[idx]->name);
+ idx++;
+ }
+ }
+
+ if( !pGesture->master_pointer || !pGesture->xtest_pointer )
+ {
+ ErrorF("[X11][GestureTimerHandler] Failed to get info of master pointer or XTest pointer !\n");
+ pGesture->device_setting_timer = TimerSet(pGesture->device_setting_timer, 0, 0, NULL, NULL);
+ pGesture->num_mt_devices = 0;
+
+ return 0;
+ }
+
+ pGesture->device_setting_timer = TimerSet(pGesture->device_setting_timer, 0, 0, NULL, NULL);
+ pGesture->first_fingerid = pGesture->mt_devices[0]->id;
+ pGesture->num_mt_devices = idx;
+
+ if( !pGesture->num_mt_devices )
+ {
+ ErrorF("[X11][GestureTimerHandler] Failed to mt device information !\n");
+ pGesture->device_setting_timer = TimerSet(pGesture->device_setting_timer, 0, 0, NULL, NULL);
+ pGesture->num_mt_devices = 0;
+
+ return 0;
+ }
+
+ memset(pGesture->fingers, 0, sizeof(TouchStatus)*pGesture->num_mt_devices);
+ pGesture->pRootWin = RootWindow(pGesture->master_pointer);
+ g_pGesture->grabMask = g_pGesture->eventMask = 0;
+ g_pGesture->pTempWin = NULL;
+ g_pGesture->inc_num_pressed = 0;
+
+ return 0;
+}
+
+BOOL
+IsXTestDevice(DeviceIntPtr dev, DeviceIntPtr master)
+{
+ if (IsMaster(dev))
+ return FALSE;
+
+ if (master)
+ return (dev->xtest_master_id == master->id);
+
+ return (dev->xtest_master_id != 0);
+}
+
+void
+GestureSetDisable(InputInfoPtr pInfo, int enable)
+{
+ if( !enable )
+ {
+ g_pGesture->ehtype = PROPAGATE_EVENTS;
+ mieqSetHandler(ET_MTSync, NULL);
+ g_pGesture->is_active = 0;
+ ErrorF("[X11][GestureSetDisable] Disabled !\n");
+ }
+ else
+ {
+ g_pGesture->ehtype = KEEP_EVENTS;
+ mieqSetHandler(ET_MTSync, GestureHandleMTSyncEvent);
+ g_pGesture->is_active = 1;
+ ErrorF("[X11][GestureSetDisable] Enabled !\n");
+ }
+}
+
+ErrorStatus
+GestureRegionsInit(void)
+{
+ int i;
+
+ if( !g_pGesture )
+ return ERROR_INVALPTR;
+
+ pixman_region_init(&g_pGesture->area);
+
+ for( i = 0 ; i < MAX_MT_DEVICES ; i++ )
+ {
+ pixman_region_init_rect (&g_pGesture->finger_rects[i], 0, 0, FINGER_WIDTH_2T, FINGER_HEIGHT_2T);
+ }
+
+ return ERROR_NONE;
+}
+
+ErrorStatus
+GestureRegionsReinit(void)
+{
+ if( !g_pGesture )
+ {
+ ErrorF("[X11][GestureRegionsReinit] Invalid pointer access !\n");
+ return ERROR_INVALPTR;
+ }
+
+ pixman_region_init(&g_pGesture->area);
+
+ return ERROR_NONE;
+}
+
+ErrorStatus
+GestureInitEQ(void)
+{
+ int i;
+ IEventPtr tmpEQ;
+
+ tmpEQ = (IEventRec *)calloc(GESTURE_EQ_SIZE, sizeof(IEventRec));
+
+ if( !tmpEQ )
+ {
+ ErrorF("[X11][GestureInitEQ] Failed to allocate memory for EQ !\n");
+ return ERROR_ALLOCFAIL;
+ }
+
+ for( i = 0 ; i < GESTURE_EQ_SIZE ; i++ )
+ {
+ tmpEQ[i].event = (InternalEvent *)malloc(sizeof(InternalEvent));
+ if( !tmpEQ[i].event )
+ {
+ ErrorF("[X11][GestureInitEQ] Failed to allocation memory for each event buffer in EQ !\n");
+ return ERROR_ALLOCFAIL;
+ }
+ }
+
+ g_pGesture->EQ = tmpEQ;
+ g_pGesture->headEQ = g_pGesture->tailEQ = 0;
+
+ return ERROR_NONE;
+}
+
+ErrorStatus
+GestureFiniEQ(void)
+{
+ int i;
+
+ if( !g_pGesture || !g_pGesture->EQ )
+ return ERROR_INVALPTR;
+
+ for( i = 0 ; i < GESTURE_EQ_SIZE ; i++ )
+ {
+ if( g_pGesture->EQ[i].event )
+ {
+ free(g_pGesture->EQ[i].event);
+ g_pGesture->EQ[i].event = NULL;
+ }
+ }
+
+ free(g_pGesture->EQ);
+ g_pGesture->EQ = NULL;
+
+ return ERROR_NONE;
+}
+
+ErrorStatus
+GestureEnqueueEvent(int screen_num, InternalEvent *ev, DeviceIntPtr device)
+{
+ int tail;
+
+ if( !g_pGesture || !g_pGesture->EQ )
+ {
+ ErrorF("[X11][GestureEnqueueEvent] Invalid pointer access !\n");
+ return ERROR_INVALPTR;
+ }
+
+ tail = g_pGesture->tailEQ;
+
+ if( tail >= GESTURE_EQ_SIZE )
+ {
+ ErrorF("[X11][GestureEnqueueEvent] Gesture EQ is full !\n");
+ return ERROR_EQFULL;
+ }
+
+#ifdef __DETAIL_DEBUG__
+ switch( ev->any.type )
+ {
+ case ET_ButtonPress:
+ ErrorF("[X11][GestureEnqueueEvent] ET_ButtonPress (id:%d)\n", device->id);
+ break;
+
+ case ET_ButtonRelease:
+ ErrorF("[X11][GestureEnqueueEvent] ET_ButtonRelease (id:%d)\n", device->id);
+ break;
+
+ case ET_Motion:
+ ErrorF("[X11][GestureEnqueueEvent] ET_Motion (id:%d)\n", device->id);
+ break;
+ }
+#endif//__DETAIL_DEBUG__
+
+ g_pGesture->EQ[tail].device = device;
+ g_pGesture->EQ[tail].screen_num = screen_num;
+ memcpy(g_pGesture->EQ[tail].event, ev, sizeof(InternalEvent));//need to be optimized
+ g_pGesture->tailEQ++;
+
+ return ERROR_NONE;
+}
+
+ErrorStatus
+GestureEventsFlush(void)
+{
+ int i;
+ DeviceIntPtr device;
+
+ if( !g_pGesture->EQ )
+ {
+ ErrorF("[X11][GestureEventsFlush] Invalid pointer access !\n");
+ return ERROR_INVALPTR;
+ }
+
+#ifdef __DETAIL_DEBUG__
+ ErrorF("[X11][GestureEventsFlush]\n");
+#endif//__DETAIL_DEBUG__
+
+ for( i = g_pGesture->headEQ ; i < g_pGesture->tailEQ ; i++)
+ {
+ device = g_pGesture->EQ[i].device;
+ device->public.processInputProc(g_pGesture->EQ[i].event, device);
+ }
+
+ for( i = 0 ; i < MAX_MT_DEVICES ; i++ )
+ g_pGesture->event_sum[i] = 0;
+
+ g_pGesture->headEQ = g_pGesture->tailEQ = 0;//Free EQ
+
+ return ERROR_NONE;
+}
+
+void
+GestureEventsDrop(void)
+{
+ g_pGesture->headEQ = g_pGesture->tailEQ = 0;//Free EQ
+}
+
+#ifdef HAVE_PROPERTIES
+static void
+GestureInitProperty(DeviceIntPtr dev)
+{
+ int rc;
+
+ prop_gesture_recognizer_onoff = MakeAtom(GESTURE_RECOGNIZER_ONOFF, strlen(GESTURE_RECOGNIZER_ONOFF), TRUE);
+ rc = XIChangeDeviceProperty(dev, prop_gesture_recognizer_onoff, XA_INTEGER, 32, PropModeReplace, 1, &g_pGesture->is_active, FALSE);
+
+ if (rc != Success)
+ return;
+
+ XISetDevicePropertyDeletable(dev, prop_gesture_recognizer_onoff, FALSE);
+}
+
+static int
+GestureSetProperty(DeviceIntPtr dev, Atom atom, XIPropertyValuePtr val,
+ BOOL checkonly)
+{
+ InputInfoPtr pInfo = dev->public.devicePrivate;
+
+ if( prop_gesture_recognizer_onoff == atom )
+ {
+ int data;
+ if( val->format != 32 || val->type != XA_INTEGER || val->size != 1 )
+ return BadMatch;
+
+ if( !checkonly )
+ {
+ data = *((int *)val->data);
+ GestureSetDisable(pInfo, data);
+ }
+ }
+
+ return Success;
+}
+#endif//HAVE_PROPERTIES
+
+static int
+GestureInit(DeviceIntPtr device)
+{
+ InputInfoPtr pInfo;
+ pInfo = device->public.devicePrivate;
+
+#ifdef HAVE_PROPERTIES
+ GestureInitProperty(device);
+ XIRegisterPropertyHandler(device, GestureSetProperty, NULL, NULL);
+#endif
+
+ return Success;
+}
+
+static void
+GestureFini(DeviceIntPtr device)
+{
+ XIRegisterPropertyHandler(device, NULL, NULL, NULL);
+}
+
+static pointer
+GesturePlug(pointer module, pointer options, int *errmaj, int *errmin)
+{
+ xf86AddInputDriver(&GESTURE, module, 0);
+ return module;
+}
+
+static void
+GestureUnplug(pointer p)
+{
+}
+
+static InputInfoPtr
+GesturePreInit(InputDriverPtr drv, IDevPtr dev, int flags)
+{
+ InputInfoPtr pInfo;
+ GestureDevicePtr pGesture;
+
+ if (!(pInfo = xf86AllocateInput(drv, 0)))
+ return NULL;
+
+ pGesture = calloc(1, sizeof(GestureDeviceRec));
+ if (!pGesture) {
+ pInfo->private = NULL;
+ xf86DeleteInput(pInfo, 0);
+ return NULL;
+ }
+
+ g_pGesture = pGesture;
+ pInfo->private = pGesture;
+ pInfo->name = xstrdup(dev->identifier);
+ pInfo->flags = 0;
+ pInfo->type_name = XI_MOUSE; /* see XI.h */
+ pInfo->conf_idev = dev;
+ pInfo->read_input = GestureReadInput; /* new data avl */
+ pInfo->switch_mode = NULL; /* toggle absolute/relative mode */
+ pInfo->device_control = GestureControl; /* enable/disable dev */
+ /* process driver specific options */
+ pGesture->device = xf86SetStrOption(dev->commonOptions, "Device", "/dev/null");
+ pGesture->is_active = xf86SetIntOption(dev->commonOptions, "Activate", 0);
+ pGesture->gestureWin = None;
+
+ xf86Msg(X_INFO, "%s: Using device %s.\n", pInfo->name, pGesture->device);
+
+ /* process generic options */
+ xf86CollectInputOptions(pInfo, NULL, NULL);
+ xf86ProcessCommonOptions(pInfo, pInfo->options);
+
+ pInfo->fd = -1;
+ pInfo->flags |= XI86_POINTER_CAPABLE;
+ pInfo->flags |= XI86_OPEN_ON_INIT;
+ pInfo->flags |= XI86_CONFIGURED;
+ return pInfo;
+}
+
+static void
+GestureUnInit(InputDriverPtr drv, InputInfoPtr pInfo, int flags)
+{
+ GestureDevicePtr pGesture = pInfo->private;
+
+ g_pGesture = pGesture = NULL;
+ pInfo->private = NULL;
+
+ xf86DeleteInput(pInfo, 0);
+}
+
+static int
+GestureControl(DeviceIntPtr device, int what)
+{
+ InputInfoPtr pInfo = device->public.devicePrivate;
+ GestureDevicePtr pGesture = pInfo->private;
+
+ switch(what)
+ {
+ case DEVICE_INIT:
+ GestureInit(device);
+ break;
+
+ /* Switch device on. Establish socket, start event delivery. */
+ case DEVICE_ON:
+ xf86Msg(X_INFO, "%s: On.\n", pInfo->name);
+
+ if (device->public.on)
+ break;
+
+ device->public.on = TRUE;
+ pGesture->this_device = device;
+ pGesture->num_mt_devices = 0;
+ if( ERROR_ABNORMAL == GestureEnableEventHandler(pInfo) )
+ goto device_off;
+ break;
+
+ case DEVICE_OFF:
+device_off:
+ GestureDisableEventHandler();
+ GestureFini(device);
+ pGesture->this_device = NULL;
+ xf86Msg(X_INFO, "%s: Off.\n", pInfo->name);
+
+ if (!device->public.on)
+ break;
+
+ pInfo->fd = -1;
+ device->public.on = FALSE;
+ break;
+
+ case DEVICE_CLOSE:
+ /* free what we have to free */
+ break;
+ }
+ return Success;
+}
+
+static void
+GestureReadInput(InputInfoPtr pInfo)
+{
+}
+