From 2c1f8c9ad367035f7fd0d5177c60816440d916b2 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Fri, 28 Jan 2011 14:53:08 +0000 Subject: [PATCH] osx: Add devices to event translation code Use a DeviceManager sub-class similar to the Win32 backend one, which creates two InputDevices: a core pointer and a core keyboard. The event translation code then uses these two devices to fill out the .device field of the events. Throw in enter/leave tracking, given that we need to update the device's state. http://bugzilla.clutter-project.org/show_bug.cgi?id=2490 --- clutter/osx/clutter-backend-osx.c | 45 +++++- clutter/osx/clutter-device-manager-osx.c | 180 +++++++++++++++++++++++ clutter/osx/clutter-device-manager-osx.h | 58 ++++++++ clutter/osx/clutter-event-osx.c | 83 ++++++++--- clutter/osx/clutter-stage-osx.c | 7 +- clutter/osx/clutter-stage-osx.h | 12 +- 6 files changed, 350 insertions(+), 35 deletions(-) create mode 100644 clutter/osx/clutter-device-manager-osx.c create mode 100644 clutter/osx/clutter-device-manager-osx.h diff --git a/clutter/osx/clutter-backend-osx.c b/clutter/osx/clutter-backend-osx.c index 501743cdb..13dd09c57 100644 --- a/clutter/osx/clutter-backend-osx.c +++ b/clutter/osx/clutter-backend-osx.c @@ -23,6 +23,7 @@ #include "clutter-osx.h" #include "clutter-backend-osx.h" +#include "clutter-device-manager-osx.h" #include "clutter-stage-osx.h" #include "clutter-debug.h" @@ -78,7 +79,7 @@ clutter_backend_osx_create_stage (ClutterBackend *backend, CLUTTER_OSX_POOL_ALLOC(); - impl = clutter_stage_osx_new (backend, wrapper); + impl = _clutter_stage_osx_new (backend, wrapper); CLUTTER_NOTE (BACKEND, "create_stage: impl=%p", impl); @@ -87,11 +88,38 @@ clutter_backend_osx_create_stage (ClutterBackend *backend, return impl; } +static inline void +clutter_backend_osx_create_device_manager (ClutterBackendOSX *backend_osx) +{ + if (backend_osx->device_manager != NULL) + return; + + backend_osx->device_manager = g_object_new (CLUTTER_TYPE_DEVICE_MANAGER_OSX, + "backend", backend, + NULL); +} + +static ClutterDeviceManager * +clutter_backend_osx_get_device_manager (ClutterBackend *backend) +{ + ClutterBackendOSX *backend_osx = CLUTTER_BACKEND_OSX (backend); + + clutter_backend_osx_create_device_manager (backend_osx); + + return backend_osx->device_manager; +} + static void clutter_backend_osx_init_events (ClutterBackend *backend) { + ClutterBackendOSX *backend_osx = CLUTTER_BACKEND_OSX (backend); + + if (backend_osx->device_manager != NULL) + return; + CLUTTER_NOTE (BACKEND, "init_events"); + clutter_backend_osx_create_device_manager (backend_osx); _clutter_events_osx_init (); } @@ -221,13 +249,14 @@ clutter_backend_osx_class_init (ClutterBackendOSXClass *klass) object_class->dispose = clutter_backend_osx_dispose; - backend_class->post_parse = clutter_backend_osx_post_parse; - backend_class->get_features = clutter_backend_osx_get_features; - backend_class->create_stage = clutter_backend_osx_create_stage; - backend_class->create_context = clutter_backend_osx_create_context; - backend_class->ensure_context = clutter_backend_osx_ensure_context; - backend_class->init_events = clutter_backend_osx_init_events; - backend_class->redraw = clutter_backend_osx_redraw; + backend_class->post_parse = clutter_backend_osx_post_parse; + backend_class->get_features = clutter_backend_osx_get_features; + backend_class->create_stage = clutter_backend_osx_create_stage; + backend_class->create_context = clutter_backend_osx_create_context; + backend_class->ensure_context = clutter_backend_osx_ensure_context; + backend_class->init_events = clutter_backend_osx_init_events; + backend_class->redraw = clutter_backend_osx_redraw; + backend_class->get_device_manager = clutter_backend_osx_get_device_manager; } GType diff --git a/clutter/osx/clutter-device-manager-osx.c b/clutter/osx/clutter-device-manager-osx.c new file mode 100644 index 000000000..db383c59f --- /dev/null +++ b/clutter/osx/clutter-device-manager-osx.c @@ -0,0 +1,180 @@ +/* + * 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 . + * + * Author: Emmanuele Bassi + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "clutter-backend-osx.h" +#include "clutter-device-manager-osx.h" +#include "clutter-device-manager-osx.h" +#include "clutter-stage-osx.h" + +#include "clutter-backend.h" +#include "clutter-debug.h" +#include "clutter-device-manager-private.h" +#include "clutter-private.h" + +enum +{ + PROP_0 +}; + +G_DEFINE_TYPE (ClutterDeviceManagerOSX, + clutter_device_manager_osx, + CLUTTER_TYPE_DEVICE_MANAGER); + +static void +clutter_device_manager_osx_constructed (GObject *gobject) +{ + ClutterDeviceManager *manager = CLUTTER_DEVICE_MANAGER (gobject); + ClutterDeviceManagerOSX *manager_osx; + ClutterInputDevice *device; + + device = g_object_new (CLUTTER_TYPE_INPUT_DEVICE, + "id", 0, + "name", "Core Pointer", + "device-type", CLUTTER_POINTER_DEVICE, + "device-mode", CLUTTER_INPUT_MODE_MASTER, + "has-cursor", TRUE, + "enabled", TRUE, + NULL); + CLUTTER_NOTE (BACKEND, "Added core pointer device"); + _clutter_device_manager_add_device (manager, device); + + device = g_object_new (CLUTTER_TYPE_INPUT_DEVICE, + "id", 1, + "name", "Core Keyboard", + "device-type", CLUTTER_KEYBOARD_DEVICE, + "device-mode", CLUTTER_INPUT_MODE_MASTER, + "enabled", TRUE, + NULL); + CLUTTER_NOTE (BACKEND, "Added core keyboard device"); + _clutter_device_manager_add_device (manager, device); + + manager_osx = CLUTTER_DEVICE_MANAGER_OSX (manager); + + _clutter_input_device_set_associated_device (manager_osx->core_pointer, + manager_osx->core_keyboard); + _clutter_input_device_set_associated_device (manager_osx->core_keyboard, + manager_osx->core_pointer); +} + +static void +clutter_device_manager_osx_add_device (ClutterDeviceManager *manager, + ClutterInputDevice *device) +{ + ClutterDeviceManagerOSX *manager_osx = CLUTTER_DEVICE_MANAGER_OSX (manager); + ClutterInputDeviceType device_type; + gboolean is_pointer, is_keyboard; + + device_type = clutter_input_device_get_device_type (device); + is_pointer = (device_type == CLUTTER_POINTER_DEVICE) ? TRUE : FALSE; + is_keyboard = (device_type == CLUTTER_KEYBOARD_DEVICE) ? TRUE : FALSE; + + manager_osx->devices = g_slist_prepend (manager_osx->devices, device); + + if (is_pointer && manager_osx->core_pointer == NULL) + manager_osx->core_pointer = device; + + if (is_keyboard && manager_osx->core_keyboard == NULL) + manager_osx->core_keyboard = device; +} + +static void +clutter_device_manager_osx_remove_device (ClutterDeviceManager *manager, + ClutterInputDevice *device) +{ + ClutterDeviceManagerOSX *manager_osx = CLUTTER_DEVICE_MANAGER_OSX (manager); + + manager_osx->devices = g_slist_remove (manager_osx->devices, device); +} + +static const GSList * +clutter_device_manager_osx_get_devices (ClutterDeviceManager *manager) +{ + return CLUTTER_DEVICE_MANAGER_OSX (manager)->devices; +} + +static ClutterInputDevice * +clutter_device_manager_osx_get_core_device (ClutterDeviceManager *manager, + ClutterInputDeviceType type) +{ + ClutterDeviceManagerOSX *manager_osx; + + manager_osx = CLUTTER_DEVICE_MANAGER_OSX (manager); + + switch (type) + { + case CLUTTER_POINTER_DEVICE: + return manager_osx->core_pointer; + + case CLUTTER_KEYBOARD_DEVICE: + return manager_osx->core_keyboard; + + case CLUTTER_EXTENSION_DEVICE: + default: + return NULL; + } + + return NULL; +} + +static ClutterInputDevice * +clutter_device_manager_osx_get_device (ClutterDeviceManager *manager, + gint id) +{ + ClutterDeviceManagerOSX *manager_osx = CLUTTER_DEVICE_MANAGER_OSX (manager); + GSList *l; + + for (l = manager_osx->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_osx_class_init (ClutterDeviceManagerOSXClass *klass) +{ + ClutterDeviceManagerClass *manager_class; + GObjectClass *gobject_class = (GObjectClass *) klass; + + gobject_class->constructed = clutter_device_manager_osx_constructed; + + manager_class = CLUTTER_DEVICE_MANAGER_CLASS (klass); + manager_class->add_device = clutter_device_manager_osx_add_device; + manager_class->remove_device = clutter_device_manager_osx_remove_device; + manager_class->get_devices = clutter_device_manager_osx_get_devices; + manager_class->get_core_device = clutter_device_manager_osx_get_core_device; + manager_class->get_device = clutter_device_manager_osx_get_device; +} + +static void +clutter_device_manager_osx_init (ClutterDeviceManagerOSX *self) +{ +} diff --git a/clutter/osx/clutter-device-manager-osx.h b/clutter/osx/clutter-device-manager-osx.h new file mode 100644 index 000000000..f9ca189e7 --- /dev/null +++ b/clutter/osx/clutter-device-manager-osx.h @@ -0,0 +1,58 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Copyright (C) 2010 Intel Corp. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * 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 . + * + * Author: Emmanuele Bassi + */ + +#ifndef __CLUTTER_DEVICE_MANAGER_OSX_H__ +#define __CLUTTER_DEVICE_MANAGER_OSX_H__ + +#include + +G_BEGIN_DECLS + +#define CLUTTER_TYPE_DEVICE_MANAGER_OSX (clutter_device_manager_osx_get_type ()) +#define CLUTTER_DEVICE_MANAGER_OSX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_DEVICE_MANAGER_OSX, ClutterDeviceManagerOSX)) +#define CLUTTER_IS_DEVICE_MANAGER_OSX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_DEVICE_MANAGER_OSX)) +#define CLUTTER_DEVICE_MANAGER_OSX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_DEVICE_MANAGER_OSX, ClutterDeviceManagerOSXClass)) +#define CLUTTER_IS_DEVICE_MANAGER_OSX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_DEVICE_MANAGER_OSX)) +#define CLUTTER_DEVICE_MANAGER_OSX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_DEVICE_MANAGER_OSX, ClutterDeviceManagerOSXClass)) + +typedef struct _ClutterDeviceManagerOSX ClutterDeviceManagerOSX; +typedef struct _ClutterDeviceManagerOSXClass ClutterDeviceManagerOSXClass; + +struct _ClutterDeviceManagerOSX +{ + ClutterDeviceManager parent_instance; + + ClutterInputDevice *core_pointer; + ClutterInputDevice *core_keyboard; +}; + +struct _ClutterDeviceManagerOSXClass +{ + ClutterDeviceManagerClass parent_class; +}; + +GType clutter_device_manager_osx_get_type (void) G_GNUC_CONST; + +G_END_DECLS + +#endif /* __CLUTTER_DEVICE_MANAGER_OSX_H__ */ diff --git a/clutter/osx/clutter-event-osx.c b/clutter/osx/clutter-event-osx.c index 859d44c91..4e639da79 100644 --- a/clutter/osx/clutter-event-osx.c +++ b/clutter/osx/clutter-event-osx.c @@ -23,14 +23,18 @@ #include "config.h" #include "clutter-osx.h" + +#include "clutter-device-manager-osx.h" #include "clutter-stage-osx.h" #import #include #include -#include +#include #include +#include +#include #include "clutter-event-loop-osx.h" @@ -220,7 +224,8 @@ take_and_queue_event (ClutterEvent *event) } static void -process_scroll_event(ClutterEvent *event, gboolean isVertical) +process_scroll_event (ClutterEvent *event, + gboolean isVertical) { ClutterStageWindow *impl; ClutterStageOSX *stage_osx; @@ -252,6 +257,8 @@ process_scroll_event(ClutterEvent *event, gboolean isVertical) *scroll_pos += WHEEL_DELTA; } + clutter_event_set_device (event_gen, clutter_event_get_device (event)); + take_and_queue_event (event_gen); CLUTTER_NOTE (EVENT, "scroll %s at %f,%f", @@ -260,20 +267,23 @@ process_scroll_event(ClutterEvent *event, gboolean isVertical) (event_gen->scroll.direction == CLUTTER_SCROLL_DOWN) ? "DOWN" : ( (event_gen->scroll.direction == CLUTTER_SCROLL_RIGHT) ? "RIGHT" : "LEFT")), - (float)event->scroll.x, (float)event->scroll.y); + event->scroll.x, event->scroll.y); } } static gboolean -clutter_event_osx_translate (NSEvent *nsevent, ClutterEvent *event) -{ - ClutterStageWindow *impl; +clutter_event_osx_translate (NSEvent *nsevent, + ClutterEvent *event) +{ + ClutterDeviceManagerOSX *manager_osx; ClutterStageOSX *stage_osx; - + ClutterStageWindow *impl; + ClutterStage *stage; + + stage = event->any.stage; impl = _clutter_stage_get_window (event->any.stage); stage_osx = CLUTTER_STAGE_OSX (impl); - - event->any.time = [nsevent clutterTime]; + manager_osx = CLUTTER_DEVICE_MANAGER_OSX (clutter_device_manager_get_default ()); switch ([nsevent type]) { @@ -292,11 +302,12 @@ clutter_event_osx_translate (NSEvent *nsevent, ClutterEvent *event) event->button.click_count = [nsevent clickCount]; event->motion.modifier_state = [nsevent clutterModifierState]; [nsevent clutterX:&(event->button.x) y:&(event->button.y)]; + clutter_event_set_device (event, manager_osx->core_pointer); CLUTTER_NOTE (EVENT, "button %d %s at %f,%f clicks=%d", (int)[nsevent buttonNumber], event->type == CLUTTER_BUTTON_PRESS ? "press" : "release", - (float)event->button.x, (float)event->button.y, + event->button.x, event->button.y, event->button.click_count); return TRUE; @@ -308,10 +319,39 @@ clutter_event_osx_translate (NSEvent *nsevent, ClutterEvent *event) [nsevent clutterX:&(event->motion.x) y:&(event->motion.y)]; event->motion.modifier_state = [nsevent clutterModifierState]; + clutter_event_set_device (event, manager_osx->core_pointer); CLUTTER_NOTE (EVENT, "motion %d at %f,%f", (int)[nsevent buttonNumber], - (float)event->button.x, (float)event->button.y); + event->button.x, event->button.y); + return TRUE; + + case NSMouseEntered: + event->type = CLUTTER_ENTER; + + [nsevent clutterX:&(event->crossing.x) y:&(event->crossing.y)]; + event->crossing.related = NULL; + event->crossing.actor = CLUTTER_ACTOR (stage); + clutter_event_set_device (event, manager_osx->core_pointer); + + _clutter_stage_add_device (stage, manager_osx->core_pointer); + + CLUTTER_NOTE (EVENT, "enter at %f,%f", + event->crossing.x, event->crossing.y); + return TRUE; + + case NSMouseExited: + event->type = CLUTTER_LEAVE; + + [nsevent clutterX:&(event->crossing.x) y:&(event->crossing.y)]; + event->crossing.related = NULL; + event->crossing.actor = CLUTTER_ACTOR (stage); + clutter_event_set_device (event, manager_osx->core_pointer); + + _clutter_stage_remove_device (stage, manager_osx->core_pointer); + + CLUTTER_NOTE (EVENT, "exit at %f,%f", + event->crossing.x, event->crossing.y); return TRUE; case NSScrollWheel: @@ -320,11 +360,11 @@ clutter_event_osx_translate (NSEvent *nsevent, ClutterEvent *event) [nsevent clutterX:&(event->scroll.x) y:&(event->scroll.y)]; event->scroll.modifier_state = [nsevent clutterModifierState]; + clutter_event_set_device (event, manager_osx->core_pointer); - process_scroll_event(event, TRUE); - process_scroll_event(event, FALSE); - - return FALSE; + process_scroll_event (event, TRUE); + process_scroll_event (event, FALSE); + break; case NSKeyDown: event->type = CLUTTER_KEY_PRESS; @@ -337,6 +377,7 @@ clutter_event_osx_translate (NSEvent *nsevent, ClutterEvent *event) event->key.modifier_state = [nsevent clutterModifierState]; event->key.keyval = [nsevent clutterKeyVal]; event->key.unicode_value = [[nsevent characters] characterAtIndex:0]; + clutter_event_set_device (event, manager_osx->core_keyboard); CLUTTER_NOTE (EVENT, "key %d (%s) (%s) %s, keyval %d", [nsevent keyCode], @@ -355,17 +396,21 @@ clutter_event_osx_translate (NSEvent *nsevent, ClutterEvent *event) } void -_clutter_event_osx_put (NSEvent *nsevent, ClutterStage *wrapper) +_clutter_event_osx_put (NSEvent *nsevent, + ClutterStage *wrapper) { - ClutterEvent event = { 0, }; + ClutterEvent *event = clutter_event_new (CLUTTER_NOTHING); - event.any.stage = wrapper; + event->any.stage = wrapper; if (clutter_event_osx_translate (nsevent, &event)) { g_assert (event.type != CLUTTER_NOTHING); - clutter_event_put (&event); + + _clutter_event_push (event, FALSE); } + else + clutter_event_free (event); } void diff --git a/clutter/osx/clutter-stage-osx.c b/clutter/osx/clutter-stage-osx.c index 4f70e1220..5d7a1faaa 100644 --- a/clutter/osx/clutter-stage-osx.c +++ b/clutter/osx/clutter-stage-osx.c @@ -33,6 +33,8 @@ static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface); +#define clutter_stage_osx_get_type _clutter_stage_osx_get_type + G_DEFINE_TYPE_WITH_CODE (ClutterStageOSX, clutter_stage_osx, G_TYPE_OBJECT, @@ -44,6 +46,7 @@ static void clutter_stage_osx_state_update (ClutterStageOSX *self, ClutterStageState unset_flags, ClutterStageState set_flags); + static ClutterActor * clutter_stage_osx_get_wrapper (ClutterStageWindow *stage_window); @@ -533,8 +536,8 @@ clutter_stage_window_iface_init (ClutterStageWindowIface *iface) /*************************************************************************/ ClutterStageWindow * -clutter_stage_osx_new (ClutterBackend *backend, - ClutterStage *wrapper) +_clutter_stage_osx_new (ClutterBackend *backend, + ClutterStage *wrapper) { ClutterStageOSX *self; diff --git a/clutter/osx/clutter-stage-osx.h b/clutter/osx/clutter-stage-osx.h index 7344eb6fa..af1d7ba90 100644 --- a/clutter/osx/clutter-stage-osx.h +++ b/clutter/osx/clutter-stage-osx.h @@ -31,7 +31,7 @@ G_BEGIN_DECLS /* convenience macros */ -#define CLUTTER_TYPE_STAGE_OSX (clutter_stage_osx_get_type()) +#define CLUTTER_TYPE_STAGE_OSX (_clutter_stage_osx_get_type()) #define CLUTTER_STAGE_OSX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),CLUTTER_TYPE_STAGE_OSX,ClutterStageOSX)) #define CLUTTER_STAGE_OSX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),CLUTTER_TYPE_STAGE_OSX,ClutterStage)) #define CLUTTER_IS_STAGE_OSX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),CLUTTER_TYPE_STAGE_OSX)) @@ -50,7 +50,7 @@ typedef struct _ClutterStageOSXClass ClutterStageOSXClass; struct _ClutterStageOSX { - ClutterGroup parent; + GObject parent; ClutterBackend *backend; ClutterStage *wrapper; @@ -74,13 +74,13 @@ struct _ClutterStageOSX struct _ClutterStageOSXClass { - ClutterGroupClass parent_class; + GObjectClass parent_class; }; -GType clutter_stage_osx_get_type (void) G_GNUC_CONST; +GType _clutter_stage_osx_get_type (void) G_GNUC_CONST; -ClutterStageWindow* clutter_stage_osx_new (ClutterBackend *backend, - ClutterStage *wrapper); +ClutterStageWindow * _clutter_stage_osx_new (ClutterBackend *backend, + ClutterStage *wrapper); G_END_DECLS