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:
parent
920687a470
commit
b241481586
21 changed files with 1257 additions and 128 deletions
25
ChangeLog
25
ChangeLog
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 ())
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 >*/
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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__ */
|
||||
|
|
19
configure.ac
19
configure.ac
|
@ -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}"
|
||||
|
|
|
@ -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
76
tests/test-devices.c
Normal 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;
|
||||
}
|
Loading…
Reference in a new issue