summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Xi/xiproperty.c11
-rw-r--r--config/hal.c9
-rw-r--r--config/udev.c10
-rw-r--r--configure.ac22
-rw-r--r--dix/main.c2
-rw-r--r--hw/xfree86/common/xf86Xinput.c101
-rw-r--r--hw/xfree86/doc/man/xorg.conf.man.pre33
-rw-r--r--hw/xfree86/parser/InputClass.c80
-rw-r--r--hw/xfree86/parser/scan.c26
-rw-r--r--hw/xfree86/parser/xf86Parser.h7
-rw-r--r--hw/xfree86/parser/xf86tokens.h1
-rw-r--r--include/input.h1
-rw-r--r--include/misc.h3
-rw-r--r--include/xserver-properties.h11
-rw-r--r--os/utils.c40
15 files changed, 305 insertions, 52 deletions
diff --git a/Xi/xiproperty.c b/Xi/xiproperty.c
index ea66c54c6..be0783107 100644
--- a/Xi/xiproperty.c
+++ b/Xi/xiproperty.c
@@ -93,6 +93,17 @@ static struct dev_properties
{0, AXIS_LABEL_PROP_ABS_TILT_Y},
{0, AXIS_LABEL_PROP_ABS_TOOL_WIDTH},
{0, AXIS_LABEL_PROP_ABS_VOLUME},
+ {0, AXIS_LABEL_PROP_ABS_MT_TOUCH_MAJOR},
+ {0, AXIS_LABEL_PROP_ABS_MT_TOUCH_MINOR},
+ {0, AXIS_LABEL_PROP_ABS_MT_WIDTH_MAJOR},
+ {0, AXIS_LABEL_PROP_ABS_MT_WIDTH_MINOR},
+ {0, AXIS_LABEL_PROP_ABS_MT_ORIENTATION},
+ {0, AXIS_LABEL_PROP_ABS_MT_POSITION_X},
+ {0, AXIS_LABEL_PROP_ABS_MT_POSITION_Y},
+ {0, AXIS_LABEL_PROP_ABS_MT_TOOL_TYPE},
+ {0, AXIS_LABEL_PROP_ABS_MT_BLOB_ID},
+ {0, AXIS_LABEL_PROP_ABS_MT_TRACKING_ID},
+ {0, AXIS_LABEL_PROP_ABS_MT_PRESSURE},
{0, AXIS_LABEL_PROP_ABS_MISC},
{0, BTN_LABEL_PROP},
diff --git a/config/hal.c b/config/hal.c
index 1b01eccaa..d3daa84cd 100644
--- a/config/hal.c
+++ b/config/hal.c
@@ -164,6 +164,7 @@ device_added(LibHalContext *hal_ctx, const char *udi)
attrs.product = xstrdup(name);
attrs.vendor = get_prop_string(hal_ctx, udi, "info.vendor");
+ attrs.tags = xstrtokenize(get_prop_string(hal_ctx, udi, "input.tags"), ",");
if (libhal_device_query_capability(hal_ctx, udi, "input.keys", NULL))
attrs.flags |= ATTR_KEYBOARD;
@@ -391,6 +392,14 @@ unwind:
xfree(attrs.product);
xfree(attrs.vendor);
xfree(attrs.device);
+ if (attrs.tags) {
+ char **tag = attrs.tags;
+ while (*tag) {
+ xfree(*tag);
+ tag++;
+ }
+ xfree(attrs.tags);
+ }
if (xkb_opts.layout)
xfree(xkb_opts.layout);
diff --git a/config/udev.c b/config/udev.c
index 3ef0d7fb3..432ab85e9 100644
--- a/config/udev.c
+++ b/config/udev.c
@@ -84,6 +84,7 @@ device_added(struct udev_device *udev_device)
add_option(&options, "path", path);
add_option(&options, "device", path);
attrs.device = path;
+ attrs.tags = xstrtokenize(udev_device_get_property_value(udev_device, "ID_INPUT.tags"), ",");
config_info = Xprintf("udev:%s", syspath);
if (!config_info)
@@ -150,6 +151,15 @@ device_added(struct udev_device *udev_device)
xfree(tmpo);
}
+ if (attrs.tags) {
+ char **tag = attrs.tags;
+ while (*tag) {
+ xfree(*tag);
+ tag++;
+ }
+ xfree(attrs.tags);
+ }
+
return;
}
diff --git a/configure.ac b/configure.ac
index bab6aee90..e3280b4d7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -507,19 +507,23 @@ XORG_FONTSUBDIR(FONT75DPIDIR, font75dpidir, 75dpi)
XORG_FONTSUBDIR(FONT100DPIDIR, font100dpidir, 100dpi)
dnl Uses --default-font-path if set, otherwise checks for /etc/X11/fontpath.d,
-dnl otherwise uses standard subdirectories of FONTROOTDIR
-AC_CHECK_FILE([${sysconfdir}/X11/fontpath.d],
- [DEFAULT_FONT_PATH='catalogue:${sysconfdir}/X11/fontpath.d'],
- [
- DEFAULT_FONT_PATH="${FONTMISCDIR}/,${FONTTTFDIR}/,${FONTOTFDIR}/,${FONTTYPE1DIR}/,${FONT100DPIDIR}/,${FONT75DPIDIR}/"
- case $host_os in
- darwin*) DEFAULT_FONT_PATH="${DEFAULT_FONT_PATH},/Library/Fonts,/System/Library/Fonts" ;;
- esac
- ])
+dnl otherwise uses standard subdirectories of FONTROOTDIR. When cross
+dnl compiling, assume default font path uses standard FONTROOTDIR directories.
+DEFAULT_FONT_PATH="${FONTMISCDIR}/,${FONTTTFDIR}/,${FONTOTFDIR}/,${FONTTYPE1DIR}/,${FONT100DPIDIR}/,${FONT75DPIDIR}/"
+if test "$cross_compiling" != yes; then
+ AC_CHECK_FILE([${sysconfdir}/X11/fontpath.d],
+ [DEFAULT_FONT_PATH='catalogue:${sysconfdir}/X11/fontpath.d'],
+ [case $host_os in
+ darwin*) DEFAULT_FONT_PATH="${DEFAULT_FONT_PATH},/Library/Fonts,/System/Library/Fonts" ;;
+ esac])
+fi
AC_ARG_WITH(default-font-path, AS_HELP_STRING([--with-default-font-path=PATH], [Comma separated list of font dirs]),
[ FONTPATH="$withval" ],
[ FONTPATH="${DEFAULT_FONT_PATH}" ])
+AC_MSG_CHECKING([for default font path])
+AC_MSG_RESULT([$FONTPATH])
+
AC_ARG_WITH(xkb-path, AS_HELP_STRING([--with-xkb-path=PATH], [Path to XKB base dir (default: ${datadir}/X11/xkb)]),
[ XKBPATH="$withval" ],
[ XKBPATH="${datadir}/X11/xkb" ])
diff --git a/dix/main.c b/dix/main.c
index d4db90c75..da910fe4b 100644
--- a/dix/main.c
+++ b/dix/main.c
@@ -255,9 +255,9 @@ int main(int argc, char *argv[], char *envp[])
InitRootWindow(WindowTable[i]);
InitCoreDevices();
- config_init();
InitInput(argc, argv);
InitAndStartDevices();
+ config_init();
dixSaveScreens(serverClient, SCREEN_SAVER_FORCER, ScreenSaverReset);
diff --git a/hw/xfree86/common/xf86Xinput.c b/hw/xfree86/common/xf86Xinput.c
index fb0ee9c3f..c2d9f49de 100644
--- a/hw/xfree86/common/xf86Xinput.c
+++ b/hw/xfree86/common/xf86Xinput.c
@@ -502,20 +502,67 @@ AddOtherInputDevices(void)
static Bool
InputClassMatches(XF86ConfInputClassPtr iclass, InputAttributes *attrs)
{
- if (iclass->match_product &&
- (!attrs->product || !strstr(attrs->product, iclass->match_product)))
- return FALSE;
- if (iclass->match_vendor &&
- (!attrs->vendor || !strstr(attrs->vendor, iclass->match_vendor)))
- return FALSE;
- if (iclass->match_device &&
+ char **cur;
+ Bool match;
+
+ if (iclass->match_product) {
+ if (!attrs->product)
+ return FALSE;
+ /* see if any of the values match */
+ for (cur = iclass->match_product, match = FALSE; *cur; cur++)
+ if (strstr(attrs->product, *cur)) {
+ match = TRUE;
+ break;
+ }
+ if (!match)
+ return FALSE;
+ }
+ if (iclass->match_vendor) {
+ if (!attrs->vendor)
+ return FALSE;
+ /* see if any of the values match */
+ for (cur = iclass->match_vendor, match = FALSE; *cur; cur++)
+ if (strstr(attrs->vendor, *cur)) {
+ match = TRUE;
+ break;
+ }
+ if (!match)
+ return FALSE;
+ }
+ if (iclass->match_device) {
+ if (!attrs->device)
+ return FALSE;
+ /* see if any of the values match */
+ for (cur = iclass->match_device, match = FALSE; *cur; cur++)
#ifdef HAVE_FNMATCH_H
- (!attrs->device ||
- fnmatch(iclass->match_device, attrs->device, 0) != 0))
+ if (fnmatch(*cur, attrs->device, FNM_PATHNAME) == 0) {
#else
- (!attrs->device || !strstr(attrs->device, iclass->match_device)))
+ if (strstr(attrs->device, *cur)) {
#endif
- return FALSE;
+ match = TRUE;
+ break;
+ }
+ if (!match)
+ return FALSE;
+ }
+ if (iclass->match_tag) {
+ if (!attrs->tags)
+ return FALSE;
+
+ for (cur = iclass->match_tag, match = FALSE; *cur && !match; cur++) {
+ const char *tag;
+ for(tag = *attrs->tags; *tag; tag++) {
+ if (!strcmp(tag, *cur)) {
+ match = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (!match)
+ return FALSE;
+ }
+
if (iclass->is_keyboard.set &&
iclass->is_keyboard.val != !!(attrs->flags & ATTR_KEYBOARD))
return FALSE;
@@ -538,9 +585,9 @@ InputClassMatches(XF86ConfInputClassPtr iclass, InputAttributes *attrs)
}
/*
- * Merge in any InputClass configurations. Each InputClass section can
- * add to the original device configuration as well as any previous
- * InputClass sections.
+ * Merge in any InputClass configurations. Options in each InputClass
+ * section have less priority than the original device configuration as
+ * well as any previous InputClass sections.
*/
static int
MergeInputClasses(IDevPtr idev, InputAttributes *attrs)
@@ -574,6 +621,27 @@ MergeInputClasses(IDevPtr idev, InputAttributes *attrs)
return Success;
}
+static Bool
+IgnoreInputClass(IDevPtr idev, InputAttributes *attrs)
+{
+ XF86ConfInputClassPtr cl;
+ Bool ignore;
+
+ for (cl = xf86configptr->conf_inputclass_lst; cl; cl = cl->list.next) {
+ if (!InputClassMatches(cl, attrs))
+ continue;
+ if (xf86findOption(cl->option_lst, "Ignore")) {
+ ignore = xf86CheckBoolOption(cl->option_lst, "Ignore", FALSE);
+ if (ignore)
+ xf86Msg(X_CONFIG,
+ "%s: Ignoring device from InputClass \"%s\"\n",
+ idev->identifier, cl->identifier);
+ return ignore;
+ }
+ }
+ return FALSE;
+}
+
/**
* Create a new input device, activate and enable it.
*
@@ -736,6 +804,11 @@ NewInputDeviceRequest (InputOption *options, InputAttributes *attrs,
/* Apply InputClass settings */
if (attrs) {
+ if (IgnoreInputClass(idev, attrs)) {
+ rval = BadIDChoice;
+ goto unwind;
+ }
+
rval = MergeInputClasses(idev, attrs);
if (rval != Success)
goto unwind;
diff --git a/hw/xfree86/doc/man/xorg.conf.man.pre b/hw/xfree86/doc/man/xorg.conf.man.pre
index 222530b41..c8a3c3ac2 100644
--- a/hw/xfree86/doc/man/xorg.conf.man.pre
+++ b/hw/xfree86/doc/man/xorg.conf.man.pre
@@ -1021,7 +1021,7 @@ The
entry specifies the name of the driver to use for this input device.
After all classes have been examined, the
.RI \*q inputdriver \*q
-module from the final
+module from the first
.B Driver
entry will be enabled when using the loadable server.
.PP
@@ -1039,17 +1039,29 @@ The allowed matching entries are shown below.
.BI "MatchProduct \*q" matchproduct \*q
This entry can be used to check if the substring
.RI \*q matchproduct \*q
-occurs in the device's product name.
+occurs in the device's product name. Multiple substrings can be matched by
+separating arguments with a '|' character.
.TP 7
.BI "MatchVendor \*q" matchvendor \*q
This entry can be used to check if the substring
.RI \*q matchvendor \*q
-occurs in the device's vendor name.
+occurs in the device's vendor name. Multiple substrings can be matched by
+separating arguments with a '|' character.
.TP 7
.BI "MatchDevicePath \*q" matchdevice \*q
This entry can be used to check if the device file matches the
.RI \*q matchdevice \*q
-pathname pattern.
+pathname pattern. Multiple patterns can be matched by separating arguments
+with a '|' character.
+.TP 7
+.BI "MatchTag \*q" matchtag \*q
+This entry can be used to check if tags assigned by the config backend
+matches the
+.RI \*q matchtag \*q
+pattern. Multiple patterns can be matched by separating arguments
+with a '|' character. A match is found if at least one of the tags given in
+.RI \*q matchtag \*q
+matches at least one of the tags assigned by the backend.
.TP 7
.BI "MatchIsKeyboard \*q" bool \*q
.TP 7
@@ -1070,11 +1082,20 @@ When an input device has been matched to the
.B InputClass
section, any
.B Option
-entries are applied to the device. See the
+entries are applied to the device. One
+.B InputClass
+specific
+.B Option
+is recognized. See the
.B InputDevice
-section above for a description of the various
+section above for a description of the remaining
.B Option
entries.
+.TP 7
+.BI "Option \*qIgnore\*q \*q" boolean \*q
+This optional entry specifies that the device should be ignored entirely,
+and not added to the server. This can be useful when the device is handled
+by another program and no X events should be generated.
.SH "DEVICE SECTION"
The config file may have multiple
.B Device
diff --git a/hw/xfree86/parser/InputClass.c b/hw/xfree86/parser/InputClass.c
index 1c9816012..7fb2866cd 100644
--- a/hw/xfree86/parser/InputClass.c
+++ b/hw/xfree86/parser/InputClass.c
@@ -29,6 +29,8 @@
#include <xorg-config.h>
#endif
+#include <string.h>
+#include "os.h"
#include "xf86Parser.h"
#include "xf86tokens.h"
#include "Configint.h"
@@ -45,6 +47,7 @@ xf86ConfigSymTabRec InputClassTab[] =
{MATCH_PRODUCT, "matchproduct"},
{MATCH_VENDOR, "matchvendor"},
{MATCH_DEVICE_PATH, "matchdevicepath"},
+ {MATCH_TAG, "matchtag"},
{MATCH_IS_KEYBOARD, "matchiskeyboard"},
{MATCH_IS_POINTER, "matchispointer"},
{MATCH_IS_JOYSTICK, "matchisjoystick"},
@@ -56,6 +59,8 @@ xf86ConfigSymTabRec InputClassTab[] =
#define CLEANUP xf86freeInputClassList
+#define TOKEN_SEP "|"
+
XF86ConfInputClassPtr
xf86parseInputClassSection(void)
{
@@ -91,17 +96,22 @@ xf86parseInputClassSection(void)
case MATCH_PRODUCT:
if (xf86getSubToken(&(ptr->comment)) != STRING)
Error(QUOTE_MSG, "MatchProduct");
- ptr->match_product = val.str;
+ ptr->match_product = xstrtokenize(val.str, TOKEN_SEP);
break;
case MATCH_VENDOR:
if (xf86getSubToken(&(ptr->comment)) != STRING)
Error(QUOTE_MSG, "MatchVendor");
- ptr->match_vendor = val.str;
+ ptr->match_vendor = xstrtokenize(val.str, TOKEN_SEP);
break;
case MATCH_DEVICE_PATH:
if (xf86getSubToken(&(ptr->comment)) != STRING)
Error(QUOTE_MSG, "MatchDevicePath");
- ptr->match_device = val.str;
+ ptr->match_device = xstrtokenize(val.str, TOKEN_SEP);
+ break;
+ case MATCH_TAG:
+ if (xf86getSubToken(&(ptr->comment)) != STRING)
+ Error(QUOTE_MSG, "MatchTag");
+ ptr->match_tag = xstrtokenize(val.str, TOKEN_SEP);
break;
case MATCH_IS_KEYBOARD:
if (xf86getSubToken(&(ptr->comment)) != STRING)
@@ -173,6 +183,8 @@ xf86parseInputClassSection(void)
void
xf86printInputClassSection (FILE * cf, XF86ConfInputClassPtr ptr)
{
+ char **list;
+
while (ptr) {
fprintf(cf, "Section \"InputClass\"\n");
if (ptr->comment)
@@ -181,12 +193,38 @@ xf86printInputClassSection (FILE * cf, XF86ConfInputClassPtr ptr)
fprintf(cf, "\tIdentifier \"%s\"\n", ptr->identifier);
if (ptr->driver)
fprintf(cf, "\tDriver \"%s\"\n", ptr->driver);
- if (ptr->match_product)
- fprintf(cf, "\tMatchProduct \"%s\"\n", ptr->match_product);
- if (ptr->match_vendor)
- fprintf(cf, "\tMatchVendor \"%s\"\n", ptr->match_vendor);
- if (ptr->match_device)
- fprintf(cf, "\tMatchDevicePath \"%s\"\n", ptr->match_device);
+ if (ptr->match_product) {
+ fprintf(cf, "\tMatchProduct \"");
+ for (list = ptr->match_product; *list; list++)
+ fprintf(cf, "%s%s",
+ list == ptr->match_product ? "" : TOKEN_SEP,
+ *list);
+ fprintf(cf, "\"\n");
+ }
+ if (ptr->match_vendor) {
+ fprintf(cf, "\tMatchVendor \"");
+ for (list = ptr->match_vendor; *list; list++)
+ fprintf(cf, "%s%s",
+ list == ptr->match_vendor ? "" : TOKEN_SEP,
+ *list);
+ fprintf(cf, "\"\n");
+ }
+ if (ptr->match_device) {
+ fprintf(cf, "\tMatchDevicePath \"");
+ for (list = ptr->match_device; *list; list++)
+ fprintf(cf, "%s%s",
+ list == ptr->match_device ? "" : TOKEN_SEP,
+ *list);
+ fprintf(cf, "\"\n");
+ }
+ if (ptr->match_tag) {
+ fprintf(cf, "\tMatchTag \"");
+ for (list = ptr->match_tag; *list; list++)
+ fprintf(cf, "%s%s",
+ list == ptr->match_tag ? "" : TOKEN_SEP,
+ *list);
+ fprintf(cf, "\"\n");
+ }
if (ptr->is_keyboard.set)
fprintf(cf, "\tIsKeyboard \"%s\"\n",
ptr->is_keyboard.val ? "yes" : "no");
@@ -215,13 +253,31 @@ void
xf86freeInputClassList (XF86ConfInputClassPtr ptr)
{
XF86ConfInputClassPtr prev;
+ char **list;
while (ptr) {
TestFree(ptr->identifier);
TestFree(ptr->driver);
- TestFree(ptr->match_product);
- TestFree(ptr->match_vendor);
- TestFree(ptr->match_device);
+ if (ptr->match_product) {
+ for (list = ptr->match_product; *list; list++)
+ free(*list);
+ free(ptr->match_product);
+ }
+ if (ptr->match_vendor) {
+ for (list = ptr->match_vendor; *list; list++)
+ free(*list);
+ free(ptr->match_vendor);
+ }
+ if (ptr->match_device) {
+ for (list = ptr->match_device; *list; list++)
+ free(*list);
+ free(ptr->match_device);
+ }
+ if (ptr->match_tag) {
+ for (list = ptr->match_tag; *list; list++)
+ free(*list);
+ free(ptr->match_tag);
+ }
TestFree(ptr->comment);
xf86optionListFree(ptr->option_lst);
diff --git a/hw/xfree86/parser/scan.c b/hw/xfree86/parser/scan.c
index b80fbfb8f..03cbc8a44 100644
--- a/hw/xfree86/parser/scan.c
+++ b/hw/xfree86/parser/scan.c
@@ -227,13 +227,15 @@ xf86getNextLine(void)
configFiles[curFileIndex].file);
if (!ret) {
- /* stop if there are no more files */
- if (++curFileIndex >= numFiles) {
- curFileIndex = 0;
+ /*
+ * if the file doesn't end in a newline, add one
+ * and trigger another read
+ */
+ if (pos != 0) {
+ strcpy(&configBuf[pos], "\n");
+ ret = configBuf;
+ } else
break;
- }
- configLineNo = 0;
- continue;
}
/* search for EOL in the new block of chars */
@@ -338,7 +340,17 @@ again:
}
if (ret == NULL)
{
- return (pushToken = EOF_TOKEN);
+ /*
+ * if necessary, move to the next file and
+ * read the first line
+ */
+ if (curFileIndex + 1 < numFiles) {
+ curFileIndex++;
+ configLineNo = 0;
+ goto again;
+ }
+ else
+ return (pushToken = EOF_TOKEN);
}
configLineNo++;
configPos = 0;
diff --git a/hw/xfree86/parser/xf86Parser.h b/hw/xfree86/parser/xf86Parser.h
index 5e8351fc4..d79544a20 100644
--- a/hw/xfree86/parser/xf86Parser.h
+++ b/hw/xfree86/parser/xf86Parser.h
@@ -343,9 +343,10 @@ typedef struct
GenericListRec list;
char *identifier;
char *driver;
- char *match_product;
- char *match_vendor;
- char *match_device;
+ char **match_product;
+ char **match_vendor;
+ char **match_device;
+ char **match_tag;
xf86TriState is_keyboard;
xf86TriState is_pointer;
xf86TriState is_joystick;
diff --git a/hw/xfree86/parser/xf86tokens.h b/hw/xfree86/parser/xf86tokens.h
index e3a9d716b..cb600704b 100644
--- a/hw/xfree86/parser/xf86tokens.h
+++ b/hw/xfree86/parser/xf86tokens.h
@@ -279,6 +279,7 @@ typedef enum {
MATCH_PRODUCT,
MATCH_VENDOR,
MATCH_DEVICE_PATH,
+ MATCH_TAG,
MATCH_IS_KEYBOARD,
MATCH_IS_POINTER,
MATCH_IS_JOYSTICK,
diff --git a/include/input.h b/include/input.h
index 7a6242d08..4a845bedf 100644
--- a/include/input.h
+++ b/include/input.h
@@ -215,6 +215,7 @@ typedef struct _InputAttributes {
char *product;
char *vendor;
char *device;
+ char **tags; /* null-terminated */
uint32_t flags;
} InputAttributes;
diff --git a/include/misc.h b/include/misc.h
index 877c682d4..62d813e0c 100644
--- a/include/misc.h
+++ b/include/misc.h
@@ -210,6 +210,9 @@ pad_to_int32(const int bytes) {
return (((bytes) + 3) & ~3);
}
+extern char**
+xstrtokenize(const char *str, const char* separators);
+
/* some macros to help swap requests, replies, and events */
#define LengthRestB(stuff) \
diff --git a/include/xserver-properties.h b/include/xserver-properties.h
index 626d0ad27..30e8efb68 100644
--- a/include/xserver-properties.h
+++ b/include/xserver-properties.h
@@ -89,6 +89,17 @@
#define AXIS_LABEL_PROP_ABS_TILT_Y "Abs Tilt Y"
#define AXIS_LABEL_PROP_ABS_TOOL_WIDTH "Abs Tool Width"
#define AXIS_LABEL_PROP_ABS_VOLUME "Abs Volume"
+#define AXIS_LABEL_PROP_ABS_MT_TOUCH_MAJOR "Abs MT Touch Major"
+#define AXIS_LABEL_PROP_ABS_MT_TOUCH_MINOR "Abs MT Touch Minor"
+#define AXIS_LABEL_PROP_ABS_MT_WIDTH_MAJOR "Abs MT Width Major"
+#define AXIS_LABEL_PROP_ABS_MT_WIDTH_MINOR "Abs MT Width Minor"
+#define AXIS_LABEL_PROP_ABS_MT_ORIENTATION "Abs MT Orientation"
+#define AXIS_LABEL_PROP_ABS_MT_POSITION_X "Abs MT Position X"
+#define AXIS_LABEL_PROP_ABS_MT_POSITION_Y "Abs MT Position Y"
+#define AXIS_LABEL_PROP_ABS_MT_TOOL_TYPE "Abs MT Tool Type"
+#define AXIS_LABEL_PROP_ABS_MT_BLOB_ID "Abs MT Blob ID"
+#define AXIS_LABEL_PROP_ABS_MT_TRACKING_ID "Abs MT Tracking ID"
+#define AXIS_LABEL_PROP_ABS_MT_PRESSURE "Abs MT Pressure"
#define AXIS_LABEL_PROP_ABS_MISC "Abs Misc"
/* Button names */
diff --git a/os/utils.c b/os/utils.c
index 1edbc5b5c..79399fa53 100644
--- a/os/utils.c
+++ b/os/utils.c
@@ -1866,6 +1866,46 @@ CheckUserAuthorization(void)
#endif
}
+/*
+ * Tokenize a string into a NULL terminated array of strings. Always returns
+ * an allocated array unless an error occurs.
+ */
+char**
+xstrtokenize(const char *str, const char *separators)
+{
+ char **list, **nlist;
+ char *tok, *tmp;
+ unsigned num = 0, n;
+
+ if (!str)
+ return NULL;
+ list = calloc(1, sizeof(*list));
+ if (!list)
+ return NULL;
+ tmp = strdup(str);
+ if (!tmp)
+ goto error;
+ for (tok = strtok(tmp, separators); tok; tok = strtok(NULL, separators)) {
+ nlist = realloc(list, (num + 2) * sizeof(*list));
+ if (!nlist)
+ goto error;
+ list = nlist;
+ list[num] = strdup(tok);
+ if (!list[num])
+ goto error;
+ list[++num] = NULL;
+ }
+ free(tmp);
+ return list;
+
+error:
+ free(tmp);
+ for (n = 0; n < num; n++)
+ free(list[n]);
+ free(list);
+ return NULL;
+}
+
#ifdef __SCO__
#include <fcntl.h>