mirror of
https://github.com/brl/mutter.git
synced 2024-12-24 12:02:04 +00:00
Merge branch 'device-manager'
* device-manager: (37 commits) x11: Re-enable XI1 extension keyboards x11: Always handle core device events before XI events docs: Documentation fixes for DeviceManager device-manager: Fix the signals definition docs: Add sections for InputDevice and DeviceManager docs: Add clutter_input_device_get_device_name() tests: Print out the device details on motion Always register core devices device: Remove unused is_default member win32: Experimental implementation of device support tests: Print the device name, as well as its Id x11: Fill out the :name property of the InputDevices device: Add the :name property to InputDevice x11: Store core devices on the X11 Backend singleton device: Unset the cursor actor when leaving the stage device: Add pointer actor getter x11: Discard the LeaveNotify for off-stage ButtonRelease device: Do not overwrite the stage for an InputDevice event: Off-stage button releases have a click count of 1 event: Scroll events do not have click count ...
This commit is contained in:
commit
5f1c8a17e4
@ -82,8 +82,9 @@ source_h = \
|
||||
$(srcdir)/clutter-child-meta.h \
|
||||
$(srcdir)/clutter-clone.h \
|
||||
$(srcdir)/clutter-color.h \
|
||||
$(srcdir)/clutter-container.h \
|
||||
$(srcdir)/clutter-deprecated.h \
|
||||
$(srcdir)/clutter-container.h \
|
||||
$(srcdir)/clutter-deprecated.h \
|
||||
$(srcdir)/clutter-device-manager.h \
|
||||
$(srcdir)/clutter-event.h \
|
||||
$(srcdir)/clutter-feature.h \
|
||||
$(srcdir)/clutter-fixed.h \
|
||||
@ -91,6 +92,7 @@ source_h = \
|
||||
$(srcdir)/clutter-flow-layout.h \
|
||||
$(srcdir)/clutter-frame-source.h \
|
||||
$(srcdir)/clutter-group.h \
|
||||
$(srcdir)/clutter-input-device.h \
|
||||
$(srcdir)/clutter-interval.h \
|
||||
$(srcdir)/clutter-keysyms.h \
|
||||
$(srcdir)/clutter-layout-manager.h \
|
||||
@ -154,6 +156,7 @@ source_c = \
|
||||
$(srcdir)/clutter-clone.c \
|
||||
$(srcdir)/clutter-color.c \
|
||||
$(srcdir)/clutter-container.c \
|
||||
$(srcdir)/clutter-device-manager.c \
|
||||
clutter-enum-types.c \
|
||||
$(srcdir)/clutter-event.c \
|
||||
$(srcdir)/clutter-feature.c \
|
||||
@ -162,6 +165,7 @@ source_c = \
|
||||
$(srcdir)/clutter-flow-layout.c \
|
||||
$(srcdir)/clutter-frame-source.c \
|
||||
$(srcdir)/clutter-group.c \
|
||||
$(srcdir)/clutter-input-device.c \
|
||||
$(srcdir)/clutter-interval.c \
|
||||
$(srcdir)/clutter-layout-manager.c \
|
||||
$(srcdir)/clutter-layout-meta.c \
|
||||
|
@ -308,6 +308,7 @@ struct _ClutterActorPrivate
|
||||
guint clip_to_allocation : 1;
|
||||
guint enable_model_view_transform : 1;
|
||||
guint enable_paint_unmapped : 1;
|
||||
guint has_pointer : 1;
|
||||
|
||||
gfloat clip[4];
|
||||
|
||||
@ -429,7 +430,8 @@ enum
|
||||
|
||||
PROP_SHOW_ON_SET_PARENT,
|
||||
|
||||
PROP_TEXT_DIRECTION
|
||||
PROP_TEXT_DIRECTION,
|
||||
PROP_HAS_POINTER
|
||||
};
|
||||
|
||||
enum
|
||||
@ -3031,6 +3033,10 @@ clutter_actor_get_property (GObject *object,
|
||||
g_value_set_enum (value, priv->text_direction);
|
||||
break;
|
||||
|
||||
case PROP_HAS_POINTER:
|
||||
g_value_set_boolean (value, priv->has_pointer);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@ -3858,6 +3864,24 @@ clutter_actor_class_init (ClutterActorClass *klass)
|
||||
PROP_TEXT_DIRECTION,
|
||||
pspec);
|
||||
|
||||
/**
|
||||
* ClutterActor:has-pointer:
|
||||
*
|
||||
* Whether the actor contains the pointer of a #ClutterInputDevice
|
||||
* or not.
|
||||
*
|
||||
* Since: 1.2
|
||||
*/
|
||||
pspec = g_param_spec_boolean ("has-pointer",
|
||||
"Has Pointer",
|
||||
"Whether the actor contains the pointer "
|
||||
"of an input device",
|
||||
FALSE,
|
||||
CLUTTER_PARAM_READABLE);
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_HAS_POINTER,
|
||||
pspec);
|
||||
|
||||
/**
|
||||
* ClutterActor::destroy:
|
||||
* @actor: the object which received the signal
|
||||
@ -9638,6 +9662,20 @@ clutter_actor_set_text_direction (ClutterActor *self,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_actor_set_has_pointer (ClutterActor *self,
|
||||
gboolean has_pointer)
|
||||
{
|
||||
ClutterActorPrivate *priv = self->priv;
|
||||
|
||||
if (priv->has_pointer != has_pointer)
|
||||
{
|
||||
priv->has_pointer = has_pointer;
|
||||
|
||||
g_object_notify (G_OBJECT (self), "has-pointer");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_actor_get_text_direction:
|
||||
* @self: a #ClutterActor
|
||||
@ -9748,3 +9786,23 @@ clutter_actor_pop_internal (void)
|
||||
|
||||
ctx->internal_child -= 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_actor_has_pointer:
|
||||
* @self: a #ClutterActor
|
||||
*
|
||||
* Checks whether an actor contains the the pointer of a
|
||||
* #ClutterInputDevice
|
||||
*
|
||||
* Return value: %TRUE if the actor contains the pointer, and
|
||||
* %FALSE otherwise
|
||||
*
|
||||
* Since: 1.2
|
||||
*/
|
||||
gboolean
|
||||
clutter_actor_has_pointer (ClutterActor *self)
|
||||
{
|
||||
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
|
||||
|
||||
return self->priv->has_pointer;
|
||||
}
|
||||
|
@ -532,6 +532,7 @@ void clutter_actor_get_transformation_matrix (ClutterActor *self
|
||||
CoglMatrix *matrix);
|
||||
|
||||
gboolean clutter_actor_is_in_clone_paint (ClutterActor *self);
|
||||
gboolean clutter_actor_has_pointer (ClutterActor *self);
|
||||
|
||||
void clutter_actor_set_text_direction (ClutterActor *self,
|
||||
ClutterTextDirection text_dir);
|
||||
|
321
clutter/clutter-device-manager.c
Normal file
321
clutter/clutter-device-manager.c
Normal file
@ -0,0 +1,321 @@
|
||||
/*
|
||||
* Clutter.
|
||||
*
|
||||
* An OpenGL based 'interactive canvas' library.
|
||||
*
|
||||
* Copyright (C) 2009 Intel Corp.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Emmanuele Bassi <ebassi@linux.intel.com>
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:clutter-device-manager
|
||||
* @short_description: Maintains the list of input devices
|
||||
*
|
||||
* #ClutterDeviceManager is a singleton object, owned by Clutter, which
|
||||
* maintains the list of #ClutterInputDevice<!-- -->s.
|
||||
*
|
||||
* Depending on the backend used by Clutter it is possible to use the
|
||||
* #ClutterDeviceManager::device-added and
|
||||
* #ClutterDeviceManager::device-removed to monitor addition and removal
|
||||
* of devices.
|
||||
*
|
||||
* #ClutterDeviceManager is available since Clutter 1.2
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "clutter-debug.h"
|
||||
#include "clutter-device-manager.h"
|
||||
#include "clutter-enum-types.h"
|
||||
#include "clutter-marshal.h"
|
||||
#include "clutter-private.h"
|
||||
|
||||
#define CLUTTER_DEVICE_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_DEVICE_MANAGER, ClutterDeviceManagerClass))
|
||||
#define CLUTTER_IS_DEVICE_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_DEVICE_MANAGER))
|
||||
#define CLUTTER_DEVICE_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_DEVICE_MANAGER, ClutterDeviceManagerClass))
|
||||
|
||||
typedef struct _ClutterDeviceManagerClass ClutterDeviceManagerClass;
|
||||
|
||||
struct _ClutterDeviceManagerClass
|
||||
{
|
||||
GObjectClass parent_instance;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
DEVICE_ADDED,
|
||||
DEVICE_REMOVED,
|
||||
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static ClutterDeviceManager *default_manager = NULL;
|
||||
|
||||
static guint manager_signals[LAST_SIGNAL] = { 0, };
|
||||
|
||||
G_DEFINE_TYPE (ClutterDeviceManager, clutter_device_manager, G_TYPE_OBJECT);
|
||||
|
||||
static void
|
||||
clutter_device_manager_class_init (ClutterDeviceManagerClass *klass)
|
||||
{
|
||||
/**
|
||||
* ClutterDeviceManager::device-added:
|
||||
* @manager: the #ClutterDeviceManager that emitted the signal
|
||||
* @device: the newly added #ClutterInputDevice
|
||||
*
|
||||
* The ::device-added signal is emitted each time a device has been
|
||||
* added to the #ClutterDeviceManager
|
||||
*
|
||||
* Since: 1.2
|
||||
*/
|
||||
manager_signals[DEVICE_ADDED] =
|
||||
g_signal_new (I_("device-added"),
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL,
|
||||
clutter_marshal_VOID__OBJECT,
|
||||
G_TYPE_NONE, 1,
|
||||
CLUTTER_TYPE_INPUT_DEVICE);
|
||||
|
||||
/**
|
||||
* ClutterDeviceManager::device-removed:
|
||||
* @manager: the #ClutterDeviceManager that emitted the signal
|
||||
* @device: the removed #ClutterInputDevice
|
||||
*
|
||||
* The ::device-removed signal is emitted each time a device has been
|
||||
* removed from the #ClutterDeviceManager
|
||||
*
|
||||
* Since: 1.2
|
||||
*/
|
||||
manager_signals[DEVICE_REMOVED] =
|
||||
g_signal_new (I_("device-removed"),
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL,
|
||||
clutter_marshal_VOID__OBJECT,
|
||||
G_TYPE_NONE, 1,
|
||||
CLUTTER_TYPE_INPUT_DEVICE);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_device_manager_init (ClutterDeviceManager *self)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_device_manager_get_default:
|
||||
*
|
||||
* Retrieves the device manager singleton
|
||||
*
|
||||
* Return value: (transfer none): the #ClutterDeviceManager singleton.
|
||||
* The returned instance is owned by Clutter and it should not be
|
||||
* modified or freed
|
||||
*
|
||||
* Since: 1.2
|
||||
*/
|
||||
ClutterDeviceManager *
|
||||
clutter_device_manager_get_default (void)
|
||||
{
|
||||
if (G_UNLIKELY (default_manager == NULL))
|
||||
default_manager = g_object_new (CLUTTER_TYPE_DEVICE_MANAGER, NULL);
|
||||
|
||||
return default_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_device_manager_list_devices:
|
||||
* @device_manager: a #ClutterDeviceManager
|
||||
*
|
||||
* Lists all currently registered input devices
|
||||
*
|
||||
* Return value: (transfer container) (element-type ClutterInputDevice):
|
||||
* a newly allocated list of #ClutterInputDevice objects. Use
|
||||
* g_slist_free() to deallocate it when done
|
||||
*
|
||||
* Since: 1.2
|
||||
*/
|
||||
GSList *
|
||||
clutter_device_manager_list_devices (ClutterDeviceManager *device_manager)
|
||||
{
|
||||
g_return_val_if_fail (CLUTTER_IS_DEVICE_MANAGER (device_manager), NULL);
|
||||
|
||||
return g_slist_copy (device_manager->devices);
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_device_manager_peek_devices:
|
||||
* @device_manager: a #ClutterDeviceManager
|
||||
*
|
||||
* Lists all currently registered input devices
|
||||
*
|
||||
* Return value: (transfer none) (element-type ClutterInputDevice):
|
||||
* a pointer to the internal list of #ClutterInputDevice objects. The
|
||||
* returned list is owned by the #ClutterDeviceManager and should never
|
||||
* be modified or freed
|
||||
*
|
||||
* Since: 1.2
|
||||
*/
|
||||
const GSList *
|
||||
clutter_device_manager_peek_devices (ClutterDeviceManager *device_manager)
|
||||
{
|
||||
g_return_val_if_fail (CLUTTER_IS_DEVICE_MANAGER (device_manager), NULL);
|
||||
|
||||
return device_manager->devices;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_device_manager_get_device:
|
||||
* @device_manager: a #ClutterDeviceManager
|
||||
* @device_id: the integer id of a device
|
||||
*
|
||||
* Retrieves the #ClutterInputDevice with the given @device_id
|
||||
*
|
||||
* Return value: (transfer none): a #ClutterInputDevice or %NULL. The
|
||||
* returned device is owned by the #ClutterDeviceManager and should
|
||||
* never be modified or freed
|
||||
*
|
||||
* Since: 1.2
|
||||
*/
|
||||
ClutterInputDevice *
|
||||
clutter_device_manager_get_device (ClutterDeviceManager *device_manager,
|
||||
gint device_id)
|
||||
{
|
||||
GSList *l;
|
||||
|
||||
g_return_val_if_fail (CLUTTER_IS_DEVICE_MANAGER (device_manager), NULL);
|
||||
|
||||
for (l = device_manager->devices; l != NULL; l = l->next)
|
||||
{
|
||||
ClutterInputDevice *device = l->data;
|
||||
|
||||
if (device->id == device_id)
|
||||
return device;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gint
|
||||
input_device_cmp (gconstpointer a,
|
||||
gconstpointer b)
|
||||
{
|
||||
const ClutterInputDevice *device_a = a;
|
||||
const ClutterInputDevice *device_b = b;
|
||||
|
||||
if (device_a->id < device_b->id)
|
||||
return -1;
|
||||
|
||||
if (device_a->id > device_b->id)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* _clutter_device_manager_add_device:
|
||||
* @device_manager: a #ClutterDeviceManager
|
||||
* @device: a #ClutterInputDevice
|
||||
*
|
||||
* Adds @device to the list of #ClutterInputDevice<!-- -->s maintained
|
||||
* by @device_manager
|
||||
*
|
||||
* The reference count of @device is not increased
|
||||
*
|
||||
* The #ClutterDeviceManager::device-added signal is emitted after
|
||||
* adding @device to the list
|
||||
*/
|
||||
void
|
||||
_clutter_device_manager_add_device (ClutterDeviceManager *device_manager,
|
||||
ClutterInputDevice *device)
|
||||
{
|
||||
g_return_if_fail (CLUTTER_IS_DEVICE_MANAGER (device_manager));
|
||||
|
||||
device_manager->devices = g_slist_insert_sorted (device_manager->devices,
|
||||
device,
|
||||
input_device_cmp);
|
||||
|
||||
g_signal_emit (device_manager, manager_signals[DEVICE_ADDED], 0, device);
|
||||
}
|
||||
|
||||
/*
|
||||
* _clutter_device_manager_remove_device:
|
||||
* @device_manager: a #ClutterDeviceManager
|
||||
* @device: a #ClutterInputDevice
|
||||
*
|
||||
* Removes @device from the list of #ClutterInputDevice<!-- -->s
|
||||
* maintained by @device_manager
|
||||
*
|
||||
* The reference count of @device is not decreased
|
||||
*
|
||||
* The #ClutterDeviceManager::device-removed signal is emitted after
|
||||
* removing @device from the list
|
||||
*/
|
||||
void
|
||||
_clutter_device_manager_remove_device (ClutterDeviceManager *device_manager,
|
||||
ClutterInputDevice *device)
|
||||
{
|
||||
g_return_if_fail (CLUTTER_IS_DEVICE_MANAGER (device_manager));
|
||||
|
||||
if (g_slist_find (device_manager->devices, device) == NULL)
|
||||
return;
|
||||
|
||||
device_manager->devices = g_slist_remove (device_manager->devices, device);
|
||||
|
||||
g_signal_emit (device_manager, manager_signals[DEVICE_REMOVED], 0, device);
|
||||
}
|
||||
|
||||
/*
|
||||
* _clutter_device_manager_update_devices:
|
||||
* @device_manager: a #ClutterDeviceManager
|
||||
*
|
||||
* Updates every #ClutterInputDevice handled by @device_manager
|
||||
* by performing a pick paint at the coordinates of each pointer
|
||||
* device
|
||||
*/
|
||||
void
|
||||
_clutter_device_manager_update_devices (ClutterDeviceManager *device_manager)
|
||||
{
|
||||
GSList *d;
|
||||
|
||||
/* the user disabled motion events delivery on actors; we
|
||||
* don't perform any picking since the source of the events
|
||||
* will always be set to be the stage
|
||||
*/
|
||||
if (!clutter_get_motion_events_enabled ())
|
||||
return;
|
||||
|
||||
for (d = device_manager->devices; d != NULL; d = d->next)
|
||||
{
|
||||
ClutterInputDevice *device = d->data;
|
||||
ClutterInputDeviceType device_type;
|
||||
|
||||
/* we only care about pointer devices */
|
||||
device_type = clutter_input_device_get_device_type (device);
|
||||
if (device_type != CLUTTER_POINTER_DEVICE)
|
||||
continue;
|
||||
|
||||
/* out of stage */
|
||||
if (device->stage == NULL)
|
||||
continue;
|
||||
|
||||
_clutter_input_device_update (device);
|
||||
}
|
||||
}
|
59
clutter/clutter-device-manager.h
Normal file
59
clutter/clutter-device-manager.h
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Clutter.
|
||||
*
|
||||
* An OpenGL based 'interactive canvas' library.
|
||||
*
|
||||
* Copyright (C) 2009 Intel Corp.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Emmanuele Bassi <ebassi@linux.intel.com>
|
||||
*/
|
||||
|
||||
#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
|
||||
#error "Only <clutter/clutter.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#ifndef __CLUTTER_DEVICE_MANAGER_H__
|
||||
#define __CLUTTER_DEVICE_MANAGER_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <clutter/clutter-event.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define CLUTTER_TYPE_DEVICE_MANAGER (clutter_device_manager_get_type ())
|
||||
#define CLUTTER_DEVICE_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_DEVICE_MANAGER, ClutterDeviceManager))
|
||||
#define CLUTTER_IS_DEVICE_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_DEVICE_MANAGER))
|
||||
|
||||
/**
|
||||
* ClutterDeviceManager:
|
||||
*
|
||||
* The #ClutterDeviceManager structure contains only
|
||||
* private data
|
||||
*/
|
||||
typedef struct _ClutterDeviceManager ClutterDeviceManager;
|
||||
|
||||
GType clutter_device_manager_get_type (void) G_GNUC_CONST;
|
||||
|
||||
ClutterDeviceManager *clutter_device_manager_get_default (void);
|
||||
GSList * clutter_device_manager_list_devices (ClutterDeviceManager *device_manager);
|
||||
const GSList * clutter_device_manager_peek_devices (ClutterDeviceManager *device_manager);
|
||||
|
||||
ClutterInputDevice * clutter_device_manager_get_device (ClutterDeviceManager *device_manager,
|
||||
gint device_id);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __CLUTTER_DEVICE_MANAGER_H__ */
|
@ -787,39 +787,3 @@ clutter_get_current_event (void)
|
||||
|
||||
return context->current_event;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_input_device_get_device_type:
|
||||
* @device: a #ClutterInputDevice
|
||||
*
|
||||
* Retrieves the type of @device
|
||||
*
|
||||
* Return value: the type of the device
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
ClutterInputDeviceType
|
||||
clutter_input_device_get_device_type (ClutterInputDevice *device)
|
||||
{
|
||||
g_return_val_if_fail (device != NULL, CLUTTER_POINTER_DEVICE);
|
||||
|
||||
return device->device_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_input_device_get_device_id:
|
||||
* @device: a #ClutterInputDevice
|
||||
*
|
||||
* Retrieves the unique identifier of @device
|
||||
*
|
||||
* Return value: the identifier of the device
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
gint
|
||||
clutter_input_device_get_device_id (ClutterInputDevice *device)
|
||||
{
|
||||
g_return_val_if_fail (device != NULL, -1);
|
||||
|
||||
return device->id;
|
||||
}
|
||||
|
@ -29,6 +29,7 @@
|
||||
#define __CLUTTER_EVENT_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <clutter/clutter-input-device.h>
|
||||
#include <clutter/clutter-types.h>
|
||||
|
||||
#define CLUTTER_TYPE_EVENT (clutter_event_get_type ())
|
||||
@ -201,37 +202,6 @@ typedef struct _ClutterScrollEvent ClutterScrollEvent;
|
||||
typedef struct _ClutterStageStateEvent ClutterStageStateEvent;
|
||||
typedef struct _ClutterCrossingEvent ClutterCrossingEvent;
|
||||
|
||||
/**
|
||||
* ClutterInputDevice:
|
||||
*
|
||||
* Generic representation of an input device. The
|
||||
* actual contents of this structure depend on the
|
||||
* backend used.
|
||||
*/
|
||||
typedef struct _ClutterInputDevice ClutterInputDevice;
|
||||
|
||||
/**
|
||||
* ClutterInputDeviceType:
|
||||
* @CLUTTER_POINTER_DEVICE: A pointer device
|
||||
* @CLUTTER_KEYBOARD_DEVICE: A keyboard device
|
||||
* @CLUTTER_EXTENSION_DEVICE: A generic extension device
|
||||
* @CLUTTER_N_DEVICE_TYPES: The number of device types
|
||||
*
|
||||
* The types of input devices available.
|
||||
*
|
||||
* The #ClutterInputDeviceType enumeration can be extended at later
|
||||
* date; not every platform supports every input device type.
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
typedef enum {
|
||||
CLUTTER_POINTER_DEVICE,
|
||||
CLUTTER_KEYBOARD_DEVICE,
|
||||
CLUTTER_EXTENSION_DEVICE,
|
||||
|
||||
CLUTTER_N_DEVICE_TYPES
|
||||
} ClutterInputDeviceType;
|
||||
|
||||
/**
|
||||
* ClutterAnyEvent:
|
||||
* @type: event type
|
||||
@ -509,9 +479,6 @@ guint32 clutter_keysym_to_unicode (guint k
|
||||
guint32 clutter_get_current_event_time (void);
|
||||
G_CONST_RETURN ClutterEvent *clutter_get_current_event (void);
|
||||
|
||||
ClutterInputDeviceType clutter_input_device_get_device_type (ClutterInputDevice *device);
|
||||
gint clutter_input_device_get_device_id (ClutterInputDevice *device);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __CLUTTER_EVENT_H__ */
|
||||
|
524
clutter/clutter-input-device.c
Normal file
524
clutter/clutter-input-device.c
Normal file
@ -0,0 +1,524 @@
|
||||
/*
|
||||
* Clutter.
|
||||
*
|
||||
* An OpenGL based 'interactive canvas' library.
|
||||
*
|
||||
* Copyright (C) 2009 Intel Corp.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Emmanuele Bassi <ebassi@linux.intel.com>
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:clutter-input-device
|
||||
* @short_description: An input device managed by Clutter
|
||||
*
|
||||
* #ClutterInputDevice represents an input device known to Clutter.
|
||||
*
|
||||
* The #ClutterInputDevice class holds the state of the device, but
|
||||
* its contents are usually defined by the Clutter backend in use.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "clutter-debug.h"
|
||||
#include "clutter-enum-types.h"
|
||||
#include "clutter-input-device.h"
|
||||
#include "clutter-private.h"
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
|
||||
PROP_ID,
|
||||
PROP_DEVICE_TYPE,
|
||||
PROP_NAME
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (ClutterInputDevice, clutter_input_device, G_TYPE_OBJECT);
|
||||
|
||||
static void
|
||||
clutter_input_device_set_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ClutterInputDevice *self = CLUTTER_INPUT_DEVICE (gobject);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ID:
|
||||
self->id = g_value_get_int (value);
|
||||
break;
|
||||
|
||||
case PROP_DEVICE_TYPE:
|
||||
self->device_type = g_value_get_enum (value);
|
||||
break;
|
||||
|
||||
case PROP_NAME:
|
||||
self->device_name = g_strdup (g_value_get_string (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_input_device_get_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ClutterInputDevice *self = CLUTTER_INPUT_DEVICE (gobject);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ID:
|
||||
g_value_set_int (value, self->id);
|
||||
break;
|
||||
|
||||
case PROP_DEVICE_TYPE:
|
||||
g_value_set_enum (value, self->device_type);
|
||||
break;
|
||||
|
||||
case PROP_NAME:
|
||||
g_value_set_string (value, self->device_name);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_input_device_class_init (ClutterInputDeviceClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
GParamSpec *pspec;
|
||||
|
||||
gobject_class->set_property = clutter_input_device_set_property;
|
||||
gobject_class->get_property = clutter_input_device_get_property;
|
||||
|
||||
/**
|
||||
* ClutterInputDevice:id:
|
||||
*
|
||||
* The unique identifier of the device
|
||||
*
|
||||
* Since: 1.2
|
||||
*/
|
||||
pspec = g_param_spec_int ("id",
|
||||
"Id",
|
||||
"Unique identifier of the device",
|
||||
-1, G_MAXINT,
|
||||
0,
|
||||
CLUTTER_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY);
|
||||
g_object_class_install_property (gobject_class, PROP_ID, pspec);
|
||||
|
||||
/**
|
||||
* ClutterInputDevice:name:
|
||||
*
|
||||
* The name of the device
|
||||
*
|
||||
* Since: 1.2
|
||||
*/
|
||||
pspec = g_param_spec_string ("name",
|
||||
"Name",
|
||||
"The name of the device",
|
||||
NULL,
|
||||
CLUTTER_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY);
|
||||
g_object_class_install_property (gobject_class, PROP_NAME, pspec);
|
||||
|
||||
/**
|
||||
* ClutterInputDevice:device-type:
|
||||
*
|
||||
* The type of the device
|
||||
*
|
||||
* Since: 1.2
|
||||
*/
|
||||
pspec = g_param_spec_enum ("device-type",
|
||||
"Device Type",
|
||||
"The type of the device",
|
||||
CLUTTER_TYPE_INPUT_DEVICE_TYPE,
|
||||
CLUTTER_POINTER_DEVICE,
|
||||
CLUTTER_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY);
|
||||
g_object_class_install_property (gobject_class, PROP_DEVICE_TYPE, pspec);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_input_device_init (ClutterInputDevice *self)
|
||||
{
|
||||
self->id = -1;
|
||||
self->device_type = CLUTTER_POINTER_DEVICE;
|
||||
|
||||
self->click_count = 0;
|
||||
|
||||
self->current_time = self->previous_time = CLUTTER_CURRENT_TIME;
|
||||
self->current_x = self->previous_x = -1;
|
||||
self->current_y = self->previous_y = -1;
|
||||
self->current_button_number = self->previous_button_number = -1;
|
||||
self->current_state = self->previous_state = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* _clutter_input_device_set_coords:
|
||||
* @device: a #ClutterInputDevice
|
||||
* @x: X coordinate of the device
|
||||
* @y: Y coordinate of the device
|
||||
*
|
||||
* Stores the last known coordinates of the device
|
||||
*/
|
||||
void
|
||||
_clutter_input_device_set_coords (ClutterInputDevice *device,
|
||||
gint x,
|
||||
gint y)
|
||||
{
|
||||
g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
|
||||
|
||||
if (device->current_x != x)
|
||||
device->current_x = x;
|
||||
|
||||
if (device->current_y != y)
|
||||
device->current_y = y;
|
||||
}
|
||||
|
||||
/*
|
||||
* _clutter_input_device_set_state:
|
||||
* @device: a #ClutterInputDevice
|
||||
* @state: a bitmask of modifiers
|
||||
*
|
||||
* Stores the last known modifiers state of the device
|
||||
*/
|
||||
void
|
||||
_clutter_input_device_set_state (ClutterInputDevice *device,
|
||||
ClutterModifierType state)
|
||||
{
|
||||
g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
|
||||
|
||||
device->current_state = state;
|
||||
}
|
||||
|
||||
/*
|
||||
* _clutter_input_device_set_time:
|
||||
* @device: a #ClutterInputDevice
|
||||
* @time_: the time
|
||||
*
|
||||
* Stores the last known event time of the device
|
||||
*/
|
||||
void
|
||||
_clutter_input_device_set_time (ClutterInputDevice *device,
|
||||
guint32 time_)
|
||||
{
|
||||
g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
|
||||
|
||||
if (device->current_time != time_)
|
||||
device->current_time = time_;
|
||||
}
|
||||
|
||||
/*
|
||||
* cursor_weak_unref:
|
||||
*
|
||||
* #ClutterInputDevice keeps a weak reference on the actor
|
||||
* under its pointer; this function unsets the reference on
|
||||
* the actor to avoid keeping around stale pointers
|
||||
*/
|
||||
static void
|
||||
cursor_weak_unref (gpointer user_data,
|
||||
GObject *object_pointer)
|
||||
{
|
||||
ClutterInputDevice *device = user_data;
|
||||
|
||||
device->cursor_actor = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* _clutter_input_device_set_stage:
|
||||
* @device: a #ClutterInputDevice
|
||||
* @stage: a #ClutterStage or %NULL
|
||||
*
|
||||
* Stores the stage under the device
|
||||
*/
|
||||
void
|
||||
_clutter_input_device_set_stage (ClutterInputDevice *device,
|
||||
ClutterStage *stage)
|
||||
{
|
||||
g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
|
||||
|
||||
device->stage = stage;
|
||||
|
||||
/* if we left the stage then we also need to unset the
|
||||
* cursor actor (and update its :has-pointer property)
|
||||
*/
|
||||
if (device->stage == NULL && device->cursor_actor != NULL)
|
||||
{
|
||||
_clutter_actor_set_has_pointer (device->cursor_actor, FALSE);
|
||||
g_object_weak_unref (G_OBJECT (device->cursor_actor),
|
||||
cursor_weak_unref,
|
||||
device);
|
||||
|
||||
device->cursor_actor = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* _clutter_input_device_set_actor:
|
||||
* @device: a #ClutterInputDevice
|
||||
* @actor: a #ClutterActor
|
||||
*
|
||||
* Sets the actor under the pointer coordinates of @device
|
||||
*
|
||||
* This function is called by _clutter_input_device_update()
|
||||
* and it will:
|
||||
*
|
||||
* - queue a %CLUTTER_LEAVE event on the previous pointer actor
|
||||
* of @device, if any
|
||||
* - set to %FALSE the :has-pointer property of the previous
|
||||
* pointer actor of @device, if any
|
||||
* - queue a %CLUTTER_ENTER event on the new pointer actor
|
||||
* - set to %TRUE the :has-pointer property of the new pointer
|
||||
* actor
|
||||
*/
|
||||
void
|
||||
_clutter_input_device_set_actor (ClutterInputDevice *device,
|
||||
ClutterActor *actor)
|
||||
{
|
||||
ClutterActor *old_actor;
|
||||
ClutterEvent cev;
|
||||
|
||||
g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
|
||||
|
||||
if (actor == device->cursor_actor)
|
||||
return;
|
||||
|
||||
old_actor = device->cursor_actor;
|
||||
if (old_actor != NULL)
|
||||
{
|
||||
cev.crossing.type = CLUTTER_LEAVE;
|
||||
cev.crossing.time = device->current_time;
|
||||
cev.crossing.flags = 0;
|
||||
cev.crossing.stage = device->stage;
|
||||
cev.crossing.source = device->cursor_actor;
|
||||
cev.crossing.x = device->current_x;
|
||||
cev.crossing.y = device->current_y;
|
||||
cev.crossing.device = device;
|
||||
cev.crossing.related = actor;
|
||||
|
||||
/* we need to make sure that this event is processed before
|
||||
* any other event we might have queued up until now, so we
|
||||
* go on and synthesize the event emission
|
||||
*/
|
||||
_clutter_process_event (&cev);
|
||||
|
||||
_clutter_actor_set_has_pointer (device->cursor_actor, FALSE);
|
||||
g_object_weak_unref (G_OBJECT (device->cursor_actor),
|
||||
cursor_weak_unref,
|
||||
device);
|
||||
|
||||
device->cursor_actor = NULL;
|
||||
}
|
||||
|
||||
if (actor != NULL)
|
||||
{
|
||||
cev.crossing.type = CLUTTER_ENTER;
|
||||
cev.crossing.time = device->current_time;
|
||||
cev.crossing.flags = 0;
|
||||
cev.crossing.stage = device->stage;
|
||||
cev.crossing.source = actor;
|
||||
cev.crossing.x = device->current_x;
|
||||
cev.crossing.y = device->current_y;
|
||||
cev.crossing.device = device;
|
||||
cev.crossing.related = old_actor;
|
||||
|
||||
/* as above: we need to make sure that this event is processed
|
||||
* before any other event we might have queued up until now, so
|
||||
* we go on and synthesize the event emission
|
||||
*/
|
||||
_clutter_process_event (&cev);
|
||||
}
|
||||
|
||||
device->cursor_actor = actor;
|
||||
|
||||
if (device->cursor_actor != NULL)
|
||||
{
|
||||
g_object_weak_ref (G_OBJECT (device->cursor_actor),
|
||||
cursor_weak_unref,
|
||||
device);
|
||||
_clutter_actor_set_has_pointer (device->cursor_actor, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_input_device_get_device_type:
|
||||
* @device: a #ClutterInputDevice
|
||||
*
|
||||
* Retrieves the type of @device
|
||||
*
|
||||
* Return value: the type of the device
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
ClutterInputDeviceType
|
||||
clutter_input_device_get_device_type (ClutterInputDevice *device)
|
||||
{
|
||||
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device),
|
||||
CLUTTER_POINTER_DEVICE);
|
||||
|
||||
return device->device_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_input_device_get_device_id:
|
||||
* @device: a #ClutterInputDevice
|
||||
*
|
||||
* Retrieves the unique identifier of @device
|
||||
*
|
||||
* Return value: the identifier of the device
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
gint
|
||||
clutter_input_device_get_device_id (ClutterInputDevice *device)
|
||||
{
|
||||
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), -1);
|
||||
|
||||
return device->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_input_device_get_device_coords:
|
||||
* @device: a #ClutterInputDevice of type %CLUTTER_POINTER_DEVICE
|
||||
* @x: (out): return location for the X coordinate
|
||||
* @y: (out): return location for the Y coordinate
|
||||
*
|
||||
* Retrieves the latest coordinates of the pointer of @device
|
||||
*
|
||||
* Since: 1.2
|
||||
*/
|
||||
void
|
||||
clutter_input_device_get_device_coords (ClutterInputDevice *device,
|
||||
gint *x,
|
||||
gint *y)
|
||||
{
|
||||
g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
|
||||
g_return_if_fail (device->device_type == CLUTTER_POINTER_DEVICE);
|
||||
|
||||
if (x)
|
||||
*x = device->current_x;
|
||||
|
||||
if (y)
|
||||
*y = device->current_y;
|
||||
}
|
||||
|
||||
/*
|
||||
* _clutter_input_device_update:
|
||||
* @device: a #ClutterInputDevice
|
||||
*
|
||||
* Updates the input @device by determining the #ClutterActor underneath the
|
||||
* pointer's cursor
|
||||
*
|
||||
* This function calls _clutter_input_device_set_actor() if needed.
|
||||
*
|
||||
* This function only works for #ClutterInputDevice of type
|
||||
* %CLUTTER_POINTER_DEVICE.
|
||||
*
|
||||
* Since: 1.2
|
||||
*/
|
||||
ClutterActor *
|
||||
_clutter_input_device_update (ClutterInputDevice *device)
|
||||
{
|
||||
ClutterStage *stage;
|
||||
ClutterActor *new_cursor_actor;
|
||||
ClutterActor *old_cursor_actor;
|
||||
gint x, y;
|
||||
|
||||
g_return_val_if_fail (device->device_type == CLUTTER_POINTER_DEVICE, NULL);
|
||||
|
||||
clutter_input_device_get_device_coords (device, &x, &y);
|
||||
|
||||
stage = device->stage;
|
||||
|
||||
old_cursor_actor = device->cursor_actor;
|
||||
new_cursor_actor = _clutter_do_pick (stage, x, y, CLUTTER_PICK_REACTIVE);
|
||||
|
||||
/* if the pick could not find an actor then we do not update the
|
||||
* input device, to avoid ghost enter/leave events; the pick should
|
||||
* never fail, except for bugs in the glReadPixels() implementation
|
||||
* in which case this is the safest course of action anyway
|
||||
*/
|
||||
if (new_cursor_actor == NULL)
|
||||
return NULL;
|
||||
|
||||
CLUTTER_NOTE (EVENT,
|
||||
"Actor under cursor (device %d, at %d, %d): %s",
|
||||
clutter_input_device_get_device_id (device),
|
||||
x, y,
|
||||
clutter_actor_get_name (new_cursor_actor) != NULL
|
||||
? clutter_actor_get_name (new_cursor_actor)
|
||||
: G_OBJECT_TYPE_NAME (new_cursor_actor));
|
||||
|
||||
/* short-circuit here */
|
||||
if (new_cursor_actor == old_cursor_actor)
|
||||
return old_cursor_actor;
|
||||
|
||||
_clutter_input_device_set_actor (device, new_cursor_actor);
|
||||
|
||||
return device->cursor_actor;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_input_device_get_pointer_actor:
|
||||
* @device: a #ClutterInputDevice of type %CLUTTER_POINTER_DEVICE
|
||||
*
|
||||
* Retrieves the #ClutterActor underneath the pointer of @device
|
||||
*
|
||||
* Return value: (transfer none): a pointer to the #ClutterActor or %NULL
|
||||
*
|
||||
* Since: 1.2
|
||||
*/
|
||||
ClutterActor *
|
||||
clutter_input_device_get_pointer_actor (ClutterInputDevice *device)
|
||||
{
|
||||
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL);
|
||||
g_return_val_if_fail (device->device_type == CLUTTER_POINTER_DEVICE, NULL);
|
||||
|
||||
return device->cursor_actor;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_input_device_get_device_name:
|
||||
* @device: a #ClutterInputDevice
|
||||
*
|
||||
* Retrieves the name of the @device
|
||||
*
|
||||
* Return value: the name of the device, or %NULL. The returned string
|
||||
* is owned by the #ClutterInputDevice and should never be modified
|
||||
* or freed
|
||||
*
|
||||
* Since: 1.2
|
||||
*/
|
||||
G_CONST_RETURN gchar *
|
||||
clutter_input_device_get_device_name (ClutterInputDevice *device)
|
||||
{
|
||||
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL);
|
||||
|
||||
return device->device_name;
|
||||
}
|
99
clutter/clutter-input-device.h
Normal file
99
clutter/clutter-input-device.h
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Clutter.
|
||||
*
|
||||
* An OpenGL based 'interactive canvas' library.
|
||||
*
|
||||
* Copyright (C) 2009 Intel Corp.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Emmanuele Bassi <ebassi@linux.intel.com>
|
||||
*/
|
||||
|
||||
#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
|
||||
#error "Only <clutter/clutter.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#ifndef __CLUTTER_INPUT_DEVICE_H__
|
||||
#define __CLUTTER_INPUT_DEVICE_H__
|
||||
|
||||
#include <clutter/clutter-types.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define CLUTTER_TYPE_INPUT_DEVICE (clutter_input_device_get_type ())
|
||||
#define CLUTTER_INPUT_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_INPUT_DEVICE, ClutterInputDevice))
|
||||
#define CLUTTER_IS_INPUT_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_INPUT_DEVICE))
|
||||
#define CLUTTER_INPUT_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_INPUT_DEVICE, ClutterInputDeviceClass))
|
||||
#define CLUTTER_IS_INPUT_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_INPUT_DEVICE))
|
||||
#define CLUTTER_INPUT_DEVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_INPUT_DEVICE, ClutterInputDeviceClass))
|
||||
|
||||
/**
|
||||
* ClutterInputDevice:
|
||||
*
|
||||
* Generic representation of an input device. The actual contents of this
|
||||
* structure depend on the backend used.
|
||||
*/
|
||||
typedef struct _ClutterInputDevice ClutterInputDevice;
|
||||
typedef struct _ClutterInputDeviceClass ClutterInputDeviceClass;
|
||||
|
||||
/**
|
||||
* ClutterInputDeviceType:
|
||||
* @CLUTTER_POINTER_DEVICE: A pointer device
|
||||
* @CLUTTER_KEYBOARD_DEVICE: A keyboard device
|
||||
* @CLUTTER_EXTENSION_DEVICE: A generic extension device
|
||||
* @CLUTTER_N_DEVICE_TYPES: The number of device types
|
||||
*
|
||||
* The types of input devices available.
|
||||
*
|
||||
* The #ClutterInputDeviceType enumeration can be extended at later
|
||||
* date; not every platform supports every input device type.
|
||||
*
|
||||
* Since: 1.0
|
||||
*/
|
||||
typedef enum {
|
||||
CLUTTER_POINTER_DEVICE,
|
||||
CLUTTER_KEYBOARD_DEVICE,
|
||||
CLUTTER_EXTENSION_DEVICE,
|
||||
|
||||
CLUTTER_N_DEVICE_TYPES
|
||||
} ClutterInputDeviceType;
|
||||
|
||||
/**
|
||||
* ClutterInputDeviceClass:
|
||||
*
|
||||
* The #ClutterInputDeviceClass structure contains only private
|
||||
* data and should not be accessed directly
|
||||
*
|
||||
* Since: 1.2
|
||||
*/
|
||||
struct _ClutterInputDeviceClass
|
||||
{
|
||||
/*< private >*/
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
GType clutter_input_device_get_type (void) G_GNUC_CONST;
|
||||
|
||||
ClutterInputDeviceType clutter_input_device_get_device_type (ClutterInputDevice *device);
|
||||
gint clutter_input_device_get_device_id (ClutterInputDevice *device);
|
||||
void clutter_input_device_get_device_coords (ClutterInputDevice *device,
|
||||
gint *x,
|
||||
gint *y);
|
||||
ClutterActor * clutter_input_device_get_pointer_actor (ClutterInputDevice *device);
|
||||
G_CONST_RETURN gchar * clutter_input_device_get_device_name (ClutterInputDevice *device);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __CLUTTER_INPUT_DEVICE_H__ */
|
@ -2045,69 +2045,93 @@ event_click_count_generate (ClutterEvent *event)
|
||||
static guint32 previous_time = 0;
|
||||
static gint previous_button_number = -1;
|
||||
|
||||
ClutterInputDevice *device = NULL;
|
||||
ClutterBackend *backend;
|
||||
guint double_click_time;
|
||||
guint double_click_distance;
|
||||
guint double_click_time;
|
||||
guint double_click_distance;
|
||||
|
||||
backend = _clutter_context_get_default ()->backend;
|
||||
backend = clutter_get_default_backend ();
|
||||
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)
|
||||
device = clutter_event_get_device (event);
|
||||
if (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;
|
||||
click_count = device->click_count;
|
||||
previous_x = device->previous_x;
|
||||
previous_y = device->previous_y;
|
||||
previous_time = device->previous_time;
|
||||
previous_button_number = device->previous_button_number;
|
||||
|
||||
CLUTTER_NOTE (EVENT,
|
||||
"Restoring previous click count:%d (device:%d, time:%u)",
|
||||
click_count,
|
||||
clutter_input_device_get_device_id (device),
|
||||
previous_time);
|
||||
}
|
||||
else
|
||||
{
|
||||
CLUTTER_NOTE (EVENT,
|
||||
"Restoring previous click count:%d (time:%u)",
|
||||
click_count,
|
||||
previous_time);
|
||||
}
|
||||
|
||||
switch (event->type)
|
||||
switch (clutter_event_type (event))
|
||||
{
|
||||
case CLUTTER_BUTTON_PRESS:
|
||||
case CLUTTER_SCROLL:
|
||||
/* check if we are in time and within distance to increment an
|
||||
* existing click count
|
||||
*/
|
||||
if (event->button.time < previous_time + double_click_time &&
|
||||
if (event->button.button == previous_button_number &&
|
||||
event->button.time < (previous_time + double_click_time) &&
|
||||
(ABS (event->button.x - previous_x) <= double_click_distance) &&
|
||||
(ABS (event->button.y - previous_y) <= double_click_distance)
|
||||
&& event->button.button == previous_button_number)
|
||||
(ABS (event->button.y - previous_y) <= double_click_distance))
|
||||
{
|
||||
click_count ++;
|
||||
CLUTTER_NOTE (EVENT, "Increase click count (button: %d, time: %u)",
|
||||
event->button.button,
|
||||
event->button.time);
|
||||
|
||||
click_count += 1;
|
||||
}
|
||||
else /* start a new click count*/
|
||||
{
|
||||
click_count=1;
|
||||
CLUTTER_NOTE (EVENT, "Reset click count (button: %d, time: %u)",
|
||||
event->button.button,
|
||||
event->button.time);
|
||||
|
||||
click_count = 1;
|
||||
previous_button_number = event->button.button;
|
||||
}
|
||||
|
||||
/* store time and position for this click for comparison with
|
||||
* next event
|
||||
*/
|
||||
previous_x = event->button.x;
|
||||
previous_y = event->button.y;
|
||||
previous_time = event->button.time;
|
||||
previous_x = event->button.x;
|
||||
previous_y = event->button.y;
|
||||
|
||||
/* fallthrough */
|
||||
case CLUTTER_BUTTON_RELEASE:
|
||||
event->button.click_count=click_count;
|
||||
event->button.click_count = click_count;
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert (NULL);
|
||||
}
|
||||
|
||||
if (event->button.device != NULL)
|
||||
if (event->type == CLUTTER_BUTTON_PRESS && 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;
|
||||
CLUTTER_NOTE (EVENT, "Storing click count: %d (device:%d, time:%u)",
|
||||
click_count,
|
||||
clutter_input_device_get_device_id (device),
|
||||
previous_time);
|
||||
|
||||
device->click_count = click_count;
|
||||
device->previous_x = previous_x;
|
||||
device->previous_y = previous_y;
|
||||
device->previous_time = previous_time;
|
||||
device->previous_button_number = previous_button_number;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
emit_event (ClutterEvent *event,
|
||||
gboolean is_key_event)
|
||||
@ -2118,7 +2142,7 @@ emit_event (ClutterEvent *event,
|
||||
ClutterActor *actor;
|
||||
gint i = 0;
|
||||
|
||||
if (!event->any.source)
|
||||
if (event->any.source == NULL)
|
||||
{
|
||||
CLUTTER_NOTE (EVENT, "No source set, discarding event");
|
||||
return;
|
||||
@ -2182,136 +2206,38 @@ static inline void
|
||||
emit_pointer_event (ClutterEvent *event,
|
||||
ClutterInputDevice *device)
|
||||
{
|
||||
/* Using the global variable directly, since it has to be initialized
|
||||
* at this point
|
||||
*/
|
||||
ClutterMainContext *context = ClutterCntx;
|
||||
ClutterMainContext *context = _clutter_context_get_default ();
|
||||
|
||||
if (G_UNLIKELY (context->pointer_grab_actor != NULL &&
|
||||
device == NULL))
|
||||
{
|
||||
/* global grab */
|
||||
clutter_actor_event (context->pointer_grab_actor, event, FALSE);
|
||||
}
|
||||
else if (G_UNLIKELY (device != NULL &&
|
||||
device->pointer_grab_actor != NULL))
|
||||
{
|
||||
/* per device grab */
|
||||
clutter_actor_event (device->pointer_grab_actor, event, FALSE);
|
||||
}
|
||||
else
|
||||
if (context->pointer_grab_actor == NULL &&
|
||||
(device == NULL || device->pointer_grab_actor == NULL))
|
||||
{
|
||||
/* no grab, time to capture and bubble */
|
||||
emit_event (event, FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (context->pointer_grab_actor != NULL)
|
||||
{
|
||||
/* global grab */
|
||||
clutter_actor_event (context->pointer_grab_actor, event, FALSE);
|
||||
}
|
||||
else if (device != NULL && device->pointer_grab_actor != NULL)
|
||||
{
|
||||
/* per device grab */
|
||||
clutter_actor_event (device->pointer_grab_actor, event, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
emit_keyboard_event (ClutterEvent *event)
|
||||
{
|
||||
ClutterMainContext *context = ClutterCntx;
|
||||
ClutterMainContext *context = _clutter_context_get_default ();
|
||||
|
||||
if (G_UNLIKELY (context->keyboard_grab_actor != NULL))
|
||||
clutter_actor_event (context->keyboard_grab_actor, event, FALSE);
|
||||
else
|
||||
if (context->keyboard_grab_actor == NULL)
|
||||
emit_event (event, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
unset_motion_last_actor (ClutterActor *actor, ClutterInputDevice *dev)
|
||||
{
|
||||
ClutterMainContext *context = ClutterCntx;
|
||||
|
||||
if (dev == NULL)
|
||||
context->motion_last_actor = NULL;
|
||||
else
|
||||
dev->motion_last_actor = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
set_motion_last_actor (ClutterActor *motion_current_actor,
|
||||
ClutterInputDevice *device)
|
||||
{
|
||||
ClutterMainContext *context = ClutterCntx;
|
||||
ClutterActor *last_actor = context->motion_last_actor;
|
||||
|
||||
if (device != NULL)
|
||||
last_actor = device->motion_last_actor;
|
||||
|
||||
if (last_actor && last_actor != motion_current_actor)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func
|
||||
(last_actor,
|
||||
G_CALLBACK (unset_motion_last_actor),
|
||||
device);
|
||||
}
|
||||
|
||||
if (motion_current_actor && last_actor != motion_current_actor)
|
||||
{
|
||||
g_signal_connect (motion_current_actor, "destroy",
|
||||
G_CALLBACK (unset_motion_last_actor),
|
||||
device);
|
||||
}
|
||||
|
||||
if (device != NULL)
|
||||
device->motion_last_actor = motion_current_actor;
|
||||
else
|
||||
context->motion_last_actor = motion_current_actor;
|
||||
}
|
||||
|
||||
static inline void
|
||||
generate_enter_leave_events (ClutterEvent *event)
|
||||
{
|
||||
ClutterMainContext *context = ClutterCntx;
|
||||
ClutterActor *motion_current_actor = event->motion.source;
|
||||
ClutterActor *last_actor = context->motion_last_actor;
|
||||
ClutterInputDevice *device = clutter_event_get_device (event);
|
||||
|
||||
if (device != NULL)
|
||||
last_actor = device->motion_last_actor;
|
||||
|
||||
if (last_actor != motion_current_actor)
|
||||
{
|
||||
if (motion_current_actor)
|
||||
{
|
||||
ClutterEvent cev;
|
||||
gfloat x, y;
|
||||
|
||||
cev.crossing.device = device;
|
||||
clutter_event_get_coords (event, &x, &y);
|
||||
|
||||
if (context->motion_last_actor)
|
||||
{
|
||||
cev.crossing.type = CLUTTER_LEAVE;
|
||||
cev.crossing.time = event->any.time;
|
||||
cev.crossing.flags = 0;
|
||||
cev.crossing.x = x;
|
||||
cev.crossing.y = y;
|
||||
cev.crossing.source = last_actor;
|
||||
cev.crossing.stage = event->any.stage;
|
||||
cev.crossing.related = motion_current_actor;
|
||||
|
||||
emit_pointer_event (&cev, device);
|
||||
}
|
||||
|
||||
cev.crossing.type = CLUTTER_ENTER;
|
||||
cev.crossing.time = event->any.time;
|
||||
cev.crossing.flags = 0;
|
||||
cev.crossing.x = x;
|
||||
cev.crossing.y = y;
|
||||
cev.crossing.source = motion_current_actor;
|
||||
cev.crossing.stage = event->any.stage;
|
||||
|
||||
if (context->motion_last_actor)
|
||||
cev.crossing.related = last_actor;
|
||||
else
|
||||
cev.crossing.related = NULL;
|
||||
|
||||
emit_pointer_event (&cev, device);
|
||||
}
|
||||
}
|
||||
|
||||
set_motion_last_actor (motion_current_actor, device);
|
||||
clutter_actor_event (context->keyboard_grab_actor, event, FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2343,7 +2269,9 @@ _clutter_process_event_details (ClutterActor *stage,
|
||||
ClutterMainContext *context,
|
||||
ClutterEvent *event)
|
||||
{
|
||||
ClutterInputDevice *device = NULL;
|
||||
ClutterInputDevice *device = NULL;
|
||||
|
||||
device = clutter_event_get_device (event);
|
||||
|
||||
switch (event->type)
|
||||
{
|
||||
@ -2352,23 +2280,8 @@ _clutter_process_event_details (ClutterActor *stage,
|
||||
break;
|
||||
|
||||
case CLUTTER_LEAVE:
|
||||
/* The source is set for generated events, not for events
|
||||
* resulting from the cursor leaving the stage
|
||||
*/
|
||||
if (event->any.source == NULL)
|
||||
{
|
||||
ClutterActor *last_actor = context->motion_last_actor;
|
||||
|
||||
if (event->crossing.device != NULL)
|
||||
last_actor = event->crossing.device->motion_last_actor;
|
||||
|
||||
event->any.source = last_actor;
|
||||
|
||||
set_motion_last_actor (NULL, event->crossing.device);
|
||||
}
|
||||
/* flow through */
|
||||
case CLUTTER_ENTER:
|
||||
emit_pointer_event (event, event->crossing.device);
|
||||
emit_pointer_event (event, device);
|
||||
break;
|
||||
|
||||
case CLUTTER_DESTROY_NOTIFY:
|
||||
@ -2400,8 +2313,6 @@ _clutter_process_event_details (ClutterActor *stage,
|
||||
break;
|
||||
|
||||
case CLUTTER_MOTION:
|
||||
device = event->motion.device;
|
||||
|
||||
/* Only stage gets motion events if clutter_set_motion_events is TRUE,
|
||||
* and the event is not a synthetic event with source set.
|
||||
*/
|
||||
@ -2434,8 +2345,7 @@ _clutter_process_event_details (ClutterActor *stage,
|
||||
break;
|
||||
}
|
||||
|
||||
/* fallthrough */
|
||||
|
||||
/* fallthrough from motion */
|
||||
case CLUTTER_BUTTON_PRESS:
|
||||
case CLUTTER_BUTTON_RELEASE:
|
||||
case CLUTTER_SCROLL:
|
||||
@ -2462,18 +2372,29 @@ _clutter_process_event_details (ClutterActor *stage,
|
||||
x, y);
|
||||
|
||||
event->button.source = stage;
|
||||
emit_pointer_event (event, event->button.device);
|
||||
event->button.click_count = 1;
|
||||
emit_pointer_event (event, device);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Map the event to a reactive actor */
|
||||
actor = _clutter_do_pick (CLUTTER_STAGE (stage),
|
||||
x, y,
|
||||
CLUTTER_PICK_REACTIVE);
|
||||
/* if the backend provides a device then we should
|
||||
* already have everything we need to update it and
|
||||
* get the actor underneath
|
||||
*/
|
||||
if (device != NULL)
|
||||
actor = _clutter_input_device_update (device);
|
||||
else
|
||||
{
|
||||
CLUTTER_NOTE (EVENT, "No device found: picking");
|
||||
|
||||
actor = _clutter_do_pick (CLUTTER_STAGE (stage),
|
||||
x, y,
|
||||
CLUTTER_PICK_REACTIVE);
|
||||
}
|
||||
|
||||
event->any.source = actor;
|
||||
if (!actor)
|
||||
if (event->any.source == NULL)
|
||||
break;
|
||||
}
|
||||
else
|
||||
@ -2482,7 +2403,6 @@ _clutter_process_event_details (ClutterActor *stage,
|
||||
actor = event->any.source;
|
||||
}
|
||||
|
||||
|
||||
/* FIXME: for an optimisation should check if there are
|
||||
* actually any reactive actors and avoid the pick all together
|
||||
* (signalling just the stage). Should be big help for gles.
|
||||
@ -2493,33 +2413,12 @@ _clutter_process_event_details (ClutterActor *stage,
|
||||
x, y,
|
||||
actor);
|
||||
|
||||
/* Create, enter/leave events if needed */
|
||||
generate_enter_leave_events (event);
|
||||
|
||||
if (event->type != CLUTTER_MOTION)
|
||||
{
|
||||
/* Generate click count */
|
||||
event_click_count_generate (event);
|
||||
}
|
||||
|
||||
if (device == NULL)
|
||||
{
|
||||
switch (event->type)
|
||||
{
|
||||
case CLUTTER_BUTTON_PRESS:
|
||||
case CLUTTER_BUTTON_RELEASE:
|
||||
device = event->button.device;
|
||||
break;
|
||||
case CLUTTER_SCROLL:
|
||||
device = event->scroll.device;
|
||||
break;
|
||||
case CLUTTER_MOTION:
|
||||
/* already handled in the MOTION case of the switch */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
emit_pointer_event (event, device);
|
||||
break;
|
||||
}
|
||||
@ -3023,9 +2922,19 @@ clutter_get_font_flags (void)
|
||||
|
||||
/**
|
||||
* clutter_get_input_device_for_id:
|
||||
* @id: a device id
|
||||
* @id: the unique id for a device
|
||||
*
|
||||
* Retrieves the #ClutterInputDevice from its id.
|
||||
* Retrieves the #ClutterInputDevice from its @id. This is a convenience
|
||||
* wrapper for clutter_device_manager_get_device() and it is functionally
|
||||
* equivalent to:
|
||||
*
|
||||
* |[
|
||||
* ClutterDeviceManager *manager;
|
||||
* ClutterInputDevice *device;
|
||||
*
|
||||
* manager = clutter_device_manager_get_default ();
|
||||
* device = clutter_device_manager_get_device (manager, id);
|
||||
* ]|
|
||||
*
|
||||
* Return value: (transfer none): a #ClutterInputDevice, or %NULL
|
||||
*
|
||||
@ -3034,23 +2943,11 @@ clutter_get_font_flags (void)
|
||||
ClutterInputDevice *
|
||||
clutter_get_input_device_for_id (gint id)
|
||||
{
|
||||
GSList *item;
|
||||
ClutterInputDevice *device = NULL;
|
||||
ClutterMainContext *context;
|
||||
ClutterDeviceManager *manager;
|
||||
|
||||
context = _clutter_context_get_default ();
|
||||
manager = clutter_device_manager_get_default ();
|
||||
|
||||
for (item = context->input_devices;
|
||||
item != NULL;
|
||||
item = item->next)
|
||||
{
|
||||
device = item->data;
|
||||
|
||||
if (device->id == id)
|
||||
return device;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return clutter_device_manager_get_device (manager, id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -12,6 +12,7 @@ VOID:INT,INT,INT,INT
|
||||
VOID:OBJECT
|
||||
VOID:OBJECT,OBJECT,PARAM
|
||||
VOID:OBJECT,POINTER
|
||||
VOID:POINTER
|
||||
VOID:STRING,BOOLEAN,BOOLEAN
|
||||
VOID:STRING,INT
|
||||
VOID:UINT
|
||||
|
@ -288,14 +288,13 @@ clutter_clock_dispatch (GSource *source,
|
||||
* event handling
|
||||
*/
|
||||
stages = clutter_stage_manager_list_stages (stage_manager);
|
||||
g_slist_foreach (stages, (GFunc)g_object_ref, NULL);
|
||||
g_slist_foreach (stages, (GFunc) g_object_ref, NULL);
|
||||
|
||||
CLUTTER_TIMER_START (_clutter_uprof_context, master_event_process);
|
||||
|
||||
master_clock->updated_stages = FALSE;
|
||||
|
||||
/* Process queued events
|
||||
*/
|
||||
/* Process queued events */
|
||||
for (l = stages; l != NULL; l = l->next)
|
||||
_clutter_stage_process_queued_events (l->data);
|
||||
|
||||
@ -311,7 +310,7 @@ clutter_clock_dispatch (GSource *source,
|
||||
for (l = stages; l != NULL; l = l->next)
|
||||
master_clock->updated_stages |= _clutter_stage_do_update (l->data);
|
||||
|
||||
g_slist_foreach (stages, (GFunc)g_object_unref, NULL);
|
||||
g_slist_foreach (stages, (GFunc) g_object_unref, NULL);
|
||||
g_slist_free (stages);
|
||||
|
||||
master_clock->prev_tick = master_clock->cur_tick;
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include "pango/cogl-pango.h"
|
||||
|
||||
#include "clutter-backend.h"
|
||||
#include "clutter-device-manager.h"
|
||||
#include "clutter-event.h"
|
||||
#include "clutter-feature.h"
|
||||
#include "clutter-id-pool.h"
|
||||
@ -52,6 +53,8 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _ClutterMainContext ClutterMainContext;
|
||||
|
||||
typedef enum {
|
||||
CLUTTER_ACTOR_UNUSED_FLAG = 0,
|
||||
|
||||
@ -82,21 +85,54 @@ typedef enum {
|
||||
|
||||
struct _ClutterInputDevice
|
||||
{
|
||||
gint id;
|
||||
GObject parent_instance;
|
||||
|
||||
gint id;
|
||||
|
||||
ClutterInputDeviceType device_type;
|
||||
|
||||
ClutterActor *pointer_grab_actor;
|
||||
ClutterActor *motion_last_actor;
|
||||
gchar *device_name;
|
||||
|
||||
gint click_count;
|
||||
gint previous_x;
|
||||
gint previous_y;
|
||||
guint32 previous_time;
|
||||
gint previous_button_number;
|
||||
/* the actor underneath the pointer */
|
||||
ClutterActor *cursor_actor;
|
||||
|
||||
/* the actor that has a grab in place for the device */
|
||||
ClutterActor *pointer_grab_actor;
|
||||
|
||||
/* the current click count */
|
||||
gint click_count;
|
||||
|
||||
/* the stage the device is on */
|
||||
ClutterStage *stage;
|
||||
|
||||
/* the current state */
|
||||
gint current_x;
|
||||
gint current_y;
|
||||
guint32 current_time;
|
||||
gint current_button_number;
|
||||
ClutterModifierType current_state;
|
||||
|
||||
/* the previous state, used for click count generation */
|
||||
gint previous_x;
|
||||
gint previous_y;
|
||||
guint32 previous_time;
|
||||
gint previous_button_number;
|
||||
ClutterModifierType previous_state;
|
||||
};
|
||||
|
||||
typedef struct _ClutterMainContext ClutterMainContext;
|
||||
struct _ClutterStageManager
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GSList *stages;
|
||||
};
|
||||
|
||||
struct _ClutterDeviceManager
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GSList *devices;
|
||||
};
|
||||
|
||||
struct _ClutterMainContext
|
||||
{
|
||||
@ -138,9 +174,6 @@ struct _ClutterMainContext
|
||||
PangoContext *pango_context; /* Global Pango context */
|
||||
CoglPangoFontMap *font_map; /* Global font map */
|
||||
|
||||
GSList *input_devices; /* For extra input devices, i.e
|
||||
MultiTouch */
|
||||
|
||||
ClutterEvent *current_event;
|
||||
guint32 last_event_time;
|
||||
|
||||
@ -170,21 +203,34 @@ PangoContext *_clutter_context_get_pango_context (ClutterMainContext *self);
|
||||
|
||||
#define I_(str) (g_intern_static_string ((str)))
|
||||
|
||||
/* device manager */
|
||||
void _clutter_device_manager_add_device (ClutterDeviceManager *device_manager,
|
||||
ClutterInputDevice *device);
|
||||
void _clutter_device_manager_remove_device (ClutterDeviceManager *device_manager,
|
||||
ClutterInputDevice *device);
|
||||
void _clutter_device_manager_update_devices (ClutterDeviceManager *device_manager);
|
||||
|
||||
/* input device */
|
||||
void _clutter_input_device_set_coords (ClutterInputDevice *device,
|
||||
gint x,
|
||||
gint y);
|
||||
void _clutter_input_device_set_state (ClutterInputDevice *device,
|
||||
ClutterModifierType state);
|
||||
void _clutter_input_device_set_time (ClutterInputDevice *device,
|
||||
guint32 time_);
|
||||
void _clutter_input_device_set_stage (ClutterInputDevice *device,
|
||||
ClutterStage *stage);
|
||||
void _clutter_input_device_set_actor (ClutterInputDevice *device,
|
||||
ClutterActor *actor);
|
||||
ClutterActor *_clutter_input_device_update (ClutterInputDevice *device);
|
||||
|
||||
/* stage manager */
|
||||
struct _ClutterStageManager
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GSList *stages;
|
||||
};
|
||||
|
||||
void _clutter_stage_manager_add_stage (ClutterStageManager *stage_manager,
|
||||
ClutterStage *stage);
|
||||
void _clutter_stage_manager_remove_stage (ClutterStageManager *stage_manager,
|
||||
ClutterStage *stage);
|
||||
|
||||
/* stage */
|
||||
|
||||
void _clutter_stage_set_window (ClutterStage *stage,
|
||||
ClutterStageWindow *stage_window);
|
||||
ClutterStageWindow *_clutter_stage_get_window (ClutterStage *stage);
|
||||
@ -198,6 +244,7 @@ void _clutter_stage_queue_event (ClutterStage *stage,
|
||||
ClutterEvent *event);
|
||||
gboolean _clutter_stage_has_queued_events (ClutterStage *stage);
|
||||
void _clutter_stage_process_queued_events (ClutterStage *stage);
|
||||
void _clutter_stage_update_input_devices (ClutterStage *stage);
|
||||
|
||||
/* vfuncs implemented by backend */
|
||||
GType _clutter_backend_impl_get_type (void);
|
||||
@ -271,6 +318,9 @@ void _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
|
||||
void _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
|
||||
gboolean enable);
|
||||
|
||||
void _clutter_actor_set_has_pointer (ClutterActor *self,
|
||||
gboolean has_pointer);
|
||||
|
||||
void _clutter_run_repaint_functions (void);
|
||||
|
||||
gint32 _clutter_backend_get_units_serial (ClutterBackend *backend);
|
||||
|
@ -69,6 +69,7 @@
|
||||
#include "clutter-id-pool.h"
|
||||
#include "clutter-container.h"
|
||||
#include "clutter-profile.h"
|
||||
#include "clutter-input-device.h"
|
||||
|
||||
#include "cogl/cogl.h"
|
||||
|
||||
@ -455,6 +456,7 @@ _clutter_stage_queue_event (ClutterStage *stage,
|
||||
{
|
||||
ClutterStagePrivate *priv;
|
||||
gboolean first_event;
|
||||
ClutterInputDevice *device;
|
||||
|
||||
g_return_if_fail (CLUTTER_IS_STAGE (stage));
|
||||
|
||||
@ -462,14 +464,31 @@ _clutter_stage_queue_event (ClutterStage *stage,
|
||||
|
||||
first_event = priv->event_queue->length == 0;
|
||||
|
||||
g_queue_push_tail (priv->event_queue,
|
||||
clutter_event_copy (event));
|
||||
g_queue_push_tail (priv->event_queue, clutter_event_copy (event));
|
||||
|
||||
if (first_event)
|
||||
{
|
||||
ClutterMasterClock *master_clock = _clutter_master_clock_get_default ();
|
||||
_clutter_master_clock_start_running (master_clock);
|
||||
}
|
||||
|
||||
/* if needed, update the state of the input device of the event.
|
||||
* we do it here to avoid calling the same code from every backend
|
||||
* event processing function
|
||||
*/
|
||||
device = clutter_event_get_device (event);
|
||||
if (device != NULL)
|
||||
{
|
||||
ClutterModifierType event_state = clutter_event_get_state (event);
|
||||
guint32 event_time = clutter_event_get_time (event);
|
||||
gfloat event_x, event_y;
|
||||
|
||||
clutter_event_get_coords (event, &event_x, &event_y);
|
||||
|
||||
_clutter_input_device_set_coords (device, event_x, event_y);
|
||||
_clutter_input_device_set_state (device, event_state);
|
||||
_clutter_input_device_set_time (device, event_time);
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
@ -488,7 +507,7 @@ void
|
||||
_clutter_stage_process_queued_events (ClutterStage *stage)
|
||||
{
|
||||
ClutterStagePrivate *priv;
|
||||
GList *events, *l;;
|
||||
GList *events, *l;
|
||||
|
||||
g_return_if_fail (CLUTTER_IS_STAGE (stage));
|
||||
|
||||
@ -507,7 +526,7 @@ _clutter_stage_process_queued_events (ClutterStage *stage)
|
||||
priv->event_queue->tail = NULL;
|
||||
priv->event_queue->length = 0;
|
||||
|
||||
for (l = events; l; l = l->next)
|
||||
for (l = events; l != NULL; l = l->next)
|
||||
{
|
||||
ClutterEvent *event;
|
||||
ClutterEvent *next_event;
|
||||
|
@ -51,12 +51,14 @@
|
||||
#include "clutter-clone.h"
|
||||
#include "clutter-color.h"
|
||||
#include "clutter-container.h"
|
||||
#include "clutter-device-manager.h"
|
||||
#include "clutter-event.h"
|
||||
#include "clutter-feature.h"
|
||||
#include "clutter-fixed-layout.h"
|
||||
#include "clutter-flow-layout.h"
|
||||
#include "clutter-frame-source.h"
|
||||
#include "clutter-group.h"
|
||||
#include "clutter-input-device.h"
|
||||
#include "clutter-interval.h"
|
||||
#include "clutter-keysyms.h"
|
||||
#include "clutter-layout-manager.h"
|
||||
|
@ -31,6 +31,7 @@
|
||||
|
||||
#include "../clutter-event.h"
|
||||
#include "../clutter-main.h"
|
||||
#include "../clutter-input-device.h"
|
||||
#include "../clutter-debug.h"
|
||||
#include "../clutter-private.h"
|
||||
#include "../clutter-version.h"
|
||||
@ -64,8 +65,30 @@ clutter_backend_win32_pre_parse (ClutterBackend *backend,
|
||||
static void
|
||||
clutter_backend_win32_init_events (ClutterBackend *backend)
|
||||
{
|
||||
ClutterBackendWin32 *backend_win32 = CLUTTER_BACKEND_WIN32 (backend);
|
||||
ClutterDeviceManager *manager;
|
||||
ClutterInputDevice *device;
|
||||
|
||||
CLUTTER_NOTE (EVENT, "initialising the event loop");
|
||||
|
||||
manager = clutter_device_manager_get_default ();
|
||||
|
||||
device = g_object_new (CLUTTER_TYPE_INPUT_DEVICE,
|
||||
"id", 0,
|
||||
"name", "Core Pointer",
|
||||
"device-type", CLUTTER_POINTER_DEVICE,
|
||||
NULL);
|
||||
_clutter_device_manager_add_device (manager, device);
|
||||
backend_win32->core_pointer = device;
|
||||
|
||||
device = g_object_new (CLUTTER_TYPE_INPUT_DEVICE,
|
||||
"id", 1,
|
||||
"name", "Core Keyboard",
|
||||
"device-type", CLUTTER_KEYBOARD_DEVICE,
|
||||
NULL);
|
||||
_clutter_device_manager_add_device (manager, device);
|
||||
backend_win32->core_keyboard = device;
|
||||
|
||||
_clutter_backend_win32_events_init (backend);
|
||||
}
|
||||
|
||||
|
@ -51,6 +51,9 @@ struct _ClutterBackendWin32
|
||||
HCURSOR invisible_cursor;
|
||||
|
||||
GSource *event_source;
|
||||
|
||||
ClutterInputDevice *core_pointer;
|
||||
ClutterInputDevice *core_keyboard;
|
||||
};
|
||||
|
||||
struct _ClutterBackendWin32Class
|
||||
|
@ -201,9 +201,13 @@ get_modifier_state (WPARAM wparam)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
make_button_event (const MSG *msg, ClutterEvent *event,
|
||||
int button, int click_count, gboolean release)
|
||||
static inline void
|
||||
make_button_event (const MSG *msg,
|
||||
ClutterEvent *event,
|
||||
int button,
|
||||
int click_count,
|
||||
gboolean release,
|
||||
ClutterInputDevice *device)
|
||||
{
|
||||
event->type = release ? CLUTTER_BUTTON_RELEASE : CLUTTER_BUTTON_PRESS;
|
||||
event->button.time = msg->time;
|
||||
@ -212,6 +216,7 @@ make_button_event (const MSG *msg, ClutterEvent *event,
|
||||
event->button.modifier_state = get_modifier_state (msg->wParam);
|
||||
event->button.button = button;
|
||||
event->button.click_count = click_count;
|
||||
event->button.device = device;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -326,11 +331,11 @@ message_translate (ClutterBackend *backend,
|
||||
const MSG *msg,
|
||||
gboolean *call_def_window_proc)
|
||||
{
|
||||
ClutterBackendWin32 *backend_win32;
|
||||
ClutterStageWin32 *stage_win32;
|
||||
ClutterStage *stage;
|
||||
ClutterStageWindow *impl;
|
||||
gboolean res;
|
||||
ClutterBackendWin32 *backend_win32;
|
||||
ClutterStageWin32 *stage_win32;
|
||||
ClutterStage *stage;
|
||||
ClutterStageWindow *impl;
|
||||
gboolean res;
|
||||
|
||||
backend_win32 = CLUTTER_BACKEND_WIN32 (backend);
|
||||
|
||||
@ -429,39 +434,39 @@ message_translate (ClutterBackend *backend,
|
||||
break;
|
||||
|
||||
case WM_LBUTTONDOWN:
|
||||
make_button_event (msg, event, 1, 1, FALSE);
|
||||
make_button_event (msg, event, 1, 1, FALSE, backend_win32->core_pointer);
|
||||
break;
|
||||
|
||||
case WM_MBUTTONDOWN:
|
||||
make_button_event (msg, event, 2, 1, FALSE);
|
||||
make_button_event (msg, event, 2, 1, FALSE, backend_win32->core_pointer);
|
||||
break;
|
||||
|
||||
case WM_RBUTTONDOWN:
|
||||
make_button_event (msg, event, 3, 1, FALSE);
|
||||
make_button_event (msg, event, 3, 1, FALSE, backend_win32->core_pointer);
|
||||
break;
|
||||
|
||||
case WM_LBUTTONUP:
|
||||
make_button_event (msg, event, 1, 1, TRUE);
|
||||
make_button_event (msg, event, 1, 1, TRUE, backend_win32->core_pointer);
|
||||
break;
|
||||
|
||||
case WM_MBUTTONUP:
|
||||
make_button_event (msg, event, 2, 1, TRUE);
|
||||
make_button_event (msg, event, 2, 1, TRUE, backend_win32->core_pointer);
|
||||
break;
|
||||
|
||||
case WM_RBUTTONUP:
|
||||
make_button_event (msg, event, 3, 1, TRUE);
|
||||
make_button_event (msg, event, 3, 1, TRUE, backend_win32->core_pointer);
|
||||
break;
|
||||
|
||||
case WM_LBUTTONDBLCLK:
|
||||
make_button_event (msg, event, 1, 2, FALSE);
|
||||
make_button_event (msg, event, 1, 2, FALSE, backend_win32->core_pointer);
|
||||
break;
|
||||
|
||||
case WM_MBUTTONDBLCLK:
|
||||
make_button_event (msg, event, 2, 2, FALSE);
|
||||
make_button_event (msg, event, 2, 2, FALSE, backend_win32->core_pointer);
|
||||
break;
|
||||
|
||||
case WM_RBUTTONDBLCLK:
|
||||
make_button_event (msg, event, 3, 2, FALSE);
|
||||
make_button_event (msg, event, 3, 2, FALSE, backend_win32->core_pointer);
|
||||
break;
|
||||
|
||||
case WM_MOUSEWHEEL:
|
||||
@ -469,8 +474,8 @@ message_translate (ClutterBackend *backend,
|
||||
|
||||
event->type = CLUTTER_SCROLL;
|
||||
event->scroll.time = msg->time;
|
||||
event->scroll.modifier_state
|
||||
= get_modifier_state (LOWORD (msg->wParam));
|
||||
event->scroll.modifier_state = get_modifier_state (LOWORD (msg->wParam));
|
||||
event->scroll.device = backend_win32->core_pointer;
|
||||
|
||||
/* conversion to window coordinates is required */
|
||||
{
|
||||
@ -500,7 +505,9 @@ message_translate (ClutterBackend *backend,
|
||||
event->motion.x = GET_X_LPARAM (msg->lParam);
|
||||
event->motion.y = GET_Y_LPARAM (msg->lParam);
|
||||
event->motion.modifier_state = get_modifier_state (msg->wParam);
|
||||
/* We need to start tracking when the mouse leaves the stage if
|
||||
event->motion.device = backend_win32->core_pointer;
|
||||
|
||||
/* We need to start tracking when the mouse enters the stage if
|
||||
we're not already */
|
||||
if (!stage_win32->tracking_mouse)
|
||||
{
|
||||
@ -511,6 +518,9 @@ message_translate (ClutterBackend *backend,
|
||||
tmevent.hwndTrack = stage_win32->hwnd;
|
||||
TrackMouseEvent (&tmevent);
|
||||
|
||||
/* we entered the stage */
|
||||
_clutter_input_device_set_stage (event->motion.device, stage);
|
||||
|
||||
stage_win32->tracking_mouse = TRUE;
|
||||
}
|
||||
break;
|
||||
@ -520,6 +530,10 @@ message_translate (ClutterBackend *backend,
|
||||
event->crossing.time = msg->time;
|
||||
event->crossing.x = msg->pt.x;
|
||||
event->crossing.y = msg->pt.y;
|
||||
event->crossing.device = backend_win32->core_pointer;
|
||||
|
||||
/* we left the stage */
|
||||
_clutter_input_device_set_stage (event->crossing.device, NULL);
|
||||
|
||||
/* When we get a leave message the mouse tracking is
|
||||
automatically cancelled so we'll need to start it again when
|
||||
@ -604,6 +618,7 @@ message_translate (ClutterBackend *backend,
|
||||
event->key.time = msg->time;
|
||||
event->key.modifier_state = get_key_modifier_state (key_states);
|
||||
event->key.hardware_keycode = scan_code;
|
||||
event->key.device = backend_win32->core_keyboard;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -43,6 +43,8 @@ libclutter_x11_la_SOURCES = \
|
||||
clutter-backend-x11.h \
|
||||
clutter-backend-x11.c \
|
||||
clutter-event-x11.c \
|
||||
clutter-input-device-x11.h \
|
||||
clutter-input-device-x11.c \
|
||||
clutter-stage-x11.h \
|
||||
clutter-stage-x11.c \
|
||||
clutter-x11-enum-types.h \
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include <errno.h>
|
||||
|
||||
#include "clutter-backend-x11.h"
|
||||
#include "clutter-input-device-x11.h"
|
||||
#include "clutter-stage-x11.h"
|
||||
#include "clutter-x11.h"
|
||||
|
||||
@ -46,31 +47,16 @@
|
||||
#include <X11/extensions/XInput.h>
|
||||
#endif
|
||||
|
||||
#include "../clutter-event.h"
|
||||
#include "../clutter-main.h"
|
||||
#include "../clutter-debug.h"
|
||||
#include "../clutter-private.h"
|
||||
|
||||
#include "cogl/cogl.h"
|
||||
|
||||
#include "../clutter-debug.h"
|
||||
#include "../clutter-device-manager.h"
|
||||
#include "../clutter-event.h"
|
||||
#include "../clutter-main.h"
|
||||
#include "../clutter-private.h"
|
||||
|
||||
G_DEFINE_TYPE (ClutterBackendX11, clutter_backend_x11, CLUTTER_TYPE_BACKEND);
|
||||
|
||||
struct _ClutterX11XInputDevice
|
||||
{
|
||||
ClutterInputDevice device;
|
||||
|
||||
#ifdef HAVE_XINPUT
|
||||
XDevice *xdevice;
|
||||
XEventClass xevent_list[5]; /* MAX 5 event types */
|
||||
int num_events;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef HAVE_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!
|
||||
@ -109,6 +95,129 @@ static gboolean clutter_synchronise = FALSE;
|
||||
static int TrappedErrorCode = 0;
|
||||
static int (* old_error_handler) (Display *, XErrorEvent *);
|
||||
|
||||
static void
|
||||
clutter_x11_register_input_devices (ClutterBackendX11 *backend)
|
||||
{
|
||||
ClutterDeviceManager *manager;
|
||||
ClutterInputDevice *device;
|
||||
#ifdef HAVE_XINPUT
|
||||
XDeviceInfo *x_devices = NULL;
|
||||
int res, opcode, event, error;
|
||||
int i, n_devices;
|
||||
#endif /* HAVE_XINPUT */
|
||||
|
||||
manager = clutter_device_manager_get_default ();
|
||||
|
||||
if (!clutter_enable_xinput)
|
||||
{
|
||||
CLUTTER_NOTE (BACKEND, "XInput support not enabled");
|
||||
goto default_device;
|
||||
}
|
||||
|
||||
#ifdef HAVE_XINPUT
|
||||
res = XQueryExtension (backend->xdpy, "XInputExtension",
|
||||
&opcode,
|
||||
&event,
|
||||
&error);
|
||||
if (!res)
|
||||
{
|
||||
CLUTTER_NOTE (BACKEND, "No XInput extension available");
|
||||
goto default_device;
|
||||
}
|
||||
|
||||
backend->xi_event_base = event;
|
||||
|
||||
x_devices = XListInputDevices (backend->xdpy, &n_devices);
|
||||
if (n_devices == 0)
|
||||
{
|
||||
CLUTTER_NOTE (BACKEND, "No XInput devices found");
|
||||
goto default_device;
|
||||
}
|
||||
|
||||
for (i = 0; i < n_devices; i++)
|
||||
{
|
||||
XDeviceInfo *info = x_devices + i;
|
||||
|
||||
CLUTTER_NOTE (BACKEND,
|
||||
"Considering device %li with type %d, %d of %d",
|
||||
info->id,
|
||||
info->use,
|
||||
i, n_devices);
|
||||
|
||||
/* we only want 'raw' devices, not virtual ones */
|
||||
if (info->use == IsXExtensionPointer ||
|
||||
/* info->use == IsXExtensionKeyboard || XInput1 is broken */
|
||||
info->use == IsXExtensionDevice)
|
||||
{
|
||||
ClutterInputDeviceType device_type;
|
||||
gint n_events = 0;
|
||||
|
||||
switch (info->use)
|
||||
{
|
||||
case IsXExtensionPointer:
|
||||
device_type = CLUTTER_POINTER_DEVICE;
|
||||
break;
|
||||
|
||||
/* XInput1 is broken for keyboards */
|
||||
case IsXExtensionKeyboard:
|
||||
device_type = CLUTTER_KEYBOARD_DEVICE;
|
||||
break;
|
||||
|
||||
case IsXExtensionDevice:
|
||||
device_type = CLUTTER_EXTENSION_DEVICE;
|
||||
break;
|
||||
}
|
||||
|
||||
device = g_object_new (CLUTTER_TYPE_INPUT_DEVICE_X11,
|
||||
"id", info->id,
|
||||
"device-type", device_type,
|
||||
"name", info->name,
|
||||
NULL);
|
||||
n_events = _clutter_input_device_x11_construct (device, backend);
|
||||
|
||||
_clutter_device_manager_add_device (manager, device);
|
||||
|
||||
if (info->use == IsXExtensionPointer && n_events > 0)
|
||||
backend->have_xinput = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
XFree (x_devices);
|
||||
#endif /* HAVE_XINPUT */
|
||||
|
||||
default_device:
|
||||
/* fallback code in case:
|
||||
*
|
||||
* - we do not have XInput support compiled in
|
||||
* - we do not have XInput support enabled
|
||||
* - we do not have the XInput extension
|
||||
*
|
||||
* we register two default devices, one for the pointer
|
||||
* and one for the keyboard. this block must also be
|
||||
* executed for the XInput support because XI does not
|
||||
* cover core devices
|
||||
*/
|
||||
device = g_object_new (CLUTTER_TYPE_INPUT_DEVICE_X11,
|
||||
"id", 0,
|
||||
"name", "Core Pointer",
|
||||
"device-type", CLUTTER_POINTER_DEVICE,
|
||||
"is-core", TRUE,
|
||||
NULL);
|
||||
CLUTTER_NOTE (BACKEND, "Added core pointer device");
|
||||
_clutter_device_manager_add_device (manager, device);
|
||||
backend->core_pointer = device;
|
||||
|
||||
device = g_object_new (CLUTTER_TYPE_INPUT_DEVICE_X11,
|
||||
"id", 1,
|
||||
"name", "Core Keyboard",
|
||||
"device-type", CLUTTER_KEYBOARD_DEVICE,
|
||||
"is-core", TRUE,
|
||||
NULL);
|
||||
CLUTTER_NOTE (BACKEND, "Added core keyboard device");
|
||||
_clutter_device_manager_add_device (manager, device);
|
||||
backend->core_keyboard = device;
|
||||
}
|
||||
|
||||
gboolean
|
||||
clutter_backend_x11_pre_parse (ClutterBackend *backend,
|
||||
GError **error)
|
||||
@ -199,9 +308,8 @@ clutter_backend_x11_post_parse (ClutterBackend *backend,
|
||||
|
||||
clutter_backend_set_resolution (backend, dpi);
|
||||
|
||||
#ifdef HAVE_XINPUT
|
||||
_clutter_x11_register_xinput ();
|
||||
#endif
|
||||
/* register input devices */
|
||||
clutter_x11_register_input_devices (backend_x11);
|
||||
|
||||
if (clutter_synchronise)
|
||||
XSynchronize (backend_x11->xdpy, True);
|
||||
@ -644,239 +752,29 @@ clutter_x11_remove_filter (ClutterX11FilterFunc func,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_x11_register_xinput ()
|
||||
{
|
||||
#ifdef HAVE_XINPUT
|
||||
XDeviceInfo *xdevices = NULL;
|
||||
XDeviceInfo *info = NULL;
|
||||
|
||||
XDevice *xdevice = NULL;
|
||||
|
||||
XInputClassInfo *xclass_info = NULL;
|
||||
|
||||
gint opcode, event, error;
|
||||
gint res;
|
||||
gint num_devices = 0;
|
||||
gint num_events = 0;
|
||||
gint i = 0, j = 0;
|
||||
gboolean have_an_xpointer = FALSE;
|
||||
|
||||
ClutterBackendX11 *x11b;
|
||||
ClutterX11XInputDevice *device = NULL;
|
||||
|
||||
ClutterMainContext *context;
|
||||
|
||||
GSList *input_devices = NULL;
|
||||
|
||||
if (!backend_singleton)
|
||||
{
|
||||
g_critical ("X11 backend has not been initialised");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!clutter_enable_xinput)
|
||||
{
|
||||
CLUTTER_NOTE (BACKEND, "Not enabling XInput");
|
||||
return;
|
||||
}
|
||||
|
||||
context = _clutter_context_get_default ();
|
||||
|
||||
backend_singleton->have_xinput = FALSE;
|
||||
|
||||
/* is the XInput extension available? */
|
||||
res = XQueryExtension (backend_singleton->xdpy, "XInputExtension",
|
||||
&opcode, &event,
|
||||
&error);
|
||||
if (!res)
|
||||
{
|
||||
CLUTTER_NOTE (BACKEND, "X Input extension not available");
|
||||
return;
|
||||
}
|
||||
|
||||
x11b = backend_singleton;
|
||||
|
||||
xdevices = XListInputDevices (x11b->xdpy, &num_devices);
|
||||
|
||||
CLUTTER_NOTE (BACKEND, "%d XINPUT devices found", num_devices);
|
||||
|
||||
if (num_devices == 0)
|
||||
return;
|
||||
|
||||
for (i = 0; i < num_devices; i++)
|
||||
{
|
||||
info = xdevices + i;
|
||||
num_events = 0;
|
||||
|
||||
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 || XInput 1.x is broken */
|
||||
info->use == IsXExtensionDevice)
|
||||
{
|
||||
clutter_x11_trap_x_errors ();
|
||||
xdevice = XOpenDevice (backend_singleton->xdpy, info->id);
|
||||
if (clutter_x11_untrap_x_errors () || xdevice == NULL)
|
||||
continue;
|
||||
|
||||
/* Create the appropriate Clutter device */
|
||||
device = g_slice_new0 (ClutterX11XInputDevice);
|
||||
|
||||
device->device.id = info->id;
|
||||
|
||||
switch (info->use)
|
||||
{
|
||||
case IsXExtensionPointer:
|
||||
device->device.device_type = CLUTTER_POINTER_DEVICE;
|
||||
have_an_xpointer = TRUE;
|
||||
break;
|
||||
|
||||
#if 0
|
||||
/* XInput 1.x is broken for keyboards: */
|
||||
case IsXExtensionKeyboard:
|
||||
device->device.type = CLUTTER_KEYBOARD_DEVICE;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case IsXExtensionDevice:
|
||||
device->device.device_type = CLUTTER_EXTENSION_DEVICE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* 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->num_events = 0;
|
||||
device->xdevice = xdevice;
|
||||
|
||||
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)
|
||||
{
|
||||
#if 0
|
||||
/* XInput 1.x is broken for keyboards: */
|
||||
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;
|
||||
#endif
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (info->use == IsXExtensionPointer && num_events > 0)
|
||||
have_an_xpointer = TRUE;
|
||||
|
||||
device->num_events = num_events;
|
||||
|
||||
input_devices = g_slist_prepend (input_devices, device);
|
||||
}
|
||||
}
|
||||
|
||||
XFree (xdevices);
|
||||
|
||||
if (!have_an_xpointer)
|
||||
{
|
||||
GSList *l;
|
||||
|
||||
/* Something is likely wrong with Xinput setup so we basically
|
||||
* abort here and fall back to lofi regular xinput.
|
||||
*/
|
||||
g_warning ("No usuable XInput pointing devices found");
|
||||
|
||||
for (l = input_devices; l != NULL; l = l->next)
|
||||
g_slice_free (ClutterX11XInputDevice, l->data);
|
||||
|
||||
g_slist_free (input_devices);
|
||||
context->input_devices = NULL;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* store the list of input devices */
|
||||
context->input_devices = g_slist_reverse (input_devices);
|
||||
|
||||
/* why yes, we are awesome */
|
||||
backend_singleton->have_xinput = TRUE;
|
||||
#endif /* HAVE_XINPUT */
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_x11_unregister_xinput ()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_x11_select_events (Window xwin)
|
||||
{
|
||||
#ifdef HAVE_XINPUT
|
||||
GSList *list_it;
|
||||
ClutterX11XInputDevice *device = NULL;
|
||||
ClutterDeviceManager *manager;
|
||||
const GSList *l;
|
||||
|
||||
ClutterMainContext *context;
|
||||
|
||||
context = _clutter_context_get_default ();
|
||||
|
||||
if (!backend_singleton)
|
||||
if (G_UNLIKELY (backend_singleton == NULL))
|
||||
{
|
||||
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;
|
||||
manager = clutter_device_manager_get_default ();
|
||||
|
||||
XSelectExtensionEvent (backend_singleton->xdpy,
|
||||
xwin,
|
||||
device->xevent_list,
|
||||
device->num_events);
|
||||
for (l = clutter_device_manager_peek_devices (manager);
|
||||
l != NULL;
|
||||
l = l->next)
|
||||
{
|
||||
ClutterInputDevice *device = l->data;
|
||||
|
||||
_clutter_input_device_x11_select_events (device, backend_singleton, xwin);
|
||||
}
|
||||
#endif /* HAVE_XINPUT */
|
||||
}
|
||||
@ -884,49 +782,34 @@ _clutter_x11_select_events (Window xwin)
|
||||
ClutterInputDevice *
|
||||
_clutter_x11_get_device_for_xid (XID id)
|
||||
{
|
||||
#ifdef HAVE_XINPUT
|
||||
ClutterMainContext *context;
|
||||
GSList *l;
|
||||
ClutterDeviceManager *manager;
|
||||
|
||||
context = _clutter_context_get_default ();
|
||||
manager = clutter_device_manager_get_default ();
|
||||
|
||||
if (!backend_singleton)
|
||||
{
|
||||
g_critical ("X11 backend has not been initialised");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (l = context->input_devices; l != NULL; l = l->next)
|
||||
{
|
||||
ClutterX11XInputDevice *device = l->data;
|
||||
|
||||
if (device->xdevice->device_id == id)
|
||||
return (ClutterInputDevice *) device;
|
||||
}
|
||||
#endif /* HAVE_XINPUT */
|
||||
|
||||
return NULL;
|
||||
return clutter_device_manager_get_device (manager, (gint) id);
|
||||
}
|
||||
|
||||
/* FIXME: This nasty little func needs moving elsewhere.. */
|
||||
/**
|
||||
* clutter_x11_get_input_devices:
|
||||
*
|
||||
* Retrieves a pointer to the list of input devices
|
||||
*
|
||||
* Deprecated: 1.2: Use clutter_device_manager_peek_devices() instead
|
||||
*
|
||||
* Since: 0.8
|
||||
*
|
||||
* Return value: a pointer to the internal list of input devices; the
|
||||
* returned list is owned by Clutter and should not be modified or
|
||||
* freed
|
||||
*/
|
||||
G_CONST_RETURN GSList *
|
||||
clutter_x11_get_input_devices (void)
|
||||
{
|
||||
#ifdef HAVE_XINPUT
|
||||
ClutterMainContext *context;
|
||||
ClutterDeviceManager *manager;
|
||||
|
||||
if (!backend_singleton)
|
||||
{
|
||||
g_critical ("X11 backend has not been initialised");
|
||||
return NULL;
|
||||
}
|
||||
manager = clutter_device_manager_get_default ();
|
||||
|
||||
context = _clutter_context_get_default ();
|
||||
|
||||
return context->input_devices;
|
||||
#else /* !HAVE_XINPUT */
|
||||
return NULL;
|
||||
#endif /* HAVE_XINPUT */
|
||||
return clutter_device_manager_peek_devices (manager);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -943,7 +826,7 @@ gboolean
|
||||
clutter_x11_has_xinput (void)
|
||||
{
|
||||
#ifdef HAVE_XINPUT
|
||||
if (!backend_singleton)
|
||||
if (backend_singleton == NULL)
|
||||
{
|
||||
g_critical ("X11 backend has not been initialised");
|
||||
return FALSE;
|
||||
|
@ -76,10 +76,14 @@ struct _ClutterBackendX11
|
||||
Atom atom_NET_WM_NAME;
|
||||
Atom atom_UTF8_STRING;
|
||||
|
||||
int xi_event_base;
|
||||
int event_types[CLUTTER_X11_XINPUT_LAST_EVENT];
|
||||
gboolean have_xinput;
|
||||
|
||||
Time last_event_time;
|
||||
|
||||
ClutterInputDevice *core_pointer;
|
||||
ClutterInputDevice *core_keyboard;
|
||||
};
|
||||
|
||||
struct _ClutterBackendX11Class
|
||||
@ -125,12 +129,6 @@ clutter_backend_x11_get_features (ClutterBackend *backend);
|
||||
XVisualInfo *
|
||||
clutter_backend_x11_get_visual_info (ClutterBackendX11 *backend_x11);
|
||||
|
||||
void
|
||||
_clutter_x11_register_xinput (void);
|
||||
|
||||
void
|
||||
_clutter_x11_unregister_xinput (void);
|
||||
|
||||
ClutterInputDevice *
|
||||
_clutter_x11_get_device_for_xid (XID id);
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
/* Clutter.
|
||||
* An OpenGL based 'interactive canvas' library.
|
||||
* Authored By Matthew Allum <mallum@openedhand.com>
|
||||
* Copyright (C) 2006-2007 OpenedHand
|
||||
*
|
||||
* Copyright (C) 2006, 2007, 2008 OpenedHand Ltd
|
||||
* Copyright (C) 2009, 2010 Intel Corp.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@ -17,6 +18,10 @@
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Authored by:
|
||||
* Matthew Allum <mallum@openedhand.com>
|
||||
* Emmanuele Bassi <ebassi@linux.intel.com>
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
@ -183,7 +188,6 @@ _clutter_backend_x11_events_init (ClutterBackend *backend)
|
||||
g_source_add_poll (source, &event_source->event_poll_fd);
|
||||
g_source_set_can_recurse (source, TRUE);
|
||||
g_source_attach (source, NULL);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
@ -263,9 +267,10 @@ set_user_time (ClutterBackendX11 *backend_x11,
|
||||
}
|
||||
}
|
||||
|
||||
#if 0 /* See XInput keyboard comment below HAVE_XINPUT */
|
||||
#ifdef HAVE_XINPUT
|
||||
static void
|
||||
convert_xdevicekey_to_xkey (XDeviceKeyEvent *xkev, XEvent *xevent)
|
||||
convert_xdevicekey_to_xkey (XDeviceKeyEvent *xkev,
|
||||
XEvent *xevent)
|
||||
{
|
||||
xevent->xany.type = xevent->xkey.type = xkev->type;
|
||||
xevent->xkey.serial = xkev->serial;
|
||||
@ -410,27 +415,28 @@ event_translate (ClutterBackend *backend,
|
||||
ClutterEvent *event,
|
||||
XEvent *xevent)
|
||||
{
|
||||
ClutterBackendX11 *backend_x11;
|
||||
ClutterStageX11 *stage_x11;
|
||||
ClutterStage *stage;
|
||||
ClutterBackendX11 *backend_x11;
|
||||
ClutterStageX11 *stage_x11;
|
||||
ClutterStage *stage;
|
||||
ClutterStageWindow *impl;
|
||||
gboolean res, not_yet_handled = FALSE;
|
||||
Window xwindow, stage_xwindow;
|
||||
gboolean res, not_yet_handled = FALSE;
|
||||
Window xwindow, stage_xwindow;
|
||||
ClutterDeviceManager *manager;
|
||||
ClutterInputDevice *device;
|
||||
|
||||
backend_x11 = CLUTTER_BACKEND_X11 (backend);
|
||||
backend_x11 = CLUTTER_BACKEND_X11 (backend);
|
||||
|
||||
xwindow = xevent->xany.window;
|
||||
|
||||
if (backend_x11->event_filters)
|
||||
{
|
||||
GSList *node;
|
||||
ClutterX11EventFilter *filter;
|
||||
GSList *node;
|
||||
|
||||
node = backend_x11->event_filters;
|
||||
|
||||
while (node)
|
||||
{
|
||||
filter = node->data;
|
||||
ClutterX11EventFilter *filter = node->data;
|
||||
|
||||
switch (filter->func (xevent, event, filter->data))
|
||||
{
|
||||
@ -448,19 +454,19 @@ event_translate (ClutterBackend *backend,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Do further processing only on events for the stage window
|
||||
* (the x11 filters might be getting events for other windows, so do not
|
||||
* mess them about.
|
||||
/* Do further processing only on events for the stage window (the x11
|
||||
* filters might be getting events for other windows, so do not mess
|
||||
* them about.
|
||||
*/
|
||||
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);
|
||||
stage_xwindow = xwindow; /* clutter_x11_get_stage_window (stage); */
|
||||
manager = clutter_device_manager_get_default ();
|
||||
|
||||
impl = _clutter_stage_get_window (stage);
|
||||
stage_x11 = CLUTTER_STAGE_X11 (impl);
|
||||
stage_xwindow = xwindow; /* clutter_x11_get_stage_window (stage); */
|
||||
|
||||
event->any.stage = stage;
|
||||
|
||||
@ -621,6 +627,8 @@ event_translate (ClutterBackend *backend,
|
||||
|
||||
case KeyPress:
|
||||
event->key.type = event->type = CLUTTER_KEY_PRESS;
|
||||
event->key.device = backend_x11->core_keyboard;
|
||||
|
||||
translate_key_event (backend, event, xevent);
|
||||
|
||||
set_user_time (backend_x11, &xwindow, xevent->xkey.time);
|
||||
@ -654,6 +662,8 @@ event_translate (ClutterBackend *backend,
|
||||
}
|
||||
|
||||
event->key.type = event->type = CLUTTER_KEY_RELEASE;
|
||||
event->key.device = backend_x11->core_keyboard;
|
||||
|
||||
translate_key_event (backend, event, xevent);
|
||||
break;
|
||||
|
||||
@ -666,239 +676,287 @@ event_translate (ClutterBackend *backend,
|
||||
/* Input device event handling.. */
|
||||
if (not_yet_handled)
|
||||
{
|
||||
if (!clutter_x11_has_xinput ())
|
||||
device = backend_x11->core_pointer;
|
||||
|
||||
/* Regular X event */
|
||||
switch (xevent->type)
|
||||
{
|
||||
/* Regular X event */
|
||||
switch (xevent->type)
|
||||
case ButtonPress:
|
||||
switch (xevent->xbutton.button)
|
||||
{
|
||||
/* KeyPress / KeyRelease should reside here if XInput
|
||||
* worked properly
|
||||
*/
|
||||
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);
|
||||
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;
|
||||
event->scroll.device = device;
|
||||
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;
|
||||
|
||||
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;
|
||||
event->button.device = device;
|
||||
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 EnterNotify:
|
||||
/* Convert enter notifies to motion events because X
|
||||
doesn't emit the corresponding motion notify */
|
||||
event->motion.type = event->type = CLUTTER_MOTION;
|
||||
event->motion.time = xevent->xcrossing.time;
|
||||
event->motion.x = xevent->xcrossing.x;
|
||||
event->motion.y = xevent->xcrossing.y;
|
||||
event->motion.modifier_state = xevent->xcrossing.state;
|
||||
break;
|
||||
set_user_time (backend_x11, &xwindow, event->button.time);
|
||||
|
||||
case LeaveNotify:
|
||||
event->crossing.type = event->type = CLUTTER_LEAVE;
|
||||
event->crossing.time = xevent->xcrossing.time;
|
||||
event->crossing.x = xevent->xcrossing.x;
|
||||
event->crossing.y = xevent->xcrossing.y;
|
||||
res = TRUE;
|
||||
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;
|
||||
goto out;
|
||||
}
|
||||
|
||||
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;
|
||||
event->button.device = device;
|
||||
|
||||
res = TRUE;
|
||||
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;
|
||||
event->motion.device = device;
|
||||
|
||||
res = TRUE;
|
||||
break;
|
||||
|
||||
case EnterNotify:
|
||||
/* we know that we are entering the stage here */
|
||||
_clutter_input_device_set_stage (device, stage);
|
||||
CLUTTER_NOTE (EVENT, "Entering the stage");
|
||||
|
||||
/* Convert enter notifies to motion events because X
|
||||
doesn't emit the corresponding motion notify */
|
||||
event->motion.type = event->type = CLUTTER_MOTION;
|
||||
event->motion.time = xevent->xcrossing.time;
|
||||
event->motion.x = xevent->xcrossing.x;
|
||||
event->motion.y = xevent->xcrossing.y;
|
||||
event->motion.modifier_state = xevent->xcrossing.state;
|
||||
event->motion.source = CLUTTER_ACTOR (stage);
|
||||
event->motion.device = device;
|
||||
|
||||
res = TRUE;
|
||||
break;
|
||||
|
||||
case LeaveNotify:
|
||||
if (device->stage == NULL)
|
||||
{
|
||||
CLUTTER_NOTE (EVENT,
|
||||
"Discarding LeaveNotify for ButtonRelease "
|
||||
"event off-stage");
|
||||
res = FALSE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* we know that we are leaving the stage here */
|
||||
_clutter_input_device_set_stage (device, NULL);
|
||||
CLUTTER_NOTE (EVENT, "Leaving the stage (time:%u)",
|
||||
event->crossing.time);
|
||||
|
||||
event->crossing.type = event->type = CLUTTER_LEAVE;
|
||||
event->crossing.time = xevent->xcrossing.time;
|
||||
event->crossing.x = xevent->xcrossing.x;
|
||||
event->crossing.y = xevent->xcrossing.y;
|
||||
event->crossing.source = CLUTTER_ACTOR (stage);
|
||||
event->crossing.device = device;
|
||||
res = TRUE;
|
||||
break;
|
||||
|
||||
default:
|
||||
res = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* XInput fun...*/
|
||||
if (!res && clutter_x11_has_xinput ())
|
||||
{
|
||||
#ifdef HAVE_XINPUT
|
||||
int *ev_types = backend_x11->event_types;
|
||||
int button_press, button_release;
|
||||
int key_press, key_release;
|
||||
int motion_notify;
|
||||
|
||||
button_press = ev_types[CLUTTER_X11_XINPUT_BUTTON_PRESS_EVENT];
|
||||
button_release = ev_types[CLUTTER_X11_XINPUT_BUTTON_RELEASE_EVENT];
|
||||
motion_notify = ev_types[CLUTTER_X11_XINPUT_MOTION_NOTIFY_EVENT];
|
||||
key_press = ev_types[CLUTTER_X11_XINPUT_KEY_PRESS_EVENT];
|
||||
key_release = ev_types[CLUTTER_X11_XINPUT_KEY_RELEASE_EVENT];
|
||||
|
||||
CLUTTER_NOTE (EVENT, "XInput event type: %d", xevent->type);
|
||||
|
||||
if (xevent->type == button_press)
|
||||
{
|
||||
XDeviceButtonEvent *xbev = (XDeviceButtonEvent *) xevent;
|
||||
|
||||
device = _clutter_x11_get_device_for_xid (xbev->deviceid);
|
||||
_clutter_input_device_set_stage (device, stage);
|
||||
|
||||
CLUTTER_NOTE (EVENT,
|
||||
"XI ButtonPress for %li ('%s') at %d, %d",
|
||||
xbev->deviceid,
|
||||
device->device_name,
|
||||
xbev->x,
|
||||
xbev->y);
|
||||
|
||||
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 = device;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* ignore every other event */
|
||||
res = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* XInput fun.. Needs clean up. */
|
||||
#ifdef HAVE_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;
|
||||
|
||||
CLUTTER_NOTE (EVENT, "XINPUT Button press event for %li at %d, %d",
|
||||
xbev->deviceid,
|
||||
xbev->x,
|
||||
xbev->y);
|
||||
|
||||
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 = _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 = _clutter_x11_get_device_for_xid (xbev->deviceid);
|
||||
break;
|
||||
}
|
||||
|
||||
set_user_time (backend_x11, &xwindow, xbev->time);
|
||||
}
|
||||
else if (xevent->type
|
||||
== ev_types[CLUTTER_X11_XINPUT_BUTTON_RELEASE_EVENT])
|
||||
{
|
||||
XDeviceButtonEvent *xbev = (XDeviceButtonEvent *)xevent;
|
||||
|
||||
CLUTTER_NOTE (EVENT, "XINPUT Button release event for %li at %d, %d",
|
||||
xbev->deviceid,
|
||||
xbev->x,
|
||||
xbev->y);
|
||||
|
||||
/* scroll events don't have a corresponding release */
|
||||
if (xbev->button == 4 ||
|
||||
xbev->button == 5 ||
|
||||
xbev->button == 6 ||
|
||||
xbev->button == 7)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
event->button.type = event->type = CLUTTER_BUTTON_RELEASE;
|
||||
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 = _clutter_x11_get_device_for_xid (xbev->deviceid);
|
||||
}
|
||||
else if (xevent->type
|
||||
== ev_types [CLUTTER_X11_XINPUT_MOTION_NOTIFY_EVENT])
|
||||
{
|
||||
XDeviceMotionEvent *xmev = (XDeviceMotionEvent *)xevent;
|
||||
|
||||
CLUTTER_NOTE(EVENT, "XINPUT Motion event for %li at %d, %d",
|
||||
xmev->deviceid,
|
||||
xmev->x,
|
||||
xmev->y);
|
||||
|
||||
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 = _clutter_x11_get_device_for_xid (xmev->deviceid);
|
||||
}
|
||||
#if 0
|
||||
/* the Xinput handling of key presses/releases disabled for now since
|
||||
* it makes keyrepeat, and key presses and releases outside the window
|
||||
* not generate events even when the window has focus
|
||||
*/
|
||||
|
||||
else if (xevent->type
|
||||
== ev_types [CLUTTER_X11_XINPUT_KEY_PRESS_EVENT])
|
||||
{
|
||||
XEvent xevent_converted;
|
||||
XDeviceKeyEvent *xkev = (XDeviceKeyEvent *)xevent;
|
||||
|
||||
convert_xdevicekey_to_xkey (xkev, &xevent_converted);
|
||||
|
||||
event->key.type = event->type = CLUTTER_KEY_PRESS;
|
||||
translate_key_event (backend, event, &xevent_converted);
|
||||
|
||||
set_user_time (backend_x11, &xwindow, xkev->time);
|
||||
}
|
||||
else if (xevent->type
|
||||
== ev_types [CLUTTER_X11_XINPUT_KEY_RELEASE_EVENT])
|
||||
{
|
||||
XEvent xevent_converted;
|
||||
XDeviceKeyEvent *xkev = (XDeviceKeyEvent *)xevent;
|
||||
|
||||
convert_xdevicekey_to_xkey (xkev, &xevent_converted);
|
||||
|
||||
event->key.type = event->type = CLUTTER_KEY_RELEASE;
|
||||
translate_key_event (backend, event, &xevent_converted);
|
||||
event->button.device = device;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
#endif /* HAVE_XINPUT */
|
||||
|
||||
set_user_time (backend_x11, &xwindow, xbev->time);
|
||||
|
||||
res = TRUE;
|
||||
}
|
||||
else if (xevent->type == button_release)
|
||||
{
|
||||
XDeviceButtonEvent *xbev = (XDeviceButtonEvent *)xevent;
|
||||
|
||||
device = _clutter_x11_get_device_for_xid (xbev->deviceid);
|
||||
_clutter_input_device_set_stage (device, stage);
|
||||
|
||||
CLUTTER_NOTE (EVENT, "XI ButtonRelease for %li ('%s') at %d, %d",
|
||||
xbev->deviceid,
|
||||
device->device_name,
|
||||
xbev->x,
|
||||
xbev->y);
|
||||
|
||||
/* scroll events don't have a corresponding release */
|
||||
if (xbev->button == 4 ||
|
||||
xbev->button == 5 ||
|
||||
xbev->button == 6 ||
|
||||
xbev->button == 7)
|
||||
{
|
||||
CLUTTER_NOTE (EVENT, "Uknown Event");
|
||||
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 = device;
|
||||
|
||||
res = TRUE;
|
||||
}
|
||||
else if (xevent->type == motion_notify)
|
||||
{
|
||||
XDeviceMotionEvent *xmev = (XDeviceMotionEvent *)xevent;
|
||||
|
||||
device = _clutter_x11_get_device_for_xid (xmev->deviceid);
|
||||
_clutter_input_device_set_stage (device, stage);
|
||||
|
||||
CLUTTER_NOTE (EVENT, "XI Motion for %li ('%s') at %d, %d",
|
||||
xmev->deviceid,
|
||||
device->device_name,
|
||||
xmev->x,
|
||||
xmev->y);
|
||||
|
||||
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 = device;
|
||||
|
||||
res = TRUE;
|
||||
}
|
||||
else if (xevent->type == key_press || xevent->type == key_release)
|
||||
{
|
||||
/* the XInput 1.x handling of key presses/releases is broken:
|
||||
* it makes key repeat, key presses and releases outside the
|
||||
* window not generate events even when the window has focus
|
||||
*/
|
||||
XDeviceKeyEvent *xkev = (XDeviceKeyEvent *) xevent;
|
||||
XEvent xevent_converted;
|
||||
|
||||
convert_xdevicekey_to_xkey (xkev, &xevent_converted);
|
||||
|
||||
event->key.type = event->type = (xevent->type == key_press)
|
||||
? CLUTTER_KEY_PRESS
|
||||
: CLUTTER_KEY_RELEASE;
|
||||
|
||||
translate_key_event (backend, event, &xevent_converted);
|
||||
|
||||
if (xevent->type == key_press)
|
||||
set_user_time (backend_x11, &xwindow, xkev->time);
|
||||
}
|
||||
else
|
||||
#endif /* HAVE_XINPUT */
|
||||
{
|
||||
CLUTTER_NOTE (EVENT, "Uknown Event");
|
||||
res = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return res;
|
||||
}
|
||||
|
||||
|
221
clutter/x11/clutter-input-device-x11.c
Normal file
221
clutter/x11/clutter-input-device-x11.c
Normal file
@ -0,0 +1,221 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "clutter-input-device-x11.h"
|
||||
#include "../clutter-debug.h"
|
||||
#include "../clutter-private.h"
|
||||
|
||||
#ifdef HAVE_XINPUT
|
||||
#include <X11/extensions/XInput.h>
|
||||
#endif
|
||||
|
||||
typedef struct _ClutterInputDeviceClass ClutterInputDeviceX11Class;
|
||||
|
||||
/* a specific X11 input device */
|
||||
struct _ClutterInputDeviceX11
|
||||
{
|
||||
ClutterInputDevice device;
|
||||
|
||||
#ifdef HAVE_XINPUT
|
||||
XDevice *xdevice;
|
||||
XEventClass xevent_list[5]; /* MAX 5 event types */
|
||||
int num_events;
|
||||
#endif
|
||||
|
||||
guint is_core : 1;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
|
||||
PROP_IS_CORE
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (ClutterInputDeviceX11,
|
||||
clutter_input_device_x11,
|
||||
CLUTTER_TYPE_INPUT_DEVICE);
|
||||
|
||||
static void
|
||||
clutter_input_device_x11_set_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ClutterInputDeviceX11 *self = CLUTTER_INPUT_DEVICE_X11 (gobject);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_IS_CORE:
|
||||
self->is_core = g_value_get_boolean (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_input_device_x11_get_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ClutterInputDeviceX11 *self = CLUTTER_INPUT_DEVICE_X11 (gobject);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_IS_CORE:
|
||||
g_value_set_boolean (value, self->is_core);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_input_device_x11_class_init (ClutterInputDeviceX11Class *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
GParamSpec *pspec;
|
||||
|
||||
gobject_class->set_property = clutter_input_device_x11_set_property;
|
||||
gobject_class->get_property = clutter_input_device_x11_get_property;
|
||||
|
||||
pspec = g_param_spec_boolean ("is-core",
|
||||
"Is Core",
|
||||
"Whether the device is a core one",
|
||||
FALSE,
|
||||
CLUTTER_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY);
|
||||
g_object_class_install_property (gobject_class, PROP_IS_CORE, pspec);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_input_device_x11_init (ClutterInputDeviceX11 *self)
|
||||
{
|
||||
self->is_core = FALSE;
|
||||
}
|
||||
|
||||
gint
|
||||
_clutter_input_device_x11_construct (ClutterInputDevice *device,
|
||||
ClutterBackendX11 *backend)
|
||||
{
|
||||
int n_events = 0;
|
||||
|
||||
#ifdef HAVE_XINPUT
|
||||
ClutterInputDeviceX11 *device_x11;
|
||||
XDevice *x_device = NULL;
|
||||
gint device_id;
|
||||
int i;
|
||||
|
||||
device_x11 = CLUTTER_INPUT_DEVICE_X11 (device);
|
||||
device_id = clutter_input_device_get_device_id (device);
|
||||
|
||||
clutter_x11_trap_x_errors ();
|
||||
|
||||
/* retrieve the X11 device */
|
||||
x_device = XOpenDevice (backend->xdpy, device_id);
|
||||
|
||||
if (clutter_x11_untrap_x_errors () || x_device == NULL)
|
||||
{
|
||||
CLUTTER_NOTE (BACKEND, "Unable to open device %i", device_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
device_x11->xdevice = x_device;
|
||||
|
||||
CLUTTER_NOTE (BACKEND,
|
||||
"Registering XINPUT device with XID: %li",
|
||||
x_device->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 (i = 0; i < x_device->num_classes; i++)
|
||||
{
|
||||
XInputClassInfo *xclass_info = x_device->classes + i;
|
||||
int *button_press, *button_release, *motion_notify;
|
||||
int *key_press, *key_release;
|
||||
|
||||
button_press =
|
||||
&backend->event_types[CLUTTER_X11_XINPUT_BUTTON_PRESS_EVENT];
|
||||
button_release =
|
||||
&backend->event_types[CLUTTER_X11_XINPUT_BUTTON_RELEASE_EVENT];
|
||||
motion_notify =
|
||||
&backend->event_types[CLUTTER_X11_XINPUT_MOTION_NOTIFY_EVENT];
|
||||
|
||||
key_press =
|
||||
&backend->event_types[CLUTTER_X11_XINPUT_KEY_PRESS_EVENT];
|
||||
key_release =
|
||||
&backend->event_types[CLUTTER_X11_XINPUT_KEY_RELEASE_EVENT];
|
||||
|
||||
switch (xclass_info->input_class)
|
||||
{
|
||||
/* event though XInput 1.x is broken for keyboard-like devices
|
||||
* it might still be useful to track them down; the core keyboard
|
||||
* will handle the right events anyway
|
||||
*/
|
||||
case KeyClass:
|
||||
DeviceKeyPress (x_device,
|
||||
*key_press,
|
||||
device_x11->xevent_list[n_events]);
|
||||
n_events++;
|
||||
|
||||
DeviceKeyRelease (x_device,
|
||||
*key_release,
|
||||
device_x11->xevent_list[n_events]);
|
||||
n_events++;
|
||||
break;
|
||||
|
||||
case ButtonClass:
|
||||
DeviceButtonPress (x_device,
|
||||
*button_press,
|
||||
device_x11->xevent_list[n_events]);
|
||||
n_events++;
|
||||
|
||||
DeviceButtonRelease (x_device,
|
||||
*button_release,
|
||||
device_x11->xevent_list[n_events]);
|
||||
n_events++;
|
||||
break;
|
||||
|
||||
case ValuatorClass:
|
||||
DeviceMotionNotify (x_device,
|
||||
*motion_notify,
|
||||
device_x11->xevent_list[n_events]);
|
||||
n_events++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
device_x11->num_events = n_events;
|
||||
#endif /* HAVE_XINPUT */
|
||||
|
||||
return n_events;
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_input_device_x11_select_events (ClutterInputDevice *device,
|
||||
ClutterBackendX11 *backend_x11,
|
||||
Window xwin)
|
||||
{
|
||||
#if HAVE_XINPUT
|
||||
ClutterInputDeviceX11 *device_x11;
|
||||
|
||||
device_x11 = CLUTTER_INPUT_DEVICE_X11 (device);
|
||||
|
||||
if (device_x11->xdevice == None || device_x11->num_events == 0)
|
||||
return;
|
||||
|
||||
XSelectExtensionEvent (backend_x11->xdpy, xwin,
|
||||
device_x11->xevent_list,
|
||||
device_x11->num_events);
|
||||
#endif /* HAVE_XINPUT */
|
||||
}
|
25
clutter/x11/clutter-input-device-x11.h
Normal file
25
clutter/x11/clutter-input-device-x11.h
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef __CLUTTER_INPUT_DEVICE_X11_H__
|
||||
#define __CLUTTER_INPUT_DEVICE_X11_H__
|
||||
|
||||
#include <clutter/clutter-input-device.h>
|
||||
#include "clutter-backend-x11.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define CLUTTER_TYPE_INPUT_DEVICE_X11 (clutter_input_device_x11_get_type ())
|
||||
#define CLUTTER_INPUT_DEVICE_X11(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_INPUT_DEVICE_X11, ClutterInputDeviceX11))
|
||||
#define CLUTTER_IS_INPUT_DEVICE_X11(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_INPUT_DEVICE_X11))
|
||||
|
||||
typedef struct _ClutterInputDeviceX11 ClutterInputDeviceX11;
|
||||
|
||||
GType clutter_input_device_x11_get_type (void) G_GNUC_CONST;
|
||||
|
||||
gint _clutter_input_device_x11_construct (ClutterInputDevice *device,
|
||||
ClutterBackendX11 *backend);
|
||||
void _clutter_input_device_x11_select_events (ClutterInputDevice *device,
|
||||
ClutterBackendX11 *backend,
|
||||
Window xwin);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __CLUTTER_INPUT_DEVICE_X11_H__ */
|
@ -121,7 +121,9 @@ gboolean clutter_x11_has_event_retrieval (void);
|
||||
|
||||
ClutterStage *clutter_x11_get_stage_from_window (Window win);
|
||||
|
||||
#ifndef CLUTTER_DISABLE_DEPRECATED
|
||||
G_CONST_RETURN GSList* clutter_x11_get_input_devices (void);
|
||||
#endif
|
||||
|
||||
void clutter_x11_enable_xinput (void);
|
||||
gboolean clutter_x11_has_xinput (void);
|
||||
|
@ -139,6 +139,8 @@
|
||||
<xi:include href="xml/clutter-main.xml"/>
|
||||
<xi:include href="xml/clutter-shader.xml"/>
|
||||
<xi:include href="xml/clutter-stage-manager.xml"/>
|
||||
<xi:include href="xml/clutter-input-device.xml"/>
|
||||
<xi:include href="xml/clutter-device-manager.xml"/>
|
||||
<xi:include href="xml/clutter-units.xml"/>
|
||||
<xi:include href="xml/clutter-util.xml"/>
|
||||
<xi:include href="xml/clutter-feature.xml"/>
|
||||
|
@ -404,6 +404,7 @@ clutter_actor_create_pango_layout
|
||||
clutter_actor_is_in_clone_paint
|
||||
clutter_actor_set_text_direction
|
||||
clutter_actor_get_text_direction
|
||||
clutter_actor_has_pointer
|
||||
|
||||
<SUBSECTION>
|
||||
ClutterActorBox
|
||||
@ -940,7 +941,6 @@ ClutterMotionEvent
|
||||
ClutterScrollEvent
|
||||
ClutterStageStateEvent
|
||||
ClutterCrossingEvent
|
||||
ClutterInputDevice
|
||||
clutter_event_new
|
||||
clutter_event_copy
|
||||
clutter_event_free
|
||||
@ -977,13 +977,9 @@ clutter_event_get_related
|
||||
clutter_event_get_scroll_direction
|
||||
|
||||
<SUBSECTION>
|
||||
ClutterInputDeviceType
|
||||
clutter_event_get_device
|
||||
clutter_event_get_device_id
|
||||
clutter_event_get_device_type
|
||||
clutter_get_input_device_for_id
|
||||
clutter_input_device_get_device_id
|
||||
clutter_input_device_get_device_type
|
||||
|
||||
<SUBSECTION>
|
||||
clutter_get_current_event_time
|
||||
@ -996,6 +992,51 @@ ClutterAnyEvent
|
||||
clutter_event_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>clutter-input-device</FILE>
|
||||
<TITLE>ClutterInputDevice</TITLE>
|
||||
ClutterInputDeviceType
|
||||
ClutterInputDevice
|
||||
ClutterInputDeviceClass
|
||||
clutter_input_device_get_device_id
|
||||
clutter_input_device_get_device_type
|
||||
clutter_input_device_get_device_name
|
||||
clutter_input_device_get_device_coords
|
||||
clutter_input_device_get_pointer_actor
|
||||
|
||||
<SUBSECTION Standard>
|
||||
CLUTTER_TYPE_INPUT_DEVICE
|
||||
CLUTTER_INPUT_DEVICE
|
||||
CLUTTER_INPUT_DEVICE_CLASS
|
||||
CLUTTER_IS_INPUT_DEVICE
|
||||
CLUTTER_IS_INPUT_DEVICE_CLASS
|
||||
CLUTTER_INPUT_DEVICE_GET_CLASS
|
||||
|
||||
<SUBSECTION Private>
|
||||
clutter_input_device_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>clutter-device-manager</FILE>
|
||||
<TITLE>ClutterDeviceManager</TITLE>
|
||||
ClutterDeviceManager
|
||||
clutter_device_manager_get_default
|
||||
clutter_device_manager_list_devices
|
||||
clutter_device_manager_peek_devices
|
||||
clutter_device_manager_get_device
|
||||
|
||||
<SUBSECTION>
|
||||
clutter_get_input_device_for_id
|
||||
|
||||
<SUBSECTION Standard>
|
||||
CLUTTER_TYPE_DEVICE_MANAGER
|
||||
CLUTTER_DEVICE_MANAGER
|
||||
CLUTTER_IS_DEVICE_MANAGER
|
||||
|
||||
<SUBSECTION Private>
|
||||
clutter_device_manager_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>clutter-main</FILE>
|
||||
<TITLE>General</TITLE>
|
||||
|
@ -40,3 +40,5 @@ clutter_fixed_layout_get_type
|
||||
clutter_bin_layout_get_type
|
||||
clutter_flow_layout_get_type
|
||||
clutter_box_layout_get_type
|
||||
clutter_input_device_get_type
|
||||
clutter_device_manager_get_type
|
||||
|
@ -9,7 +9,31 @@ typedef struct {
|
||||
|
||||
} TestDevicesApp;
|
||||
|
||||
|
||||
static const gchar *
|
||||
device_type_name (ClutterInputDevice *device)
|
||||
{
|
||||
ClutterInputDeviceType d_type;
|
||||
|
||||
d_type = clutter_input_device_get_device_type (device);
|
||||
switch (d_type)
|
||||
{
|
||||
case CLUTTER_POINTER_DEVICE:
|
||||
return "Pointer";
|
||||
|
||||
case CLUTTER_KEYBOARD_DEVICE:
|
||||
return "Keyboard";
|
||||
|
||||
case CLUTTER_EXTENSION_DEVICE:
|
||||
return "Extension";
|
||||
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
g_warn_if_reached ();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
stage_motion_event_cb (ClutterActor *actor,
|
||||
@ -24,6 +48,11 @@ stage_motion_event_cb (ClutterActor *actor,
|
||||
|
||||
hand = g_hash_table_lookup (app->devices, device);
|
||||
|
||||
g_print ("Device: '%s' (id:%d, type:%s)\n",
|
||||
clutter_input_device_get_device_name (device),
|
||||
clutter_input_device_get_device_id (device),
|
||||
device_type_name (device));
|
||||
|
||||
if (hand != NULL)
|
||||
{
|
||||
gfloat event_x, event_y;
|
||||
@ -43,6 +72,7 @@ test_devices_main (int argc, char **argv)
|
||||
ClutterActor *stage;
|
||||
TestDevicesApp *app;
|
||||
ClutterColor stage_color = { 0x61, 0x64, 0x8c, 0xff };
|
||||
ClutterDeviceManager *manager;
|
||||
const GSList *stage_devices, *l;
|
||||
|
||||
/* force enabling X11 support */
|
||||
@ -63,10 +93,11 @@ test_devices_main (int argc, char **argv)
|
||||
|
||||
clutter_actor_show_all (stage);
|
||||
|
||||
stage_devices = clutter_x11_get_input_devices ();
|
||||
manager = clutter_device_manager_get_default ();
|
||||
stage_devices = clutter_device_manager_peek_devices (manager);
|
||||
|
||||
if (stage_devices == NULL)
|
||||
g_error ("No extended input devices found.");
|
||||
g_error ("No input devices found.");
|
||||
|
||||
for (l = stage_devices; l != NULL; l = l->next)
|
||||
{
|
||||
@ -74,12 +105,15 @@ test_devices_main (int argc, char **argv)
|
||||
ClutterInputDeviceType device_type;
|
||||
ClutterActor *hand = NULL;
|
||||
|
||||
device_type = clutter_input_device_get_device_type (device);
|
||||
if (device_type == CLUTTER_POINTER_DEVICE)
|
||||
{
|
||||
g_print ("got a pointer device with id %d...\n",
|
||||
clutter_input_device_get_device_id (device));
|
||||
g_print ("got a %s device '%s' with id %d...\n",
|
||||
device_type_name (device),
|
||||
clutter_input_device_get_device_name (device),
|
||||
clutter_input_device_get_device_id (device));
|
||||
|
||||
device_type = clutter_input_device_get_device_type (device);
|
||||
if (device_type == CLUTTER_POINTER_DEVICE ||
|
||||
device_type == CLUTTER_EXTENSION_DEVICE)
|
||||
{
|
||||
hand = clutter_texture_new_from_file (TESTS_DATADIR
|
||||
G_DIR_SEPARATOR_S
|
||||
"redhand.png",
|
||||
|
@ -27,6 +27,12 @@ get_event_type_name (const ClutterEvent *event)
|
||||
case CLUTTER_LEAVE:
|
||||
return "LEAVE";
|
||||
|
||||
case CLUTTER_MOTION:
|
||||
return "MOTION";
|
||||
|
||||
case CLUTTER_DELETE:
|
||||
return "DELETE";
|
||||
|
||||
default:
|
||||
return "EVENT";
|
||||
}
|
||||
@ -124,94 +130,122 @@ fill_keybuf (char *keybuf, ClutterKeyEvent *event)
|
||||
/* printable character, if any (ß, ∑) */
|
||||
len = g_unichar_to_utf8 (event->unicode_value, utf8);
|
||||
utf8[len] = '\0';
|
||||
sprintf(keybuf, "'%s' ", utf8);
|
||||
sprintf (keybuf, "'%s' ", utf8);
|
||||
|
||||
/* key combination (<Mod1>s, <Shift><Mod1>S, <Ctrl><Mod1>Delete) */
|
||||
len = g_unichar_to_utf8 (clutter_keysym_to_unicode (event->keyval),
|
||||
utf8);
|
||||
len = g_unichar_to_utf8 (clutter_keysym_to_unicode (event->keyval), utf8);
|
||||
utf8[len] = '\0';
|
||||
|
||||
if (event->modifier_state & CLUTTER_SHIFT_MASK)
|
||||
strcat (keybuf, "<Shift>");
|
||||
|
||||
if (event->modifier_state & CLUTTER_LOCK_MASK)
|
||||
strcat (keybuf, "<Lock>");
|
||||
|
||||
if (event->modifier_state & CLUTTER_CONTROL_MASK)
|
||||
strcat (keybuf, "<Control>");
|
||||
|
||||
if (event->modifier_state & CLUTTER_MOD1_MASK)
|
||||
strcat (keybuf, "<Mod1>");
|
||||
|
||||
if (event->modifier_state & CLUTTER_MOD2_MASK)
|
||||
strcat (keybuf, "<Mod2>");
|
||||
|
||||
if (event->modifier_state & CLUTTER_MOD3_MASK)
|
||||
strcat (keybuf, "<Mod3>");
|
||||
|
||||
if (event->modifier_state & CLUTTER_MOD4_MASK)
|
||||
strcat (keybuf, "<Mod4>");
|
||||
|
||||
if (event->modifier_state & CLUTTER_MOD5_MASK)
|
||||
strcat (keybuf, "<Mod5>");
|
||||
|
||||
strcat (keybuf, utf8);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
input_cb (ClutterActor *actor,
|
||||
ClutterEvent *event,
|
||||
gpointer data)
|
||||
input_cb (ClutterActor *actor,
|
||||
ClutterEvent *event,
|
||||
gpointer data)
|
||||
{
|
||||
ClutterStage *stage = CLUTTER_STAGE (clutter_stage_get_default ());
|
||||
gchar keybuf[128], *source = (gchar*)data;
|
||||
ClutterActor *source_actor = clutter_event_get_source (event);
|
||||
gchar keybuf[128];
|
||||
|
||||
switch (event->type)
|
||||
{
|
||||
case CLUTTER_KEY_PRESS:
|
||||
fill_keybuf (keybuf, &event->key);
|
||||
printf ("[%s] KEY PRESS %s", source, keybuf);
|
||||
printf ("[%s] KEY PRESS %s",
|
||||
clutter_actor_get_name (source_actor),
|
||||
keybuf);
|
||||
break;
|
||||
case CLUTTER_KEY_RELEASE:
|
||||
fill_keybuf (keybuf, &event->key);
|
||||
printf ("[%s] KEY RELEASE %s", source, keybuf);
|
||||
printf ("[%s] KEY RELEASE %s",
|
||||
clutter_actor_get_name (source_actor),
|
||||
keybuf);
|
||||
break;
|
||||
case CLUTTER_MOTION:
|
||||
g_print ("[%s] MOTION", source);
|
||||
g_print ("[%s] MOTION",
|
||||
clutter_actor_get_name (source_actor));
|
||||
break;
|
||||
case CLUTTER_ENTER:
|
||||
g_print ("[%s] ENTER", source);
|
||||
g_print ("[%s] ENTER (from:%s)",
|
||||
clutter_actor_get_name (source_actor),
|
||||
clutter_event_get_related (event) != NULL
|
||||
? clutter_actor_get_name (clutter_event_get_related (event))
|
||||
: "<out of stage>");
|
||||
break;
|
||||
case CLUTTER_LEAVE:
|
||||
g_print ("[%s] LEAVE", source);
|
||||
g_print ("[%s] LEAVE (to:%s)",
|
||||
clutter_actor_get_name (source_actor),
|
||||
clutter_event_get_related (event) != NULL
|
||||
? clutter_actor_get_name (clutter_event_get_related (event))
|
||||
: "<out of stage>");
|
||||
break;
|
||||
case CLUTTER_BUTTON_PRESS:
|
||||
g_print ("[%s] BUTTON PRESS (click count:%i)",
|
||||
source, event->button.click_count);
|
||||
g_print ("[%s] BUTTON PRESS (button:%i, click count:%i)",
|
||||
clutter_actor_get_name (source_actor),
|
||||
clutter_event_get_button (event),
|
||||
clutter_event_get_click_count (event));
|
||||
break;
|
||||
case CLUTTER_BUTTON_RELEASE:
|
||||
g_print ("[%s] BUTTON RELEASE (click count:%i)",
|
||||
source, event->button.click_count);
|
||||
g_print ("[%s] BUTTON RELEASE (button:%i, click count:%i)",
|
||||
clutter_actor_get_name (source_actor),
|
||||
clutter_event_get_button (event),
|
||||
clutter_event_get_click_count (event));
|
||||
|
||||
if (clutter_event_get_source (event) == CLUTTER_ACTOR (stage))
|
||||
if (source_actor == CLUTTER_ACTOR (stage))
|
||||
clutter_stage_set_key_focus (stage, NULL);
|
||||
else if (clutter_event_get_source (event) == actor
|
||||
&& clutter_actor_get_parent (actor) == CLUTTER_ACTOR (stage))
|
||||
else if (source_actor == actor &&
|
||||
clutter_actor_get_parent (actor) == CLUTTER_ACTOR (stage))
|
||||
clutter_stage_set_key_focus (stage, actor);
|
||||
break;
|
||||
case CLUTTER_SCROLL:
|
||||
g_print ("[%s] BUTTON SCROLL (click count:%i)",
|
||||
source, event->button.click_count);
|
||||
g_print ("[%s] BUTTON SCROLL (direction:%s)",
|
||||
clutter_actor_get_name (source_actor),
|
||||
clutter_event_get_scroll_direction (event) == CLUTTER_SCROLL_UP
|
||||
? "up"
|
||||
: "down");
|
||||
break;
|
||||
case CLUTTER_STAGE_STATE:
|
||||
g_print ("[%s] STAGE STATE", source);
|
||||
g_print ("[%s] STAGE STATE", clutter_actor_get_name (source_actor));
|
||||
break;
|
||||
case CLUTTER_DESTROY_NOTIFY:
|
||||
g_print ("[%s] DESTROY NOTIFY", source);
|
||||
g_print ("[%s] DESTROY NOTIFY", clutter_actor_get_name (source_actor));
|
||||
break;
|
||||
case CLUTTER_CLIENT_MESSAGE:
|
||||
g_print ("[%s] CLIENT MESSAGE", source);
|
||||
g_print ("[%s] CLIENT MESSAGE", clutter_actor_get_name (source_actor));
|
||||
break;
|
||||
case CLUTTER_DELETE:
|
||||
g_print ("[%s] DELETE", source);
|
||||
g_print ("[%s] DELETE", clutter_actor_get_name (source_actor));
|
||||
break;
|
||||
case CLUTTER_NOTHING:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (clutter_event_get_source (event) == actor)
|
||||
if (source_actor == actor)
|
||||
g_print (" *source*");
|
||||
|
||||
g_print ("\n");
|
||||
@ -234,8 +268,8 @@ test_events_main (int argc, char *argv[])
|
||||
|
||||
|
||||
stage = clutter_stage_get_default ();
|
||||
clutter_actor_set_name (stage, "Stage");
|
||||
g_signal_connect (stage, "event", G_CALLBACK (input_cb), "stage");
|
||||
|
||||
g_signal_connect (stage, "fullscreen",
|
||||
G_CALLBACK (stage_state_cb), "fullscreen");
|
||||
g_signal_connect (stage, "unfullscreen",
|
||||
@ -244,24 +278,21 @@ test_events_main (int argc, char *argv[])
|
||||
G_CALLBACK (stage_state_cb), "activate");
|
||||
g_signal_connect (stage, "deactivate",
|
||||
G_CALLBACK (stage_state_cb), "deactivate");
|
||||
|
||||
g_signal_connect (stage, "captured-event", G_CALLBACK (capture_cb), NULL);
|
||||
/*g_signal_connect (stage, "captured-event", G_CALLBACK (capture_cb), NULL);*/
|
||||
|
||||
focus_box = clutter_rectangle_new_with_color (&ncol);
|
||||
clutter_actor_set_name (focus_box, "Focus Box");
|
||||
clutter_container_add (CLUTTER_CONTAINER(stage), focus_box, NULL);
|
||||
|
||||
actor = clutter_rectangle_new_with_color (&rcol);
|
||||
clutter_actor_set_name (actor, "Red Box");
|
||||
clutter_actor_set_size (actor, 100, 100);
|
||||
clutter_actor_set_position (actor, 100, 100);
|
||||
|
||||
clutter_actor_set_reactive (actor, TRUE);
|
||||
|
||||
clutter_container_add (CLUTTER_CONTAINER (stage), actor, NULL);
|
||||
|
||||
g_signal_connect (actor, "event", G_CALLBACK (input_cb), "red box");
|
||||
g_signal_connect (actor, "key-focus-in", G_CALLBACK (key_focus_in_cb),
|
||||
focus_box);
|
||||
|
||||
/* Toggle motion - enter/leave capture */
|
||||
g_signal_connect (actor, "button-press-event",
|
||||
G_CALLBACK (red_button_cb), NULL);
|
||||
@ -269,27 +300,22 @@ test_events_main (int argc, char *argv[])
|
||||
clutter_stage_set_key_focus (CLUTTER_STAGE (stage), actor);
|
||||
|
||||
actor = clutter_rectangle_new_with_color (&gcol);
|
||||
clutter_actor_set_name (actor, "Green Box");
|
||||
clutter_actor_set_size (actor, 100, 100);
|
||||
clutter_actor_set_position (actor, 250, 100);
|
||||
|
||||
clutter_actor_set_reactive (actor, TRUE);
|
||||
|
||||
clutter_container_add (CLUTTER_CONTAINER (stage), actor, NULL);
|
||||
|
||||
g_signal_connect (actor, "event", G_CALLBACK (input_cb), "green box");
|
||||
g_signal_connect (actor, "key-focus-in", G_CALLBACK (key_focus_in_cb),
|
||||
focus_box);
|
||||
|
||||
g_signal_connect (actor, "captured-event", G_CALLBACK (capture_cb), NULL);
|
||||
|
||||
actor = clutter_rectangle_new_with_color (&bcol);
|
||||
clutter_actor_set_name (actor, "Blue Box");
|
||||
clutter_actor_set_size (actor, 100, 100);
|
||||
clutter_actor_set_position (actor, 400, 100);
|
||||
|
||||
clutter_actor_set_reactive (actor, TRUE);
|
||||
|
||||
clutter_container_add (CLUTTER_CONTAINER(stage), actor, NULL);
|
||||
|
||||
g_signal_connect (actor, "event", G_CALLBACK (input_cb), "blue box");
|
||||
g_signal_connect (actor, "key-focus-in", G_CALLBACK (key_focus_in_cb),
|
||||
focus_box);
|
||||
@ -299,20 +325,19 @@ test_events_main (int argc, char *argv[])
|
||||
|
||||
/* non reactive */
|
||||
actor = clutter_rectangle_new_with_color (&ncol);
|
||||
clutter_actor_set_name (actor, "Black Box");
|
||||
clutter_actor_set_size (actor, 400, 50);
|
||||
clutter_actor_set_position (actor, 100, 250);
|
||||
|
||||
clutter_container_add (CLUTTER_CONTAINER(stage), actor, NULL);
|
||||
|
||||
g_signal_connect (actor, "event", G_CALLBACK (input_cb), "blue box");
|
||||
g_signal_connect (actor, "key-focus-in", G_CALLBACK (key_focus_in_cb),
|
||||
focus_box);
|
||||
|
||||
g_signal_connect (stage, "key-focus-in", G_CALLBACK (key_focus_in_cb),
|
||||
focus_box);
|
||||
|
||||
/* non reactive group, with reactive child */
|
||||
actor = clutter_rectangle_new_with_color (&ycol);
|
||||
clutter_actor_set_name (actor, "Yellow Box");
|
||||
clutter_actor_set_size (actor, 100, 100);
|
||||
clutter_actor_set_reactive (actor, TRUE);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user