2008-06-23 Matthew Allum <mallum@openedhand.com>

* clutter/clutter-actor.c:
        * clutter/clutter-actor.h:
        * clutter/clutter-event.c:
        * clutter/clutter-event.h:
        * clutter/clutter-main.c:
        * clutter/clutter-main.h:
        * clutter/clutter-private.h:
        * clutter/eglx/clutter-stage-egl.c:
        * clutter/fruity/clutter-backend-fruity.c:
        * clutter/fruity/clutter-backend-fruity.h:
        * clutter/fruity/clutter-fruity.c:
        * clutter/glx/clutter-stage-glx.c:
        * clutter/x11/clutter-backend-x11.c:
        * clutter/x11/clutter-backend-x11.h:
        * clutter/x11/clutter-event-x11.c:
        * clutter/x11/clutter-stage-x11.h:
        * clutter/x11/clutter-x11.h:
        * configure.ac:
        * tests/Makefile.am:
        * tests/test-devices.c:
        Merge of 'xinput' branch giving initial basic support of
        multiple input devices.
This commit is contained in:
Matthew Allum 2008-06-23 09:55:42 +00:00
parent 920687a470
commit b241481586
21 changed files with 1257 additions and 128 deletions

View File

@ -1,3 +1,28 @@
2008-06-23 Matthew Allum <mallum@openedhand.com>
* clutter/clutter-actor.c:
* clutter/clutter-actor.h:
* clutter/clutter-event.c:
* clutter/clutter-event.h:
* clutter/clutter-main.c:
* clutter/clutter-main.h:
* clutter/clutter-private.h:
* clutter/eglx/clutter-stage-egl.c:
* clutter/fruity/clutter-backend-fruity.c:
* clutter/fruity/clutter-backend-fruity.h:
* clutter/fruity/clutter-fruity.c:
* clutter/glx/clutter-stage-glx.c:
* clutter/x11/clutter-backend-x11.c:
* clutter/x11/clutter-backend-x11.h:
* clutter/x11/clutter-event-x11.c:
* clutter/x11/clutter-stage-x11.h:
* clutter/x11/clutter-x11.h:
* configure.ac:
* tests/Makefile.am:
* tests/test-devices.c:
Merge of 'xinput' branch giving initial basic support of
multiple input devices.
2008-06-23 Matthew Allum <mallum@openedhand.com>
* clutter/clutter-actor.c:

View File

