mirror of
https://github.com/brl/mutter.git
synced 2024-12-23 11:32:04 +00:00
event/x11: Rework the way we translate X11 events
This is a lump commit that is fairly difficult to break down without either breaking bisecting or breaking the test cases. The new design for handling X11 event translation works this way: - ClutterBackend::translate_event() has been added as the central point used by a ClutterBackend implementation to translate a native event into a ClutterEvent; - ClutterEventTranslator is a private interface that should be implemented by backend-specific objects, like stage implementations and ClutterDeviceManager sub-classes, and allows dealing with class-specific event translation; - ClutterStageX11 implements EventTranslator, and deals with the stage-relative X11 events coming from the X11 event source; - ClutterStageGLX overrides EventTranslator, in order to deal with the INTEL_GLX_swap_event extension, and it chains up to the X11 default implementation; - ClutterDeviceManagerX11 has been split into two separate classes, one that deals with core and (optionally) XI1 events, and the other that deals with XI2 events; the selection is done at run-time, since the core+XI1 and XI2 mechanisms are mutually exclusive. All the other backends we officially support still use their own custom event source and translation function, but the end goal is to migrate them to the translate_event() virtual function, and have the event source be a shared part of Clutter core.
This commit is contained in:
parent
ca092477c2
commit
1b1e77b469
@ -232,6 +232,7 @@ source_h_priv = \
|
||||
$(srcdir)/clutter-bezier.h \
|
||||
$(srcdir)/clutter-debug.h \
|
||||
$(srcdir)/clutter-device-manager-private.h \
|
||||
$(srcdir)/clutter-event-translator.h \
|
||||
$(srcdir)/clutter-id-pool.h \
|
||||
$(srcdir)/clutter-keysyms-table.h \
|
||||
$(srcdir)/clutter-master-clock.h \
|
||||
@ -247,6 +248,7 @@ source_h_priv = \
|
||||
|
||||
# private source code; these should not be introspected
|
||||
source_c_priv = \
|
||||
$(srcdir)/clutter-event-translator.c \
|
||||
$(srcdir)/clutter-id-pool.c \
|
||||
$(srcdir)/clutter-profile.c \
|
||||
$(srcdir)/clutter-timeout-interval.c \
|
||||
@ -294,9 +296,9 @@ backend_source_built =
|
||||
# X11 backend rules
|
||||
x11_source_c = \
|
||||
$(srcdir)/x11/clutter-backend-x11.c \
|
||||
$(srcdir)/x11/clutter-device-manager-x11.c \
|
||||
$(srcdir)/x11/clutter-device-manager-core-x11.c \
|
||||
$(srcdir)/x11/clutter-event-x11.c \
|
||||
$(srcdir)/x11/clutter-input-device-x11.c \
|
||||
$(srcdir)/x11/clutter-input-device-core-x11.c \
|
||||
$(srcdir)/x11/clutter-keymap-x11.c \
|
||||
$(srcdir)/x11/clutter-stage-x11.c \
|
||||
$(srcdir)/x11/clutter-x11-texture-pixmap.c \
|
||||
@ -309,8 +311,8 @@ x11_source_h = \
|
||||
|
||||
x11_source_h_priv = \
|
||||
$(srcdir)/x11/clutter-backend-x11.h \
|
||||
$(srcdir)/x11/clutter-device-manager-x11.h \
|
||||
$(srcdir)/x11/clutter-input-device-x11.h \
|
||||
$(srcdir)/x11/clutter-device-manager-core-x11.h \
|
||||
$(srcdir)/x11/clutter-input-device-core-x11.h \
|
||||
$(srcdir)/x11/clutter-keymap-x11.h \
|
||||
$(srcdir)/x11/clutter-settings-x11.h \
|
||||
$(srcdir)/x11/clutter-stage-x11.h \
|
||||
@ -323,6 +325,18 @@ x11_source_c_priv = \
|
||||
$(srcdir)/x11/xsettings/xsettings-common.h \
|
||||
$(NULL)
|
||||
|
||||
if BUILD_XI2
|
||||
x11_source_c += \
|
||||
$(srcdir)/x11/clutter-device-manager-xi2.c \
|
||||
$(srcdir)/x11/clutter-input-device-xi2.c \
|
||||
$(NULL)
|
||||
|
||||
x11_source_h_priv += \
|
||||
$(srcdir)/x11/clutter-device-manager-xi2.h \
|
||||
$(srcdir)/x11/clutter-input-device-xi2.h \
|
||||
$(NULL)
|
||||
endif # BUILD_XI2
|
||||
|
||||
if SUPPORT_X11
|
||||
backend_source_h += $(x11_source_h)
|
||||
backend_source_c += $(x11_source_c)
|
||||
@ -345,7 +359,6 @@ endif # SUPPORT_X11
|
||||
# GLX backend rules
|
||||
glx_source_c = \
|
||||
$(srcdir)/glx/clutter-backend-glx.c \
|
||||
$(srcdir)/glx/clutter-event-glx.c \
|
||||
$(srcdir)/glx/clutter-glx-texture-pixmap.c \
|
||||
$(srcdir)/glx/clutter-stage-glx.c \
|
||||
$(NULL)
|
||||
@ -357,7 +370,6 @@ glx_source_h = \
|
||||
|
||||
glx_source_h_priv = \
|
||||
$(srcdir)/glx/clutter-backend-glx.h \
|
||||
$(srcdir)/glx/clutter-event-glx.h \
|
||||
$(srcdir)/glx/clutter-stage-glx.h \
|
||||
$(NULL)
|
||||
|
||||
|
@ -71,6 +71,10 @@ struct _ClutterBackendClass
|
||||
void (* free_event_data) (ClutterBackend *backend,
|
||||
ClutterEvent *event);
|
||||
|
||||
gboolean (* translate_event) (ClutterBackend *backend,
|
||||
gpointer native,
|
||||
ClutterEvent *event);
|
||||
|
||||
/* signals */
|
||||
void (* resolution_changed) (ClutterBackend *backend);
|
||||
void (* font_changed) (ClutterBackend *backend);
|
||||
@ -114,6 +118,10 @@ gfloat _clutter_backend_get_units_per_em (ClutterBackend *backend
|
||||
|
||||
gint32 _clutter_backend_get_units_serial (ClutterBackend *backend);
|
||||
|
||||
gboolean _clutter_backend_translate_event (ClutterBackend *backend,
|
||||
gpointer native,
|
||||
ClutterEvent *event);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __CLUTTER_BACKEND_PRIVATE_H__ */
|
||||
|
@ -881,3 +881,15 @@ _clutter_backend_get_units_serial (ClutterBackend *backend)
|
||||
|
||||
return backend->priv->units_serial;
|
||||
}
|
||||
|
||||
gboolean
|
||||
_clutter_backend_translate_event (ClutterBackend *backend,
|
||||
gpointer native,
|
||||
ClutterEvent *event)
|
||||
{
|
||||
g_return_val_if_fail (CLUTTER_IS_BACKEND (backend), FALSE);
|
||||
|
||||
return CLUTTER_BACKEND_GET_CLASS (backend)->translate_event (backend,
|
||||
native,
|
||||
event);
|
||||
}
|
||||
|
@ -25,11 +25,31 @@
|
||||
#ifndef __CLUTTER_DEVICE_MANAGER_PRIVATE_H__
|
||||
#define __CLUTTER_DEVICE_MANAGER_PRIVATE_H__
|
||||
|
||||
#include <clutter/clutter-backend.h>
|
||||
#include <clutter/clutter-device-manager.h>
|
||||
#include <clutter/clutter-event.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _ClutterAxisInfo
|
||||
{
|
||||
ClutterInputAxis axis;
|
||||
|
||||
gdouble min_axis;
|
||||
gdouble max_axis;
|
||||
|
||||
gdouble min_value;
|
||||
gdouble max_value;
|
||||
|
||||
gdouble resolution;
|
||||
} ClutterAxisInfo;
|
||||
|
||||
typedef struct _ClutterKeyInfo
|
||||
{
|
||||
guint keyval;
|
||||
ClutterModifierType modifiers;
|
||||
} ClutterKeyInfo;
|
||||
|
||||
struct _ClutterInputDevice
|
||||
{
|
||||
GObject parent_instance;
|
||||
@ -37,9 +57,19 @@ struct _ClutterInputDevice
|
||||
gint id;
|
||||
|
||||
ClutterInputDeviceType device_type;
|
||||
ClutterInputMode device_mode;
|
||||
|
||||
gchar *device_name;
|
||||
|
||||
ClutterDeviceManager *device_manager;
|
||||
|
||||
ClutterBackend *backend;
|
||||
|
||||
/* the associated device */
|
||||
ClutterInputDevice *associated;
|
||||
|
||||
GList *slaves;
|
||||
|
||||
/* the actor underneath the pointer */
|
||||
ClutterActor *cursor_actor;
|
||||
|
||||
@ -65,28 +95,69 @@ struct _ClutterInputDevice
|
||||
guint32 previous_time;
|
||||
gint previous_button_number;
|
||||
ClutterModifierType previous_state;
|
||||
|
||||
GArray *axes;
|
||||
|
||||
guint n_keys;
|
||||
GArray *keys;
|
||||
gint min_keycode;
|
||||
gint max_keycode;
|
||||
|
||||
guint has_cursor : 1;
|
||||
};
|
||||
|
||||
/* 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);
|
||||
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);
|
||||
void _clutter_device_manager_select_stage_events (ClutterDeviceManager *device_manager,
|
||||
ClutterStage *stage,
|
||||
gint event_mask);
|
||||
ClutterBackend *_clutter_device_manager_get_backend (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);
|
||||
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);
|
||||
void _clutter_input_device_set_keys (ClutterInputDevice *device,
|
||||
guint n_keys,
|
||||
gint min_keycode,
|
||||
gint max_keycode);
|
||||
guint _clutter_input_device_add_axis (ClutterInputDevice *device,
|
||||
ClutterInputAxis axis,
|
||||
gdouble min_value,
|
||||
gdouble max_value,
|
||||
gdouble resolution);
|
||||
ClutterInputAxis _clutter_input_device_get_axis (ClutterInputDevice *device,
|
||||
guint index_);
|
||||
void _clutter_input_device_reset_axes (ClutterInputDevice *device);
|
||||
|
||||
void _clutter_input_device_set_associated_device (ClutterInputDevice *device,
|
||||
ClutterInputDevice *associated);
|
||||
void _clutter_input_device_add_slave (ClutterInputDevice *master,
|
||||
ClutterInputDevice *slave);
|
||||
void _clutter_input_device_remove_slave (ClutterInputDevice *master,
|
||||
ClutterInputDevice *slave);
|
||||
|
||||
void _clutter_input_device_select_stage_events (ClutterInputDevice *device,
|
||||
ClutterStage *stage,
|
||||
gint event_flags);
|
||||
|
||||
gboolean _clutter_input_device_translate_axis (ClutterInputDevice *device,
|
||||
guint index_,
|
||||
gint value,
|
||||
gdouble *axis_value);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@ -308,6 +308,27 @@ clutter_device_manager_get_core_device (ClutterDeviceManager *device_manager,
|
||||
return manager_class->get_core_device (device_manager, device_type);
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_device_manager_select_stage_events (ClutterDeviceManager *device_manager,
|
||||
ClutterStage *stage,
|
||||
gint event_flags)
|
||||
{
|
||||
ClutterDeviceManagerClass *manager_class;
|
||||
const GSList *devices, *d;
|
||||
|
||||
g_return_if_fail (CLUTTER_IS_DEVICE_MANAGER (device_manager));
|
||||
|
||||
manager_class = CLUTTER_DEVICE_MANAGER_GET_CLASS (device_manager);
|
||||
devices = manager_class->get_devices (device_manager);
|
||||
|
||||
for (d = devices; d != NULL; d = d->next)
|
||||
{
|
||||
ClutterInputDevice *device = d->data;
|
||||
|
||||
_clutter_input_device_select_stage_events (device, stage, event_flags);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* _clutter_device_manager_add_device:
|
||||
* @device_manager: a #ClutterDeviceManager
|
||||
@ -405,3 +426,11 @@ _clutter_device_manager_update_devices (ClutterDeviceManager *device_manager)
|
||||
_clutter_input_device_update (device);
|
||||
}
|
||||
}
|
||||
|
||||
ClutterBackend *
|
||||
_clutter_device_manager_get_backend (ClutterDeviceManager *manager)
|
||||
{
|
||||
g_return_val_if_fail (CLUTTER_IS_DEVICE_MANAGER (manager), NULL);
|
||||
|
||||
return manager->priv->backend;
|
||||
}
|
||||
|
@ -29,6 +29,7 @@
|
||||
#define __CLUTTER_DEVICE_MANAGER_H__
|
||||
|
||||
#include <clutter/clutter-input-device.h>
|
||||
#include <clutter/clutter-stage.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
38
clutter/clutter-event-translator.c
Normal file
38
clutter/clutter-event-translator.c
Normal file
@ -0,0 +1,38 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "clutter-event-translator.h"
|
||||
|
||||
#include "clutter-backend.h"
|
||||
#include "clutter-private.h"
|
||||
|
||||
#define clutter_event_translator_get_type _clutter_event_translator_get_type
|
||||
|
||||
typedef ClutterEventTranslatorIface ClutterEventTranslatorInterface;
|
||||
|
||||
G_DEFINE_INTERFACE (ClutterEventTranslator, clutter_event_translator, G_TYPE_OBJECT);
|
||||
|
||||
static ClutterTranslateReturn
|
||||
default_translate_event (ClutterEventTranslator *translator,
|
||||
gpointer native,
|
||||
ClutterEvent *event)
|
||||
{
|
||||
return CLUTTER_TRANSLATE_CONTINUE;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_event_translator_default_init (ClutterEventTranslatorIface *iface)
|
||||
{
|
||||
iface->translate_event = default_translate_event;
|
||||
}
|
||||
|
||||
ClutterTranslateReturn
|
||||
_clutter_event_translator_translate_event (ClutterEventTranslator *translator,
|
||||
gpointer native,
|
||||
ClutterEvent *translated)
|
||||
{
|
||||
ClutterEventTranslatorIface *iface;
|
||||
|
||||
iface = CLUTTER_EVENT_TRANSLATOR_GET_IFACE (translator);
|
||||
|
||||
return iface->translate_event (translator, native, translated);
|
||||
}
|
40
clutter/clutter-event-translator.h
Normal file
40
clutter/clutter-event-translator.h
Normal file
@ -0,0 +1,40 @@
|
||||
#ifndef __CLUTTER_EVENT_TRANSLATOR_H__
|
||||
#define __CLUTTER_EVENT_TRANSLATOR_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <clutter/clutter-event.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define CLUTTER_TYPE_EVENT_TRANSLATOR (_clutter_event_translator_get_type ())
|
||||
#define CLUTTER_EVENT_TRANSLATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_EVENT_TRANSLATOR, ClutterEventTranslator))
|
||||
#define CLUTTER_IS_EVENT_TRANSLATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_EVENT_TRANSLATOR))
|
||||
#define CLUTTER_EVENT_TRANSLATOR_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), CLUTTER_TYPE_EVENT_TRANSLATOR, ClutterEventTranslatorIface))
|
||||
|
||||
typedef struct _ClutterEventTranslator ClutterEventTranslator;
|
||||
typedef struct _ClutterEventTranslatorIface ClutterEventTranslatorIface;
|
||||
|
||||
typedef enum {
|
||||
CLUTTER_TRANSLATE_CONTINUE,
|
||||
CLUTTER_TRANSLATE_REMOVE,
|
||||
CLUTTER_TRANSLATE_QUEUE
|
||||
} ClutterTranslateReturn;
|
||||
|
||||
struct _ClutterEventTranslatorIface
|
||||
{
|
||||
GTypeInterface g_iface;
|
||||
|
||||
ClutterTranslateReturn (* translate_event) (ClutterEventTranslator *translator,
|
||||
gpointer native,
|
||||
ClutterEvent *translated);
|
||||
};
|
||||
|
||||
GType _clutter_event_translator_get_type (void) G_GNUC_CONST;
|
||||
|
||||
ClutterTranslateReturn _clutter_event_translator_translate_event (ClutterEventTranslator *translator,
|
||||
gpointer native,
|
||||
ClutterEvent *translated);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __CLUTTER_EVENT_TRANSLATOR_H__ */
|
@ -680,6 +680,35 @@ clutter_event_copy (const ClutterEvent *event)
|
||||
new_event = clutter_event_new (CLUTTER_NOTHING);
|
||||
*new_event = *event;
|
||||
|
||||
switch (event->type)
|
||||
{
|
||||
case CLUTTER_BUTTON_PRESS:
|
||||
case CLUTTER_BUTTON_RELEASE:
|
||||
if (event->button.device != NULL && event->button.axes != NULL)
|
||||
{
|
||||
gint n_axes;
|
||||
|
||||
n_axes = clutter_input_device_get_n_axes (event->button.device);
|
||||
new_event->button.axes = g_memdup (event->button.axes,
|
||||
sizeof (gdouble) * n_axes);
|
||||
}
|
||||
break;
|
||||
|
||||
case CLUTTER_MOTION:
|
||||
if (event->motion.device != NULL && event->motion.axes != NULL)
|
||||
{
|
||||
gint n_axes;
|
||||
|
||||
n_axes = clutter_input_device_get_n_axes (event->motion.device);
|
||||
new_event->motion.axes = g_memdup (event->motion.axes,
|
||||
sizeof (gdouble) * n_axes);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_event_allocated (event))
|
||||
_clutter_backend_copy_event_data (clutter_get_default_backend (),
|
||||
event,
|
||||
@ -701,6 +730,21 @@ clutter_event_free (ClutterEvent *event)
|
||||
{
|
||||
_clutter_backend_free_event_data (clutter_get_default_backend (), event);
|
||||
|
||||
switch (event->type)
|
||||
{
|
||||
case CLUTTER_BUTTON_PRESS:
|
||||
case CLUTTER_BUTTON_RELEASE:
|
||||
g_free (event->button.axes);
|
||||
break;
|
||||
|
||||
case CLUTTER_MOTION:
|
||||
g_free (event->motion.axes);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
g_hash_table_remove (all_events, event);
|
||||
g_slice_free (ClutterEventPrivate, (ClutterEventPrivate *) event);
|
||||
}
|
||||
@ -756,6 +800,28 @@ clutter_event_peek (void)
|
||||
return g_queue_peek_tail (context->events_queue);
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_event_push (const ClutterEvent *event,
|
||||
gboolean do_copy)
|
||||
{
|
||||
ClutterMainContext *context = _clutter_context_get_default ();
|
||||
|
||||
/* FIXME: check queue is valid */
|
||||
g_assert (context != NULL);
|
||||
|
||||
if (do_copy)
|
||||
{
|
||||
ClutterEvent *copy;
|
||||
|
||||
copy = clutter_event_copy (event);
|
||||
copy->any.flags |= CLUTTER_EVENT_FLAG_SYNTHETIC;
|
||||
|
||||
event = copy;
|
||||
}
|
||||
|
||||
g_queue_push_head (context->events_queue, (gpointer) event);
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_event_put:
|
||||
* @event: a #ClutterEvent
|
||||
@ -771,16 +837,7 @@ clutter_event_peek (void)
|
||||
void
|
||||
clutter_event_put (const ClutterEvent *event)
|
||||
{
|
||||
ClutterMainContext *context = _clutter_context_get_default ();
|
||||
ClutterEvent *event_copy;
|
||||
|
||||
/* FIXME: check queue is valid */
|
||||
g_return_if_fail (context != NULL);
|
||||
|
||||
event_copy = clutter_event_copy (event);
|
||||
event_copy->any.flags |= CLUTTER_EVENT_FLAG_SYNTHETIC;
|
||||
|
||||
g_queue_push_head (context->events_queue, event_copy);
|
||||
_clutter_event_push (event, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -54,57 +54,6 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* ClutterModifierType:
|
||||
* @CLUTTER_SHIFT_MASK: Mask applied by the Shift key
|
||||
* @CLUTTER_LOCK_MASK: Mask applied by the Caps Lock key
|
||||
* @CLUTTER_CONTROL_MASK: Mask applied by the Control key
|
||||
* @CLUTTER_MOD1_MASK: Mask applied by the first Mod key
|
||||
* @CLUTTER_MOD2_MASK: Mask applied by the second Mod key
|
||||
* @CLUTTER_MOD3_MASK: Mask applied by the third Mod key
|
||||
* @CLUTTER_MOD4_MASK: Mask applied by the fourth Mod key
|
||||
* @CLUTTER_MOD5_MASK: Mask applied by the fifth Mod key
|
||||
* @CLUTTER_BUTTON1_MASK: Mask applied by the first pointer button
|
||||
* @CLUTTER_BUTTON2_MASK: Mask applied by the second pointer button
|
||||
* @CLUTTER_BUTTON3_MASK: Mask applied by the third pointer button
|
||||
* @CLUTTER_BUTTON4_MASK: Mask applied by the fourth pointer button
|
||||
* @CLUTTER_BUTTON5_MASK: Mask applied by the fifth pointer button
|
||||
* @CLUTTER_SUPER_MASK: Mask applied by the Super key
|
||||
* @CLUTTER_HYPER_MASK: Mask applied by the Hyper key
|
||||
* @CLUTTER_META_MASK: Mask applied by the Meta key
|
||||
* @CLUTTER_RELEASE_MASK: Mask applied during release
|
||||
* @CLUTTER_MODIFIER_MASK: A mask covering all modifier types
|
||||
*
|
||||
* Masks applied to a #ClutterEvent by modifiers.
|
||||
*
|
||||
* Since: 0.4
|
||||
*/
|
||||
typedef enum {
|
||||
CLUTTER_SHIFT_MASK = 1 << 0,
|
||||
CLUTTER_LOCK_MASK = 1 << 1,
|
||||
CLUTTER_CONTROL_MASK = 1 << 2,
|
||||
CLUTTER_MOD1_MASK = 1 << 3,
|
||||
CLUTTER_MOD2_MASK = 1 << 4,
|
||||
CLUTTER_MOD3_MASK = 1 << 5,
|
||||
CLUTTER_MOD4_MASK = 1 << 6,
|
||||
CLUTTER_MOD5_MASK = 1 << 7,
|
||||
CLUTTER_BUTTON1_MASK = 1 << 8,
|
||||
CLUTTER_BUTTON2_MASK = 1 << 9,
|
||||
CLUTTER_BUTTON3_MASK = 1 << 10,
|
||||
CLUTTER_BUTTON4_MASK = 1 << 11,
|
||||
CLUTTER_BUTTON5_MASK = 1 << 12,
|
||||
|
||||
/* bits 15 to 25 are currently unused; bit 29 is used internally */
|
||||
|
||||
CLUTTER_SUPER_MASK = 1 << 26,
|
||||
CLUTTER_HYPER_MASK = 1 << 27,
|
||||
CLUTTER_META_MASK = 1 << 28,
|
||||
|
||||
CLUTTER_RELEASE_MASK = 1 << 30,
|
||||
|
||||
CLUTTER_MODIFIER_MASK = 0x5c001fff
|
||||
} ClutterModifierType;
|
||||
|
||||
/**
|
||||
* ClutterEventFlags:
|
||||
* @CLUTTER_EVENT_NONE: No flag set
|
||||
|
@ -35,11 +35,13 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "clutter-input-device.h"
|
||||
|
||||
#include "clutter-actor-private.h"
|
||||
#include "clutter-debug.h"
|
||||
#include "clutter-device-manager-private.h"
|
||||
#include "clutter-enum-types.h"
|
||||
#include "clutter-input-device.h"
|
||||
#include "clutter-marshal.h"
|
||||
#include "clutter-private.h"
|
||||
#include "clutter-stage-private.h"
|
||||
|
||||
@ -47,17 +49,67 @@ enum
|
||||
{
|
||||
PROP_0,
|
||||
|
||||
PROP_BACKEND,
|
||||
|
||||
PROP_ID,
|
||||
PROP_DEVICE_TYPE,
|
||||
PROP_NAME,
|
||||
|
||||
PROP_DEVICE_TYPE,
|
||||
PROP_DEVICE_MANAGER,
|
||||
PROP_DEVICE_MODE,
|
||||
|
||||
PROP_HAS_CURSOR,
|
||||
|
||||
PROP_N_AXES,
|
||||
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
static GParamSpec *obj_props[PROP_LAST];
|
||||
enum
|
||||
{
|
||||
SELECT_STAGE_EVENTS,
|
||||
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static GParamSpec *obj_props[PROP_LAST] = { NULL, };
|
||||
|
||||
static guint device_signals[LAST_SIGNAL] = { 0, };
|
||||
|
||||
G_DEFINE_TYPE (ClutterInputDevice, clutter_input_device, G_TYPE_OBJECT);
|
||||
|
||||
static void
|
||||
clutter_input_device_dispose (GObject *gobject)
|
||||
{
|
||||
ClutterInputDevice *device = CLUTTER_INPUT_DEVICE (gobject);
|
||||
|
||||
g_free (device->device_name);
|
||||
|
||||
if (device->device_mode == CLUTTER_INPUT_MODE_SLAVE)
|
||||
_clutter_input_device_remove_slave (device->associated, device);
|
||||
|
||||
if (device->associated != NULL)
|
||||
{
|
||||
_clutter_input_device_set_associated_device (device->associated, NULL);
|
||||
g_object_unref (device->associated);
|
||||
device->associated = NULL;
|
||||
}
|
||||
|
||||
if (device->axes != NULL)
|
||||
{
|
||||
g_array_free (device->axes, TRUE);
|
||||
device->axes = NULL;
|
||||
}
|
||||
|
||||
if (device->keys != NULL)
|
||||
{
|
||||
g_array_free (device->keys, TRUE);
|
||||
device->keys = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (clutter_input_device_parent_class)->dispose (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_input_device_set_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
@ -76,8 +128,24 @@ clutter_input_device_set_property (GObject *gobject,
|
||||
self->device_type = g_value_get_enum (value);
|
||||
break;
|
||||
|
||||
case PROP_DEVICE_MANAGER:
|
||||
self->device_manager = g_value_get_object (value);
|
||||
break;
|
||||
|
||||
case PROP_DEVICE_MODE:
|
||||
self->device_mode = g_value_get_enum (value);
|
||||
break;
|
||||
|
||||
case PROP_BACKEND:
|
||||
self->backend = g_value_get_object (value);
|
||||
break;
|
||||
|
||||
case PROP_NAME:
|
||||
self->device_name = g_strdup (g_value_get_string (value));
|
||||
self->device_name = g_value_dup_string (value);
|
||||
break;
|
||||
|
||||
case PROP_HAS_CURSOR:
|
||||
self->has_cursor = g_value_get_boolean (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -104,10 +172,33 @@ clutter_input_device_get_property (GObject *gobject,
|
||||
g_value_set_enum (value, self->device_type);
|
||||
break;
|
||||
|
||||
case PROP_DEVICE_MANAGER:
|
||||
g_value_set_object (value, self->device_manager);
|
||||
break;
|
||||
|
||||
case PROP_DEVICE_MODE:
|
||||
g_value_set_enum (value, self->device_mode);
|
||||
break;
|
||||
|
||||
case PROP_BACKEND:
|
||||
g_value_set_object (value, self->backend);
|
||||
break;
|
||||
|
||||
case PROP_NAME:
|
||||
g_value_set_string (value, self->device_name);
|
||||
break;
|
||||
|
||||
case PROP_HAS_CURSOR:
|
||||
g_value_set_boolean (value, self->has_cursor);
|
||||
break;
|
||||
|
||||
case PROP_N_AXES:
|
||||
if (self->axes != NULL)
|
||||
g_value_set_uint (value, self->axes->len);
|
||||
else
|
||||
g_value_set_uint (value, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||
break;
|
||||
@ -118,10 +209,6 @@ 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:
|
||||
@ -130,15 +217,14 @@ clutter_input_device_class_init (ClutterInputDeviceClass *klass)
|
||||
*
|
||||
* Since: 1.2
|
||||
*/
|
||||
pspec = g_param_spec_int ("id",
|
||||
P_("Id"),
|
||||
P_("Unique identifier of the device"),
|
||||
-1, G_MAXINT,
|
||||
0,
|
||||
CLUTTER_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY);
|
||||
obj_props[PROP_ID] = pspec;
|
||||
g_object_class_install_property (gobject_class, PROP_ID, pspec);
|
||||
obj_props[PROP_ID] =
|
||||
g_param_spec_int ("id",
|
||||
P_("Id"),
|
||||
P_("Unique identifier of the device"),
|
||||
-1, G_MAXINT,
|
||||
0,
|
||||
CLUTTER_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY);
|
||||
|
||||
/**
|
||||
* ClutterInputDevice:name:
|
||||
@ -147,14 +233,13 @@ clutter_input_device_class_init (ClutterInputDeviceClass *klass)
|
||||
*
|
||||
* Since: 1.2
|
||||
*/
|
||||
pspec = g_param_spec_string ("name",
|
||||
P_("Name"),
|
||||
P_("The name of the device"),
|
||||
NULL,
|
||||
CLUTTER_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY);
|
||||
obj_props[PROP_NAME] = pspec;
|
||||
g_object_class_install_property (gobject_class, PROP_NAME, pspec);
|
||||
obj_props[PROP_NAME] =
|
||||
g_param_spec_string ("name",
|
||||
P_("Name"),
|
||||
P_("The name of the device"),
|
||||
NULL,
|
||||
CLUTTER_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY);
|
||||
|
||||
/**
|
||||
* ClutterInputDevice:device-type:
|
||||
@ -163,15 +248,67 @@ clutter_input_device_class_init (ClutterInputDeviceClass *klass)
|
||||
*
|
||||
* Since: 1.2
|
||||
*/
|
||||
pspec = g_param_spec_enum ("device-type",
|
||||
P_("Device Type"),
|
||||
P_("The type of the device"),
|
||||
CLUTTER_TYPE_INPUT_DEVICE_TYPE,
|
||||
CLUTTER_POINTER_DEVICE,
|
||||
CLUTTER_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY);
|
||||
obj_props[PROP_DEVICE_TYPE] = pspec;
|
||||
g_object_class_install_property (gobject_class, PROP_DEVICE_TYPE, pspec);
|
||||
obj_props[PROP_DEVICE_TYPE] =
|
||||
g_param_spec_enum ("device-type",
|
||||
P_("Device Type"),
|
||||
P_("The type of the device"),
|
||||
CLUTTER_TYPE_INPUT_DEVICE_TYPE,
|
||||
CLUTTER_POINTER_DEVICE,
|
||||
CLUTTER_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY);
|
||||
|
||||
obj_props[PROP_DEVICE_MANAGER] =
|
||||
g_param_spec_object ("device-manager",
|
||||
P_("Device Manager"),
|
||||
P_("The device manager instance"),
|
||||
CLUTTER_TYPE_DEVICE_MANAGER,
|
||||
CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
||||
|
||||
obj_props[PROP_DEVICE_MODE] =
|
||||
g_param_spec_enum ("device-mode",
|
||||
P_("Device Mode"),
|
||||
P_("The mode of the device"),
|
||||
CLUTTER_TYPE_INPUT_MODE,
|
||||
CLUTTER_INPUT_MODE_FLOATING,
|
||||
CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
||||
|
||||
obj_props[PROP_HAS_CURSOR] =
|
||||
g_param_spec_boolean ("has-cursor",
|
||||
P_("Has Cursor"),
|
||||
P_("Whether the device has a cursor"),
|
||||
FALSE,
|
||||
CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
||||
|
||||
obj_props[PROP_N_AXES] =
|
||||
g_param_spec_uint ("n-axes",
|
||||
P_("Number of Axes"),
|
||||
P_("The number of axes on the device"),
|
||||
0, G_MAXUINT,
|
||||
0,
|
||||
CLUTTER_PARAM_READABLE);
|
||||
|
||||
obj_props[PROP_BACKEND] =
|
||||
g_param_spec_object ("backend",
|
||||
P_("Backend"),
|
||||
P_("The backend instance"),
|
||||
CLUTTER_TYPE_BACKEND,
|
||||
CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
||||
|
||||
gobject_class->dispose = clutter_input_device_dispose;
|
||||
gobject_class->set_property = clutter_input_device_set_property;
|
||||
gobject_class->get_property = clutter_input_device_get_property;
|
||||
g_object_class_install_properties (gobject_class, PROP_LAST, obj_props);
|
||||
|
||||
device_signals[SELECT_STAGE_EVENTS] =
|
||||
g_signal_new (I_("select-stage-events"),
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
0,
|
||||
NULL, NULL,
|
||||
_clutter_marshal_VOID__OBJECT_INT,
|
||||
G_TYPE_NONE, 2,
|
||||
CLUTTER_TYPE_STAGE,
|
||||
G_TYPE_INT);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -187,6 +324,9 @@ clutter_input_device_init (ClutterInputDevice *self)
|
||||
self->current_y = self->previous_y = -1;
|
||||
self->current_button_number = self->previous_button_number = -1;
|
||||
self->current_state = self->previous_state = 0;
|
||||
|
||||
self->min_keycode = 0;
|
||||
self->max_keycode = G_MAXUINT;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -483,7 +623,6 @@ clutter_input_device_get_device_coords (ClutterInputDevice *device,
|
||||
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;
|
||||
@ -514,7 +653,8 @@ _clutter_input_device_update (ClutterInputDevice *device)
|
||||
ClutterActor *old_cursor_actor;
|
||||
gint x, y;
|
||||
|
||||
g_return_val_if_fail (device->device_type == CLUTTER_POINTER_DEVICE, NULL);
|
||||
if (device->device_type == CLUTTER_KEYBOARD_DEVICE)
|
||||
return NULL;
|
||||
|
||||
stage = device->stage;
|
||||
if (G_UNLIKELY (stage == NULL))
|
||||
@ -700,3 +840,267 @@ clutter_input_device_update_from_event (ClutterInputDevice *device,
|
||||
if (update_stage)
|
||||
_clutter_input_device_set_stage (device, event_stage);
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_input_device_reset_axes (ClutterInputDevice *device)
|
||||
{
|
||||
if (device->axes != NULL)
|
||||
{
|
||||
g_array_free (device->axes, TRUE);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (device), obj_props[PROP_N_AXES]);
|
||||
}
|
||||
}
|
||||
|
||||
guint
|
||||
_clutter_input_device_add_axis (ClutterInputDevice *device,
|
||||
ClutterInputAxis axis,
|
||||
gdouble minimum,
|
||||
gdouble maximum,
|
||||
gdouble resolution)
|
||||
{
|
||||
ClutterAxisInfo info;
|
||||
guint pos;
|
||||
|
||||
if (device->axes == NULL)
|
||||
device->axes = g_array_new (FALSE, TRUE, sizeof (ClutterAxisInfo));
|
||||
|
||||
info.axis = axis;
|
||||
info.min_value = minimum;
|
||||
info.max_value = maximum;
|
||||
info.resolution = resolution;
|
||||
|
||||
switch (axis)
|
||||
{
|
||||
case CLUTTER_INPUT_AXIS_X:
|
||||
case CLUTTER_INPUT_AXIS_Y:
|
||||
info.min_axis = 0;
|
||||
info.max_axis = 0;
|
||||
break;
|
||||
|
||||
case CLUTTER_INPUT_AXIS_XTILT:
|
||||
case CLUTTER_INPUT_AXIS_YTILT:
|
||||
info.min_axis = -1;
|
||||
info.max_axis = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
info.min_axis = 0;
|
||||
info.max_axis = 1;
|
||||
}
|
||||
|
||||
device->axes = g_array_append_val (device->axes, info);
|
||||
pos = device->axes->len - 1;
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (device), obj_props[PROP_N_AXES]);
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
gboolean
|
||||
_clutter_input_device_translate_axis (ClutterInputDevice *device,
|
||||
guint index_,
|
||||
gint value,
|
||||
gdouble *axis_value)
|
||||
{
|
||||
ClutterAxisInfo *info;
|
||||
gdouble width;
|
||||
gdouble real_value;
|
||||
|
||||
if (device->axes == NULL || index_ >= device->axes->len)
|
||||
return FALSE;
|
||||
|
||||
info = &g_array_index (device->axes, ClutterAxisInfo, index_);
|
||||
|
||||
if (info->axis == CLUTTER_INPUT_AXIS_X ||
|
||||
info->axis == CLUTTER_INPUT_AXIS_Y)
|
||||
return FALSE;
|
||||
|
||||
width = info->max_value - info->min_value;
|
||||
real_value = (info->max_axis * (value - info->min_value)
|
||||
+ info->min_axis * (info->max_value - value))
|
||||
/ width;
|
||||
|
||||
if (axis_value)
|
||||
*axis_value = real_value;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
ClutterInputAxis
|
||||
_clutter_input_device_get_axis (ClutterInputDevice *device,
|
||||
guint index_)
|
||||
{
|
||||
ClutterAxisInfo *info;
|
||||
|
||||
if (device->axes == NULL)
|
||||
return CLUTTER_INPUT_AXIS_IGNORE;
|
||||
|
||||
if (index_ >= device->axes->len)
|
||||
return CLUTTER_INPUT_AXIS_IGNORE;
|
||||
|
||||
info = &g_array_index (device->axes, ClutterAxisInfo, index_);
|
||||
|
||||
return info->axis;
|
||||
}
|
||||
|
||||
guint
|
||||
clutter_input_device_get_n_axes (ClutterInputDevice *device)
|
||||
{
|
||||
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), 0);
|
||||
|
||||
if (device->axes != NULL)
|
||||
return device->axes->len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_input_device_set_keys (ClutterInputDevice *device,
|
||||
guint n_keys,
|
||||
gint min_keycode,
|
||||
gint max_keycode)
|
||||
{
|
||||
if (device->keys != NULL)
|
||||
g_array_free (device->keys, TRUE);
|
||||
|
||||
device->n_keys = n_keys;
|
||||
device->keys = g_array_sized_new (FALSE, TRUE,
|
||||
sizeof (ClutterKeyInfo),
|
||||
n_keys);
|
||||
|
||||
device->min_keycode = min_keycode;
|
||||
device->max_keycode = max_keycode;
|
||||
}
|
||||
|
||||
guint
|
||||
clutter_input_device_get_n_keys (ClutterInputDevice *device)
|
||||
{
|
||||
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), 0);
|
||||
|
||||
if (device->keys != NULL)
|
||||
return device->keys->len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
clutter_input_device_set_key (ClutterInputDevice *device,
|
||||
guint index_,
|
||||
guint keyval,
|
||||
ClutterModifierType modifiers)
|
||||
{
|
||||
ClutterKeyInfo *key_info;
|
||||
|
||||
g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
|
||||
g_return_if_fail (index_ < device->n_keys);
|
||||
g_return_if_fail (keyval >= device->min_keycode &&
|
||||
keyval <= device->max_keycode);
|
||||
|
||||
key_info = &g_array_index (device->keys, ClutterKeyInfo, index_);
|
||||
key_info->keyval = keyval;
|
||||
key_info->modifiers = modifiers;
|
||||
}
|
||||
|
||||
gboolean
|
||||
clutter_input_device_get_key (ClutterInputDevice *device,
|
||||
guint index_,
|
||||
guint *keyval,
|
||||
ClutterModifierType *modifiers)
|
||||
{
|
||||
ClutterKeyInfo *key_info;
|
||||
|
||||
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE);
|
||||
|
||||
if (device->keys == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (index_ > device->keys->len)
|
||||
return FALSE;
|
||||
|
||||
key_info = &g_array_index (device->keys, ClutterKeyInfo, index_);
|
||||
|
||||
if (!key_info->keyval && !key_info->modifiers)
|
||||
return FALSE;
|
||||
|
||||
if (keyval)
|
||||
*keyval = key_info->keyval;
|
||||
|
||||
if (modifiers)
|
||||
*modifiers = key_info->modifiers;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_input_device_add_slave (ClutterInputDevice *master,
|
||||
ClutterInputDevice *slave)
|
||||
{
|
||||
if (g_list_find (master->slaves, slave) == NULL)
|
||||
master->slaves = g_list_prepend (master->slaves, slave);
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_input_device_remove_slave (ClutterInputDevice *master,
|
||||
ClutterInputDevice *slave)
|
||||
{
|
||||
if (g_list_find (master->slaves, slave) != NULL)
|
||||
master->slaves = g_list_remove (master->slaves, slave);
|
||||
}
|
||||
|
||||
GList *
|
||||
clutter_input_device_get_slave_devices (ClutterInputDevice *device)
|
||||
{
|
||||
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL);
|
||||
|
||||
return g_list_copy (device->slaves);
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_input_device_set_associated_device (ClutterInputDevice *device,
|
||||
ClutterInputDevice *associated)
|
||||
{
|
||||
if (device->associated == associated)
|
||||
return;
|
||||
|
||||
if (device->associated != NULL)
|
||||
g_object_unref (device->associated);
|
||||
|
||||
device->associated = associated;
|
||||
if (device->associated != NULL)
|
||||
g_object_ref (device->associated);
|
||||
|
||||
CLUTTER_NOTE (MISC, "Associating device '%s' to device '%s'",
|
||||
clutter_input_device_get_device_name (device),
|
||||
device->associated != NULL
|
||||
? clutter_input_device_get_device_name (device->associated)
|
||||
: "(none)");
|
||||
|
||||
if (device->device_mode != CLUTTER_INPUT_MODE_MASTER)
|
||||
{
|
||||
if (device->associated != NULL)
|
||||
device->device_mode = CLUTTER_INPUT_MODE_SLAVE;
|
||||
else
|
||||
device->device_mode = CLUTTER_INPUT_MODE_FLOATING;
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (device), obj_props[PROP_DEVICE_MODE]);
|
||||
}
|
||||
}
|
||||
|
||||
ClutterInputDevice *
|
||||
clutter_input_device_get_associated_device (ClutterInputDevice *device)
|
||||
{
|
||||
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL);
|
||||
|
||||
return device->associated;
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_input_device_select_stage_events (ClutterInputDevice *device,
|
||||
ClutterStage *stage,
|
||||
gint event_mask)
|
||||
{
|
||||
g_signal_emit (device, device_signals[SELECT_STAGE_EVENTS], 0,
|
||||
stage,
|
||||
event_mask);
|
||||
}
|
||||
|
@ -74,10 +74,29 @@ typedef enum {
|
||||
CLUTTER_TABLET_DEVICE,
|
||||
CLUTTER_TOUCHPAD_DEVICE,
|
||||
CLUTTER_TOUCHSCREEN_DEVICE,
|
||||
CLUTTER_PEN_DEVICE,
|
||||
CLUTTER_ERASER_DEVICE,
|
||||
CLUTTER_CURSOR_DEVICE,
|
||||
|
||||
CLUTTER_N_DEVICE_TYPES
|
||||
} ClutterInputDeviceType;
|
||||
|
||||
typedef enum {
|
||||
CLUTTER_INPUT_MODE_MASTER,
|
||||
CLUTTER_INPUT_MODE_SLAVE,
|
||||
CLUTTER_INPUT_MODE_FLOATING
|
||||
} ClutterInputMode;
|
||||
|
||||
typedef enum {
|
||||
CLUTTER_INPUT_AXIS_IGNORE,
|
||||
CLUTTER_INPUT_AXIS_X,
|
||||
CLUTTER_INPUT_AXIS_Y,
|
||||
CLUTTER_INPUT_AXIS_PRESSURE,
|
||||
CLUTTER_INPUT_AXIS_XTILT,
|
||||
CLUTTER_INPUT_AXIS_YTILT,
|
||||
CLUTTER_INPUT_AXIS_WHEEL
|
||||
} ClutterInputAxis;
|
||||
|
||||
/**
|
||||
* ClutterInputDeviceClass:
|
||||
*
|
||||
@ -94,18 +113,32 @@ struct _ClutterInputDeviceClass
|
||||
|
||||
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);
|
||||
ClutterStage * clutter_input_device_get_pointer_stage (ClutterInputDevice *device);
|
||||
G_CONST_RETURN gchar * clutter_input_device_get_device_name (ClutterInputDevice *device);
|
||||
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);
|
||||
ClutterStage * clutter_input_device_get_pointer_stage (ClutterInputDevice *device);
|
||||
G_CONST_RETURN gchar * clutter_input_device_get_device_name (ClutterInputDevice *device);
|
||||
|
||||
void clutter_input_device_update_from_event (ClutterInputDevice *device,
|
||||
ClutterEvent *event,
|
||||
gboolean update_stage);
|
||||
guint clutter_input_device_get_n_axes (ClutterInputDevice *device);
|
||||
|
||||
void clutter_input_device_set_key (ClutterInputDevice *device,
|
||||
guint index_,
|
||||
guint keyval,
|
||||
ClutterModifierType modifiers);
|
||||
gboolean clutter_input_device_get_key (ClutterInputDevice *device,
|
||||
guint index_,
|
||||
guint *keyval,
|
||||
ClutterModifierType *modifiers);
|
||||
|
||||
ClutterInputDevice * clutter_input_device_get_associated_device (ClutterInputDevice *device);
|
||||
GList * clutter_input_device_get_slave_devices (ClutterInputDevice *device);
|
||||
|
||||
void clutter_input_device_update_from_event (ClutterInputDevice *device,
|
||||
ClutterEvent *event,
|
||||
gboolean update_stage);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@ -13,6 +13,7 @@ VOID:INT,INT,INT,INT
|
||||
VOID:OBJECT
|
||||
VOID:OBJECT,FLOAT,FLOAT
|
||||
VOID:OBJECT,FLOAT,FLOAT,FLAGS
|
||||
VOID:OBJECT,INT
|
||||
VOID:OBJECT,PARAM
|
||||
VOID:OBJECT,POINTER
|
||||
VOID:OBJECT,UINT
|
||||
|
@ -228,6 +228,9 @@ void _clutter_event_set_platform_data (ClutterEvent *event,
|
||||
gpointer data);
|
||||
gpointer _clutter_event_get_platform_data (const ClutterEvent *event);
|
||||
|
||||
void _clutter_event_push (const ClutterEvent *event,
|
||||
gboolean do_copy);
|
||||
|
||||
void _clutter_util_fully_transform_vertices (const CoglMatrix *modelview,
|
||||
const CoglMatrix *projection,
|
||||
const int *viewport,
|
||||
|
@ -489,6 +489,57 @@ void clutter_paint_volume_union (ClutterPaintVolume
|
||||
gboolean clutter_paint_volume_set_from_allocation (ClutterPaintVolume *pv,
|
||||
ClutterActor *actor);
|
||||
|
||||
/**
|
||||
* ClutterModifierType:
|
||||
* @CLUTTER_SHIFT_MASK: Mask applied by the Shift key
|
||||
* @CLUTTER_LOCK_MASK: Mask applied by the Caps Lock key
|
||||
* @CLUTTER_CONTROL_MASK: Mask applied by the Control key
|
||||
* @CLUTTER_MOD1_MASK: Mask applied by the first Mod key
|
||||
* @CLUTTER_MOD2_MASK: Mask applied by the second Mod key
|
||||
* @CLUTTER_MOD3_MASK: Mask applied by the third Mod key
|
||||
* @CLUTTER_MOD4_MASK: Mask applied by the fourth Mod key
|
||||
* @CLUTTER_MOD5_MASK: Mask applied by the fifth Mod key
|
||||
* @CLUTTER_BUTTON1_MASK: Mask applied by the first pointer button
|
||||
* @CLUTTER_BUTTON2_MASK: Mask applied by the second pointer button
|
||||
* @CLUTTER_BUTTON3_MASK: Mask applied by the third pointer button
|
||||
* @CLUTTER_BUTTON4_MASK: Mask applied by the fourth pointer button
|
||||
* @CLUTTER_BUTTON5_MASK: Mask applied by the fifth pointer button
|
||||
* @CLUTTER_SUPER_MASK: Mask applied by the Super key
|
||||
* @CLUTTER_HYPER_MASK: Mask applied by the Hyper key
|
||||
* @CLUTTER_META_MASK: Mask applied by the Meta key
|
||||
* @CLUTTER_RELEASE_MASK: Mask applied during release
|
||||
* @CLUTTER_MODIFIER_MASK: A mask covering all modifier types
|
||||
*
|
||||
* Masks applied to a #ClutterEvent by modifiers.
|
||||
*
|
||||
* Since: 0.4
|
||||
*/
|
||||
typedef enum {
|
||||
CLUTTER_SHIFT_MASK = 1 << 0,
|
||||
CLUTTER_LOCK_MASK = 1 << 1,
|
||||
CLUTTER_CONTROL_MASK = 1 << 2,
|
||||
CLUTTER_MOD1_MASK = 1 << 3,
|
||||
CLUTTER_MOD2_MASK = 1 << 4,
|
||||
CLUTTER_MOD3_MASK = 1 << 5,
|
||||
CLUTTER_MOD4_MASK = 1 << 6,
|
||||
CLUTTER_MOD5_MASK = 1 << 7,
|
||||
CLUTTER_BUTTON1_MASK = 1 << 8,
|
||||
CLUTTER_BUTTON2_MASK = 1 << 9,
|
||||
CLUTTER_BUTTON3_MASK = 1 << 10,
|
||||
CLUTTER_BUTTON4_MASK = 1 << 11,
|
||||
CLUTTER_BUTTON5_MASK = 1 << 12,
|
||||
|
||||
/* bits 15 to 25 are currently unused; bit 29 is used internally */
|
||||
|
||||
CLUTTER_SUPER_MASK = 1 << 26,
|
||||
CLUTTER_HYPER_MASK = 1 << 27,
|
||||
CLUTTER_META_MASK = 1 << 28,
|
||||
|
||||
CLUTTER_RELEASE_MASK = 1 << 30,
|
||||
|
||||
CLUTTER_MODIFIER_MASK = 0x5c001fff
|
||||
} ClutterModifierType;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __CLUTTER_TYPES_H__ */
|
||||
|
@ -37,12 +37,12 @@
|
||||
#include <GL/gl.h>
|
||||
|
||||
#include "clutter-backend-glx.h"
|
||||
#include "clutter-event-glx.h"
|
||||
#include "clutter-stage-glx.h"
|
||||
#include "clutter-glx.h"
|
||||
#include "clutter-profile.h"
|
||||
|
||||
#include "clutter-debug.h"
|
||||
#include "clutter-event-translator.h"
|
||||
#include "clutter-event.h"
|
||||
#include "clutter-main.h"
|
||||
#include "clutter-private.h"
|
||||
@ -108,8 +108,8 @@ clutter_backend_glx_post_parse (ClutterBackend *backend,
|
||||
/* XXX: Technically we should require >= GLX 1.3 support but for a long
|
||||
* time Mesa has exported a hybrid GLX, exporting extensions specified
|
||||
* to require GLX 1.3, but still reporting 1.2 via glXQueryVersion. */
|
||||
if (!glXQueryVersion (backend_x11->xdpy, &glx_major, &glx_minor)
|
||||
|| !(glx_major == 1 && glx_minor >= 2))
|
||||
if (!glXQueryVersion (backend_x11->xdpy, &glx_major, &glx_minor) ||
|
||||
!(glx_major == 1 && glx_minor >= 2))
|
||||
{
|
||||
g_set_error (error, CLUTTER_INIT_ERROR,
|
||||
CLUTTER_INIT_ERROR_BACKEND,
|
||||
@ -787,6 +787,7 @@ clutter_backend_glx_create_stage (ClutterBackend *backend,
|
||||
GError **error)
|
||||
{
|
||||
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
|
||||
ClutterEventTranslator *translator;
|
||||
ClutterStageWindow *stage_window;
|
||||
ClutterStageX11 *stage_x11;
|
||||
|
||||
@ -799,6 +800,9 @@ clutter_backend_glx_create_stage (ClutterBackend *backend,
|
||||
stage_x11 = CLUTTER_STAGE_X11 (stage_window);
|
||||
stage_x11->wrapper = wrapper;
|
||||
|
||||
translator = CLUTTER_EVENT_TRANSLATOR (stage_x11);
|
||||
_clutter_backend_x11_add_event_translator (backend_x11, translator);
|
||||
|
||||
CLUTTER_NOTE (BACKEND,
|
||||
"GLX stage created[%p] (dpy:%p, screen:%d, root:%u, wrap:%p)",
|
||||
stage_window,
|
||||
@ -831,7 +835,6 @@ _clutter_backend_glx_class_init (ClutterBackendGLXClass *klass)
|
||||
backend_class->ensure_context = clutter_backend_glx_ensure_context;
|
||||
|
||||
backendx11_class->get_visual_info = clutter_backend_glx_get_visual_info;
|
||||
backendx11_class->handle_event = _clutter_backend_glx_handle_event;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1,105 +0,0 @@
|
||||
/* Clutter.
|
||||
* An OpenGL based 'interactive canvas' library.
|
||||
* Authored By Matthew Allum <mallum@openedhand.com>
|
||||
* Copyright (C) 2006-2007 OpenedHand
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "clutter-x11.h"
|
||||
#include "clutter-stage-x11.h"
|
||||
#include "clutter-backend-x11.h"
|
||||
#include "clutter-stage-glx.h"
|
||||
#include "clutter-backend-glx.h"
|
||||
|
||||
#include "clutter-private.h"
|
||||
#include "clutter-stage-private.h"
|
||||
|
||||
#include <clutter/clutter-backend.h>
|
||||
#include <clutter/clutter-stage-manager.h>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
#include <GL/glxext.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
gboolean
|
||||
_clutter_backend_glx_handle_event (ClutterBackendX11 *backend_x11,
|
||||
XEvent *xevent)
|
||||
{
|
||||
#ifdef GLX_INTEL_swap_event
|
||||
ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (backend_x11);
|
||||
ClutterStageManager *stage_manager;
|
||||
GLXBufferSwapComplete *swap_complete_event;
|
||||
const GSList *l;
|
||||
|
||||
if (xevent->type != (backend_glx->event_base + GLX_BufferSwapComplete))
|
||||
return FALSE; /* Unhandled */
|
||||
|
||||
swap_complete_event = (GLXBufferSwapComplete *)xevent;
|
||||
|
||||
#if 0
|
||||
{
|
||||
const char *event_name;
|
||||
if (swap_complete_event->event_type == GLX_EXCHANGE_COMPLETE_INTEL)
|
||||
event_name = "GLX_EXCHANGE_COMPLETE";
|
||||
else if (swap_complete_event->event_type == GLX_BLIT_COMPLETE_INTEL)
|
||||
event_name = "GLX_BLIT_COMPLETE";
|
||||
else
|
||||
{
|
||||
g_assert (swap_complete_event->event_type == GLX_FLIP_COMPLETE_INTEL);
|
||||
event_name = "GLX_FLIP_COMPLETE";
|
||||
}
|
||||
|
||||
g_print ("XXX: clutter_backend_glx_event_handle event = %s\n",
|
||||
event_name);
|
||||
}
|
||||
#endif
|
||||
|
||||
stage_manager = clutter_stage_manager_get_default ();
|
||||
|
||||
for (l = clutter_stage_manager_peek_stages (stage_manager); l; l = l->next)
|
||||
{
|
||||
ClutterStageWindow *stage_win = _clutter_stage_get_window (l->data);
|
||||
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (stage_win);
|
||||
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_win);
|
||||
|
||||
if (stage_x11->xwin == swap_complete_event->drawable)
|
||||
{
|
||||
/* Early versions of the swap_event implementation in Mesa
|
||||
* deliver BufferSwapComplete event when not selected for,
|
||||
* so if we get a swap event we aren't expecting, just ignore it.
|
||||
*
|
||||
* https://bugs.freedesktop.org/show_bug.cgi?id=27962
|
||||
*/
|
||||
if (stage_glx->pending_swaps > 0)
|
||||
stage_glx->pending_swaps--;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
#else
|
||||
return FALSE;
|
||||
#endif
|
||||
}
|
||||
|
@ -1,38 +0,0 @@
|
||||
/* Clutter.
|
||||
* An OpenGL based 'interactive canvas' library.
|
||||
* Copyright (C) 2009 Intel Corporation.
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __CLUTTER_EVENT_GLX_H__
|
||||
#define __CLUTTER_EVENT_GLX_H__
|
||||
|
||||
#include <glib.h>
|
||||
#include <clutter/clutter-event.h>
|
||||
#include <clutter/clutter-backend.h>
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
gboolean
|
||||
_clutter_backend_glx_handle_event (ClutterBackendX11 *backend,
|
||||
XEvent *xevent);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __CLUTTER_EVENT_GLX_H__ */
|
||||
|
@ -30,6 +30,7 @@
|
||||
|
||||
#include "clutter-actor-private.h"
|
||||
#include "clutter-debug.h"
|
||||
#include "clutter-device-manager.h"
|
||||
#include "clutter-event.h"
|
||||
#include "clutter-enum-types.h"
|
||||
#include "clutter-feature.h"
|
||||
@ -51,7 +52,8 @@
|
||||
#include <drm.h>
|
||||
#endif
|
||||
|
||||
static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface);
|
||||
static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface);
|
||||
static void clutter_event_translator_iface_init (ClutterEventTranslatorIface *iface);
|
||||
|
||||
static ClutterStageWindowIface *clutter_stage_glx_parent_iface = NULL;
|
||||
|
||||
@ -59,7 +61,9 @@ G_DEFINE_TYPE_WITH_CODE (ClutterStageGLX,
|
||||
_clutter_stage_glx,
|
||||
CLUTTER_TYPE_STAGE_X11,
|
||||
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW,
|
||||
clutter_stage_window_iface_init));
|
||||
clutter_stage_window_iface_init)
|
||||
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_EVENT_TRANSLATOR,
|
||||
clutter_event_translator_iface_init));
|
||||
|
||||
static void
|
||||
clutter_stage_glx_unrealize (ClutterStageWindow *stage_window)
|
||||
@ -70,7 +74,7 @@ clutter_stage_glx_unrealize (ClutterStageWindow *stage_window)
|
||||
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (stage_window);
|
||||
|
||||
/* Note unrealize should free up any backend stage related resources */
|
||||
CLUTTER_NOTE (BACKEND, "Unrealizing stage");
|
||||
CLUTTER_NOTE (BACKEND, "Unrealizing GLX stage [%p]", stage_glx);
|
||||
|
||||
clutter_x11_trap_x_errors ();
|
||||
|
||||
@ -80,19 +84,11 @@ clutter_stage_glx_unrealize (ClutterStageWindow *stage_window)
|
||||
stage_glx->glxwin = None;
|
||||
}
|
||||
|
||||
if (!stage_x11->is_foreign_xwin && stage_x11->xwin != None)
|
||||
{
|
||||
XDestroyWindow (backend_x11->xdpy, stage_x11->xwin);
|
||||
stage_x11->xwin = None;
|
||||
}
|
||||
else
|
||||
stage_x11->xwin = None;
|
||||
_clutter_stage_x11_destroy_window_untrapped (stage_x11);
|
||||
|
||||
XSync (backend_x11->xdpy, False);
|
||||
|
||||
clutter_x11_untrap_x_errors ();
|
||||
|
||||
CLUTTER_MARK ();
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@ -103,7 +99,6 @@ clutter_stage_glx_realize (ClutterStageWindow *stage_window)
|
||||
ClutterBackendX11 *backend_x11;
|
||||
ClutterBackendGLX *backend_glx;
|
||||
ClutterBackend *backend;
|
||||
int event_flags;
|
||||
|
||||
CLUTTER_NOTE (ACTOR, "Realizing stage '%s' [%p]",
|
||||
G_OBJECT_TYPE_NAME (stage_window),
|
||||
@ -113,62 +108,8 @@ clutter_stage_glx_realize (ClutterStageWindow *stage_window)
|
||||
backend_glx = CLUTTER_BACKEND_GLX (backend);
|
||||
backend_x11 = CLUTTER_BACKEND_X11 (backend);
|
||||
|
||||
if (stage_x11->xwin == None)
|
||||
{
|
||||
XSetWindowAttributes xattr;
|
||||
unsigned long mask;
|
||||
XVisualInfo *xvisinfo;
|
||||
gfloat width, height;
|
||||
|
||||
CLUTTER_NOTE (MISC, "Creating stage X window");
|
||||
|
||||
xvisinfo = clutter_backend_x11_get_visual_info (backend_x11);
|
||||
if (xvisinfo == NULL)
|
||||
{
|
||||
g_critical ("Unable to find suitable GL visual.");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* window attributes */
|
||||
xattr.background_pixel = WhitePixel (backend_x11->xdpy,
|
||||
backend_x11->xscreen_num);
|
||||
xattr.border_pixel = 0;
|
||||
xattr.colormap = XCreateColormap (backend_x11->xdpy,
|
||||
backend_x11->xwin_root,
|
||||
xvisinfo->visual,
|
||||
AllocNone);
|
||||
mask = CWBorderPixel | CWColormap;
|
||||
|
||||
/* Call get_size - this will either get the geometry size (which
|
||||
* before we create the window is set to 640x480), or if a size
|
||||
* is set, it will get that. This lets you set a size on the
|
||||
* stage before it's realized.
|
||||
*/
|
||||
clutter_actor_get_size (CLUTTER_ACTOR (stage_x11->wrapper),
|
||||
&width,
|
||||
&height);
|
||||
stage_x11->xwin_width = (gint)width;
|
||||
stage_x11->xwin_height = (gint)height;
|
||||
|
||||
stage_x11->xwin = XCreateWindow (backend_x11->xdpy,
|
||||
backend_x11->xwin_root,
|
||||
0, 0,
|
||||
stage_x11->xwin_width,
|
||||
stage_x11->xwin_height,
|
||||
0,
|
||||
xvisinfo->depth,
|
||||
InputOutput,
|
||||
xvisinfo->visual,
|
||||
mask, &xattr);
|
||||
|
||||
CLUTTER_NOTE (BACKEND, "Stage [%p], window: 0x%x, size: %dx%d",
|
||||
stage_window,
|
||||
(unsigned int) stage_x11->xwin,
|
||||
stage_x11->xwin_width,
|
||||
stage_x11->xwin_height);
|
||||
|
||||
XFree (xvisinfo);
|
||||
}
|
||||
if (!_clutter_stage_x11_create_window (stage_x11))
|
||||
return FALSE;
|
||||
|
||||
if (stage_glx->glxwin == None)
|
||||
{
|
||||
@ -190,52 +131,12 @@ clutter_stage_glx_realize (ClutterStageWindow *stage_window)
|
||||
}
|
||||
}
|
||||
|
||||
/* the masks for the events we want to select on a stage window;
|
||||
* KeyPressMask and KeyReleaseMask are necessary even with XI1
|
||||
* because key events are broken with that extension, and will
|
||||
* be fixed by XI2
|
||||
*/
|
||||
event_flags = StructureNotifyMask
|
||||
| FocusChangeMask
|
||||
| ExposureMask
|
||||
| PropertyChangeMask
|
||||
| EnterWindowMask
|
||||
| LeaveWindowMask
|
||||
| KeyPressMask
|
||||
| KeyReleaseMask;
|
||||
|
||||
/* if we don't use XI1 then we also want core pointer events */
|
||||
if (!clutter_x11_has_xinput ())
|
||||
event_flags |= (ButtonPressMask | ButtonReleaseMask | PointerMotionMask);
|
||||
#ifdef HAVE_XINPUT
|
||||
else
|
||||
_clutter_x11_select_events (stage_x11->xwin);
|
||||
#endif
|
||||
|
||||
/* we unconditionally select input events even with event retrieval
|
||||
* disabled because we need to guarantee that the Clutter internal
|
||||
* state is maintained when calling clutter_x11_handle_event() without
|
||||
* requiring applications or embedding toolkits to select events
|
||||
* themselves. if we did that, we'd have to document the events to be
|
||||
* selected, and also update applications and embedding toolkits each
|
||||
* time we added a new mask, or a new class of events.
|
||||
*
|
||||
* see: http://bugzilla.clutter-project.org/show_bug.cgi?id=998
|
||||
* for the rationale of why we did conditional selection. it is now
|
||||
* clear that a compositor should clear out the input region, since
|
||||
* it cannot assume a perfectly clean slate coming from us.
|
||||
*
|
||||
* see: http://bugzilla.clutter-project.org/show_bug.cgi?id=2228
|
||||
* for an example of things that break if we do conditional event
|
||||
* selection.
|
||||
*/
|
||||
XSelectInput (backend_x11->xdpy, stage_x11->xwin, event_flags);
|
||||
|
||||
#ifdef GLX_INTEL_swap_event
|
||||
if (clutter_feature_available (CLUTTER_FEATURE_SWAP_EVENTS))
|
||||
{
|
||||
GLXDrawable drawable =
|
||||
stage_glx->glxwin ? stage_glx->glxwin : stage_x11->xwin;
|
||||
GLXDrawable drawable = stage_glx->glxwin
|
||||
? stage_glx->glxwin
|
||||
: stage_x11->xwin;
|
||||
|
||||
/* similarly to above, we unconditionally select this event
|
||||
* because we rely on it to advance the master clock, and
|
||||
@ -247,14 +148,6 @@ clutter_stage_glx_realize (ClutterStageWindow *stage_window)
|
||||
}
|
||||
#endif /* GLX_INTEL_swap_event */
|
||||
|
||||
/* no user resize.. */
|
||||
clutter_stage_x11_fix_window_size (stage_x11,
|
||||
stage_x11->xwin_width,
|
||||
stage_x11->xwin_height);
|
||||
clutter_stage_x11_set_wm_protocols (stage_x11);
|
||||
|
||||
CLUTTER_NOTE (BACKEND, "Successfully realized stage");
|
||||
|
||||
/* chain up to the StageX11 implementation */
|
||||
return clutter_stage_glx_parent_iface->realize (stage_window);
|
||||
}
|
||||
@ -439,6 +332,57 @@ clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
|
||||
/* the rest is inherited from ClutterStageX11 */
|
||||
}
|
||||
|
||||
static ClutterEventTranslatorIface *event_translator_parent_iface = NULL;
|
||||
|
||||
static ClutterTranslateReturn
|
||||
clutter_stage_glx_translate_event (ClutterEventTranslator *translator,
|
||||
gpointer native,
|
||||
ClutterEvent *event)
|
||||
{
|
||||
#ifdef GLX_INTEL_swap_event
|
||||
ClutterBackendGLX *backend_glx;
|
||||
XEvent *xevent = native;
|
||||
|
||||
backend_glx = CLUTTER_BACKEND_GLX (clutter_get_default_backend ());
|
||||
|
||||
if (xevent->type == (backend_glx->event_base + GLX_BufferSwapComplete))
|
||||
{
|
||||
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (translator);
|
||||
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (translator);
|
||||
GLXBufferSwapComplete *swap_complete_event;
|
||||
|
||||
swap_complete_event = (GLXBufferSwapComplete *) xevent;
|
||||
|
||||
if (stage_x11->xwin == swap_complete_event->drawable)
|
||||
{
|
||||
/* Early versions of the swap_event implementation in Mesa
|
||||
* deliver BufferSwapComplete event when not selected for,
|
||||
* so if we get a swap event we aren't expecting, just ignore it.
|
||||
*
|
||||
* https://bugs.freedesktop.org/show_bug.cgi?id=27962
|
||||
*/
|
||||
if (stage_glx->pending_swaps > 0)
|
||||
stage_glx->pending_swaps--;
|
||||
|
||||
return CLUTTER_TRANSLATE_REMOVE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* chain up to the common X11 implementation */
|
||||
return event_translator_parent_iface->translate_event (translator,
|
||||
native,
|
||||
event);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_event_translator_iface_init (ClutterEventTranslatorIface *iface)
|
||||
{
|
||||
event_translator_parent_iface = g_type_interface_peek_parent (iface);
|
||||
|
||||
iface->translate_event = clutter_stage_glx_translate_event;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DRM
|
||||
static int
|
||||
drm_wait_vblank(int fd, drm_wait_vblank_t *vbl)
|
||||
@ -491,7 +435,7 @@ wait_for_vblank (ClutterBackendGLX *backend_glx)
|
||||
|
||||
void
|
||||
_clutter_stage_glx_redraw (ClutterStageGLX *stage_glx,
|
||||
ClutterStage *stage)
|
||||
ClutterStage *stage)
|
||||
{
|
||||
ClutterBackend *backend;
|
||||
ClutterBackendX11 *backend_x11;
|
||||
|
@ -38,8 +38,8 @@
|
||||
#include <errno.h>
|
||||
|
||||
#include "clutter-backend-x11.h"
|
||||
#include "clutter-device-manager-x11.h"
|
||||
#include "clutter-input-device-x11.h"
|
||||
#include "clutter-device-manager-core-x11.h"
|
||||
#include "clutter-device-manager-xi2.h"
|
||||
#include "clutter-settings-x11.h"
|
||||
#include "clutter-stage-x11.h"
|
||||
#include "clutter-x11.h"
|
||||
@ -54,12 +54,16 @@
|
||||
#include <X11/extensions/XInput.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_XINPUT_2
|
||||
#include <X11/extensions/XInput2.h>
|
||||
#endif
|
||||
|
||||
#include "cogl/cogl.h"
|
||||
#include "cogl/cogl-internal.h"
|
||||
|
||||
#include "clutter-backend.h"
|
||||
#include "clutter-debug.h"
|
||||
#include "clutter-device-manager.h"
|
||||
#include "clutter-device-manager-private.h"
|
||||
#include "clutter-event.h"
|
||||
#include "clutter-main.h"
|
||||
#include "clutter-private.h"
|
||||
@ -120,6 +124,30 @@ xsettings_filter (XEvent *xevent,
|
||||
return CLUTTER_X11_FILTER_CONTINUE;
|
||||
}
|
||||
|
||||
static ClutterX11FilterReturn
|
||||
cogl_xlib_filter (XEvent *xevent,
|
||||
ClutterEvent *event,
|
||||
gpointer data)
|
||||
{
|
||||
CoglXlibFilterReturn ret;
|
||||
ClutterX11FilterReturn retval;
|
||||
|
||||
ret = _cogl_xlib_handle_event (xevent);
|
||||
switch (ret)
|
||||
{
|
||||
case COGL_XLIB_FILTER_REMOVE:
|
||||
retval = CLUTTER_X11_FILTER_REMOVE;
|
||||
break;
|
||||
|
||||
case COGL_XLIB_FILTER_CONTINUE:
|
||||
default:
|
||||
retval = CLUTTER_X11_FILTER_CONTINUE;
|
||||
break;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_backend_x11_xsettings_notify (const char *name,
|
||||
XSettingsAction action,
|
||||
@ -192,6 +220,62 @@ clutter_backend_x11_xsettings_notify (const char *name,
|
||||
g_object_thaw_notify (G_OBJECT (settings));
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_backend_x11_create_device_manager (ClutterBackendX11 *backend_x11)
|
||||
{
|
||||
if (G_UNLIKELY (backend_x11->device_manager == NULL))
|
||||
{
|
||||
ClutterEventTranslator *translator;
|
||||
|
||||
#if defined(HAVE_XINPUT) || defined(HAVE_XINPUT_2)
|
||||
if (clutter_enable_xinput)
|
||||
{
|
||||
int event_base, first_event, first_error;
|
||||
|
||||
if (XQueryExtension (backend_x11->xdpy, "XInputExtension",
|
||||
&event_base,
|
||||
&first_event,
|
||||
&first_error))
|
||||
{
|
||||
int major = 2;
|
||||
int minor = 0;
|
||||
|
||||
if (XIQueryVersion (backend_x11->xdpy, &major, &minor) != BadRequest)
|
||||
{
|
||||
CLUTTER_NOTE (BACKEND, "Creating XI2 device manager");
|
||||
|
||||
backend_x11->device_manager =
|
||||
g_object_new (CLUTTER_TYPE_DEVICE_MANAGER_XI2,
|
||||
"backend", backend_x11,
|
||||
"opcode", event_base,
|
||||
NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
CLUTTER_NOTE (BACKEND, "Creating Core+XI device manager");
|
||||
backend_x11->device_manager =
|
||||
g_object_new (CLUTTER_TYPE_DEVICE_MANAGER_X11,
|
||||
"backend", backend_x11,
|
||||
"event-base", first_event,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif /* HAVE_XINPUT || HAVE_XINPUT_2 */
|
||||
{
|
||||
CLUTTER_NOTE (BACKEND, "Creating Core device manager");
|
||||
backend_x11->device_manager =
|
||||
g_object_new (CLUTTER_TYPE_DEVICE_MANAGER_X11,
|
||||
"backend", backend_x11,
|
||||
NULL);
|
||||
}
|
||||
|
||||
translator = CLUTTER_EVENT_TRANSLATOR (backend_x11->device_manager);
|
||||
_clutter_backend_x11_add_event_translator (backend_x11, translator);
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
clutter_backend_x11_pre_parse (ClutterBackend *backend,
|
||||
GError **error)
|
||||
@ -215,6 +299,13 @@ clutter_backend_x11_pre_parse (ClutterBackend *backend,
|
||||
env_string = NULL;
|
||||
}
|
||||
|
||||
env_string = g_getenv ("CLUTTER_ENABLE_XINPUT");
|
||||
if (env_string)
|
||||
{
|
||||
clutter_enable_xinput = TRUE;
|
||||
env_string = NULL;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -271,6 +362,9 @@ clutter_backend_x11_post_parse (ClutterBackend *backend,
|
||||
CoglTexturePixmapX11 */
|
||||
_cogl_xlib_set_display (backend_x11->xdpy);
|
||||
|
||||
/* add event filter for Cogl events */
|
||||
clutter_x11_add_filter (cogl_xlib_filter, NULL);
|
||||
|
||||
if (clutter_screen == -1)
|
||||
backend_x11->xscreen = DefaultScreenOfDisplay (backend_x11->xdpy);
|
||||
else
|
||||
@ -278,6 +372,8 @@ clutter_backend_x11_post_parse (ClutterBackend *backend,
|
||||
clutter_screen);
|
||||
|
||||
backend_x11->xscreen_num = XScreenNumberOfScreen (backend_x11->xscreen);
|
||||
backend_x11->xscreen_width = WidthOfScreen (backend_x11->xscreen);
|
||||
backend_x11->xscreen_height = HeightOfScreen (backend_x11->xscreen);
|
||||
|
||||
backend_x11->xwin_root = RootWindow (backend_x11->xdpy,
|
||||
backend_x11->xscreen_num);
|
||||
@ -289,12 +385,8 @@ clutter_backend_x11_post_parse (ClutterBackend *backend,
|
||||
|
||||
g_object_set (settings, "font-dpi", (int) dpi * 1024, NULL);
|
||||
|
||||
/* register input devices */
|
||||
backend_x11->device_manager =
|
||||
g_object_new (CLUTTER_TYPE_DEVICE_MANAGER_X11,
|
||||
"use-xinput-1", clutter_enable_xinput,
|
||||
"backend", backend_x11,
|
||||
NULL);
|
||||
/* create the device manager */
|
||||
clutter_backend_x11_create_device_manager (backend_x11);
|
||||
|
||||
/* register keymap */
|
||||
backend_x11->keymap =
|
||||
@ -310,6 +402,7 @@ clutter_backend_x11_post_parse (ClutterBackend *backend,
|
||||
NULL,
|
||||
backend_x11);
|
||||
|
||||
/* add event filter for XSETTINGS events */
|
||||
clutter_x11_add_filter (xsettings_filter, backend_x11);
|
||||
|
||||
if (clutter_synchronise)
|
||||
@ -374,7 +467,7 @@ static const GOptionEntry entries[] =
|
||||
G_OPTION_ARG_NONE, &clutter_synchronise,
|
||||
N_("Make X calls synchronous"), NULL
|
||||
},
|
||||
#ifdef HAVE_XINPUT
|
||||
#if defined(HAVE_XINPUT) || defined(HAVE_XINPUT_2)
|
||||
{
|
||||
"enable-xinput", 0,
|
||||
0,
|
||||
@ -480,36 +573,128 @@ clutter_backend_x11_free_event_data (ClutterBackend *backend,
|
||||
_clutter_event_x11_free (event_x11);
|
||||
}
|
||||
|
||||
gboolean
|
||||
clutter_backend_x11_handle_event (ClutterBackendX11 *backend_x11,
|
||||
XEvent *xevent)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static ClutterDeviceManager *
|
||||
clutter_backend_x11_get_device_manager (ClutterBackend *backend)
|
||||
{
|
||||
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
|
||||
|
||||
if (G_UNLIKELY (backend_x11->device_manager == NULL))
|
||||
{
|
||||
backend_x11->device_manager =
|
||||
g_object_new (CLUTTER_TYPE_DEVICE_MANAGER_X11,
|
||||
"use-xinput-1", clutter_enable_xinput,
|
||||
"backend", backend_x11,
|
||||
NULL);
|
||||
}
|
||||
clutter_backend_x11_create_device_manager (backend_x11);
|
||||
|
||||
return backend_x11->device_manager;
|
||||
}
|
||||
|
||||
static void
|
||||
update_last_event_time (ClutterBackendX11 *backend_x11,
|
||||
XEvent *xevent)
|
||||
{
|
||||
Time current_time = CurrentTime;
|
||||
Time last_time = backend_x11->last_event_time;
|
||||
|
||||
switch (xevent->type)
|
||||
{
|
||||
case KeyPress:
|
||||
case KeyRelease:
|
||||
current_time = xevent->xkey.time;
|
||||
break;
|
||||
|
||||
case ButtonPress:
|
||||
case ButtonRelease:
|
||||
current_time = xevent->xbutton.time;
|
||||
break;
|
||||
|
||||
case MotionNotify:
|
||||
current_time = xevent->xmotion.time;
|
||||
break;
|
||||
|
||||
case EnterNotify:
|
||||
case LeaveNotify:
|
||||
current_time = xevent->xcrossing.time;
|
||||
break;
|
||||
|
||||
case PropertyNotify:
|
||||
current_time = xevent->xproperty.time;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* only change the current event time if it's after the previous event
|
||||
* time, or if it is at least 30 seconds earlier - in case the system
|
||||
* clock was changed
|
||||
*/
|
||||
if ((current_time != CurrentTime) &&
|
||||
(current_time > last_time || (last_time - current_time > (30 * 1000))))
|
||||
backend_x11->last_event_time = current_time;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clutter_backend_x11_translate_event (ClutterBackend *backend,
|
||||
gpointer native,
|
||||
ClutterEvent *event)
|
||||
{
|
||||
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
|
||||
XEvent *xevent = native;
|
||||
GList *l;
|
||||
|
||||
if (backend_x11->event_filters)
|
||||
{
|
||||
GSList *node = backend_x11->event_filters;
|
||||
|
||||
while (node != NULL)
|
||||
{
|
||||
ClutterX11EventFilter *filter = node->data;
|
||||
|
||||
switch (filter->func (xevent, event, filter->data))
|
||||
{
|
||||
case CLUTTER_X11_FILTER_CONTINUE:
|
||||
break;
|
||||
|
||||
case CLUTTER_X11_FILTER_TRANSLATE:
|
||||
return TRUE;
|
||||
|
||||
case CLUTTER_X11_FILTER_REMOVE:
|
||||
return FALSE;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* we update the event time only for events that can
|
||||
* actually reach Clutter's event queue
|
||||
*/
|
||||
update_last_event_time (backend_x11, xevent);
|
||||
|
||||
for (l = backend_x11->event_translators;
|
||||
l != NULL;
|
||||
l = l->next)
|
||||
{
|
||||
ClutterEventTranslator *translator = l->data;
|
||||
ClutterTranslateReturn retval;
|
||||
|
||||
retval = _clutter_event_translator_translate_event (translator,
|
||||
native,
|
||||
event);
|
||||
|
||||
if (retval == CLUTTER_TRANSLATE_QUEUE)
|
||||
return TRUE;
|
||||
|
||||
if (retval == CLUTTER_TRANSLATE_REMOVE)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_backend_x11_class_init (ClutterBackendX11Class *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
ClutterBackendClass *backend_class = CLUTTER_BACKEND_CLASS (klass);
|
||||
ClutterBackendX11Class *backendx11_class = CLUTTER_BACKEND_X11_CLASS (klass);
|
||||
|
||||
gobject_class->constructor = clutter_backend_x11_constructor;
|
||||
gobject_class->dispose = clutter_backend_x11_dispose;
|
||||
@ -523,8 +708,7 @@ clutter_backend_x11_class_init (ClutterBackendX11Class *klass)
|
||||
backend_class->get_device_manager = clutter_backend_x11_get_device_manager;
|
||||
backend_class->copy_event_data = clutter_backend_x11_copy_event_data;
|
||||
backend_class->free_event_data = clutter_backend_x11_free_event_data;
|
||||
|
||||
backendx11_class->handle_event = clutter_backend_x11_handle_event;
|
||||
backend_class->translate_event = clutter_backend_x11_translate_event;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -634,18 +818,12 @@ clutter_x11_set_display (Display *xdpy)
|
||||
* want to use clutter_x11_has_xinput() to see if support was enabled.
|
||||
*
|
||||
* Since: 0.8
|
||||
*
|
||||
* Deprecated: 1.6: This function does not do anything.
|
||||
*/
|
||||
void
|
||||
clutter_x11_enable_xinput (void)
|
||||
{
|
||||
if (_clutter_context_is_initialized ())
|
||||
{
|
||||
g_critical ("clutter_x11_enable_xinput() can only be called "
|
||||
"before clutter_init()");
|
||||
return;
|
||||
}
|
||||
|
||||
clutter_enable_xinput = TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -815,33 +993,6 @@ clutter_x11_remove_filter (ClutterX11FilterFunc func,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_x11_select_events (Window xwin)
|
||||
{
|
||||
#ifdef HAVE_XINPUT
|
||||
ClutterDeviceManager *manager;
|
||||
const GSList *l;
|
||||
|
||||
if (G_UNLIKELY (backend_singleton == NULL))
|
||||
{
|
||||
g_critical ("X11 backend has not been initialised");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
manager = clutter_device_manager_get_default ();
|
||||
|
||||
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 */
|
||||
}
|
||||
|
||||
ClutterInputDevice *
|
||||
_clutter_x11_get_device_for_xid (XID id)
|
||||
{
|
||||
@ -884,18 +1035,14 @@ clutter_x11_get_input_devices (void)
|
||||
* and XInput support is available at run time.
|
||||
*
|
||||
* Since: 0.8
|
||||
*
|
||||
* Deprecated: 1.6
|
||||
*/
|
||||
gboolean
|
||||
clutter_x11_has_xinput (void)
|
||||
{
|
||||
#ifdef HAVE_XINPUT
|
||||
if (backend_singleton == NULL)
|
||||
{
|
||||
g_critical ("X11 backend has not been initialised");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return backend_singleton->have_xinput;
|
||||
#if defined(HAVE_XINPUT) || defined(HAVE_XINPUT_2)
|
||||
return TRUE;
|
||||
#else
|
||||
return FALSE;
|
||||
#endif
|
||||
@ -1031,3 +1178,76 @@ clutter_x11_get_visual_info (void)
|
||||
|
||||
return clutter_backend_x11_get_visual_info (backend_x11);
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_backend_x11_add_event_translator (ClutterBackendX11 *backend_x11,
|
||||
ClutterEventTranslator *translator)
|
||||
{
|
||||
if (g_list_find (backend_x11->event_translators, translator) != NULL)
|
||||
return;
|
||||
|
||||
backend_x11->event_translators =
|
||||
g_list_prepend (backend_x11->event_translators, translator);
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_backend_x11_remove_event_translator (ClutterBackendX11 *backend_x11,
|
||||
ClutterEventTranslator *translator)
|
||||
{
|
||||
if (g_list_find (backend_x11->event_translators, translator) == NULL)
|
||||
return;
|
||||
|
||||
backend_x11->event_translators =
|
||||
g_list_remove (backend_x11->event_translators, translator);
|
||||
}
|
||||
|
||||
gboolean
|
||||
_clutter_x11_input_device_translate_screen_coord (ClutterInputDevice *device,
|
||||
gint stage_root_x,
|
||||
gint stage_root_y,
|
||||
guint index_,
|
||||
gdouble value,
|
||||
gdouble *axis_value)
|
||||
{
|
||||
ClutterAxisInfo *info;
|
||||
ClutterBackendX11 *backend_x11;
|
||||
gdouble width, scale, offset;
|
||||
|
||||
backend_x11 = CLUTTER_BACKEND_X11 (device->backend);
|
||||
|
||||
if (device->axes == NULL || index_ >= device->axes->len)
|
||||
return FALSE;
|
||||
|
||||
info = &g_array_index (device->axes, ClutterAxisInfo, index_);
|
||||
if (info->axis != CLUTTER_INPUT_AXIS_X ||
|
||||
info->axis != CLUTTER_INPUT_AXIS_Y)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
width = info->max_value - info->min_value;
|
||||
|
||||
if (info->axis == CLUTTER_INPUT_AXIS_X)
|
||||
{
|
||||
if (width > 0)
|
||||
scale = backend_x11->xscreen_width / width;
|
||||
else
|
||||
scale = 1;
|
||||
|
||||
offset = - stage_root_x;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (width > 0)
|
||||
scale = backend_x11->xscreen_height / width;
|
||||
else
|
||||
scale = 1;
|
||||
|
||||
offset = - stage_root_y;
|
||||
}
|
||||
|
||||
if (axis_value)
|
||||
*axis_value = offset + scale * (value - info->min_value);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -28,8 +28,11 @@
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
#include "clutter-x11.h"
|
||||
|
||||
#include "clutter-backend-private.h"
|
||||
#include "clutter-event-translator.h"
|
||||
#include "clutter-keymap-x11.h"
|
||||
|
||||
#include "xsettings/xsettings-client.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
@ -43,23 +46,39 @@ G_BEGIN_DECLS
|
||||
|
||||
typedef struct _ClutterBackendX11 ClutterBackendX11;
|
||||
typedef struct _ClutterBackendX11Class ClutterBackendX11Class;
|
||||
typedef struct _ClutterEventX11 ClutterEventX11;
|
||||
typedef struct _ClutterX11EventFilter ClutterX11EventFilter;
|
||||
|
||||
typedef struct _ClutterX11EventFilter
|
||||
struct _ClutterX11EventFilter
|
||||
{
|
||||
ClutterX11FilterFunc func;
|
||||
gpointer data;
|
||||
|
||||
} ClutterX11EventFilter;
|
||||
};
|
||||
|
||||
struct _ClutterEventX11
|
||||
{
|
||||
/* additional fields for Key events */
|
||||
gint key_group;
|
||||
|
||||
guint key_is_modifier : 1;
|
||||
guint num_lock_set : 1;
|
||||
guint caps_lock_set : 1;
|
||||
};
|
||||
|
||||
struct _ClutterBackendX11
|
||||
{
|
||||
ClutterBackend parent_instance;
|
||||
|
||||
Display *xdpy;
|
||||
Window xwin_root;
|
||||
gchar *display_name;
|
||||
|
||||
Screen *xscreen;
|
||||
int xscreen_num;
|
||||
gchar *display_name;
|
||||
int xscreen_width;
|
||||
int xscreen_height;
|
||||
|
||||
Window xwin_root;
|
||||
|
||||
/* event source */
|
||||
GSource *event_source;
|
||||
@ -93,6 +112,8 @@ struct _ClutterBackendX11
|
||||
int xkb_event_base;
|
||||
gboolean use_xkb;
|
||||
gboolean have_xkb_autorepeat;
|
||||
|
||||
GList *event_translators;
|
||||
};
|
||||
|
||||
struct _ClutterBackendX11Class
|
||||
@ -105,18 +126,8 @@ struct _ClutterBackendX11Class
|
||||
* may need to be handled differently for different backends.
|
||||
*/
|
||||
XVisualInfo *(* get_visual_info) (ClutterBackendX11 *backend);
|
||||
|
||||
/*
|
||||
* Different X11 backends may care about some special events so they all have
|
||||
* a chance to intercept them.
|
||||
*/
|
||||
gboolean (*handle_event) (ClutterBackendX11 *backend,
|
||||
XEvent *xevent);
|
||||
};
|
||||
|
||||
/* platform-specific event data */
|
||||
typedef struct _ClutterEventX11 ClutterEventX11;
|
||||
|
||||
void _clutter_backend_x11_events_init (ClutterBackend *backend);
|
||||
void _clutter_backend_x11_events_uninit (ClutterBackend *backend);
|
||||
|
||||
@ -163,6 +174,22 @@ _clutter_event_x11_copy (ClutterEventX11 *event_x11);
|
||||
void
|
||||
_clutter_event_x11_free (ClutterEventX11 *event_x11);
|
||||
|
||||
void
|
||||
_clutter_backend_x11_add_event_translator (ClutterBackendX11 *backend_x11,
|
||||
ClutterEventTranslator *translator);
|
||||
|
||||
void
|
||||
_clutter_backend_x11_remove_event_translator (ClutterBackendX11 *backend_x11,
|
||||
ClutterEventTranslator *translator);
|
||||
|
||||
gboolean
|
||||
_clutter_x11_input_device_translate_screen_coord (ClutterInputDevice *device,
|
||||
gint stage_root_x,
|
||||
gint stage_root_y,
|
||||
guint index_,
|
||||
gdouble value,
|
||||
gdouble *axis_value);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __CLUTTER_BACKEND_X11_H__ */
|
||||
|
745
clutter/x11/clutter-device-manager-core-x11.c
Normal file
745
clutter/x11/clutter-device-manager-core-x11.c
Normal file
@ -0,0 +1,745 @@
|
||||
/*
|
||||
* 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>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "clutter-device-manager-core-x11.h"
|
||||
|
||||
#include "clutter-backend-x11.h"
|
||||
#include "clutter-input-device-core-x11.h"
|
||||
#include "clutter-stage-x11.h"
|
||||
|
||||
#include "clutter-backend.h"
|
||||
#include "clutter-debug.h"
|
||||
#include "clutter-device-manager-private.h"
|
||||
#include "clutter-event-translator.h"
|
||||
#include "clutter-stage-private.h"
|
||||
#include "clutter-private.h"
|
||||
|
||||
#ifdef HAVE_XINPUT
|
||||
#include <X11/extensions/XInput.h>
|
||||
|
||||
/* old versions of XI.h don't define these */
|
||||
#ifndef IsXExtensionKeyboard
|
||||
#define IsXExtensionKeyboard 3
|
||||
#define IsXExtensionPointer 4
|
||||
#endif
|
||||
|
||||
#endif /* HAVE_XINPUT */
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
|
||||
PROP_EVENT_BASE,
|
||||
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
static GParamSpec *obj_props[PROP_LAST] = { NULL, };
|
||||
|
||||
static void clutter_event_translator_iface_init (ClutterEventTranslatorIface *iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (ClutterDeviceManagerX11,
|
||||
clutter_device_manager_x11,
|
||||
CLUTTER_TYPE_DEVICE_MANAGER,
|
||||
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_EVENT_TRANSLATOR,
|
||||
clutter_event_translator_iface_init));
|
||||
|
||||
#ifdef HAVE_XINPUT
|
||||
static void
|
||||
translate_class_info (ClutterInputDevice *device,
|
||||
XDeviceInfo *info)
|
||||
{
|
||||
XAnyClassPtr any_class;
|
||||
gint i;
|
||||
|
||||
any_class = info->inputclassinfo;
|
||||
|
||||
for (i = 0; i < info->num_classes; i++)
|
||||
{
|
||||
switch (any_class->class)
|
||||
{
|
||||
case ButtonClass:
|
||||
break;
|
||||
|
||||
case KeyClass:
|
||||
{
|
||||
XKeyInfo *xk_info = (XKeyInfo *) any_class;
|
||||
guint n_keys;
|
||||
|
||||
n_keys = xk_info->max_keycode - xk_info->min_keycode + 1;
|
||||
_clutter_input_device_set_keys (device, n_keys,
|
||||
xk_info->min_keycode,
|
||||
xk_info->max_keycode);
|
||||
}
|
||||
break;
|
||||
|
||||
case ValuatorClass:
|
||||
{
|
||||
XValuatorInfo *xv_info = (XValuatorInfo *) any_class;
|
||||
gint j;
|
||||
|
||||
for (j = 0; j < xv_info->num_axes; j++)
|
||||
{
|
||||
ClutterInputAxis axis;
|
||||
|
||||
switch (j)
|
||||
{
|
||||
case 0:
|
||||
axis = CLUTTER_INPUT_AXIS_X;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
axis = CLUTTER_INPUT_AXIS_Y;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
axis = CLUTTER_INPUT_AXIS_PRESSURE;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
axis = CLUTTER_INPUT_AXIS_XTILT;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
axis = CLUTTER_INPUT_AXIS_YTILT;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
axis = CLUTTER_INPUT_AXIS_WHEEL;
|
||||
break;
|
||||
|
||||
default:
|
||||
axis = CLUTTER_INPUT_AXIS_IGNORE;
|
||||
break;
|
||||
}
|
||||
|
||||
_clutter_input_device_add_axis (device, axis,
|
||||
xv_info->axes[j].min_value,
|
||||
xv_info->axes[j].max_value,
|
||||
xv_info->axes[j].resolution);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
any_class = (XAnyClassPtr) (((char *) any_class) + any_class->length);
|
||||
}
|
||||
}
|
||||
|
||||
static ClutterInputDevice *
|
||||
create_device (ClutterDeviceManagerX11 *manager_x11,
|
||||
ClutterBackendX11 *backend_x11,
|
||||
XDeviceInfo *info)
|
||||
{
|
||||
ClutterInputDeviceType source;
|
||||
ClutterInputDevice *retval;
|
||||
|
||||
if (info->use != IsXExtensionPointer &&
|
||||
info->use != IsXExtensionKeyboard)
|
||||
return NULL;
|
||||
|
||||
if (info->use == IsXExtensionKeyboard)
|
||||
source = CLUTTER_KEYBOARD_DEVICE;
|
||||
else
|
||||
{
|
||||
gchar *name;
|
||||
|
||||
name = g_ascii_strdown (info->name, -1);
|
||||
|
||||
if (strstr (name, "eraser") != NULL)
|
||||
source = CLUTTER_ERASER_DEVICE;
|
||||
else if (strstr (name, "cursor") != NULL)
|
||||
source = CLUTTER_CURSOR_DEVICE;
|
||||
else if (strstr (name, "wacom") != NULL || strstr (name, "pen") != NULL)
|
||||
source = CLUTTER_PEN_DEVICE;
|
||||
else
|
||||
source = CLUTTER_POINTER_DEVICE;
|
||||
|
||||
g_free (name);
|
||||
}
|
||||
|
||||
retval = g_object_new (CLUTTER_TYPE_INPUT_DEVICE_X11,
|
||||
"name", info->name,
|
||||
"id", info->id,
|
||||
"has-cursor", FALSE,
|
||||
"device-manager", manager_x11,
|
||||
"device-type", source,
|
||||
"device-mode", CLUTTER_INPUT_MODE_FLOATING,
|
||||
"backend", backend_x11,
|
||||
NULL);
|
||||
translate_class_info (retval, info);
|
||||
|
||||
CLUTTER_NOTE (BACKEND,
|
||||
"XI Device '%s' (id: %d) created",
|
||||
info->name,
|
||||
(int) info->id);
|
||||
|
||||
return retval;
|
||||
}
|
||||
#endif /* HAVE_XINPUT */
|
||||
|
||||
static inline void
|
||||
translate_key_event (ClutterBackendX11 *backend_x11,
|
||||
ClutterDeviceManagerX11 *manager_x11,
|
||||
ClutterEvent *event,
|
||||
XEvent *xevent)
|
||||
{
|
||||
ClutterEventX11 *event_x11;
|
||||
char buffer[256 + 1];
|
||||
int n;
|
||||
|
||||
event->key.type = xevent->xany.type == KeyPress ? CLUTTER_KEY_PRESS
|
||||
: CLUTTER_KEY_RELEASE;
|
||||
event->key.time = xevent->xkey.time;
|
||||
event->key.device = manager_x11->core_keyboard;
|
||||
|
||||
/* KeyEvents have platform specific data associated to them */
|
||||
event_x11 = _clutter_event_x11_new ();
|
||||
_clutter_event_set_platform_data (event, event_x11);
|
||||
|
||||
event->key.modifier_state = (ClutterModifierType) xevent->xkey.state;
|
||||
event->key.hardware_keycode = xevent->xkey.keycode;
|
||||
|
||||
/* keyval is the key ignoring all modifiers ('1' vs. '!') */
|
||||
event->key.keyval =
|
||||
_clutter_keymap_x11_translate_key_state (backend_x11->keymap,
|
||||
event->key.hardware_keycode,
|
||||
event->key.modifier_state,
|
||||
NULL);
|
||||
|
||||
event_x11->key_group =
|
||||
_clutter_keymap_x11_get_key_group (backend_x11->keymap,
|
||||
event->key.modifier_state);
|
||||
event_x11->key_is_modifier =
|
||||
_clutter_keymap_x11_get_is_modifier (backend_x11->keymap,
|
||||
event->key.hardware_keycode);
|
||||
event_x11->num_lock_set =
|
||||
_clutter_keymap_x11_get_num_lock_state (backend_x11->keymap);
|
||||
event_x11->caps_lock_set =
|
||||
_clutter_keymap_x11_get_caps_lock_state (backend_x11->keymap);
|
||||
|
||||
/* unicode_value is the printable representation */
|
||||
n = XLookupString (&xevent->xkey, buffer, sizeof (buffer) - 1, NULL, NULL);
|
||||
|
||||
if (n != NoSymbol)
|
||||
{
|
||||
event->key.unicode_value = g_utf8_get_char_validated (buffer, n);
|
||||
if ((event->key.unicode_value != -1) &&
|
||||
(event->key.unicode_value != -2))
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
event->key.unicode_value = (gunichar)'\0';
|
||||
|
||||
out:
|
||||
CLUTTER_NOTE (EVENT,
|
||||
"%s: win:0x%x, key: %12s (%d)",
|
||||
event->any.type == CLUTTER_KEY_PRESS
|
||||
? "key press "
|
||||
: "key release",
|
||||
(unsigned int) xevent->xkey.window,
|
||||
event->key.keyval ? buffer : "(none)",
|
||||
event->key.keyval);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef HAVE_XINPUT
|
||||
static ClutterInputDevice *
|
||||
get_device_from_event (ClutterDeviceManagerX11 *manager_x11,
|
||||
XEvent *xevent)
|
||||
{
|
||||
guint32 device_id;
|
||||
|
||||
device_id = ((XDeviceButtonEvent *) xevent)->deviceid;
|
||||
|
||||
return g_hash_table_lookup (manager_x11->devices_by_id,
|
||||
GINT_TO_POINTER (device_id));
|
||||
}
|
||||
#endif /* HAVE_XINPUT */
|
||||
|
||||
static ClutterTranslateReturn
|
||||
clutter_device_manager_x11_translate_event (ClutterEventTranslator *translator,
|
||||
gpointer native,
|
||||
ClutterEvent *event)
|
||||
{
|
||||
ClutterDeviceManagerX11 *manager_x11;
|
||||
ClutterBackendX11 *backend_x11;
|
||||
ClutterInputDevice *device;
|
||||
ClutterStageX11 *stage_x11;
|
||||
ClutterTranslateReturn res;
|
||||
ClutterStage *stage;
|
||||
XEvent *xevent;
|
||||
|
||||
manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (translator);
|
||||
backend_x11 = CLUTTER_BACKEND_X11 (clutter_get_default_backend ());
|
||||
device = NULL;
|
||||
|
||||
xevent = native;
|
||||
|
||||
stage = clutter_x11_get_stage_from_window (xevent->xany.window);
|
||||
if (stage == NULL)
|
||||
return CLUTTER_TRANSLATE_CONTINUE;
|
||||
|
||||
if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
|
||||
return CLUTTER_TRANSLATE_CONTINUE;
|
||||
|
||||
stage_x11 = CLUTTER_STAGE_X11 (_clutter_stage_get_window (stage));
|
||||
|
||||
event->any.stage = stage;
|
||||
|
||||
res = CLUTTER_TRANSLATE_CONTINUE;
|
||||
|
||||
#ifdef HAVE_XINPUT
|
||||
device = get_device_from_event (manager_x11, xevent);
|
||||
if (device != NULL)
|
||||
{
|
||||
ClutterInputDeviceX11 *device_x11;
|
||||
gboolean retval;
|
||||
|
||||
device_x11 = CLUTTER_INPUT_DEVICE_X11 (device);
|
||||
retval = _clutter_input_device_x11_translate_xi_event (device_x11,
|
||||
stage_x11,
|
||||
xevent,
|
||||
event);
|
||||
if (retval)
|
||||
return CLUTTER_TRANSLATE_QUEUE;
|
||||
}
|
||||
#endif /* HAVE_XINPUT */
|
||||
|
||||
switch (xevent->type)
|
||||
{
|
||||
case KeyPress:
|
||||
translate_key_event (backend_x11, manager_x11, event, xevent);
|
||||
_clutter_stage_x11_set_user_time (stage_x11, xevent->xkey.time);
|
||||
res = CLUTTER_TRANSLATE_QUEUE;
|
||||
break;
|
||||
|
||||
case KeyRelease:
|
||||
/* old-style X11 terminals require that even modern X11 send
|
||||
* KeyPress/KeyRelease pairs when auto-repeating. for this
|
||||
* reason modern(-ish) API like XKB has a way to detect
|
||||
* auto-repeat and do a single KeyRelease at the end of a
|
||||
* KeyPress sequence.
|
||||
*
|
||||
* this check emulates XKB's detectable auto-repeat; we peek
|
||||
* the next event and check if it's a KeyPress for the same key
|
||||
* and timestamp - and then ignore it if it matches the
|
||||
* KeyRelease
|
||||
*
|
||||
* if we have XKB, and autorepeat is enabled, then this becomes
|
||||
* a no-op
|
||||
*/
|
||||
if (!backend_x11->have_xkb_autorepeat && XPending (xevent->xkey.display))
|
||||
{
|
||||
XEvent next_event;
|
||||
|
||||
XPeekEvent (xevent->xkey.display, &next_event);
|
||||
|
||||
if (next_event.type == KeyPress &&
|
||||
next_event.xkey.keycode == xevent->xkey.keycode &&
|
||||
next_event.xkey.time == xevent->xkey.time)
|
||||
{
|
||||
res = CLUTTER_TRANSLATE_REMOVE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
translate_key_event (backend_x11, manager_x11, event, xevent);
|
||||
res = CLUTTER_TRANSLATE_QUEUE;
|
||||
break;
|
||||
|
||||
case ButtonPress:
|
||||
CLUTTER_NOTE (EVENT,
|
||||
"button press: win: 0x%x, coords: %d, %d, button: %d",
|
||||
(unsigned int) stage_x11->xwin,
|
||||
xevent->xbutton.x,
|
||||
xevent->xbutton.y,
|
||||
xevent->xbutton.button);
|
||||
|
||||
switch (xevent->xbutton.button)
|
||||
{
|
||||
case 4: /* up */
|
||||
case 5: /* down */
|
||||
case 6: /* left */
|
||||
case 7: /* right */
|
||||
event->scroll.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 = manager_x11->core_pointer;
|
||||
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;
|
||||
event->button.device = manager_x11->core_pointer;
|
||||
event->button.axes = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
_clutter_stage_x11_set_user_time (stage_x11, xevent->xbutton.time);
|
||||
res = CLUTTER_TRANSLATE_QUEUE;
|
||||
break;
|
||||
|
||||
case ButtonRelease:
|
||||
CLUTTER_NOTE (EVENT,
|
||||
"button press: win: 0x%x, coords: %d, %d, button: %d",
|
||||
(unsigned int) stage_x11->xwin,
|
||||
xevent->xbutton.x,
|
||||
xevent->xbutton.y,
|
||||
xevent->xbutton.button);
|
||||
|
||||
/* 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 = CLUTTER_TRANSLATE_REMOVE;
|
||||
break;
|
||||
}
|
||||
|
||||
event->button.type = event->type = CLUTTER_BUTTON_RELEASE;
|
||||
event->button.time = xevent->xbutton.time;
|
||||
event->button.x = xevent->xbutton.x;
|
||||
event->button.y = xevent->xbutton.y;
|
||||
event->button.modifier_state = xevent->xbutton.state;
|
||||
event->button.button = xevent->xbutton.button;
|
||||
event->button.axes = NULL;
|
||||
event->button.device = manager_x11->core_pointer;
|
||||
res = CLUTTER_TRANSLATE_QUEUE;
|
||||
break;
|
||||
|
||||
case MotionNotify:
|
||||
CLUTTER_NOTE (EVENT,
|
||||
"motion: win: 0x%x, coords: %d, %d",
|
||||
(unsigned int) stage_x11->xwin,
|
||||
xevent->xmotion.x,
|
||||
xevent->xmotion.y);
|
||||
|
||||
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 = manager_x11->core_pointer;
|
||||
event->motion.axes = NULL;
|
||||
res = CLUTTER_TRANSLATE_QUEUE;
|
||||
break;
|
||||
|
||||
case EnterNotify:
|
||||
/* we know that we are entering the stage here */
|
||||
_clutter_input_device_set_stage (manager_x11->core_pointer, 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 = manager_x11->core_pointer;
|
||||
res = CLUTTER_TRANSLATE_QUEUE;
|
||||
break;
|
||||
|
||||
case LeaveNotify:
|
||||
if (manager_x11->core_pointer->stage == NULL)
|
||||
{
|
||||
CLUTTER_NOTE (EVENT, "Discarding LeaveNotify for "
|
||||
"ButtonRelease event off-stage");
|
||||
res = CLUTTER_TRANSLATE_REMOVE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* we know that we are leaving the stage here */
|
||||
_clutter_input_device_set_stage (manager_x11->core_pointer, NULL);
|
||||
CLUTTER_NOTE (EVENT, "Leaving the stage (time:%u)",
|
||||
event->crossing.time);
|
||||
|
||||
event->crossing.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 = manager_x11->core_pointer;
|
||||
res = CLUTTER_TRANSLATE_QUEUE;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_event_translator_iface_init (ClutterEventTranslatorIface *iface)
|
||||
{
|
||||
iface->translate_event = clutter_device_manager_x11_translate_event;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_device_manager_x11_constructed (GObject *gobject)
|
||||
{
|
||||
ClutterDeviceManagerX11 *manager_x11;
|
||||
ClutterBackendX11 *backend_x11;
|
||||
ClutterDeviceManager *manager;
|
||||
#ifdef HAVE_XINPUT
|
||||
XDeviceInfo *x_devices = NULL;
|
||||
int i, n_devices;
|
||||
#endif /* HAVE_XINPUT */
|
||||
|
||||
manager = CLUTTER_DEVICE_MANAGER (gobject);
|
||||
manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (gobject);
|
||||
|
||||
g_object_get (gobject, "backend", &backend_x11, NULL);
|
||||
g_assert (backend_x11 != NULL);
|
||||
|
||||
#ifdef HAVE_XINPUT
|
||||
x_devices = XListInputDevices (backend_x11->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;
|
||||
ClutterInputDevice *device;
|
||||
|
||||
CLUTTER_NOTE (BACKEND,
|
||||
"Considering device %li with type %d, %d of %d",
|
||||
info->id,
|
||||
info->use,
|
||||
i, n_devices);
|
||||
|
||||
device = create_device (manager_x11, backend_x11, info);
|
||||
if (device != NULL)
|
||||
_clutter_device_manager_add_device (manager, device);
|
||||
}
|
||||
|
||||
XFreeDeviceList (x_devices);
|
||||
|
||||
default_device:
|
||||
#endif /* HAVE_XINPUT */
|
||||
|
||||
/* fallback code in case:
|
||||
*
|
||||
* - we do not have XInput support compiled in
|
||||
* - 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
|
||||
*/
|
||||
manager_x11->core_pointer =
|
||||
g_object_new (CLUTTER_TYPE_INPUT_DEVICE,
|
||||
"name", "Core Pointer",
|
||||
"has-cursor", TRUE,
|
||||
"device-type", CLUTTER_POINTER_DEVICE,
|
||||
"device-manager", manager_x11,
|
||||
"device-mode", CLUTTER_INPUT_MODE_MASTER,
|
||||
"backend", backend_x11,
|
||||
NULL);
|
||||
CLUTTER_NOTE (BACKEND, "Added core pointer device");
|
||||
|
||||
manager_x11->core_keyboard =
|
||||
g_object_new (CLUTTER_TYPE_INPUT_DEVICE,
|
||||
"name", "Core Keyboard",
|
||||
"has-cursor", FALSE,
|
||||
"device-type", CLUTTER_KEYBOARD_DEVICE,
|
||||
"device-manager", manager_x11,
|
||||
"device-mode", CLUTTER_INPUT_MODE_MASTER,
|
||||
"backend", backend_x11,
|
||||
NULL);
|
||||
CLUTTER_NOTE (BACKEND, "Added core keyboard device");
|
||||
|
||||
/* associate core devices */
|
||||
_clutter_input_device_set_associated_device (manager_x11->core_pointer,
|
||||
manager_x11->core_keyboard);
|
||||
_clutter_input_device_set_associated_device (manager_x11->core_keyboard,
|
||||
manager_x11->core_pointer);
|
||||
|
||||
if (G_OBJECT_CLASS (clutter_device_manager_x11_parent_class)->constructed)
|
||||
G_OBJECT_CLASS (clutter_device_manager_x11_parent_class)->constructed (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_device_manager_x11_add_device (ClutterDeviceManager *manager,
|
||||
ClutterInputDevice *device)
|
||||
{
|
||||
ClutterDeviceManagerX11 *manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (manager);
|
||||
|
||||
manager_x11->devices = g_slist_prepend (manager_x11->devices, device);
|
||||
g_hash_table_replace (manager_x11->devices_by_id,
|
||||
GINT_TO_POINTER (device->id),
|
||||
device);
|
||||
|
||||
/* blow the cache */
|
||||
g_slist_free (manager_x11->all_devices);
|
||||
manager_x11->all_devices = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_device_manager_x11_remove_device (ClutterDeviceManager *manager,
|
||||
ClutterInputDevice *device)
|
||||
{
|
||||
ClutterDeviceManagerX11 *manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (manager);
|
||||
|
||||
g_hash_table_remove (manager_x11->devices_by_id,
|
||||
GINT_TO_POINTER (device->id));
|
||||
manager_x11->devices = g_slist_remove (manager_x11->devices, device);
|
||||
|
||||
/* blow the cache */
|
||||
g_slist_free (manager_x11->all_devices);
|
||||
manager_x11->all_devices = NULL;
|
||||
}
|
||||
|
||||
static const GSList *
|
||||
clutter_device_manager_x11_get_devices (ClutterDeviceManager *manager)
|
||||
{
|
||||
ClutterDeviceManagerX11 *manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (manager);
|
||||
|
||||
/* cache the devices list so that we can keep the core pointer
|
||||
* and keyboard outside of the ManagerX11:devices list
|
||||
*/
|
||||
if (manager_x11->all_devices == NULL)
|
||||
{
|
||||
GSList *all_devices = manager_x11->devices;
|
||||
|
||||
all_devices = g_slist_prepend (all_devices, manager_x11->core_keyboard);
|
||||
all_devices = g_slist_prepend (all_devices, manager_x11->core_pointer);
|
||||
|
||||
manager_x11->all_devices = all_devices;
|
||||
}
|
||||
|
||||
return CLUTTER_DEVICE_MANAGER_X11 (manager)->all_devices;
|
||||
}
|
||||
|
||||
static ClutterInputDevice *
|
||||
clutter_device_manager_x11_get_core_device (ClutterDeviceManager *manager,
|
||||
ClutterInputDeviceType type)
|
||||
{
|
||||
ClutterDeviceManagerX11 *manager_x11;
|
||||
|
||||
manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (manager);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case CLUTTER_POINTER_DEVICE:
|
||||
return manager_x11->core_pointer;
|
||||
|
||||
case CLUTTER_KEYBOARD_DEVICE:
|
||||
return manager_x11->core_keyboard;
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static ClutterInputDevice *
|
||||
clutter_device_manager_x11_get_device (ClutterDeviceManager *manager,
|
||||
gint id)
|
||||
{
|
||||
ClutterDeviceManagerX11 *manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (manager);
|
||||
|
||||
return g_hash_table_lookup (manager_x11->devices_by_id,
|
||||
GINT_TO_POINTER (id));
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_device_manager_x11_set_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ClutterDeviceManagerX11 *manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (gobject);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_EVENT_BASE:
|
||||
manager_x11->xi_event_base = g_value_get_int (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_device_manager_x11_class_init (ClutterDeviceManagerX11Class *klass)
|
||||
{
|
||||
ClutterDeviceManagerClass *manager_class;
|
||||
GObjectClass *gobject_class;
|
||||
|
||||
obj_props[PROP_EVENT_BASE] =
|
||||
g_param_spec_int ("event-base",
|
||||
"Event Base",
|
||||
"The first XI event",
|
||||
-1, G_MAXINT,
|
||||
-1,
|
||||
CLUTTER_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->constructed = clutter_device_manager_x11_constructed;
|
||||
gobject_class->set_property = clutter_device_manager_x11_set_property;
|
||||
|
||||
g_object_class_install_properties (gobject_class, PROP_LAST, obj_props);
|
||||
|
||||
manager_class = CLUTTER_DEVICE_MANAGER_CLASS (klass);
|
||||
manager_class->add_device = clutter_device_manager_x11_add_device;
|
||||
manager_class->remove_device = clutter_device_manager_x11_remove_device;
|
||||
manager_class->get_devices = clutter_device_manager_x11_get_devices;
|
||||
manager_class->get_core_device = clutter_device_manager_x11_get_core_device;
|
||||
manager_class->get_device = clutter_device_manager_x11_get_device;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_device_manager_x11_init (ClutterDeviceManagerX11 *self)
|
||||
{
|
||||
self->devices_by_id = g_hash_table_new (NULL, NULL);
|
||||
}
|
@ -42,6 +42,8 @@ struct _ClutterDeviceManagerX11
|
||||
{
|
||||
ClutterDeviceManager parent_instance;
|
||||
|
||||
GHashTable *devices_by_id;
|
||||
|
||||
/* the list of transient devices */
|
||||
GSList *devices;
|
||||
|
||||
@ -53,7 +55,7 @@ struct _ClutterDeviceManagerX11
|
||||
ClutterInputDevice *core_pointer;
|
||||
ClutterInputDevice *core_keyboard;
|
||||
|
||||
guint use_xinput_1 : 1;
|
||||
int xi_event_base;
|
||||
};
|
||||
|
||||
struct _ClutterDeviceManagerX11Class
|
@ -1,354 +0,0 @@
|
||||
/*
|
||||
* 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>
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "clutter-backend-x11.h"
|
||||
#include "clutter-device-manager-x11.h"
|
||||
#include "clutter-input-device-x11.h"
|
||||
#include "clutter-stage-x11.h"
|
||||
|
||||
#include "clutter-backend.h"
|
||||
#include "clutter-debug.h"
|
||||
#include "clutter-device-manager-private.h"
|
||||
#include "clutter-private.h"
|
||||
|
||||
#ifdef HAVE_XINPUT
|
||||
#include <X11/extensions/XInput.h>
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
|
||||
PROP_USE_XINPUT_1,
|
||||
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
static GParamSpec *obj_props[PROP_LAST];
|
||||
|
||||
G_DEFINE_TYPE (ClutterDeviceManagerX11,
|
||||
clutter_device_manager_x11,
|
||||
CLUTTER_TYPE_DEVICE_MANAGER);
|
||||
|
||||
static void
|
||||
clutter_device_manager_x11_constructed (GObject *gobject)
|
||||
{
|
||||
ClutterDeviceManagerX11 *manager_x11;
|
||||
ClutterBackendX11 *backend_x11;
|
||||
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 (gobject);
|
||||
manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (gobject);
|
||||
if (!manager_x11->use_xinput_1)
|
||||
{
|
||||
CLUTTER_NOTE (BACKEND, "XInput support not enabled");
|
||||
goto default_device;
|
||||
}
|
||||
|
||||
g_object_get (gobject, "backend", &backend_x11, NULL);
|
||||
g_assert (backend_x11 != NULL);
|
||||
|
||||
#ifdef HAVE_XINPUT
|
||||
res = XQueryExtension (backend_x11->xdpy, "XInputExtension",
|
||||
&opcode,
|
||||
&event,
|
||||
&error);
|
||||
if (!res)
|
||||
{
|
||||
CLUTTER_NOTE (BACKEND, "No XInput extension available");
|
||||
goto default_device;
|
||||
}
|
||||
|
||||
backend_x11->xi_event_base = event;
|
||||
|
||||
x_devices = XListInputDevices (backend_x11->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:
|
||||
default:
|
||||
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_x11);
|
||||
|
||||
_clutter_device_manager_add_device (manager, device);
|
||||
|
||||
if (info->use == IsXExtensionPointer && n_events > 0)
|
||||
backend_x11->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");
|
||||
manager_x11->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");
|
||||
manager_x11->core_keyboard = device;
|
||||
|
||||
if (G_OBJECT_CLASS (clutter_device_manager_x11_parent_class)->constructed)
|
||||
G_OBJECT_CLASS (clutter_device_manager_x11_parent_class)->constructed (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_device_manager_x11_add_device (ClutterDeviceManager *manager,
|
||||
ClutterInputDevice *device)
|
||||
{
|
||||
ClutterDeviceManagerX11 *manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (manager);
|
||||
|
||||
manager_x11->devices = g_slist_prepend (manager_x11->devices, device);
|
||||
|
||||
/* blow the cache */
|
||||
g_slist_free (manager_x11->all_devices);
|
||||
manager_x11->all_devices = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_device_manager_x11_remove_device (ClutterDeviceManager *manager,
|
||||
ClutterInputDevice *device)
|
||||
{
|
||||
ClutterDeviceManagerX11 *manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (manager);
|
||||
|
||||
manager_x11->devices = g_slist_remove (manager_x11->devices, device);
|
||||
|
||||
/* blow the cache */
|
||||
g_slist_free (manager_x11->all_devices);
|
||||
manager_x11->all_devices = NULL;
|
||||
}
|
||||
|
||||
static const GSList *
|
||||
clutter_device_manager_x11_get_devices (ClutterDeviceManager *manager)
|
||||
{
|
||||
ClutterDeviceManagerX11 *manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (manager);
|
||||
|
||||
/* cache the devices list so that we can keep the core pointer
|
||||
* and keyboard outside of the ManagerX11:devices list
|
||||
*/
|
||||
if (manager_x11->all_devices == NULL)
|
||||
{
|
||||
GSList *all_devices;
|
||||
|
||||
all_devices = manager_x11->devices;
|
||||
all_devices = g_slist_prepend (all_devices, manager_x11->core_keyboard);
|
||||
all_devices = g_slist_prepend (all_devices, manager_x11->core_pointer);
|
||||
|
||||
manager_x11->all_devices = all_devices;
|
||||
}
|
||||
|
||||
return CLUTTER_DEVICE_MANAGER_X11 (manager)->all_devices;
|
||||
}
|
||||
|
||||
static ClutterInputDevice *
|
||||
clutter_device_manager_x11_get_core_device (ClutterDeviceManager *manager,
|
||||
ClutterInputDeviceType type)
|
||||
{
|
||||
ClutterDeviceManagerX11 *manager_x11;
|
||||
|
||||
manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (manager);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case CLUTTER_POINTER_DEVICE:
|
||||
return manager_x11->core_pointer;
|
||||
|
||||
case CLUTTER_KEYBOARD_DEVICE:
|
||||
return manager_x11->core_keyboard;
|
||||
|
||||
case CLUTTER_EXTENSION_DEVICE:
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static ClutterInputDevice *
|
||||
clutter_device_manager_x11_get_device (ClutterDeviceManager *manager,
|
||||
gint id)
|
||||
{
|
||||
ClutterDeviceManagerX11 *manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (manager);
|
||||
GSList *l;
|
||||
|
||||
for (l = manager_x11->devices; l != NULL; l = l->next)
|
||||
{
|
||||
ClutterInputDevice *device = l->data;
|
||||
|
||||
if (clutter_input_device_get_device_id (device) == id)
|
||||
return device;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_device_manager_x11_set_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ClutterDeviceManagerX11 *manager_x11;
|
||||
|
||||
manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (gobject);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_USE_XINPUT_1:
|
||||
manager_x11->use_xinput_1 = g_value_get_boolean (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_device_manager_x11_get_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ClutterDeviceManagerX11 *manager_x11;
|
||||
|
||||
manager_x11 = CLUTTER_DEVICE_MANAGER_X11 (gobject);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_USE_XINPUT_1:
|
||||
g_value_set_boolean (value, manager_x11->use_xinput_1);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_device_manager_x11_class_init (ClutterDeviceManagerX11Class *klass)
|
||||
{
|
||||
ClutterDeviceManagerClass *manager_class;
|
||||
GObjectClass *gobject_class;
|
||||
GParamSpec *pspec;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->set_property = clutter_device_manager_x11_set_property;
|
||||
gobject_class->get_property = clutter_device_manager_x11_get_property;
|
||||
gobject_class->constructed = clutter_device_manager_x11_constructed;
|
||||
|
||||
manager_class = CLUTTER_DEVICE_MANAGER_CLASS (klass);
|
||||
manager_class->add_device = clutter_device_manager_x11_add_device;
|
||||
manager_class->remove_device = clutter_device_manager_x11_remove_device;
|
||||
manager_class->get_devices = clutter_device_manager_x11_get_devices;
|
||||
manager_class->get_core_device = clutter_device_manager_x11_get_core_device;
|
||||
manager_class->get_device = clutter_device_manager_x11_get_device;
|
||||
|
||||
pspec = g_param_spec_boolean ("use-xinput-1",
|
||||
"Use XInput 1",
|
||||
"Use the XInput 1.0 extension",
|
||||
FALSE,
|
||||
CLUTTER_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY);
|
||||
obj_props[PROP_USE_XINPUT_1] = pspec;
|
||||
g_object_class_install_property (gobject_class, PROP_USE_XINPUT_1, pspec);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_device_manager_x11_init (ClutterDeviceManagerX11 *self)
|
||||
{
|
||||
self->use_xinput_1 = FALSE;
|
||||
}
|
1058
clutter/x11/clutter-device-manager-xi2.c
Normal file
1058
clutter/x11/clutter-device-manager-xi2.c
Normal file
File diff suppressed because it is too large
Load Diff
66
clutter/x11/clutter-device-manager-xi2.h
Normal file
66
clutter/x11/clutter-device-manager-xi2.h
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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>
|
||||
*/
|
||||
|
||||
#ifndef __CLUTTER_DEVICE_MANAGER_XI2_H__
|
||||
#define __CLUTTER_DEVICE_MANAGER_XI2_H__
|
||||
|
||||
#include <clutter/clutter-device-manager.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define CLUTTER_TYPE_DEVICE_MANAGER_XI2 (_clutter_device_manager_xi2_get_type ())
|
||||
#define CLUTTER_DEVICE_MANAGER_XI2(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_DEVICE_MANAGER_XI2, ClutterDeviceManagerXI2))
|
||||
#define CLUTTER_IS_DEVICE_MANAGER_XI2(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_DEVICE_MANAGER_XI2))
|
||||
#define CLUTTER_DEVICE_MANAGER_XI2_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_DEVICE_MANAGER_XI2, ClutterDeviceManagerXI2Class))
|
||||
#define CLUTTER_IS_DEVICE_MANAGER_XI2_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_DEVICE_MANAGER_XI2))
|
||||
#define CLUTTER_DEVICE_MANAGER_XI2_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_DEVICE_MANAGER_XI2, ClutterDeviceManagerXI2Class))
|
||||
|
||||
typedef struct _ClutterDeviceManagerXI2 ClutterDeviceManagerXI2;
|
||||
typedef struct _ClutterDeviceManagerXI2Class ClutterDeviceManagerXI2Class;
|
||||
|
||||
struct _ClutterDeviceManagerXI2
|
||||
{
|
||||
ClutterDeviceManager parent_instance;
|
||||
|
||||
GHashTable *devices_by_id;
|
||||
|
||||
GSList *all_devices;
|
||||
|
||||
GList *master_devices;
|
||||
GList *slave_devices;
|
||||
|
||||
ClutterInputDevice *client_pointer;
|
||||
|
||||
int opcode;
|
||||
};
|
||||
|
||||
struct _ClutterDeviceManagerXI2Class
|
||||
{
|
||||
ClutterDeviceManagerClass parent_class;
|
||||
};
|
||||
|
||||
GType _clutter_device_manager_xi2_get_type (void) G_GNUC_CONST;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __CLUTTER_DEVICE_MANAGER_XI2_H__ */
|
@ -63,6 +63,7 @@
|
||||
#include <X11/XKBlib.h>
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/* XEMBED protocol support for toolkit embedding */
|
||||
#define XEMBED_MAPPED (1 << 0)
|
||||
#define MAX_SUPPORTED_XEMBED_VERSION 1
|
||||
@ -83,6 +84,7 @@
|
||||
#define XEMBED_ACTIVATE_ACCELERATOR 14
|
||||
|
||||
static Window ParentEmbedderWin = None;
|
||||
#endif
|
||||
|
||||
typedef struct _ClutterEventSource ClutterEventSource;
|
||||
|
||||
@ -94,16 +96,6 @@ struct _ClutterEventSource
|
||||
GPollFD event_poll_fd;
|
||||
};
|
||||
|
||||
struct _ClutterEventX11
|
||||
{
|
||||
/* additional fields for Key events */
|
||||
gint key_group;
|
||||
|
||||
guint key_is_modifier : 1;
|
||||
guint num_lock_set : 1;
|
||||
guint caps_lock_set : 1;
|
||||
};
|
||||
|
||||
ClutterEventX11 *
|
||||
_clutter_event_x11_new (void)
|
||||
{
|
||||
@ -148,7 +140,6 @@ clutter_event_source_new (ClutterBackend *backend)
|
||||
GSource *source = g_source_new (&event_funcs, sizeof (ClutterEventSource));
|
||||
ClutterEventSource *event_source = (ClutterEventSource *) source;
|
||||
|
||||
g_source_set_name (source, "Clutter X11 Event");
|
||||
event_source->backend = backend;
|
||||
|
||||
return source;
|
||||
@ -160,6 +151,7 @@ check_xpending (ClutterBackend *backend)
|
||||
return XPending (CLUTTER_BACKEND_X11 (backend)->xdpy);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static gboolean
|
||||
xembed_send_message (ClutterBackendX11 *backend_x11,
|
||||
Window window,
|
||||
@ -208,6 +200,7 @@ xembed_set_info (ClutterBackendX11 *backend_x11,
|
||||
backend_x11->atom_XEMBED_INFO, 32,
|
||||
PropModeReplace, (unsigned char *) list, 2);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
_clutter_backend_x11_events_init (ClutterBackend *backend)
|
||||
@ -216,6 +209,7 @@ _clutter_backend_x11_events_init (ClutterBackend *backend)
|
||||
GSource *source;
|
||||
ClutterEventSource *event_source;
|
||||
int connection_number;
|
||||
gchar *name;
|
||||
|
||||
connection_number = ConnectionNumber (backend_x11->xdpy);
|
||||
CLUTTER_NOTE (EVENT, "Connection number: %d", connection_number);
|
||||
@ -224,6 +218,11 @@ _clutter_backend_x11_events_init (ClutterBackend *backend)
|
||||
event_source = (ClutterEventSource *) source;
|
||||
g_source_set_priority (source, CLUTTER_PRIORITY_EVENTS);
|
||||
|
||||
name = g_strdup_printf ("Clutter X11 Event (connection: %d)",
|
||||
connection_number);
|
||||
g_source_set_name (source, name);
|
||||
g_free (name);
|
||||
|
||||
event_source->event_poll_fd.fd = connection_number;
|
||||
event_source->event_poll_fd.events = G_IO_IN;
|
||||
|
||||
@ -252,6 +251,7 @@ _clutter_backend_x11_events_uninit (ClutterBackend *backend)
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void
|
||||
update_last_event_time (ClutterBackendX11 *backend_x11,
|
||||
XEvent *xevent)
|
||||
@ -426,51 +426,6 @@ handle_wm_protocols_event (ClutterBackendX11 *backend_x11,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_xembed_event (ClutterBackendX11 *backend_x11,
|
||||
XEvent *xevent)
|
||||
{
|
||||
ClutterActor *stage;
|
||||
|
||||
stage = clutter_stage_get_default ();
|
||||
|
||||
switch (xevent->xclient.data.l[1])
|
||||
{
|
||||
case XEMBED_EMBEDDED_NOTIFY:
|
||||
CLUTTER_NOTE (EVENT, "got XEMBED_EMBEDDED_NOTIFY from %lx",
|
||||
xevent->xclient.data.l[3]);
|
||||
|
||||
ParentEmbedderWin = xevent->xclient.data.l[3];
|
||||
|
||||
clutter_actor_realize (stage);
|
||||
clutter_actor_show (stage);
|
||||
|
||||
xembed_set_info (backend_x11,
|
||||
clutter_x11_get_stage_window (CLUTTER_STAGE (stage)),
|
||||
XEMBED_MAPPED);
|
||||
break;
|
||||
case XEMBED_WINDOW_ACTIVATE:
|
||||
CLUTTER_NOTE (EVENT, "got XEMBED_WINDOW_ACTIVATE");
|
||||
break;
|
||||
case XEMBED_WINDOW_DEACTIVATE:
|
||||
CLUTTER_NOTE (EVENT, "got XEMBED_WINDOW_DEACTIVATE");
|
||||
break;
|
||||
case XEMBED_FOCUS_IN:
|
||||
CLUTTER_NOTE (EVENT, "got XEMBED_FOCUS_IN");
|
||||
if (ParentEmbedderWin)
|
||||
xembed_send_message (backend_x11, ParentEmbedderWin,
|
||||
XEMBED_FOCUS_NEXT,
|
||||
0, 0, 0);
|
||||
break;
|
||||
default:
|
||||
CLUTTER_NOTE (EVENT, "got unknown XEMBED message");
|
||||
break;
|
||||
}
|
||||
|
||||
/* do not propagate the XEMBED events to the stage */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clipped_redraws_cool_off_cb (void *data)
|
||||
{
|
||||
@ -1135,34 +1090,24 @@ event_translate (ClutterBackend *backend,
|
||||
out:
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
events_queue (ClutterBackend *backend)
|
||||
{
|
||||
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
|
||||
ClutterBackendX11Class *backend_x11_class =
|
||||
CLUTTER_BACKEND_X11_GET_CLASS (backend_x11);
|
||||
ClutterEvent *event;
|
||||
Display *xdisplay = backend_x11->xdpy;
|
||||
XEvent xevent;
|
||||
ClutterMainContext *clutter_context;
|
||||
|
||||
clutter_context = _clutter_context_get_default ();
|
||||
Display *xdisplay = backend_x11->xdpy;
|
||||
ClutterEvent *event;
|
||||
XEvent xevent;
|
||||
|
||||
while (!clutter_events_pending () && XPending (xdisplay))
|
||||
{
|
||||
XNextEvent (xdisplay, &xevent);
|
||||
|
||||
if (backend_x11_class->handle_event (backend_x11, &xevent))
|
||||
continue;
|
||||
|
||||
event = clutter_event_new (CLUTTER_NOTHING);
|
||||
|
||||
if (event_translate (backend, event, &xevent))
|
||||
{
|
||||
/* push directly here to avoid copy of queue_put */
|
||||
g_queue_push_head (clutter_context->events_queue, event);
|
||||
}
|
||||
if (_clutter_backend_translate_event (backend, &xevent, event))
|
||||
_clutter_event_push (event, FALSE);
|
||||
else
|
||||
clutter_event_free (event);
|
||||
}
|
||||
@ -1192,12 +1137,12 @@ events_queue (ClutterBackend *backend)
|
||||
ClutterX11FilterReturn
|
||||
clutter_x11_handle_event (XEvent *xevent)
|
||||
{
|
||||
ClutterBackend *backend;
|
||||
ClutterBackendX11Class *backend_x11_class;
|
||||
ClutterEvent *event;
|
||||
ClutterMainContext *clutter_context;
|
||||
ClutterMainContext *clutter_context;
|
||||
ClutterX11FilterReturn result;
|
||||
gint spin = 1;
|
||||
ClutterBackend *backend;
|
||||
ClutterEvent *event;
|
||||
gint spin = 1;
|
||||
|
||||
/* The return values here are someone approximate; we return
|
||||
* CLUTTER_X11_FILTER_REMOVE if a clutter event is
|
||||
@ -1213,22 +1158,16 @@ clutter_x11_handle_event (XEvent *xevent)
|
||||
clutter_threads_enter ();
|
||||
|
||||
clutter_context = _clutter_context_get_default ();
|
||||
backend = clutter_context->backend;
|
||||
backend = clutter_get_default_backend ();
|
||||
backend_x11_class = CLUTTER_BACKEND_X11_GET_CLASS (backend);
|
||||
|
||||
/* If the backend just observed the event and didn't want it
|
||||
* removed it could return FALSE, so assume that a TRUE return
|
||||
* means that our caller should also do no further processing. */
|
||||
if (backend_x11_class->handle_event (CLUTTER_BACKEND_X11(backend), xevent))
|
||||
return CLUTTER_X11_FILTER_REMOVE;
|
||||
|
||||
event = clutter_event_new (CLUTTER_NOTHING);
|
||||
|
||||
if (event_translate (backend, event, xevent))
|
||||
if (_clutter_backend_translate_event (backend, xevent, event))
|
||||
{
|
||||
/* push directly here to avoid copy of queue_put */
|
||||
_clutter_event_push (event, FALSE);
|
||||
|
||||
result = CLUTTER_X11_FILTER_REMOVE;
|
||||
g_queue_push_head (clutter_context->events_queue, event);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1253,7 +1192,7 @@ clutter_x11_handle_event (XEvent *xevent)
|
||||
--spin;
|
||||
}
|
||||
|
||||
out:
|
||||
out:
|
||||
clutter_threads_leave ();
|
||||
|
||||
return result;
|
||||
@ -1312,8 +1251,7 @@ clutter_event_dispatch (GSource *source,
|
||||
|
||||
/* Pop an event off the queue if any */
|
||||
event = clutter_event_get ();
|
||||
|
||||
if (event)
|
||||
if (event != NULL)
|
||||
{
|
||||
/* forward the event into clutter for emission etc. */
|
||||
clutter_do_event (event);
|
||||
|
414
clutter/x11/clutter-input-device-core-x11.c
Normal file
414
clutter/x11/clutter-input-device-core-x11.c
Normal file
@ -0,0 +1,414 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "clutter-input-device-core-x11.h"
|
||||
|
||||
#include "clutter-debug.h"
|
||||
#include "clutter-device-manager-private.h"
|
||||
#include "clutter-private.h"
|
||||
#include "clutter-stage-private.h"
|
||||
|
||||
#include "clutter-backend-x11.h"
|
||||
#include "clutter-stage-x11.h"
|
||||
|
||||
#ifdef HAVE_XINPUT
|
||||
#include <X11/extensions/XInput.h>
|
||||
#endif
|
||||
|
||||
#define MAX_DEVICE_CLASSES 13
|
||||
|
||||
typedef struct _ClutterInputDeviceClass ClutterInputDeviceX11Class;
|
||||
|
||||
/* a specific X11 input device */
|
||||
struct _ClutterInputDeviceX11
|
||||
{
|
||||
ClutterInputDevice device;
|
||||
|
||||
#ifdef HAVE_XINPUT
|
||||
XDevice *xdevice;
|
||||
|
||||
XEventClass event_classes[MAX_DEVICE_CLASSES];
|
||||
int num_classes;
|
||||
|
||||
int button_press_type;
|
||||
int button_release_type;
|
||||
int motion_notify_type;
|
||||
int state_notify_type;
|
||||
int key_press_type;
|
||||
int key_release_type;
|
||||
#endif /* HAVE_XINPUT */
|
||||
|
||||
gint *axis_data;
|
||||
};
|
||||
|
||||
#define clutter_input_device_x11_get_type _clutter_input_device_x11_get_type
|
||||
|
||||
G_DEFINE_TYPE (ClutterInputDeviceX11,
|
||||
clutter_input_device_x11,
|
||||
CLUTTER_TYPE_INPUT_DEVICE);
|
||||
|
||||
static void
|
||||
clutter_input_device_x11_select_stage_events (ClutterInputDevice *device,
|
||||
ClutterStage *stage,
|
||||
gint event_mask)
|
||||
{
|
||||
#if HAVE_XINPUT
|
||||
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (device->backend);
|
||||
ClutterInputDeviceX11 *device_x11;
|
||||
ClutterStageX11 *stage_x11;
|
||||
XEventClass class;
|
||||
gint i;
|
||||
|
||||
device_x11 = CLUTTER_INPUT_DEVICE_X11 (device);
|
||||
|
||||
stage_x11 = CLUTTER_STAGE_X11 (_clutter_stage_get_window (stage));
|
||||
|
||||
i = 0;
|
||||
|
||||
if (event_mask & ButtonPressMask)
|
||||
{
|
||||
DeviceButtonPress (device_x11->xdevice,
|
||||
device_x11->button_press_type,
|
||||
class);
|
||||
if (class != 0)
|
||||
device_x11->event_classes[i++] = class;
|
||||
|
||||
DeviceButtonPressGrab (device_x11->xdevice, 0, class);
|
||||
if (class != 0)
|
||||
device_x11->event_classes[i++] = class;
|
||||
}
|
||||
|
||||
if (event_mask & ButtonReleaseMask)
|
||||
{
|
||||
DeviceButtonRelease (device_x11->xdevice,
|
||||
device_x11->button_release_type,
|
||||
class);
|
||||
if (class != 0)
|
||||
device_x11->event_classes[i++] = class;
|
||||
}
|
||||
|
||||
if (event_mask & PointerMotionMask)
|
||||
{
|
||||
DeviceMotionNotify (device_x11->xdevice,
|
||||
device_x11->motion_notify_type,
|
||||
class);
|
||||
if (class != 0)
|
||||
device_x11->event_classes[i++] = class;
|
||||
|
||||
DeviceStateNotify (device_x11->xdevice,
|
||||
device_x11->state_notify_type,
|
||||
class);
|
||||
if (class != 0)
|
||||
device_x11->event_classes[i++] = class;
|
||||
}
|
||||
|
||||
if (event_mask & KeyPressMask)
|
||||
{
|
||||
DeviceKeyPress (device_x11->xdevice,
|
||||
device_x11->key_press_type,
|
||||
class);
|
||||
if (class != 0)
|
||||
device_x11->event_classes[i++] = class;
|
||||
}
|
||||
|
||||
if (event_mask & KeyReleaseMask)
|
||||
{
|
||||
DeviceKeyRelease (device_x11->xdevice,
|
||||
device_x11->key_release_type,
|
||||
class);
|
||||
if (class != 0)
|
||||
device_x11->event_classes[i++] = class;
|
||||
}
|
||||
|
||||
device_x11->num_classes = i;
|
||||
|
||||
XSelectExtensionEvent (backend_x11->xdpy,
|
||||
stage_x11->xwin,
|
||||
device_x11->event_classes,
|
||||
device_x11->num_classes);
|
||||
#endif /* HAVE_XINPUT */
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_input_device_x11_dispose (GObject *gobject)
|
||||
{
|
||||
ClutterInputDeviceX11 *device_x11 = CLUTTER_INPUT_DEVICE_X11 (gobject);
|
||||
|
||||
#ifdef HAVE_XINPUT
|
||||
if (device_x11->xdevice)
|
||||
{
|
||||
ClutterInputDevice *device = CLUTTER_INPUT_DEVICE (gobject);
|
||||
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (device->backend);
|
||||
|
||||
XCloseDevice (backend_x11->xdpy, device_x11->xdevice);
|
||||
device_x11->xdevice = NULL;
|
||||
}
|
||||
#endif /* HAVE_XINPUT */
|
||||
|
||||
g_free (device_x11->axis_data);
|
||||
|
||||
G_OBJECT_CLASS (clutter_input_device_x11_parent_class)->dispose (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_input_device_x11_constructed (GObject *gobject)
|
||||
{
|
||||
#ifdef HAVE_XINPUT
|
||||
ClutterInputDeviceX11 *device_x11 = CLUTTER_INPUT_DEVICE_X11 (gobject);
|
||||
ClutterInputDevice *device = CLUTTER_INPUT_DEVICE (gobject);
|
||||
ClutterBackendX11 *backend_x11;
|
||||
|
||||
backend_x11 = CLUTTER_BACKEND_X11 (device->backend);
|
||||
|
||||
clutter_x11_trap_x_errors ();
|
||||
|
||||
device_x11->xdevice = XOpenDevice (backend_x11->xdpy, device->id);
|
||||
|
||||
if (clutter_x11_untrap_x_errors ())
|
||||
{
|
||||
g_warning ("Device '%s' cannot be opened",
|
||||
clutter_input_device_get_device_name (device));
|
||||
}
|
||||
#endif /* HAVE_XINPUT */
|
||||
|
||||
if (G_OBJECT_CLASS (clutter_input_device_x11_parent_class)->constructed)
|
||||
G_OBJECT_CLASS (clutter_input_device_x11_parent_class)->constructed (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_input_device_x11_class_init (ClutterInputDeviceX11Class *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
gobject_class->constructed = clutter_input_device_x11_constructed;
|
||||
gobject_class->dispose = clutter_input_device_x11_dispose;
|
||||
|
||||
g_signal_override_class_handler ("select-stage-events",
|
||||
CLUTTER_TYPE_INPUT_DEVICE_X11,
|
||||
G_CALLBACK (clutter_input_device_x11_select_stage_events));
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_input_device_x11_init (ClutterInputDeviceX11 *self)
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef HAVE_XINPUT
|
||||
static void
|
||||
update_axes (ClutterInputDeviceX11 *device_x11,
|
||||
guint n_axes,
|
||||
gint first_axis,
|
||||
gint *axes_data)
|
||||
{
|
||||
ClutterInputDevice *device = CLUTTER_INPUT_DEVICE (device_x11);
|
||||
gint i;
|
||||
|
||||
if (device_x11->axis_data == NULL)
|
||||
{
|
||||
device_x11->axis_data =
|
||||
g_new0 (gint, clutter_input_device_get_n_axes (device));
|
||||
}
|
||||
|
||||
for (i = 0; i < n_axes; i++)
|
||||
device_x11->axis_data[first_axis + i] = axes_data[i];
|
||||
}
|
||||
|
||||
static void
|
||||
translate_axes (ClutterInputDeviceX11 *device_x11,
|
||||
ClutterStageX11 *stage_x11,
|
||||
gdouble *event_axes,
|
||||
gfloat *event_x,
|
||||
gfloat *event_y)
|
||||
{
|
||||
ClutterInputDevice *device = CLUTTER_INPUT_DEVICE (device_x11);
|
||||
gint root_x, root_y;
|
||||
gint n_axes, i;
|
||||
gfloat x, y;
|
||||
|
||||
if (!_clutter_stage_x11_get_root_coords (stage_x11, &root_x, &root_y))
|
||||
return;
|
||||
|
||||
x = y = 0.0f;
|
||||
n_axes = clutter_input_device_get_n_axes (device);
|
||||
|
||||
for (i = 0; i < n_axes; i++)
|
||||
{
|
||||
ClutterInputAxis axis;
|
||||
|
||||
axis = _clutter_input_device_get_axis (device, i);
|
||||
|
||||
switch (axis)
|
||||
{
|
||||
case CLUTTER_INPUT_AXIS_X:
|
||||
case CLUTTER_INPUT_AXIS_Y:
|
||||
_clutter_x11_input_device_translate_screen_coord (device,
|
||||
root_x, root_y,
|
||||
i,
|
||||
device_x11->axis_data[i],
|
||||
&event_axes[i]);
|
||||
if (axis == CLUTTER_INPUT_AXIS_X)
|
||||
x = event_axes[i];
|
||||
else if (axis == CLUTTER_INPUT_AXIS_Y)
|
||||
y = event_axes[i];
|
||||
break;
|
||||
|
||||
default:
|
||||
_clutter_input_device_translate_axis (device, i,
|
||||
device_x11->axis_data[i],
|
||||
&event_axes[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (event_x)
|
||||
*event_x = x;
|
||||
|
||||
if (event_y)
|
||||
*event_y = y;
|
||||
}
|
||||
|
||||
/*
|
||||
* translate_state:
|
||||
* @state: the keyboard state of the core device
|
||||
* @device_state: the button state of the device
|
||||
*
|
||||
* Trivially translates the state and the device state into a
|
||||
* single bitmask.
|
||||
*/
|
||||
static guint
|
||||
translate_state (guint state,
|
||||
guint device_state)
|
||||
{
|
||||
return device_state | (state & 0xff);
|
||||
}
|
||||
#endif /* HAVE_XINPUT */
|
||||
|
||||
gboolean
|
||||
_clutter_input_device_x11_translate_xi_event (ClutterInputDeviceX11 *device_x11,
|
||||
ClutterStageX11 *stage_x11,
|
||||
XEvent *xevent,
|
||||
ClutterEvent *event)
|
||||
{
|
||||
#ifdef HAVE_XINPUT
|
||||
ClutterInputDevice *device = CLUTTER_INPUT_DEVICE (device_x11);
|
||||
|
||||
if ((xevent->type == device_x11->button_press_type) ||
|
||||
(xevent->type == device_x11->button_release_type))
|
||||
{
|
||||
XDeviceButtonEvent *xdbe = (XDeviceButtonEvent *) xevent;
|
||||
|
||||
event->button.type = event->type =
|
||||
(xdbe->type == device_x11->button_press_type) ? CLUTTER_BUTTON_PRESS
|
||||
: CLUTTER_BUTTON_RELEASE;
|
||||
event->button.device = device;
|
||||
event->button.time = xdbe->time;
|
||||
event->button.button = xdbe->button;
|
||||
event->button.modifier_state =
|
||||
translate_state (xdbe->state, xdbe->device_state);
|
||||
|
||||
event->button.axes =
|
||||
g_new0 (gdouble, clutter_input_device_get_n_axes (device));
|
||||
|
||||
update_axes (device_x11,
|
||||
xdbe->axes_count,
|
||||
xdbe->first_axis,
|
||||
xdbe->axis_data);
|
||||
translate_axes (device_x11, stage_x11,
|
||||
event->button.axes,
|
||||
&event->button.x,
|
||||
&event->button.y);
|
||||
|
||||
_clutter_stage_x11_set_user_time (stage_x11, event->button.time);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if ((xevent->type == device_x11->key_press_type) ||
|
||||
(xevent->type == device_x11->key_release_type))
|
||||
{
|
||||
XDeviceKeyEvent *xdke = (XDeviceKeyEvent *) xevent;
|
||||
|
||||
if (xdke->keycode < device->min_keycode ||
|
||||
xdke->keycode >= device->max_keycode)
|
||||
{
|
||||
g_warning ("Invalid device key code received: %d", xdke->keycode);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
clutter_input_device_get_key (device,
|
||||
xdke->keycode - device->min_keycode,
|
||||
&event->key.keyval,
|
||||
&event->key.modifier_state);
|
||||
if (event->key.keyval == 0)
|
||||
return FALSE;
|
||||
|
||||
event->key.type = event->type =
|
||||
(xdke->type == device_x11->key_press_type) ? CLUTTER_KEY_PRESS
|
||||
: CLUTTER_KEY_RELEASE;
|
||||
event->key.time = xdke->time;
|
||||
event->key.modifier_state |=
|
||||
translate_state (xdke->state, xdke->device_state);
|
||||
event->key.device = device;
|
||||
|
||||
#if 0
|
||||
if ((event->key.keyval >= 0x20) && (event->key.keyval <= 0xff))
|
||||
{
|
||||
event->key.unicode = (gunichar) event->key.keyval;
|
||||
}
|
||||
#endif
|
||||
|
||||
_clutter_stage_x11_set_user_time (stage_x11, event->key.time);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (xevent->type == device_x11->motion_notify_type)
|
||||
{
|
||||
XDeviceMotionEvent *xdme = (XDeviceMotionEvent *) xevent;
|
||||
|
||||
event->motion.type = event->type = CLUTTER_MOTION;
|
||||
event->motion.time = xdme->time;
|
||||
event->motion.modifier_state =
|
||||
translate_state (xdme->state, xdme->device_state);
|
||||
event->motion.device = device;
|
||||
|
||||
event->motion.axes =
|
||||
g_new0 (gdouble, clutter_input_device_get_n_axes (device));
|
||||
|
||||
update_axes (device_x11,
|
||||
xdme->axes_count,
|
||||
xdme->first_axis,
|
||||
xdme->axis_data);
|
||||
translate_axes (device_x11, stage_x11,
|
||||
event->motion.axes,
|
||||
&event->motion.x,
|
||||
&event->motion.y);
|
||||
|
||||
_clutter_stage_x11_set_user_time (stage_x11, event->motion.time);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (xevent->type == device_x11->state_notify_type)
|
||||
{
|
||||
XDeviceStateNotifyEvent *xdse = (XDeviceStateNotifyEvent *) xevent;
|
||||
XInputClass *input_class = (XInputClass *) xdse->data;
|
||||
gint n_axes = clutter_input_device_get_n_axes (device);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < xdse->num_classes; i++)
|
||||
{
|
||||
if (input_class->class == ValuatorClass)
|
||||
{
|
||||
int *axis_data = ((XValuatorState *) input_class)->valuators;
|
||||
|
||||
update_axes (device_x11, n_axes, 0, axis_data);
|
||||
}
|
||||
|
||||
input_class =
|
||||
(XInputClass *)(((char *) input_class) + input_class->length);
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_XINPUT */
|
||||
|
||||
return FALSE;
|
||||
}
|
26
clutter/x11/clutter-input-device-core-x11.h
Normal file
26
clutter/x11/clutter-input-device-core-x11.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef __CLUTTER_INPUT_DEVICE_X11_H__
|
||||
#define __CLUTTER_INPUT_DEVICE_X11_H__
|
||||
|
||||
#include <clutter/clutter-input-device.h>
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
#include "clutter-stage-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;
|
||||
|
||||
gboolean _clutter_input_device_x11_translate_xi_event (ClutterInputDeviceX11 *device_x11,
|
||||
ClutterStageX11 *stage_x11,
|
||||
XEvent *xevent,
|
||||
ClutterEvent *event);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __CLUTTER_INPUT_DEVICE_X11_H__ */
|
@ -1,228 +0,0 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "clutter-input-device-x11.h"
|
||||
|
||||
#include "clutter-debug.h"
|
||||
#include "clutter-device-manager-private.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,
|
||||
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
static GParamSpec *obj_props[PROP_LAST];
|
||||
|
||||
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);
|
||||
obj_props[PROP_IS_CORE] = pspec;
|
||||
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 */
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
#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__ */
|
161
clutter/x11/clutter-input-device-xi2.c
Normal file
161
clutter/x11/clutter-input-device-xi2.c
Normal file
@ -0,0 +1,161 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "clutter-input-device-xi2.h"
|
||||
|
||||
#include "clutter-debug.h"
|
||||
#include "clutter-device-manager-private.h"
|
||||
#include "clutter-private.h"
|
||||
#include "clutter-stage-private.h"
|
||||
|
||||
#include "clutter-backend-x11.h"
|
||||
#include "clutter-stage-x11.h"
|
||||
|
||||
#include <X11/extensions/XInput2.h>
|
||||
|
||||
typedef struct _ClutterInputDeviceClass ClutterInputDeviceXI2Class;
|
||||
|
||||
/* a specific XI2 input device */
|
||||
struct _ClutterInputDeviceXI2
|
||||
{
|
||||
ClutterInputDevice device;
|
||||
|
||||
gint device_id;
|
||||
};
|
||||
|
||||
#define N_BUTTONS 5
|
||||
|
||||
#define clutter_input_device_xi2_get_type _clutter_input_device_xi2_get_type
|
||||
|
||||
G_DEFINE_TYPE (ClutterInputDeviceXI2,
|
||||
clutter_input_device_xi2,
|
||||
CLUTTER_TYPE_INPUT_DEVICE);
|
||||
|
||||
static void
|
||||
clutter_input_device_xi2_select_stage_events (ClutterInputDevice *device,
|
||||
ClutterStage *stage,
|
||||
gint event_mask)
|
||||
{
|
||||
ClutterInputDeviceXI2 *device_xi2 = CLUTTER_INPUT_DEVICE_XI2 (device);
|
||||
ClutterBackendX11 *backend_x11;
|
||||
ClutterStageX11 *stage_x11;
|
||||
XIEventMask xi_event_mask;
|
||||
unsigned char *mask;
|
||||
int len;
|
||||
|
||||
backend_x11 = CLUTTER_BACKEND_X11 (device->backend);
|
||||
stage_x11 = CLUTTER_STAGE_X11 (_clutter_stage_get_window (stage));
|
||||
|
||||
len = XIMaskLen (XI_LASTEVENT);
|
||||
mask = g_new0 (unsigned char, len);
|
||||
|
||||
if (event_mask & PointerMotionMask)
|
||||
XISetMask (mask, XI_Motion);
|
||||
|
||||
if (event_mask & ButtonPressMask)
|
||||
XISetMask (mask, XI_ButtonPress);
|
||||
|
||||
if (event_mask & ButtonReleaseMask)
|
||||
XISetMask (mask, XI_ButtonRelease);
|
||||
|
||||
if (event_mask & KeyPressMask)
|
||||
XISetMask (mask, XI_KeyPress);
|
||||
|
||||
if (event_mask & KeyReleaseMask)
|
||||
XISetMask (mask, XI_KeyRelease);
|
||||
|
||||
if (event_mask & EnterWindowMask)
|
||||
XISetMask (mask, XI_Enter);
|
||||
|
||||
if (event_mask & LeaveWindowMask)
|
||||
XISetMask (mask, XI_Leave);
|
||||
|
||||
xi_event_mask.deviceid = device_xi2->device_id;
|
||||
xi_event_mask.mask = mask;
|
||||
xi_event_mask.mask_len = len;
|
||||
|
||||
CLUTTER_NOTE (BACKEND, "Selecting device id '%d' events",
|
||||
device_xi2->device_id);
|
||||
|
||||
XISelectEvents (backend_x11->xdpy, stage_x11->xwin, &xi_event_mask, 1);
|
||||
|
||||
g_free (mask);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_input_device_xi2_constructed (GObject *gobject)
|
||||
{
|
||||
ClutterInputDeviceXI2 *device_xi2 = CLUTTER_INPUT_DEVICE_XI2 (gobject);
|
||||
|
||||
g_object_get (gobject, "id", &device_xi2->device_id, NULL);
|
||||
|
||||
if (G_OBJECT_CLASS (clutter_input_device_xi2_parent_class)->constructed)
|
||||
G_OBJECT_CLASS (clutter_input_device_xi2_parent_class)->constructed (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_input_device_xi2_class_init (ClutterInputDeviceXI2Class *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
gobject_class->constructed = clutter_input_device_xi2_constructed;
|
||||
|
||||
g_signal_override_class_handler ("select-stage-events",
|
||||
CLUTTER_TYPE_INPUT_DEVICE_XI2,
|
||||
G_CALLBACK (clutter_input_device_xi2_select_stage_events));
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_input_device_xi2_init (ClutterInputDeviceXI2 *self)
|
||||
{
|
||||
}
|
||||
|
||||
guint
|
||||
_clutter_input_device_xi2_translate_state (XIModifierState *modifiers_state,
|
||||
XIButtonState *buttons_state)
|
||||
{
|
||||
guint retval = 0;
|
||||
|
||||
if (modifiers_state)
|
||||
retval = (guint) modifiers_state->effective;
|
||||
|
||||
if (buttons_state)
|
||||
{
|
||||
int len, i;
|
||||
|
||||
len = MIN (N_BUTTONS, buttons_state->mask_len * 8);
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
if (!XIMaskIsSet (buttons_state->mask, i))
|
||||
continue;
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case 1:
|
||||
retval |= CLUTTER_BUTTON1_MASK;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
retval |= CLUTTER_BUTTON2_MASK;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
retval |= CLUTTER_BUTTON3_MASK;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
retval |= CLUTTER_BUTTON4_MASK;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
retval |= CLUTTER_BUTTON5_MASK;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
22
clutter/x11/clutter-input-device-xi2.h
Normal file
22
clutter/x11/clutter-input-device-xi2.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef __CLUTTER_INPUT_DEVICE_XI2_H__
|
||||
#define __CLUTTER_INPUT_DEVICE_XI2_H__
|
||||
|
||||
#include <clutter/clutter-input-device.h>
|
||||
#include <X11/extensions/XInput2.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define CLUTTER_TYPE_INPUT_DEVICE_XI2 (_clutter_input_device_xi2_get_type ())
|
||||
#define CLUTTER_INPUT_DEVICE_XI2(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_INPUT_DEVICE_XI2, ClutterInputDeviceXI2))
|
||||
#define CLUTTER_IS_INPUT_DEVICE_XI2(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_INPUT_DEVICE_XI2))
|
||||
|
||||
typedef struct _ClutterInputDeviceXI2 ClutterInputDeviceXI2;
|
||||
|
||||
GType _clutter_input_device_xi2_get_type (void) G_GNUC_CONST;
|
||||
|
||||
guint _clutter_input_device_xi2_translate_state (XIModifierState *modifiers_state,
|
||||
XIButtonState *buttons_state);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __CLUTTER_INPUT_DEVICE_XI2_H__ */
|
@ -23,6 +23,8 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
@ -33,10 +35,13 @@
|
||||
|
||||
#include "clutter-actor-private.h"
|
||||
#include "clutter-debug.h"
|
||||
#include "clutter-main.h"
|
||||
#include "clutter-feature.h"
|
||||
#include "clutter-event.h"
|
||||
#include "clutter-device-manager-private.h"
|
||||
#include "clutter-enum-types.h"
|
||||
#include "clutter-event-translator.h"
|
||||
#include "clutter-event.h"
|
||||
#include "clutter-feature.h"
|
||||
#include "clutter-main.h"
|
||||
#include "clutter-paint-volume-private.h"
|
||||
#include "clutter-private.h"
|
||||
#include "clutter-stage-private.h"
|
||||
|
||||
@ -48,13 +53,16 @@
|
||||
|
||||
#define STAGE_X11_IS_MAPPED(s) ((((ClutterStageX11 *) (s))->wm_state & STAGE_X11_WITHDRAWN) == 0)
|
||||
|
||||
static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface);
|
||||
static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface);
|
||||
static void clutter_event_translator_iface_init (ClutterEventTranslatorIface *iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (ClutterStageX11,
|
||||
clutter_stage_x11,
|
||||
G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW,
|
||||
clutter_stage_window_iface_init));
|
||||
clutter_stage_window_iface_init)
|
||||
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_EVENT_TRANSLATOR,
|
||||
clutter_event_translator_iface_init));
|
||||
|
||||
#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */
|
||||
#define _NET_WM_STATE_ADD 1 /* add/set property */
|
||||
@ -393,11 +401,69 @@ static gboolean
|
||||
clutter_stage_x11_realize (ClutterStageWindow *stage_window)
|
||||
{
|
||||
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
|
||||
ClutterDeviceManager *device_manager;
|
||||
ClutterBackendX11 *backend_x11;
|
||||
int event_flags;
|
||||
|
||||
set_wm_pid (stage_x11);
|
||||
set_wm_title (stage_x11);
|
||||
set_cursor_visible (stage_x11);
|
||||
|
||||
backend_x11 = CLUTTER_BACKEND_X11 (clutter_get_default_backend ());
|
||||
|
||||
/* the masks for the events we want to select on a stage window;
|
||||
* KeyPressMask and KeyReleaseMask are necessary even with XI1
|
||||
* because key events are broken with that extension, and will
|
||||
* be fixed by XI2
|
||||
*/
|
||||
event_flags = StructureNotifyMask
|
||||
| FocusChangeMask
|
||||
| ExposureMask
|
||||
| PropertyChangeMask
|
||||
| EnterWindowMask
|
||||
| LeaveWindowMask
|
||||
| KeyPressMask
|
||||
| KeyReleaseMask
|
||||
| ButtonPressMask
|
||||
| ButtonReleaseMask
|
||||
| PointerMotionMask;
|
||||
|
||||
/* we unconditionally select input events even with event retrieval
|
||||
* disabled because we need to guarantee that the Clutter internal
|
||||
* state is maintained when calling clutter_x11_handle_event() without
|
||||
* requiring applications or embedding toolkits to select events
|
||||
* themselves. if we did that, we'd have to document the events to be
|
||||
* selected, and also update applications and embedding toolkits each
|
||||
* time we added a new mask, or a new class of events.
|
||||
*
|
||||
* see: http://bugzilla.clutter-project.org/show_bug.cgi?id=998
|
||||
* for the rationale of why we did conditional selection. it is now
|
||||
* clear that a compositor should clear out the input region, since
|
||||
* it cannot assume a perfectly clean slate coming from us.
|
||||
*
|
||||
* see: http://bugzilla.clutter-project.org/show_bug.cgi?id=2228
|
||||
* for an example of things that break if we do conditional event
|
||||
* selection.
|
||||
*/
|
||||
XSelectInput (backend_x11->xdpy, stage_x11->xwin, event_flags);
|
||||
|
||||
/* input events also depent on the actual device, so we need to
|
||||
* use the device manager to let every device select them, using
|
||||
* the event mask we passed to XSelectInput as the template
|
||||
*/
|
||||
device_manager = clutter_device_manager_get_default ();
|
||||
_clutter_device_manager_select_stage_events (device_manager,
|
||||
stage_x11->wrapper,
|
||||
event_flags);
|
||||
|
||||
/* no user resize.. */
|
||||
clutter_stage_x11_fix_window_size (stage_x11,
|
||||
stage_x11->xwin_width,
|
||||
stage_x11->xwin_height);
|
||||
clutter_stage_x11_set_wm_protocols (stage_x11);
|
||||
|
||||
CLUTTER_NOTE (BACKEND, "Successfully realized stage");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -677,6 +743,12 @@ clutter_stage_x11_finalize (GObject *gobject)
|
||||
static void
|
||||
clutter_stage_x11_dispose (GObject *gobject)
|
||||
{
|
||||
ClutterEventTranslator *translator = CLUTTER_EVENT_TRANSLATOR (gobject);
|
||||
ClutterBackendX11 *backend_x11;
|
||||
|
||||
backend_x11 = CLUTTER_BACKEND_X11 (clutter_get_default_backend ());
|
||||
_clutter_backend_x11_remove_event_translator (backend_x11, translator);
|
||||
|
||||
G_OBJECT_CLASS (clutter_stage_x11_parent_class)->dispose (gobject);
|
||||
}
|
||||
|
||||
@ -724,6 +796,343 @@ clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
|
||||
iface->realize = clutter_stage_x11_realize;
|
||||
}
|
||||
|
||||
static inline void
|
||||
set_user_time (ClutterBackendX11 *backend_x11,
|
||||
ClutterStageX11 *stage_x11,
|
||||
long timestamp)
|
||||
{
|
||||
if (timestamp != CLUTTER_CURRENT_TIME)
|
||||
{
|
||||
XChangeProperty (backend_x11->xdpy,
|
||||
stage_x11->xwin,
|
||||
backend_x11->atom_NET_WM_USER_TIME,
|
||||
XA_CARDINAL, 32,
|
||||
PropModeReplace,
|
||||
(unsigned char *) ×tamp, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_wm_protocols_event (ClutterBackendX11 *backend_x11,
|
||||
ClutterStageX11 *stage_x11,
|
||||
XEvent *xevent)
|
||||
{
|
||||
Atom atom = (Atom) xevent->xclient.data.l[0];
|
||||
|
||||
if (atom == backend_x11->atom_WM_DELETE_WINDOW &&
|
||||
xevent->xany.window == stage_x11->xwin)
|
||||
{
|
||||
/* the WM_DELETE_WINDOW is a request: we do not destroy
|
||||
* the window right away, as it might contain vital data;
|
||||
* we relay the event to the application and we let it
|
||||
* handle the request
|
||||
*/
|
||||
CLUTTER_NOTE (EVENT, "Delete stage %s[%p], win:0x%x",
|
||||
_clutter_actor_get_debug_name (CLUTTER_ACTOR (stage_x11->wrapper)),
|
||||
stage_x11->wrapper,
|
||||
(unsigned int) stage_x11->xwin);
|
||||
|
||||
set_user_time (backend_x11, stage_x11, xevent->xclient.data.l[1]);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else if (atom == backend_x11->atom_NET_WM_PING &&
|
||||
xevent->xany.window == stage_x11->xwin)
|
||||
{
|
||||
XClientMessageEvent xclient = xevent->xclient;
|
||||
|
||||
xclient.window = backend_x11->xwin_root;
|
||||
XSendEvent (backend_x11->xdpy, xclient.window,
|
||||
False,
|
||||
SubstructureRedirectMask | SubstructureNotifyMask,
|
||||
(XEvent *) &xclient);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* do not send any of the WM_PROTOCOLS events to the queue */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clipped_redraws_cool_off_cb (void *data)
|
||||
{
|
||||
ClutterStageX11 *stage_x11 = data;
|
||||
|
||||
stage_x11->clipped_redraws_cool_off = 0;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static ClutterTranslateReturn
|
||||
clutter_stage_x11_translate_event (ClutterEventTranslator *translator,
|
||||
gpointer native,
|
||||
ClutterEvent *event)
|
||||
{
|
||||
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (translator);
|
||||
ClutterTranslateReturn res = CLUTTER_TRANSLATE_CONTINUE;
|
||||
XEvent *xevent = native;
|
||||
ClutterBackendX11 *backend_x11;
|
||||
ClutterStage *stage;
|
||||
Window stage_xwindow = stage_x11->xwin;
|
||||
|
||||
stage = clutter_x11_get_stage_from_window (xevent->xany.window);
|
||||
if (stage == NULL)
|
||||
return CLUTTER_TRANSLATE_CONTINUE;
|
||||
|
||||
backend_x11 = CLUTTER_BACKEND_X11 (clutter_get_default_backend ());
|
||||
|
||||
switch (xevent->type)
|
||||
{
|
||||
case ConfigureNotify:
|
||||
if (!stage_x11->is_foreign_xwin)
|
||||
{
|
||||
CLUTTER_NOTE (BACKEND, "%s: ConfigureNotify[%x] (%d, %d)",
|
||||
G_STRLOC,
|
||||
(unsigned int) stage_x11->xwin,
|
||||
xevent->xconfigure.width,
|
||||
xevent->xconfigure.height);
|
||||
|
||||
/* Queue a relayout - we want glViewport to be called
|
||||
* with the correct values, and this is done in ClutterStage
|
||||
* via _cogl_onscreen_clutter_backend_set_size ().
|
||||
*
|
||||
* We queue a relayout, because if this ConfigureNotify is
|
||||
* in response to a size we set in the application, the
|
||||
* set_size() call below is essentially a null-op.
|
||||
*
|
||||
* Make sure we do this only when the size has changed,
|
||||
* otherwise we end up relayouting on window moves.
|
||||
*/
|
||||
if ((stage_x11->state & CLUTTER_STAGE_STATE_FULLSCREEN) ||
|
||||
(stage_x11->xwin_width != xevent->xconfigure.width) ||
|
||||
(stage_x11->xwin_height != xevent->xconfigure.height))
|
||||
{
|
||||
clutter_actor_queue_relayout (CLUTTER_ACTOR (stage));
|
||||
}
|
||||
|
||||
/* If we're fullscreened, we want these variables to
|
||||
* represent the size of the window before it was set
|
||||
* to fullscreen.
|
||||
*/
|
||||
if (!(stage_x11->state & CLUTTER_STAGE_STATE_FULLSCREEN))
|
||||
{
|
||||
stage_x11->xwin_width = xevent->xconfigure.width;
|
||||
stage_x11->xwin_height = xevent->xconfigure.height;
|
||||
}
|
||||
|
||||
clutter_actor_set_size (CLUTTER_ACTOR (stage),
|
||||
xevent->xconfigure.width,
|
||||
xevent->xconfigure.height);
|
||||
|
||||
/* XXX: This is a workaround for a race condition when
|
||||
* resizing windows while there are in-flight
|
||||
* glXCopySubBuffer blits happening.
|
||||
*
|
||||
* The problem stems from the fact that rectangles for the
|
||||
* blits are described relative to the bottom left of the
|
||||
* window and because we can't guarantee control over the X
|
||||
* window gravity used when resizing so the gravity is
|
||||
* typically NorthWest not SouthWest.
|
||||
*
|
||||
* This means if you grow a window vertically the server
|
||||
* will make sure to place the old contents of the window
|
||||
* at the top-left/north-west of your new larger window, but
|
||||
* that may happen asynchronous to GLX preparing to do a
|
||||
* blit specified relative to the bottom-left/south-west of
|
||||
* the window (based on the old smaller window geometry).
|
||||
*
|
||||
* When the GLX issued blit finally happens relative to the
|
||||
* new bottom of your window, the destination will have
|
||||
* shifted relative to the top-left where all the pixels you
|
||||
* care about are so it will result in a nasty artefact
|
||||
* making resizing look very ugly!
|
||||
*
|
||||
* We can't currently fix this completely, in-part because
|
||||
* the window manager tends to trample any gravity we might
|
||||
* set. This workaround instead simply disables blits for a
|
||||
* while if we are notified of any resizes happening so if
|
||||
* the user is resizing a window via the window manager then
|
||||
* they may see an artefact for one frame but then we will
|
||||
* fallback to redrawing the full stage until the cooling
|
||||
* off period is over.
|
||||
*/
|
||||
if (stage_x11->clipped_redraws_cool_off)
|
||||
g_source_remove (stage_x11->clipped_redraws_cool_off);
|
||||
|
||||
stage_x11->clipped_redraws_cool_off =
|
||||
g_timeout_add_seconds (1, clipped_redraws_cool_off_cb, stage_x11);
|
||||
|
||||
CLUTTER_UNSET_PRIVATE_FLAGS (stage_x11->wrapper, CLUTTER_IN_RESIZE);
|
||||
|
||||
/* the resize process is complete, so we can ask the stage
|
||||
* to set up the GL viewport with the new size
|
||||
*/
|
||||
clutter_stage_ensure_viewport (stage);
|
||||
}
|
||||
break;
|
||||
|
||||
case PropertyNotify:
|
||||
if (xevent->xproperty.atom == backend_x11->atom_NET_WM_STATE &&
|
||||
xevent->xproperty.window == stage_xwindow &&
|
||||
!stage_x11->is_foreign_xwin)
|
||||
{
|
||||
Atom type;
|
||||
gint format;
|
||||
gulong n_items, bytes_after;
|
||||
guchar *data = NULL;
|
||||
gboolean fullscreen_set = FALSE;
|
||||
|
||||
clutter_x11_trap_x_errors ();
|
||||
XGetWindowProperty (backend_x11->xdpy, stage_xwindow,
|
||||
backend_x11->atom_NET_WM_STATE,
|
||||
0, G_MAXLONG,
|
||||
False, XA_ATOM,
|
||||
&type, &format, &n_items,
|
||||
&bytes_after, &data);
|
||||
clutter_x11_untrap_x_errors ();
|
||||
|
||||
if (type != None && data != NULL)
|
||||
{
|
||||
Atom *atoms = (Atom *) data;
|
||||
gulong i;
|
||||
gboolean is_fullscreen = FALSE;
|
||||
|
||||
for (i = 0; i < n_items; i++)
|
||||
{
|
||||
if (atoms[i] == backend_x11->atom_NET_WM_STATE_FULLSCREEN)
|
||||
fullscreen_set = TRUE;
|
||||
}
|
||||
|
||||
is_fullscreen =
|
||||
(stage_x11->state & CLUTTER_STAGE_STATE_FULLSCREEN);
|
||||
|
||||
if (fullscreen_set != is_fullscreen)
|
||||
{
|
||||
if (fullscreen_set)
|
||||
stage_x11->state |= CLUTTER_STAGE_STATE_FULLSCREEN;
|
||||
else
|
||||
stage_x11->state &= ~CLUTTER_STAGE_STATE_FULLSCREEN;
|
||||
|
||||
stage_x11->fullscreening = fullscreen_set;
|
||||
|
||||
event->any.type = CLUTTER_STAGE_STATE;
|
||||
event->any.source = CLUTTER_ACTOR (stage);
|
||||
event->any.stage = stage;
|
||||
event->stage_state.changed_mask =
|
||||
CLUTTER_STAGE_STATE_FULLSCREEN;
|
||||
event->stage_state.new_state = stage_x11->state;
|
||||
|
||||
res = CLUTTER_TRANSLATE_QUEUE;
|
||||
}
|
||||
|
||||
XFree (data);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case FocusIn:
|
||||
if (!(stage_x11->state & CLUTTER_STAGE_STATE_ACTIVATED))
|
||||
{
|
||||
/* TODO: check the detail? */
|
||||
stage_x11->state |= CLUTTER_STAGE_STATE_ACTIVATED;
|
||||
|
||||
event->type = CLUTTER_STAGE_STATE;
|
||||
event->any.source = CLUTTER_ACTOR (stage);
|
||||
event->any.stage = stage;
|
||||
event->stage_state.changed_mask = CLUTTER_STAGE_STATE_ACTIVATED;
|
||||
event->stage_state.new_state = stage_x11->state;
|
||||
|
||||
res = CLUTTER_TRANSLATE_QUEUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case FocusOut:
|
||||
if (stage_x11->state & CLUTTER_STAGE_STATE_ACTIVATED)
|
||||
{
|
||||
/* TODO: check the detail? */
|
||||
stage_x11->state &= ~CLUTTER_STAGE_STATE_ACTIVATED;
|
||||
|
||||
event->any.type = CLUTTER_STAGE_STATE;
|
||||
event->any.source = CLUTTER_ACTOR (stage);
|
||||
event->any.stage = stage;
|
||||
event->stage_state.changed_mask = CLUTTER_STAGE_STATE_ACTIVATED;
|
||||
event->stage_state.new_state = stage_x11->state;
|
||||
|
||||
res = CLUTTER_TRANSLATE_QUEUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case Expose:
|
||||
{
|
||||
XExposeEvent *expose = (XExposeEvent *) xevent;
|
||||
ClutterPaintVolume clip;
|
||||
ClutterVertex origin;
|
||||
|
||||
CLUTTER_NOTE (EVENT,
|
||||
"expose for stage: %s[%p], win:0x%x - "
|
||||
"redrawing area (x: %d, y: %d, width: %d, height: %d)",
|
||||
_clutter_actor_get_debug_name (CLUTTER_ACTOR (stage)),
|
||||
stage,
|
||||
(unsigned int) stage_xwindow,
|
||||
expose->x,
|
||||
expose->y,
|
||||
expose->width,
|
||||
expose->height);
|
||||
|
||||
origin.x = expose->x;
|
||||
origin.y = expose->y;
|
||||
origin.z = 0;
|
||||
|
||||
_clutter_paint_volume_init_static (CLUTTER_ACTOR (stage), &clip);
|
||||
|
||||
clutter_paint_volume_set_origin (&clip, &origin);
|
||||
clutter_paint_volume_set_width (&clip, expose->width);
|
||||
clutter_paint_volume_set_height (&clip, expose->height);
|
||||
|
||||
_clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stage), 0, &clip);
|
||||
|
||||
clutter_paint_volume_free (&clip);
|
||||
}
|
||||
break;
|
||||
|
||||
case DestroyNotify:
|
||||
CLUTTER_NOTE (EVENT,
|
||||
"Destroy notification received for stage %s[%p], win:0x%x",
|
||||
_clutter_actor_get_debug_name (CLUTTER_ACTOR (stage)),
|
||||
stage,
|
||||
(unsigned int) stage_xwindow);
|
||||
event->any.type = CLUTTER_DESTROY_NOTIFY;
|
||||
event->any.stage = stage;
|
||||
res = CLUTTER_TRANSLATE_QUEUE;
|
||||
break;
|
||||
|
||||
case ClientMessage:
|
||||
CLUTTER_NOTE (EVENT, "Client message for stage %s[%p], win:0x%x",
|
||||
_clutter_actor_get_debug_name (CLUTTER_ACTOR (stage)),
|
||||
stage,
|
||||
(unsigned int) stage_xwindow);
|
||||
if (handle_wm_protocols_event (backend_x11, stage_x11, xevent))
|
||||
{
|
||||
event->any.type = CLUTTER_DELETE;
|
||||
event->any.stage = stage;
|
||||
res = CLUTTER_TRANSLATE_QUEUE;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
res = CLUTTER_TRANSLATE_CONTINUE;
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_event_translator_iface_init (ClutterEventTranslatorIface *iface)
|
||||
{
|
||||
iface->translate_event = clutter_stage_x11_translate_event;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_x11_get_stage_window:
|
||||
* @stage: a #ClutterStage
|
||||
@ -959,3 +1368,136 @@ clutter_x11_set_stage_foreign (ClutterStage *stage,
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_stage_x11_destroy_window_untrapped (ClutterStageX11 *stage_x11)
|
||||
{
|
||||
if (!stage_x11->is_foreign_xwin && stage_x11->xwin != None)
|
||||
{
|
||||
ClutterBackendX11 *backend_x11;
|
||||
|
||||
backend_x11 = CLUTTER_BACKEND_X11 (clutter_get_default_backend ());
|
||||
|
||||
XDestroyWindow (backend_x11->xdpy, stage_x11->xwin);
|
||||
stage_x11->xwin = None;
|
||||
}
|
||||
else
|
||||
stage_x11->xwin = None;
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_stage_x11_destroy_window (ClutterStageX11 *stage_x11)
|
||||
{
|
||||
if (stage_x11->xwin == None)
|
||||
return;
|
||||
|
||||
clutter_x11_trap_x_errors ();
|
||||
|
||||
_clutter_stage_x11_destroy_window_untrapped (stage_x11);
|
||||
|
||||
clutter_x11_untrap_x_errors ();
|
||||
}
|
||||
|
||||
gboolean
|
||||
_clutter_stage_x11_create_window (ClutterStageX11 *stage_x11)
|
||||
{
|
||||
ClutterBackendX11 *backend_x11;
|
||||
XSetWindowAttributes xattr;
|
||||
XVisualInfo *xvisinfo;
|
||||
unsigned long mask;
|
||||
gfloat width, height;
|
||||
|
||||
if (stage_x11->xwin != None)
|
||||
return TRUE;
|
||||
|
||||
CLUTTER_NOTE (MISC, "Creating stage X window");
|
||||
|
||||
backend_x11 = CLUTTER_BACKEND_X11 (clutter_get_default_backend ());
|
||||
|
||||
xvisinfo = clutter_backend_x11_get_visual_info (backend_x11);
|
||||
if (xvisinfo == NULL)
|
||||
{
|
||||
g_critical ("Unable to find suitable GL visual.");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* window attributes */
|
||||
xattr.background_pixel = WhitePixel (backend_x11->xdpy,
|
||||
backend_x11->xscreen_num);
|
||||
xattr.border_pixel = 0;
|
||||
xattr.colormap = XCreateColormap (backend_x11->xdpy,
|
||||
backend_x11->xwin_root,
|
||||
xvisinfo->visual,
|
||||
AllocNone);
|
||||
mask = CWBorderPixel | CWColormap;
|
||||
|
||||
/* Call get_size - this will either get the geometry size (which
|
||||
* before we create the window is set to 640x480), or if a size
|
||||
* is set, it will get that. This lets you set a size on the
|
||||
* stage before it's realized.
|
||||
*
|
||||
* we also round to the nearest integer because stage sizes
|
||||
* should always be in pixels
|
||||
*/
|
||||
clutter_actor_get_size (CLUTTER_ACTOR (stage_x11->wrapper), &width, &height);
|
||||
stage_x11->xwin_width = floorf (width + 0.5);
|
||||
stage_x11->xwin_height = floorf (height + 0.5);
|
||||
|
||||
stage_x11->xwin = XCreateWindow (backend_x11->xdpy,
|
||||
backend_x11->xwin_root,
|
||||
0, 0,
|
||||
stage_x11->xwin_width,
|
||||
stage_x11->xwin_height,
|
||||
0,
|
||||
xvisinfo->depth,
|
||||
InputOutput,
|
||||
xvisinfo->visual,
|
||||
mask, &xattr);
|
||||
|
||||
CLUTTER_NOTE (BACKEND, "Stage [%p], window: 0x%x, size: %dx%d",
|
||||
stage_x11,
|
||||
(unsigned int) stage_x11->xwin,
|
||||
stage_x11->xwin_width,
|
||||
stage_x11->xwin_height);
|
||||
|
||||
XFree (xvisinfo);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_stage_x11_set_user_time (ClutterStageX11 *stage_x11,
|
||||
guint32 user_time)
|
||||
{
|
||||
ClutterBackendX11 *backend_x11;
|
||||
|
||||
backend_x11 = CLUTTER_BACKEND_X11 (clutter_get_default_backend ());
|
||||
set_user_time (backend_x11, stage_x11, user_time);
|
||||
}
|
||||
|
||||
gboolean
|
||||
_clutter_stage_x11_get_root_coords (ClutterStageX11 *stage_x11,
|
||||
gint *root_x,
|
||||
gint *root_y)
|
||||
{
|
||||
ClutterBackendX11 *backend_x11;
|
||||
gint return_val;
|
||||
Window child;
|
||||
gint tx, ty;
|
||||
|
||||
backend_x11 = CLUTTER_BACKEND_X11 (clutter_get_default_backend ());
|
||||
|
||||
return_val = XTranslateCoordinates (backend_x11->xdpy,
|
||||
stage_x11->xwin,
|
||||
backend_x11->xwin_root,
|
||||
0, 0, &tx, &ty,
|
||||
&child);
|
||||
|
||||
if (root_x)
|
||||
*root_x = tx;
|
||||
|
||||
if (root_y)
|
||||
*root_y = ty;
|
||||
|
||||
return (return_val == 0);
|
||||
}
|
||||
|
@ -90,6 +90,15 @@ void clutter_stage_x11_unmap (ClutterStageX11 *stage_x11);
|
||||
|
||||
GList *clutter_stage_x11_get_input_devices (ClutterStageX11 *stage_x11);
|
||||
|
||||
gboolean _clutter_stage_x11_create_window (ClutterStageX11 *stage_x11);
|
||||
void _clutter_stage_x11_destroy_window_untrapped (ClutterStageX11 *stage_x11);
|
||||
void _clutter_stage_x11_destroy_window (ClutterStageX11 *stage_x11);
|
||||
void _clutter_stage_x11_set_user_time (ClutterStageX11 *stage_x11,
|
||||
guint32 user_time);
|
||||
gboolean _clutter_stage_x11_get_root_coords (ClutterStageX11 *stage_x11,
|
||||
gint *root_x,
|
||||
gint *root_y);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __CLUTTER_STAGE_H__ */
|
||||
|
48
configure.ac
48
configure.ac
@ -861,29 +861,47 @@ AS_IF([test "x$SUPPORT_XLIB" = "x1"],
|
||||
[AC_MSG_ERROR([not found])]
|
||||
)
|
||||
|
||||
# XINPUT (optional)
|
||||
xinput=no
|
||||
# XI (optional)
|
||||
AC_ARG_ENABLE([xinput],
|
||||
[AS_HELP_STRING([--enable-xinput], [Use the XINPUT X extension])],
|
||||
[
|
||||
AS_IF([test "x$enableval" = "xyes"],
|
||||
[PKG_CHECK_MODULES(XINPUT, [xi], [xinput=yes], [xinput=no])]
|
||||
)
|
||||
],
|
||||
[xinput=no])
|
||||
[AS_HELP_STRING([--enable-xinput], [Use the XI X extension])],
|
||||
[],
|
||||
[enable_xinput=no])
|
||||
|
||||
AS_CASE([$xinput],
|
||||
AS_IF([test "x$enable_xinput" = "xyes"],
|
||||
[
|
||||
PKG_CHECK_EXISTS([xi], [have_xinput=yes], [have_xinput=no])
|
||||
],
|
||||
[
|
||||
have_xinput=no
|
||||
])
|
||||
|
||||
AS_CASE([$have_xinput],
|
||||
|
||||
[yes],
|
||||
[
|
||||
AC_DEFINE(HAVE_XINPUT, 1, [Use the XINPUT X extension])
|
||||
AC_CHECK_HEADERS([X11/extensions/XInput2.h],
|
||||
[
|
||||
have_xinput2=yes
|
||||
AC_DEFINE([HAVE_XINPUT_2],
|
||||
[1],
|
||||
[Define to 1 if XI2 is available])
|
||||
],
|
||||
[
|
||||
have_xinput2=no
|
||||
AC_DEFINE([HAVE_XINPUT],
|
||||
[1],
|
||||
[Define to 1 if XInput is available])
|
||||
])
|
||||
|
||||
X11_LIBS="$X11_LIBS -lXi"
|
||||
X11_LIBS="$X11_LIBS $XINPUT_LIBS"
|
||||
X11_PC_FILES="$X11_PC_FILES xi"
|
||||
],
|
||||
|
||||
[no],
|
||||
[],
|
||||
[have_xinput2=no],
|
||||
|
||||
[*],
|
||||
[AC_MSG_ERROR([Invalid argument for --enable-xinput])]
|
||||
)
|
||||
|
||||
# XKB
|
||||
@ -910,6 +928,7 @@ AS_IF([test "x$SUPPORT_XLIB" = "x1"],
|
||||
]
|
||||
)
|
||||
|
||||
AM_CONDITIONAL([BUILD_XI2], [test "x$have_xinput2" = "xyes"])
|
||||
AM_CONDITIONAL(X11_TESTS, [test "x$x11_tests" = "xyes"])
|
||||
|
||||
dnl === Enable debug level ====================================================
|
||||
@ -1258,7 +1277,8 @@ fi
|
||||
|
||||
if test "x$SUPPORT_XLIB" = "x1"; then
|
||||
echo " Enable XComposite: ${have_xcomposite}"
|
||||
echo " Enable XInput 1.0: ${xinput}"
|
||||
echo " Enable XInput: ${have_xinput}"
|
||||
echo " Enable XI2: ${have_xinput2}"
|
||||
echo " Enable XKB: ${have_xkb}"
|
||||
echo " Enable X11 tests: ${x11_tests}"
|
||||
fi
|
||||
|
@ -63,6 +63,19 @@ stage_motion_event_cb (ClutterActor *actor,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (event->motion.axes != NULL)
|
||||
{
|
||||
guint n_axes = clutter_input_device_get_n_axes (event->motion.device);
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < n_axes; i++)
|
||||
{
|
||||
g_print ("Axis[%02d].value: %.2f\n",
|
||||
i,
|
||||
event->motion.axes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user