mutter/tests/conform/events-touch.c
Emmanuele Bassi 526d0ea884 conformance: Add more tests
Add back some deprecated and general purpose API tests. These are the
ones that were written already pretty much conforming to the GTest API
and style, and thus require minimal porting.
2013-12-12 18:51:11 +00:00

393 lines
9.2 KiB
C

/*
* Copyright (C) 2009 Red Hat, Inc.
* Copyright (C) 2012 Collabora Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
* more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
* Boston, MA 02111-1307, USA.
*
*/
#include <clutter/clutter.h>
#if defined CLUTTER_WINDOWING_X11 && OS_LINUX && HAVE_XINPUT_2_2
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <math.h>
#include <linux/input.h>
#include <linux/uinput.h>
#include <dlfcn.h>
#include <clutter/x11/clutter-x11.h>
#define ABS_MAX_X 32768
#define ABS_MAX_Y 32768
#define TOUCH_POINTS 10
static ClutterPoint gesture_points[] = {
{ 100., 100. },
{ 110., 100. },
{ 120., 100. },
{ 130., 100. },
{ 140., 100. },
{ 150., 100. },
{ 160., 100. },
{ 170., 100. },
{ 180., 100. },
{ 190., 100. },
};
typedef struct _State State;
struct _State
{
gboolean pass;
ClutterPoint gesture_points_to_check[TOUCH_POINTS];
int gesture_points;
};
static int fd = -1;
static void send_event(int fd, int type, int code, int value, int sec, int usec)
{
static int sec_offset = -1;
static long last_time = -1;
long newtime;
struct input_event event;
event.type = type;
event.code = code;
event.value = value;
if (sec_offset == -1)
sec_offset = sec;
sec -= sec_offset;
newtime = sec * 1000000 + usec;
if (last_time > 0)
usleep(newtime - last_time);
gettimeofday(&event.time, NULL);
if (write(fd, &event, sizeof(event)) < sizeof(event))
perror("Send event failed.");
last_time = newtime;
}
static gboolean
event_cb (ClutterActor *actor, ClutterEvent *event, State *state)
{
int i;
if (event->type != CLUTTER_TOUCH_BEGIN &&
event->type != CLUTTER_TOUCH_UPDATE)
return FALSE;
state->gesture_points_to_check[state->gesture_points].x = ceil (event->touch.x);
state->gesture_points_to_check[state->gesture_points].y = ceil (event->touch.y);
state->gesture_points++;
if (state->gesture_points == TOUCH_POINTS)
{
for (i = 0; i < TOUCH_POINTS; i++)
{
if (state->gesture_points_to_check[i].x != gesture_points[i].x ||
state->gesture_points_to_check[i].y != gesture_points[i].y)
{
if (g_test_verbose ())
g_print ("error: expected (%d, %d) but found (%d, %d) at position %d\n",
(int) gesture_points[i].x, (int) gesture_points[i].y,
(int) state->gesture_points_to_check[i].x,
(int) state->gesture_points_to_check[i].y,
i);
state->pass = FALSE;
break;
}
}
clutter_main_quit ();
}
return TRUE;
}
static void
screen_coords_to_device (int screen_x, int screen_y,
int *device_x, int *device_y)
{
int display_width = DisplayWidth (clutter_x11_get_default_display (),
clutter_x11_get_default_screen ());
int display_height = DisplayHeight (clutter_x11_get_default_display (),
clutter_x11_get_default_screen ());
*device_x = (screen_x * ABS_MAX_X) / display_width;
*device_y = (screen_y * ABS_MAX_Y) / display_height;
}
static gboolean
perform_gesture (gpointer data)
{
int i;
for (i = 0; i < TOUCH_POINTS; i++)
{
int x = gesture_points[i].x;
int y = gesture_points[i].y;
screen_coords_to_device (x, y, &x, &y);
send_event(fd, EV_ABS, ABS_MT_SLOT, 0, 1, i * 100);
send_event(fd, EV_ABS, ABS_MT_TRACKING_ID, 1, 1, i * 100 + 10);
send_event(fd, EV_ABS, ABS_MT_POSITION_X, x, 1, i * 100 + 20);
send_event(fd, EV_ABS, ABS_MT_POSITION_Y, y, 1, i * 100 + 30);
send_event(fd, EV_SYN, SYN_MT_REPORT, 0, 1, i * 100 + 40);
send_event(fd, EV_SYN, SYN_REPORT, 0, 1, i * 100 + 50);
}
send_event(fd, EV_ABS, ABS_MT_TRACKING_ID, -1, 1, TOUCH_POINTS * 100 + 10);
send_event(fd, EV_SYN, SYN_MT_REPORT, 0, 1, TOUCH_POINTS * 100 + 20);
send_event(fd, EV_SYN, SYN_REPORT, 0, 1, TOUCH_POINTS * 100 + 30);
return G_SOURCE_REMOVE;
}
static int
setup (struct uinput_user_dev *dev, int fd)
{
strcpy (dev->name, "eGalax Touch Screen");
dev->id.bustype = 0x18;
dev->id.vendor = 0xeef;
dev->id.product = 0x20;
dev->id.version = 0x1;
if (ioctl (fd, UI_SET_EVBIT, EV_SYN) == -1)
goto error;
if (ioctl (fd, UI_SET_EVBIT, EV_KEY) == -1)
goto error;
if (ioctl (fd, UI_SET_KEYBIT, BTN_TOUCH) == -1)
goto error;
if (ioctl (fd, UI_SET_EVBIT, EV_ABS) == -1)
goto error;
if (ioctl (fd, UI_SET_ABSBIT, ABS_X) == -1)
goto error;
else
{
int idx = ABS_X;
dev->absmin[idx] = 0;
dev->absmax[idx] = ABS_MAX_X;
dev->absfuzz[idx] = 1;
dev->absflat[idx] = 0;
if (dev->absmin[idx] == dev->absmax[idx])
dev->absmax[idx]++;
}
if (ioctl (fd, UI_SET_ABSBIT, ABS_Y) == -1)
goto error;
else
{
int idx = ABS_Y;
dev->absmin[idx] = 0;
dev->absmax[idx] = ABS_MAX_Y;
dev->absfuzz[idx] = 1;
dev->absflat[idx] = 0;
if (dev->absmin[idx] == dev->absmax[idx])
dev->absmax[idx]++;
}
if (ioctl (fd, UI_SET_ABSBIT, ABS_PRESSURE) == -1)
goto error;
else
{
int idx = ABS_PRESSURE;
dev->absmin[idx] = 0;
dev->absmax[idx] = 0;
dev->absfuzz[idx] = 0;
dev->absflat[idx] = 0;
if (dev->absmin[idx] == dev->absmax[idx])
dev->absmax[idx]++;
}
if (ioctl (fd, UI_SET_ABSBIT, ABS_MT_TOUCH_MAJOR) == -1)
goto error;
else
{
int idx = ABS_MT_TOUCH_MAJOR;
dev->absmin[idx] = 0;
dev->absmax[idx] = 255;
dev->absfuzz[idx] = 1;
dev->absflat[idx] = 0;
if (dev->absmin[idx] == dev->absmax[idx])
dev->absmax[idx]++;
}
if (ioctl (fd, UI_SET_ABSBIT, ABS_MT_WIDTH_MAJOR) == -1)
goto error;
else
{
int idx = ABS_MT_WIDTH_MAJOR;
dev->absmin[idx] = 0;
dev->absmax[idx] = 255;
dev->absfuzz[idx] = 1;
dev->absflat[idx] = 0;
if (dev->absmin[idx] == dev->absmax[idx])
dev->absmax[idx]++;
}
if (ioctl (fd, UI_SET_ABSBIT, ABS_MT_POSITION_X) == -1)
goto error;
else
{
int idx = ABS_MT_POSITION_X;
dev->absmin[idx] = 0;
dev->absmax[idx] = ABS_MAX_X;
dev->absfuzz[idx] = 1;
dev->absflat[idx] = 0;
if (dev->absmin[idx] == dev->absmax[idx])
dev->absmax[idx]++;
}
if (ioctl (fd, UI_SET_ABSBIT, ABS_MT_POSITION_Y) == -1)
goto error;
else
{
int idx = ABS_MT_POSITION_Y;
dev->absmin[idx] = 0;
dev->absmax[idx] = ABS_MAX_Y;
dev->absfuzz[idx] = 1;
dev->absflat[idx] = 0;
if (dev->absmin[idx] == dev->absmax[idx])
dev->absmax[idx]++;
}
if (ioctl (fd, UI_SET_ABSBIT, ABS_MT_TRACKING_ID) == -1)
goto error;
else
{
int idx = ABS_MT_TRACKING_ID;
dev->absmin[idx] = 0;
dev->absmax[idx] = 5;
dev->absfuzz[idx] = 0;
dev->absflat[idx] = 0;
if (dev->absmin[idx] == dev->absmax[idx])
dev->absmax[idx]++;
}
return 0;
error:
perror ("ioctl failed.");
return -1;
}
static int
init_uinput (void)
{
struct uinput_user_dev dev;
fd = open ("/dev/uinput", O_RDWR);
if (fd < 0 && errno == ENODEV)
fd = open ("/dev/input/uinput", O_RDWR);
if (fd < 0)
{
if (g_test_verbose ())
perror ("open");
return 0;
};
memset (&dev, 0, sizeof (dev));
setup (&dev, fd);
if (write (fd, &dev, sizeof (dev)) < sizeof (dev))
{
if (g_test_verbose ())
perror ("write");
goto error;
}
if (ioctl (fd, UI_DEV_CREATE, NULL) == -1)
{
if (g_test_verbose ())
perror ("ioctl");
goto error;
}
return 1;
error:
if (fd != -1)
close (fd);
return 0;
}
#endif /* defined CLUTTER_WINDOWING_X11 && OS_LINUX && HAVE_XINPUT_2_2 */
static void
events_touch (void)
{
#if defined CLUTTER_WINDOWING_X11 && OS_LINUX && HAVE_XINPUT_2_2
ClutterActor *stage;
State state;
/* bail out if we could not initialize evdev */
if (!init_uinput ())
return;
state.pass = TRUE;
state.gesture_points = 0;
stage = clutter_test_get_stage ();
g_signal_connect (stage, "event", G_CALLBACK (event_cb), &state);
clutter_stage_set_fullscreen (CLUTTER_STAGE (stage), TRUE);
clutter_actor_show (stage);
clutter_threads_add_timeout (500, perform_gesture, &state);
clutter_main ();
if (g_test_verbose ())
g_print ("end result: %s\n", state.pass ? "pass" : "FAIL");
g_assert (state.pass);
#endif /* defined CLUTTER_WINDOWING_X11 && OS_LINUX && HAVE_XINPUT_2_2 */
}
CLUTTER_TEST_SUITE (
CLUTTER_TEST_UNIT ("/events/touch", events_touch)
)