@ -7293,9 +7293,10 @@ clutter_actor_get_stage (ClutterActor *actor)
*
* This function is a utility call for #ClutterActor implementations
* that allocates the actor's preferred natural size. It can be used
* by fixed layout managers (like #ClutterGroup) inside the
* ClutterActor::allocate implementation to give each child exactly
* how much space it requires.
* by fixed layout managers (like #ClutterGroup or so called
* 'composite actors') inside the ClutterActor::allocate
* implementation to give each child exactly how much space it
* requires.
*
* This function is not meant to be used by applications. It is also
* not meant to be used outside the implementation of the

View File

@ -550,6 +550,8 @@ void clutter_actor_apply_relative_transform_to_point (ClutterActor *self,
ClutterActor *ancestor,
ClutterVertex *point,
ClutterVertex *vertex);
void clutter_actor_allocate_preferred_size (ClutterActor *actor,
gboolean absolute_origin_changed);
G_END_DECLS

View File

@ -315,6 +315,54 @@ clutter_keysym_to_unicode (guint keyval)
return 0;
}
/**
* clutter_event_get_device_id:
* @event: a clutter event
*
* Retrieves the events device id if set.
*
* Return value: A unique identifier for the device or -1 if the event has
* no specific device set.
**/
gint
clutter_event_get_device_id (ClutterEvent *event)
{
g_return_val_if_fail (-1, event != NULL);
ClutterInputDevice *device = NULL;
switch (event->type)
{
case CLUTTER_NOTHING:
case CLUTTER_STAGE_STATE:
case CLUTTER_DESTROY_NOTIFY:
case CLUTTER_CLIENT_MESSAGE:
case CLUTTER_DELETE:
case CLUTTER_ENTER:
case CLUTTER_LEAVE:
break;
case CLUTTER_BUTTON_PRESS:
case CLUTTER_BUTTON_RELEASE:
device = event->button.device;
break;
case CLUTTER_MOTION:
device = event->motion.device;
break;
case CLUTTER_SCROLL:
device = event->scroll.device;
break;
case CLUTTER_KEY_PRESS:
case CLUTTER_KEY_RELEASE:
break;
}
if (device)
return device->id;
else
return -1;
}
GType
clutter_event_get_type (void)
{

View File

@ -350,6 +350,7 @@ ClutterModifierType clutter_event_get_state (ClutterEvent *event);
void clutter_event_get_coords (ClutterEvent *event,
gint *x,
gint *y);
gint clutter_event_get_device_id (ClutterEvent *event);
ClutterActor* clutter_event_get_source (ClutterEvent *event);
guint clutter_key_event_symbol (ClutterKeyEvent *keyev);

View File

@ -1415,6 +1415,15 @@ event_click_count_generate (ClutterEvent *event)
double_click_distance = clutter_backend_get_double_click_distance (backend);
double_click_time = clutter_backend_get_double_click_time (backend);
if (event->button.device != NULL)
{
click_count = event->button.device->click_count;
previous_x = event->button.device->previous_x;
previous_y = event->button.device->previous_y;
previous_time = event->button.device->previous_time;
previous_button_number = event->button.device->previous_button_number;
}
switch (event->type)
{
case CLUTTER_BUTTON_PRESS:
@ -1449,6 +1458,15 @@ event_click_count_generate (ClutterEvent *event)
default:
g_assert (NULL);
}
if (event->button.device != NULL)
{
event->button.device->click_count = click_count;
event->button.device->previous_x = previous_x;
event->button.device->previous_y = previous_y;
event->button.device->previous_time = previous_time;
event->button.device->previous_button_number = previous_button_number;
}
}
@ -1546,11 +1564,14 @@ emit_keyboard_event (ClutterEvent *event)
}
static void
unset_motion_last_actor (ClutterActor *actor)
unset_motion_last_actor (ClutterActor *actor, ClutterInputDevice *dev)
{
ClutterMainContext *context = ClutterCntx;
context->motion_last_actor = NULL;
if (dev == NULL)
context->motion_last_actor = NULL;
else
dev->motion_last_actor = NULL;
}
static inline void
@ -1558,8 +1579,12 @@ generate_enter_leave_events (ClutterEvent *event)
{
ClutterMainContext *context = ClutterCntx;
ClutterActor *motion_current_actor = event->motion.source;
ClutterActor *last_actor = context->motion_last_actor;
if (context->motion_last_actor != motion_current_actor)
if (event->motion.device != NULL)
last_actor = event->motion.device->motion_last_actor;
if (last_actor != motion_current_actor)
{
if (motion_current_actor)
{
@ -1572,7 +1597,7 @@ generate_enter_leave_events (ClutterEvent *event)
cev.crossing.flags = 0;
cev.crossing.x = event->motion.x;
cev.crossing.y = event->motion.y;
cev.crossing.source = context->motion_last_actor;
cev.crossing.source = last_actor;
cev.crossing.stage = event->any.stage;
/* unref in free */
cev.crossing.related = motion_current_actor;
@ -1590,7 +1615,7 @@ generate_enter_leave_events (ClutterEvent *event)
cev.crossing.stage = event->any.stage;
if (context->motion_last_actor)
cev.crossing.related = context->motion_last_actor;
cev.crossing.related = last_actor;
else
{
/* the previous actor we were getting events from seems to have
@ -1604,23 +1629,25 @@ generate_enter_leave_events (ClutterEvent *event)
}
}
if (context->motion_last_actor &&
context->motion_last_actor != motion_current_actor)
if (last_actor && last_actor != motion_current_actor)
{
g_signal_handlers_disconnect_by_func (context->motion_last_actor,
G_CALLBACK (unset_motion_last_actor),
NULL);
g_signal_handlers_disconnect_by_func
(last_actor,
G_CALLBACK (unset_motion_last_actor),
event->motion.device);
}
if (motion_current_actor &&
context->motion_last_actor != motion_current_actor)
if (motion_current_actor && last_actor != motion_current_actor)
{
g_signal_connect (motion_current_actor, "destroy",
G_CALLBACK (unset_motion_last_actor),
NULL);
event->motion.device);
}
context->motion_last_actor = motion_current_actor;
if (event->motion.device != NULL)
event->motion.device->motion_last_actor = motion_current_actor;
else
context->motion_last_actor = motion_current_actor;
}
/**
@ -1641,7 +1668,9 @@ clutter_do_event (ClutterEvent *event)
ClutterMainContext *context;
ClutterBackend *backend;
ClutterActor *stage;
ClutterInputDevice *device = NULL;
static gint32 motion_last_time = 0L;
gint32 local_motion_time;
context = clutter_context_get_default ();
backend = context->backend;
@ -1699,6 +1728,12 @@ clutter_do_event (ClutterEvent *event)
break;
case CLUTTER_MOTION:
device = event->motion.device;
if (device)
local_motion_time = device->motion_last_time;
else
local_motion_time = motion_last_time;
/* avoid rate throttling for synthetic motion events or if
* the per-actor events are disabled
@ -1716,17 +1751,22 @@ clutter_do_event (ClutterEvent *event)
CLUTTER_NOTE (EVENT,
"skip motion event: %s (last:%d, delta:%d, time:%d)",
(event->any.time < (motion_last_time + delta) ? "yes" : "no"),
motion_last_time,
(event->any.time < (local_motion_time + delta) ? "yes" : "no"),
local_motion_time,
delta,
event->any.time);
if (event->any.time < (motion_last_time + delta))
if (event->any.time < (local_motion_time + delta))
break;
else
motion_last_time = event->any.time;
local_motion_time = event->any.time;
}
if (device)
device->motion_last_time = local_motion_time;
else
motion_last_time = local_motion_time;
/* Only stage gets motion events if clutter_set_motion_events is TRUE,
* and the event is not a synthetic event with source set.
*/
@ -1736,9 +1776,17 @@ clutter_do_event (ClutterEvent *event)
/* Only stage gets motion events */
event->any.source = stage;
/* global grabs */
if (context->pointer_grab_actor != NULL)
{
clutter_actor_event (context->pointer_grab_actor, event, FALSE);
clutter_actor_event (context->pointer_grab_actor,
event, FALSE);
break;
}
else if (device != NULL && device->pointer_grab_actor != NULL)
{
clutter_actor_event (device->pointer_grab_actor,
event, FALSE);
break;
}
@ -1774,7 +1822,8 @@ clutter_do_event (ClutterEvent *event)
{
if (event->type == CLUTTER_BUTTON_RELEASE)
{
CLUTTER_NOTE (EVENT,"Release off stage received at %i, %i",
CLUTTER_NOTE (EVENT,
"Release off stage received at %i, %i",
x, y);
event->button.source = stage;
@ -1922,12 +1971,21 @@ static void
on_pointer_grab_weak_notify (gpointer data,
GObject *where_the_object_was)
{
ClutterInputDevice *dev = (ClutterInputDevice *)data;
ClutterMainContext *context;
context = clutter_context_get_default ();
context->pointer_grab_actor = NULL;
clutter_ungrab_pointer ();
if (dev)
{
dev->pointer_grab_actor = NULL;
clutter_ungrab_pointer_for_device (dev->id);
}
else
{
context->pointer_grab_actor = NULL;
clutter_ungrab_pointer ();
}
}
/**
@ -1971,6 +2029,48 @@ clutter_grab_pointer (ClutterActor *actor)
}
}
void
clutter_grab_pointer_for_device (ClutterActor *actor,
gint id)
{
ClutterInputDevice *dev;
g_return_if_fail (actor == NULL || CLUTTER_IS_ACTOR (actor));
/* essentially a global grab */
if (id == -1)
{
clutter_grab_pointer (actor);
return;
}
dev = clutter_get_input_device_for_id (id);
if (!dev)
return;
if (dev->pointer_grab_actor == actor)
return;
if (dev->pointer_grab_actor)
{
g_object_weak_unref (G_OBJECT (dev->pointer_grab_actor),
on_pointer_grab_weak_notify,
dev);
dev->pointer_grab_actor = NULL;
}
if (actor)
{
dev->pointer_grab_actor = actor;
g_object_weak_ref (G_OBJECT (actor),
on_pointer_grab_weak_notify,
dev);
}
}
/**
* clutter_ungrab_pointer:
*
@ -1984,6 +2084,13 @@ clutter_ungrab_pointer (void)
clutter_grab_pointer (NULL);
}
void
clutter_ungrab_pointer_for_device (gint id)
{
clutter_grab_pointer_for_device (NULL, id);
}
/**
* clutter_get_pointer_grab:
*
@ -2200,3 +2307,25 @@ clutter_get_use_mipmapped_text (void)
return FALSE;
}
ClutterInputDevice*
clutter_get_input_device_for_id (gint id)
{
GSList *item;
ClutterInputDevice *device = NULL;
ClutterMainContext *context;
context = clutter_context_get_default ();
for (item = context->input_devices;
item != NULL;
item = item->next)
{
device = (ClutterInputDevice *)item->data;
if (device->id == id)
return device;
}
return NULL;
}

View File

@ -131,6 +131,14 @@ void clutter_clear_glyph_cache (void);
void clutter_set_use_mipmapped_text (gboolean value);
gboolean clutter_get_use_mipmapped_text (void);
ClutterInputDevice* clutter_get_input_device_for_id (gint id);
void clutter_grab_pointer_for_device (ClutterActor *actor,
gint id);
void clutter_ungrab_pointer_for_device (gint id);
G_END_DECLS
#endif /* _HAVE_CLUTTER_MAIN_H */

View File

@ -69,6 +69,20 @@ typedef enum {
CLUTTER_PICK_ALL
} ClutterPickMode;
struct _ClutterInputDevice
{
gint id;
gint32 motion_last_time;
ClutterActor *pointer_grab_actor;
ClutterActor *motion_last_actor;
gint click_count;
gint previous_x;
gint previous_y;
guint32 previous_time;
gint previous_button_number;
};
typedef struct _ClutterMainContext ClutterMainContext;
struct _ClutterMainContext
@ -83,8 +97,7 @@ struct _ClutterMainContext
ClutterPickMode pick_mode; /* Indicates pick render mode */
guint motion_events_per_actor : 1;/* set f
or enter/leave events */
guint motion_events_per_actor : 1;/* set for enter/leave events */
guint motion_frequency; /* Motion events per second */
gint num_reactives; /* Num of reactive actors */
@ -110,6 +123,9 @@ or enter/leave events */
gint fb_r_mask_used, fb_g_mask_used, fb_b_mask_used;
PangoClutterFontMap *font_map; /* Global font map */
GSList *input_devices; /* For extra input devices, i.e
MultiTouch */
};
#define CLUTTER_CONTEXT() (clutter_context_get_default ())

View File

@ -76,6 +76,7 @@ clutter_stage_egl_realize (ClutterActor *actor)
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (actor);
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (actor);
ClutterBackendEGL *backend_egl;
ClutterBackendX11 *backend_x11;
EGLConfig configs[2];
EGLint config_count;
EGLBoolean status;
@ -86,6 +87,7 @@ clutter_stage_egl_realize (ClutterActor *actor)
g_object_get (stage_x11->wrapper, "offscreen", &is_offscreen, NULL);
backend_egl = CLUTTER_BACKEND_EGL (clutter_get_default_backend ());
backend_x11 = CLUTTER_BACKEND_X11 (clutter_get_default_backend ());
if (G_LIKELY (!is_offscreen))
{
@ -168,16 +170,27 @@ clutter_stage_egl_realize (ClutterActor *actor)
WhitePixel (stage_x11->xdpy,
stage_x11->xscreen));
XSelectInput (stage_x11->xdpy, stage_x11->xwin,
StructureNotifyMask
| ExposureMask
/* FIXME: we may want to eplicity enable MotionMask */
| PointerMotionMask
| KeyPressMask
| KeyReleaseMask
| ButtonPressMask
| ButtonReleaseMask
| PropertyChangeMask);
if (clutter_x11_has_xinput())
{
XSelectInput (stage_x11->xdpy, stage_x11->xwin,
StructureNotifyMask |
FocusChangeMask |
ExposureMask |
PropertyChangeMask);
#ifdef USE_XINPUT
_clutter_x11_select_events (stage_x11->xwin);
#endif
}
else
XSelectInput (stage_x11->xdpy, stage_x11->xwin,
StructureNotifyMask |
FocusChangeMask |
ExposureMask |
/* FIXME: we may want to eplicity enable MotionMask */
PointerMotionMask |
KeyPressMask | KeyReleaseMask |
ButtonPressMask | ButtonReleaseMask |
PropertyChangeMask);
/* FIXME, do these in a clutterstage_x11_realise? */
clutter_stage_x11_fix_window_size (stage_x11);

View File

@ -213,10 +213,33 @@ static void
clutter_backend_egl_init (ClutterBackendEGL *backend_egl)
{
ClutterBackend *backend = CLUTTER_BACKEND (backend_egl);
ClutterMainContext *context;
int i;
clutter_backend_set_resolution (backend, 96.0);
clutter_backend_set_double_click_time (backend, 250);
clutter_backend_set_double_click_distance (backend, 5);
context = clutter_context_get_default ();
#define MAX_FINGERS 5
for (i=0; i<MAX_FINGERS; i++)
{
ClutterFruityFingerDevice *device;
device = g_new0 (ClutterFruityFingerDevice, 1);
context->input_devices = g_slist_append (context->input_devices, device);
device->device.id = i;
device->device.click_count = 0;
device->device.previous_time = 0;
device->device.previous_x = -1;
device->device.previous_y = -1;
device->device.previous_button_number = -1;
device->x = 0;
device->y = 0;
}
}
GType

View File

@ -33,6 +33,7 @@
#include <glib-object.h>
#include <clutter/clutter-backend.h>
#include <clutter/clutter-private.h>
G_BEGIN_DECLS
#define CLUTTER_TYPE_BACKEND_FRUITY (clutter_backend_egl_get_type ())
@ -44,7 +45,14 @@ G_BEGIN_DECLS
typedef struct _ClutterBackendEGL ClutterBackendEGL;
typedef struct _ClutterBackendEGLClass ClutterBackendEGLClass;
typedef struct _ClutterFruityFingerDevice ClutterFruityFingerDevice;
struct _ClutterFruityFingerDevice
{
ClutterInputDevice device;
int x, y;
gboolean is_down;
};
struct _ClutterBackendEGL
{
@ -64,6 +72,8 @@ struct _ClutterBackendEGL
/* event source */
GSource *event_source;
int num_fingers;
/*< private >*/
};

View File

@ -50,6 +50,191 @@ static CoreSurfaceBufferRef CreateSurface(int w, int h)
@implementation StageView
struct GSPathPoint {
char unk0;
char unk1;
short int status;
int unk2;
float x;
float y;
};
typedef struct {
int unk0;
int unk1;
int type;
int subtype;
float unk2;
float unk3;
float x;
float y;
int timestamp1;
int timestamp2;
int unk4;
int modifierFlags;
int unk5;
int unk6;
int mouseEvent;
short int dx;
short int fingerCount;
int unk7;
int unk8;
char unk9;
char numPoints;
short int unk10;
struct GSPathPoint points[10];
} MEvent;
- (void)doEvent:(GSEvent*)gs_event
{
ClutterBackendEGL *ba = CLUTTER_BACKEND_EGL (clutter_get_default_backend());
int i, j;
ClutterMainContext *context;
ClutterStage *stage = CLUTTER_STAGE_EGL(ba->stage)->wrapper;
int n_fingers = 0;
MEvent *event = (MEvent*)gs_event;
context = clutter_context_get_default ();
bool mapped[5] = {false, false, false, false, false}; /* an event has been mapped to this device */
int evs[5] = {0,0,0,0,0};
for (i = 0; i < event->fingerCount; i++)
{
bool found = false;
/* NSLog(@"IncomingEvent: %d, pos: %f, %f", i, event->points[i].x, event->points[i].y);*/
/* check if this finger maps to one of the existing devices */
for (j = 0; j < 5; j++)
{
ClutterFruityFingerDevice *dev;
if (mapped[j])
continue; /* we're already using device j */
dev = g_slist_nth_data (context->input_devices, j);
if (!dev->is_down)
continue; /* device isn't down we cannot really match against it */
int dist = ABS(event->points[i].x - dev->x) +
ABS(event->points[i].y - dev->y);
if (dist < 20)
{
found = true;
mapped[j] = true;
if (dist >= 1)
{
dev->x = event->points[i].x;
dev->y = event->points[i].y;
// MOUSEMOVE
/*NSLog(@"MouseMove: %d, pos: %d, %d", j, dev->x, dev->y);*/
evs[j] = 3;
}
break;
}
}
if (!found)
{
ClutterFruityFingerDevice *dev;
for (j = 0; j < 5 /*n_fingers*/; j++)
{
dev = g_slist_nth_data (context->input_devices, j);
if (!dev->is_down)
break;
}
dev->x = event->points[i].x;
dev->y = event->points[i].y;
dev->is_down = TRUE;
mapped[j] = true;
// MOUSEDOWN
/* NSLog(@"MouseDown: %d, pos: %d, %d", j, event->points[i].x, dev->x, dev->y); */
evs[j] = 2;
}
}
for (j = 0; j < 5; j++)
{
ClutterFruityFingerDevice *dev;
dev = g_slist_nth_data (context->input_devices, j);
if (dev->is_down && !mapped[j])
{
// MOUSEUP
/* NSLog(@"MouseUp: %d, pos: %d, %d", j, dev->x, dev->y); */
evs[j] = 1;
dev->is_down = FALSE;
}
}
/* Now I guess go through device list and deliver an event for each
* if valid and devliver if so...
*/
{
i = 0;
GSList *list_it;
for (list_it = context->input_devices;
list_it != NULL;
list_it = list_it->next)
{
ClutterFruityFingerDevice *dev = (ClutterFruityFingerDevice *)list_it->data;
if (evs[i] > 0)
{
ClutterEvent *cev;
if (evs[i] == 1)
{
cev = clutter_event_new (CLUTTER_BUTTON_RELEASE);
cev->button.device = (ClutterInputDevice *)dev;
cev->button.x = dev->x;
cev->button.y = dev->y;
cev->button.button = 1;
cev->button.time = clutter_get_timestamp () / 1000;
cev->any.stage = stage;
clutter_do_event (cev);
clutter_event_free (cev);
}
else if (evs[i] == 2)
{
cev = clutter_event_new (CLUTTER_BUTTON_PRESS);
cev->button.device = (ClutterInputDevice *)dev;
cev->button.x = dev->x;
cev->button.y = dev->y;
cev->button.button = 1;
cev->button.time = clutter_get_timestamp () / 1000;
cev->any.stage = stage;
clutter_do_event (cev);
clutter_event_free (cev);
}
else /* evs = 3, motion */
{
cev = clutter_event_new (CLUTTER_MOTION);
cev->motion.device = (ClutterInputDevice *)dev;
cev->motion.x = dev->x;
cev->motion.y = dev->y;
cev->motion.time = clutter_get_timestamp () / 1000;
cev->any.stage = stage;
clutter_do_event (cev);
clutter_event_free (cev);
}
}
i++;
}
}
}
#if 0 // old stylie
- (void) mouseDown:(GSEvent*)event
{
CGPoint location= GSEventGetLocationInWindow(event);
@ -106,6 +291,67 @@ static CoreSurfaceBufferRef CreateSurface(int w, int h)
clutter_do_event (cev);
clutter_event_free (cev);
}
#endif
/* New... */
- (void)gestureChanged:(GSEvent*)event {
/*NSLog(@"gestureChanged:");*/
[self doEvent: event];
}
- (void)gestureEnded:(GSEvent*)event {
/*NSLog(@"gestureEnded:");*/
[self doEvent: event];
}
- (void)gestureStarted:(GSEvent*)event {
/*NSLog(@"gestureStarted:");*/
[self doEvent: event];
}
- (void)mouseDown:(GSEvent*)event {
/*NSLog(@"mouseDown:");*/
[self doEvent: event];
}
- (void)mouseDragged:(GSEvent*)event {
/*NSLog(@"mouseDragged:");*/
[self doEvent: event];
}
- (void)mouseEntered:(GSEvent*)event {
/*NSLog(@"mouseEntered:");*/
[self doEvent: event];
}
- (void)mouseExited:(GSEvent*)event {
/*NSLog(@"mouseExited:");*/
[self doEvent: event];
}
- (void)mouseMoved:(GSEvent*)event {
/*NSLog(@"mouseMoved:");*/
[self doEvent: event];
}
- (void)mouseUp:(GSEvent*)event {
/*NSLog(@"mouseUp:");*/
[self doEvent: event];
}
- (void)view:(UIView *)view handleTapWithCount:(int)count event:(GSEvent *)event {
/*NSLog(@"handleTapWithCount: %d", count);*/
[self doEvent: event];
}
- (double)viewTouchPauseThreshold:(UIView *)view {
return 0.5;
}
- (BOOL)isFirstResponder {
return YES;
}
@end

View File

@ -112,6 +112,7 @@ clutter_stage_glx_realize (ClutterActor *actor)
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (actor);
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (actor);
ClutterBackendGLX *backend_glx;
ClutterBackendX11 *backend_x11;
gboolean is_offscreen;
CLUTTER_NOTE (MISC, "Realizing main stage");
@ -119,6 +120,7 @@ clutter_stage_glx_realize (ClutterActor *actor)
g_object_get (stage_x11->wrapper, "offscreen", &is_offscreen, NULL);
backend_glx = CLUTTER_BACKEND_GLX (clutter_get_default_backend ());
backend_x11 = CLUTTER_BACKEND_X11 (clutter_get_default_backend ());
if (G_LIKELY (!is_offscreen))
{
@ -178,16 +180,27 @@ clutter_stage_glx_realize (ClutterActor *actor)
mask, &xattr);
}
CLUTTER_NOTE (MISC, "XSelectInput");
XSelectInput (stage_x11->xdpy, stage_x11->xwin,
StructureNotifyMask |
FocusChangeMask |
ExposureMask |
/* FIXME: we may want to eplicity enable MotionMask */
PointerMotionMask |
KeyPressMask | KeyReleaseMask |
ButtonPressMask | ButtonReleaseMask |
PropertyChangeMask);
if (clutter_x11_has_xinput())
{
XSelectInput (stage_x11->xdpy, stage_x11->xwin,
StructureNotifyMask |
FocusChangeMask |
ExposureMask |
PropertyChangeMask);
#ifdef USE_XINPUT
_clutter_x11_select_events (stage_x11->xwin);
#endif
}
else
XSelectInput (stage_x11->xdpy, stage_x11->xwin,
StructureNotifyMask |
FocusChangeMask |
ExposureMask |
/* FIXME: we may want to eplicity enable MotionMask */
PointerMotionMask |
KeyPressMask | KeyReleaseMask |
ButtonPressMask | ButtonReleaseMask |
PropertyChangeMask);
/* no user resize.. */
clutter_stage_x11_fix_window_size (stage_x11);

View File

@ -38,6 +38,7 @@
#include "clutter-stage-x11.h"
#include "clutter-x11.h"
#include "../clutter-event.h"
#include "../clutter-main.h"
#include "../clutter-debug.h"
@ -47,6 +48,22 @@
G_DEFINE_TYPE (ClutterBackendX11, clutter_backend_x11, CLUTTER_TYPE_BACKEND);
struct _ClutterX11XInputDevice
{
ClutterInputDevice device;
#ifdef USE_XINPUT
XDevice *xdevice;
XEventClass xevent_list[5]; /* MAX 5 event types */
int num_events;
#endif
ClutterX11InputDeviceType type; /* FIXME: generic to ClutterInputDevice? */
};
#ifdef USE_XINPUT
void _clutter_x11_register_xinput ();
#endif
/* atoms; remember to add the code that assigns the atom value to
* the member of the ClutterBackendX11 structure if you add an
* atom name here. do not change the order!
@ -151,6 +168,10 @@ clutter_backend_x11_post_parse (ClutterBackend *backend,
clutter_backend_set_resolution (backend, dpi);
#ifdef USE_XINPUT
_clutter_x11_register_xinput ();
#endif
if (clutter_synchronise)
XSynchronize (backend_x11->xdpy, True);
@ -530,3 +551,259 @@ clutter_x11_remove_filter (ClutterX11FilterFunc func,
}
}
}
#ifdef USE_XINPUT
void
_clutter_x11_register_xinput ()
{
XDeviceInfo *xdevices = NULL;
XDeviceInfo *info = NULL;
XDevice *xdevice = NULL;
XInputClassInfo *xclass_info = NULL;
XExtensionVersion *ext;
gint num_devices = 0;
gint num_events = 0;
gint i = 0, j = 0;
ClutterBackendX11 *x11b;
ClutterX11XInputDevice *device = NULL;
ClutterMainContext *context;
if (!backend_singleton)
{
g_critical ("X11 backend has not been initialised");
return;
}
context = clutter_context_get_default ();
backend_singleton->have_xinput = TRUE;
ext = XGetExtensionVersion(backend_singleton->xdpy, INAME);
if (!ext || (ext == (XExtensionVersion*) NoSuchExtension))
{
backend_singleton->have_xinput = FALSE;
return;
}
x11b = backend_singleton;
xdevices = XListInputDevices (x11b->xdpy, &num_devices);
CLUTTER_NOTE (BACKEND, "%d XINPUT devices found", num_devices);
if (num_devices == 0)
{
backend_singleton->have_xinput = FALSE;
return;
}
for (i = 0; i < num_devices; i++)
{
num_events = 0;
info = xdevices + i;
CLUTTER_NOTE (BACKEND, "Considering %li with type %d",
info->id, info->use);
/* Only want 'raw' devices themselves not virtual ones */
if (info->use == IsXExtensionPointer ||
info->use == IsXExtensionKeyboard ||
info->use == IsXExtensionDevice)
{
/* Create the appropriate Clutter device */
device = g_new0 (ClutterX11XInputDevice, 1);
context->input_devices = g_slist_append (context->input_devices, device);
xdevice = XOpenDevice (x11b->xdpy, info->id);
device->device.id = info->id;
/* FIXME: some kind of general device_init() call should do below */
device->device.click_count = 0;
device->device.previous_time = 0;
device->device.previous_x = -1;
device->device.previous_y = -1;
device->device.previous_button_number = -1;
device->xdevice = xdevice;
device->num_events = 0;
switch (info->use)
{
case IsXExtensionPointer:
device->type = CLUTTER_X11_XINPUT_POINTER_DEVICE;
break;
case IsXExtensionKeyboard:
device->type = CLUTTER_X11_XINPUT_KEYBOARD_DEVICE;
break;
case IsXExtensionDevice:
device->type = CLUTTER_X11_XINPUT_EXTENSION_DEVICE;
break;
}
CLUTTER_NOTE (BACKEND, "Registering XINPUT device with XID: %li",
xdevice->device_id);
/* We must go through all the classes supported by this device and
* register the appropriate events we want. Each class only appears
* once. We need to store the types with the stage since they are
* created dynamically by the server. They are not device specific.
*/
for (j = 0; j < xdevice->num_classes; j++)
{
xclass_info = xdevice->classes + j;
switch (xclass_info->input_class)
{
case KeyClass:
DeviceKeyPress (xdevice,
x11b->event_types [CLUTTER_X11_XINPUT_KEY_PRESS_EVENT],
device->xevent_list [num_events]);
num_events++;
DeviceKeyRelease (xdevice,
x11b->event_types [CLUTTER_X11_XINPUT_KEY_RELEASE_EVENT],
device->xevent_list [num_events]);
num_events++;
break;
case ButtonClass:
DeviceButtonPress (xdevice,
x11b->event_types [CLUTTER_X11_XINPUT_BUTTON_PRESS_EVENT],
device->xevent_list [num_events]);
num_events++;
DeviceButtonRelease (xdevice,
x11b->event_types [CLUTTER_X11_XINPUT_BUTTON_RELEASE_EVENT],
device->xevent_list [num_events]);
num_events++;
break;
case ValuatorClass:
DeviceMotionNotify (xdevice,
x11b->event_types [CLUTTER_X11_XINPUT_MOTION_NOTIFY_EVENT],
device->xevent_list [num_events]);
num_events++;
break;
}
}
device->num_events = num_events;
}
}
XFree (xdevices);
}
void
_clutter_x11_unregister_xinput ()
{
}
void
_clutter_x11_select_events (Window xwin)
{
GSList *list_it;
ClutterX11XInputDevice *device = NULL;
ClutterMainContext *context;
context = clutter_context_get_default ();
if (!backend_singleton)
{
g_critical ("X11 backend has not been initialised");
return;
}
for (list_it = context->input_devices;
list_it != NULL;
list_it = list_it->next)
{
device = (ClutterX11XInputDevice *)list_it->data;
XSelectExtensionEvent (backend_singleton->xdpy,
xwin,
device->xevent_list,
device->num_events);
}
}
ClutterX11XInputDevice*
_clutter_x11_get_device_for_xid (XID id)
{
GSList *list_it;
ClutterX11XInputDevice *device = NULL;
ClutterMainContext *context;
context = clutter_context_get_default ();
if (!backend_singleton)
{
g_critical ("X11 backend has not been initialised");
return NULL;
}
for (list_it = context->input_devices;
list_it != NULL;
list_it = list_it->next)
{
device = (ClutterX11XInputDevice *)list_it->data;
if (device->xdevice->device_id == id)
return device;
}
return NULL;
}
#endif
/* FIXME: This nasty little func needs moving elsewhere.. */
GSList*
clutter_x11_get_input_devices (void)
{
ClutterMainContext *context;
#ifdef USE_XINPUT
if (!backend_singleton)
{
g_critical ("X11 backend has not been initialised");
return NULL;
}
context = clutter_context_get_default ();
return context->input_devices;
#else
return NULL;
#endif
}
ClutterX11InputDeviceType
clutter_x11_get_input_device_type (ClutterX11XInputDevice *device)
{
return device->type;
}
gboolean
clutter_x11_has_xinput (void)
{
#ifdef USE_XINPUT
if (!backend_singleton)
{
g_critical ("X11 backend has not been initialised");
return FALSE;
}
return backend_singleton->have_xinput;
#else
return FALSE;
#endif
}

View File

@ -28,6 +28,10 @@
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#ifdef USE_XINPUT
#include <X11/extensions/XInput.h>
#endif
#include "clutter-x11.h"
G_BEGIN_DECLS
@ -76,6 +80,12 @@ struct _ClutterBackendX11
Atom atom_XEMBED_INFO;
Atom atom_NET_WM_NAME;
Atom atom_UTF8_STRING;
#ifdef USE_XINPUT
int event_types[CLUTTER_X11_XINPUT_LAST_EVENT];
gboolean have_xinput;
#endif
};
struct _ClutterBackendX11Class
@ -111,6 +121,19 @@ clutter_backend_x11_add_options (ClutterBackend *backend,
ClutterFeatureFlags
clutter_backend_x11_get_features (ClutterBackend *backend);
#ifdef USE_XINPUT
void
_clutter_x11_register_xinput (void);
void
_clutter_x11_unregister_xinput (void);
ClutterX11XInputDevice *
_clutter_x11_get_device_for_xid (XID id);
#endif
void
_clutter_x11_select_events (Window xwin);
G_END_DECLS

View File

@ -41,6 +41,10 @@
#include <X11/Xatom.h>
#ifdef USE_XINPUT
#include <X11/extensions/XInput.h>
#endif
/* XEMBED protocol support for toolkit embedding */
#define XEMBED_MAPPED (1 << 0)
#define MAX_SUPPORTED_XEMBED_VERSION 1
@ -215,6 +219,7 @@ set_user_time (ClutterBackendX11 *backend_x11,
}
}
static void
translate_key_event (ClutterBackend *backend,
ClutterEvent *event,
@ -347,7 +352,7 @@ event_translate (ClutterBackend *backend,
ClutterStageX11 *stage_x11;
ClutterStage *stage;
ClutterStageWindow *impl;
gboolean res;
gboolean res, not_yet_handled = FALSE;
Window xwindow, stage_xwindow;
backend_x11 = CLUTTER_BACKEND_X11 (backend);
@ -389,7 +394,7 @@ event_translate (ClutterBackend *backend,
stage = clutter_x11_get_stage_from_window (xwindow);
if (stage == NULL)
return FALSE;
return FALSE;
impl = _clutter_stage_get_window (stage);
stage_x11 = CLUTTER_STAGE_X11 (impl);
@ -397,6 +402,7 @@ event_translate (ClutterBackend *backend,
event->any.stage = stage;
res = TRUE;
switch (xevent->type)
@ -522,83 +528,6 @@ event_translate (ClutterBackend *backend,
res = FALSE;
}
break;
case KeyPress:
event->type = CLUTTER_KEY_PRESS;
translate_key_event (backend, event, xevent);
set_user_time (backend_x11, &xwindow, xevent->xkey.time);
break;
case KeyRelease:
event->type = CLUTTER_KEY_RELEASE;
translate_key_event (backend, event, xevent);
break;
case ButtonPress:
switch (xevent->xbutton.button)
{
case 4: /* up */
case 5: /* down */
case 6: /* left */
case 7: /* right */
event->scroll.type = event->type = CLUTTER_SCROLL;
if (xevent->xbutton.button == 4)
event->scroll.direction = CLUTTER_SCROLL_UP;
else if (xevent->xbutton.button == 5)
event->scroll.direction = CLUTTER_SCROLL_DOWN;
else if (xevent->xbutton.button == 6)
event->scroll.direction = CLUTTER_SCROLL_LEFT;
else
event->scroll.direction = CLUTTER_SCROLL_RIGHT;
event->scroll.time = xevent->xbutton.time;
event->scroll.x = xevent->xbutton.x;
event->scroll.y = xevent->xbutton.y;
event->scroll.modifier_state = xevent->xbutton.state;
break;
default:
event->button.type = event->type = CLUTTER_BUTTON_PRESS;
event->button.time = xevent->xbutton.time;
event->button.x = xevent->xbutton.x;
event->button.y = xevent->xbutton.y;
event->button.modifier_state = xevent->xbutton.state;
event->button.button = xevent->xbutton.button;
break;
}
set_user_time (backend_x11, &xwindow, event->button.time);
break;
case ButtonRelease:
/* scroll events don't have a corresponding release */
if (xevent->xbutton.button == 4 ||
xevent->xbutton.button == 5 ||
xevent->xbutton.button == 6 ||
xevent->xbutton.button == 7)
{
res = FALSE;
break;
}
event->button.type = event->type = CLUTTER_BUTTON_RELEASE;
event->button.time = xevent->xbutton.time;
event->button.x = xevent->xbutton.x;
event->button.y = xevent->xbutton.y;
event->button.modifier_state = xevent->xbutton.state;
event->button.button = xevent->xbutton.button;
break;
case MotionNotify:
event->motion.type = event->type = CLUTTER_MOTION;
event->motion.time = xevent->xmotion.time;
event->motion.x = xevent->xmotion.x;
event->motion.y = xevent->xmotion.y;
event->motion.modifier_state = xevent->xmotion.state;
break;
case DestroyNotify:
CLUTTER_NOTE (EVENT, "destroy notify:\txid: %ld",
xevent->xdestroywindow.window);
@ -625,10 +554,244 @@ event_translate (ClutterBackend *backend,
default:
/* ignore every other event */
res = FALSE;
not_yet_handled = TRUE;
break;
}
/* Input device event handling.. */
if (not_yet_handled)
{
if (!clutter_x11_has_xinput ())
{
/* Regular X event */
switch (xevent->type)
{
case KeyPress:
event->type = CLUTTER_KEY_PRESS;
translate_key_event (backend, event, xevent);
set_user_time (backend_x11, &xwindow, xevent->xkey.time);
break;
case KeyRelease:
event->type = CLUTTER_KEY_RELEASE;
translate_key_event (backend, event, xevent);
break;
case ButtonPress:
switch (xevent->xbutton.button)
{
case 4: /* up */
case 5: /* down */
case 6: /* left */
case 7: /* right */
event->scroll.type = event->type = CLUTTER_SCROLL;
if (xevent->xbutton.button == 4)
event->scroll.direction = CLUTTER_SCROLL_UP;
else if (xevent->xbutton.button == 5)
event->scroll.direction = CLUTTER_SCROLL_DOWN;
else if (xevent->xbutton.button == 6)
event->scroll.direction = CLUTTER_SCROLL_LEFT;
else
event->scroll.direction = CLUTTER_SCROLL_RIGHT;
event->scroll.time = xevent->xbutton.time;
event->scroll.x = xevent->xbutton.x;
event->scroll.y = xevent->xbutton.y;
event->scroll.modifier_state = xevent->xbutton.state;
break;
default:
event->button.type = event->type = CLUTTER_BUTTON_PRESS;
event->button.time = xevent->xbutton.time;
event->button.x = xevent->xbutton.x;
event->button.y = xevent->xbutton.y;
event->button.modifier_state = xevent->xbutton.state;
event->button.button = xevent->xbutton.button;
break;
}
set_user_time (backend_x11, &xwindow, event->button.time);
break;
case ButtonRelease:
/* scroll events don't have a corresponding release */
if (xevent->xbutton.button == 4 ||
xevent->xbutton.button == 5 ||
xevent->xbutton.button == 6 ||
xevent->xbutton.button == 7)
{
res = FALSE;
break;
}
event->button.type = event->type = CLUTTER_BUTTON_RELEASE;
event->button.time = xevent->xbutton.time;
event->button.x = xevent->xbutton.x;
event->button.y = xevent->xbutton.y;
event->button.modifier_state = xevent->xbutton.state;
event->button.button = xevent->xbutton.button;
break;
case MotionNotify:
event->motion.type = event->type = CLUTTER_MOTION;
event->motion.time = xevent->xmotion.time;
event->motion.x = xevent->xmotion.x;
event->motion.y = xevent->xmotion.y;
event->motion.modifier_state = xevent->xmotion.state;
break;
default:
/* ignore every other event */
res = FALSE;
break;
}
}
else
{ /* XInput fun.. Needs clean up. */
#ifdef USE_XINPUT
int *ev_types = backend_x11->event_types;
CLUTTER_NOTE (EVENT, "XInput event type: %d", xevent->type);
if (xevent->type == ev_types [CLUTTER_X11_XINPUT_BUTTON_PRESS_EVENT])
{
XDeviceButtonEvent *xbev = (XDeviceButtonEvent *)xevent;
switch (xbev->button)
{
case 4:
case 5:
case 6:
case 7:
event->scroll.type = event->type = CLUTTER_SCROLL;
if (xbev->button == 4)
event->scroll.direction = CLUTTER_SCROLL_UP;
else if (xbev->button == 5)
event->scroll.direction = CLUTTER_SCROLL_DOWN;
else if (xbev->button == 6)
event->scroll.direction = CLUTTER_SCROLL_LEFT;
else
event->scroll.direction = CLUTTER_SCROLL_RIGHT;
event->scroll.time = xbev->time;
event->scroll.x = xbev->x;
event->scroll.y = xbev->y;
event->scroll.modifier_state = xbev->state;
event->scroll.device
= (ClutterInputDevice *)_clutter_x11_get_device_for_xid (xbev->deviceid);
break;
default:
event->button.type = event->type = CLUTTER_BUTTON_PRESS;
event->button.time = xbev->time;
event->button.x = xbev->x;
event->button.y = xbev->y;
event->button.modifier_state = xbev->state;
event->button.button = xbev->button;
event->button.device
= (ClutterInputDevice *)_clutter_x11_get_device_for_xid (xbev->deviceid);
break;
}
set_user_time (backend_x11, &xwindow, xbev->time);
CLUTTER_NOTE(EVENT, "XINPUT Button press event for %li %d %d",
xbev->deviceid, xbev->x, xbev->y);
}
else if (xevent->type
== ev_types[CLUTTER_X11_XINPUT_BUTTON_RELEASE_EVENT])
{
XDeviceButtonEvent *xbev = (XDeviceButtonEvent *)xevent;
/* scroll events don't have a corresponding release */
if (xbev->button == 4 ||
xbev->button == 5 ||
xbev->button == 6 ||
xbev->button == 7)
{
res = FALSE;
goto out;
}
event->button.type = event->type = CLUTTER_BUTTON_RELEASE;
event->button.time = xbev->time;
event->button.x = xbev->x;
event->button.y = xbev->y;
event->button.modifier_state = xbev->state;
event->button.button = xbev->button;
event->button.device
= (ClutterInputDevice *)_clutter_x11_get_device_for_xid (xbev->deviceid);
CLUTTER_NOTE(EVENT, "XINPUT Button release event for %li %d %d",
xbev->deviceid, xbev->x, xbev->y);
}
else if (xevent->type
== ev_types [CLUTTER_X11_XINPUT_MOTION_NOTIFY_EVENT])
{
XDeviceMotionEvent *xmev = (XDeviceMotionEvent *)xevent;
event->motion.type = event->type = CLUTTER_MOTION;
event->motion.time = xmev->time;
event->motion.x = xmev->x;
event->motion.y = xmev->y;
event->motion.modifier_state = xmev->state;
event->motion.device
= (ClutterInputDevice *) _clutter_x11_get_device_for_xid (xmev->deviceid);
CLUTTER_NOTE(EVENT, "XINPUT Motion event for %li %d %d",
xmev->deviceid,
xmev->x,
xmev->y);
}
else if (xevent->type
== ev_types [CLUTTER_X11_XINPUT_KEY_PRESS_EVENT])
{
XDeviceKeyEvent *xkev = (XDeviceKeyEvent *)xevent;
event->key.type = CLUTTER_KEY_PRESS;
event->key.time = xkev->time;
event->key.modifier_state = (ClutterModifierType) xkev->state;
event->key.hardware_keycode = xkev->keycode;
/* Note key events have no device field */
/* FIXME: We need to handle other modifiers rather than
just shift */
event->key.keyval =
XKeycodeToKeysym (xevent->xany.display,
xkev->keycode,
(event->key.modifier_state
& CLUTTER_SHIFT_MASK) ? 1 : 0);
set_user_time (backend_x11, &xwindow, xkev->time);
}
else if (xevent->type
== ev_types [CLUTTER_X11_XINPUT_KEY_RELEASE_EVENT])
{
XDeviceKeyEvent *xkev = (XDeviceKeyEvent *)xevent;
event->key.type = CLUTTER_KEY_RELEASE;
event->key.time = xkev->time;
event->key.modifier_state = (ClutterModifierType) xkev->state;
event->key.hardware_keycode = xkev->keycode;
/* FIXME: We need to handle other modifiers rather than
just shift */
event->key.keyval =
XKeycodeToKeysym (xevent->xany.display,
xkev->keycode,
(event->key.modifier_state
& CLUTTER_SHIFT_MASK) ? 1 : 0);
}
else
#endif
{
CLUTTER_NOTE (EVENT, "Uknown Event");
res = FALSE;
}
}
}
out:
return res;
}

View File

@ -63,6 +63,11 @@ struct _ClutterStageX11
ClutterBackendX11 *backend;
ClutterStageState state;
#ifdef USE_XINPUT
int event_types[CLUTTER_X11_XINPUT_LAST_EVENT];
GList *devices;
#endif
ClutterStage *wrapper;
};
@ -79,6 +84,8 @@ void clutter_stage_x11_set_wm_protocols (ClutterStageX11 *stage_x11);
void clutter_stage_x11_map (ClutterStageX11 *stage_x11);
void clutter_stage_x11_unmap (ClutterStageX11 *stage_x11);
GList *clutter_stage_x11_get_input_devices (ClutterStageX11 *stage_x11);
G_END_DECLS
#endif /* __CLUTTER_STAGE_H__ */

View File

@ -64,6 +64,23 @@ typedef enum {
CLUTTER_X11_FILTER_REMOVE
} ClutterX11FilterReturn;
typedef enum {
CLUTTER_X11_XINPUT_KEY_PRESS_EVENT = 0,
CLUTTER_X11_XINPUT_KEY_RELEASE_EVENT,
CLUTTER_X11_XINPUT_BUTTON_PRESS_EVENT,
CLUTTER_X11_XINPUT_BUTTON_RELEASE_EVENT,
CLUTTER_X11_XINPUT_MOTION_NOTIFY_EVENT,
CLUTTER_X11_XINPUT_LAST_EVENT
} ClutterX11XInputEventTypes;
typedef enum {
CLUTTER_X11_XINPUT_POINTER_DEVICE,
CLUTTER_X11_XINPUT_KEYBOARD_DEVICE,
CLUTTER_X11_XINPUT_EXTENSION_DEVICE
} ClutterX11InputDeviceType;
typedef struct _ClutterX11XInputDevice ClutterX11XInputDevice;
/**
* ClutterX11FilterFunc:
* @xev: Native X11 event structure
@ -104,6 +121,16 @@ void clutter_x11_disable_event_retrieval (void);
ClutterStage *clutter_x11_get_stage_from_window (Window win);
GSList*
clutter_x11_get_input_devices (void);
ClutterX11InputDeviceType
clutter_x11_get_input_device_type (ClutterX11XInputDevice *device);
gboolean
clutter_x11_has_xinput (void);
G_END_DECLS
#endif /* __CLUTTER_X11_H__ */

View File

@ -225,6 +225,22 @@ fi
AM_CONDITIONAL(X11_TESTS, test "x$x11_tests" != "xno")
xinput=no
AC_ARG_ENABLE(xinput,
AS_HELP_STRING([--enable-xinput],
["Use the XINPUT X extension"]),[
if test "x$enableval" = "xyes" ; then
PKG_CHECK_MODULES(XINPUT,[xi],
xinput=yes,
xinput=no)
fi],
[xinput=yes])
if test "x$xinput" = "xyes"; then
AC_DEFINE(USE_XINPUT, 1, Use the XINPUT X extension)
X11_LIBS="$X11_LIBS -lXi"
fi
clutter_gl_header=""
use_gles2_wrapper="no"
@ -657,6 +673,9 @@ echo ""
echo " prefix: ${prefix}"
echo ""
echo " Flavour: ${clutterbackend}/${CLUTTER_COGL}"
if test "x$clutterbackend" = "xeglx" || test "x$clutterbackend" = "xglx"; then
echo " XInput: ${xinput}"
fi
echo " GL Headers: ${CLUTTER_GL_HEADER}"
echo " Image backend: ${imagebackend}"
echo " Target library: ${clutterbackendlib}"

View File

@ -18,6 +18,7 @@ noinst_PROGRAMS = test-textures test-events test-offscreen test-scale \
if X11_TESTS
noinst_PROGRAMS += test-pixmap
noinst_PROGRAMS += test-devices
endif
INCLUDES = -I$(top_srcdir)/ -I$(top_srcdir)/clutter -I$(top_builddir)/clutter
@ -70,5 +71,6 @@ test_texture_quality_SOURCES = test-texture-quality.c
test_entry_auto_SOURCES = test-entry-auto.c
test_layout_SOURCES = test-layout.c
test_invariants_SOURCES = test-invariants.c
test_devices_SOURCES = test-devices.c
EXTRA_DIST = redhand.png test-script.json

76
tests/test-devices.c Normal file
View File

@ -0,0 +1,76 @@
#include <clutter/clutter.h>
#include <clutter/x11/clutter-x11.h>
typedef struct {
GHashTable *devices;
} TestDevicesApp;
static gboolean
stage_motion_event_cb (ClutterActor *actor,
ClutterEvent *event,
gpointer userdata)
{
TestDevicesApp *app = (TestDevicesApp *)userdata;
ClutterActor *hand = NULL;
ClutterMotionEvent *mev = (ClutterMotionEvent *)event;
hand = g_hash_table_lookup (app->devices, mev->device);
clutter_actor_set_position (hand, mev->x, mev->y);
}
int
main (int argc, char **argv)
{
ClutterActor *stage = NULL;
GSList *stage_devices = NULL;
TestDevicesApp *app = NULL;
ClutterColor stage_color = { 0x61, 0x64, 0x8c, 0xff };
clutter_init (&argc, &argv);
app = g_new0 (TestDevicesApp, 1);
app->devices = g_hash_table_new (g_direct_hash, g_direct_equal) ;
stage = clutter_stage_get_default ();
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
//clutter_stage_fullscreen (CLUTTER_STAGE (stage));
g_signal_connect (stage,
"motion-event",
G_CALLBACK(stage_motion_event_cb),
app);
clutter_actor_show_all (stage);
stage_devices = clutter_x11_get_input_devices ();
do
{
if (stage_devices)
{
ClutterX11XInputDevice *device = NULL;
ClutterActor *hand = NULL;
device = (ClutterX11XInputDevice *)stage_devices->data;
if (clutter_x11_get_input_device_type (device)
== CLUTTER_X11_XINPUT_POINTER_DEVICE)
{
g_debug("got a pointer device...\n");
hand = clutter_texture_new_from_file ("redhand.png", NULL);
g_hash_table_insert (app->devices, device, hand);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), hand);
}
}
} while ((stage_devices = stage_devices->next) != NULL);
clutter_main ();
return 0;
}