static void handle_idletime_for_event (const ClutterEvent *event) { #ifdef HAVE_NATIVE_BACKEND /* This is handled by XSync under X11. */ MetaBackend *backend = meta_get_backend (); if (META_IS_BACKEND_NATIVE (backend)) { ClutterInputDevice *device, *source_device; MetaIdleMonitor *core_monitor, *device_monitor; int device_id; device = clutter_event_get_device (event); if (device == NULL) return; device_id = clutter_input_device_get_device_id (device); core_monitor = meta_idle_monitor_get_core (); device_monitor = meta_idle_monitor_get_for_device (device_id); meta_idle_monitor_native_reset_idletime (core_monitor); meta_idle_monitor_native_reset_idletime (device_monitor); source_device = clutter_event_get_source_device (event); if (source_device != device) { device_id = clutter_input_device_get_device_id (device); device_monitor = meta_idle_monitor_get_for_device (device_id); meta_idle_monitor_native_reset_idletime (device_monitor); } } #endif /* HAVE_NATIVE_BACKEND */ }
static void manager_device_removed_cb (ClutterDeviceManager *manager, ClutterInputDevice *device, TestDevicesApp *app) { ClutterInputDeviceType device_type; ClutterActor *hand = NULL; g_print ("removed a %s device '%s' with id %d\n", device_type_name (device), clutter_input_device_get_device_name (device), clutter_input_device_get_device_id (device)); device_type = clutter_input_device_get_device_type (device); if (device_type == CLUTTER_POINTER_DEVICE || device_type == CLUTTER_PEN_DEVICE || device_type == CLUTTER_POINTER_DEVICE) { hand = g_hash_table_lookup (app->devices, device); if (hand != NULL) clutter_container_add_actor (CLUTTER_CONTAINER (app->stage), hand); g_hash_table_remove (app->devices, device); } }
static void manager_device_added_cb (ClutterDeviceManager *manager, ClutterInputDevice *device, TestDevicesApp *app) { ClutterInputDeviceType device_type; ClutterActor *hand = NULL; g_print ("got a %s device '%s' with id %d\n", device_type_name (device), clutter_input_device_get_device_name (device), clutter_input_device_get_device_id (device)); device_type = clutter_input_device_get_device_type (device); if (device_type == CLUTTER_POINTER_DEVICE || device_type == CLUTTER_PEN_DEVICE || device_type == CLUTTER_POINTER_DEVICE) { g_print ("*** enabling device '%s' ***\n", clutter_input_device_get_device_name (device)); clutter_input_device_set_enabled (device, TRUE); hand = clutter_texture_new_from_file (TESTS_DATADIR G_DIR_SEPARATOR_S "redhand.png", NULL); g_hash_table_insert (app->devices, device, hand); clutter_container_add_actor (CLUTTER_CONTAINER (app->stage), hand); } }
static void change_property (ClutterInputDevice *device, const gchar *property, Atom type, int format, void *data, gulong nitems) { MetaBackend *backend = meta_get_backend (); Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend)); int device_id; Atom property_atom; guchar *data_ret; property_atom = XInternAtom (xdisplay, property, False); device_id = clutter_input_device_get_device_id (device); data_ret = get_property (device, property, type, format, nitems); if (!data_ret) return; XIChangeProperty (xdisplay, device_id, property_atom, type, format, XIPropModeReplace, data, nitems); meta_XFree (data_ret); }
static void * get_property (ClutterInputDevice *device, const gchar *property, Atom type, int format, gulong nitems) { MetaBackend *backend = meta_get_backend (); Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend)); gulong nitems_ret, bytes_after_ret; int rc, device_id, format_ret; Atom property_atom, type_ret; guchar *data_ret = NULL; property_atom = XInternAtom (xdisplay, property, False); device_id = clutter_input_device_get_device_id (device); rc = XIGetProperty (xdisplay, device_id, property_atom, 0, 10, False, type, &type_ret, &format_ret, &nitems_ret, &bytes_after_ret, &data_ret); if (rc == Success && type_ret == type && format_ret == format && nitems_ret >= nitems) { if (nitems_ret > nitems) g_warning ("Property '%s' for device '%s' returned %lu items, expected %lu", property, clutter_input_device_get_device_name (device), nitems_ret, nitems); return data_ret; } meta_XFree (data_ret); return NULL; }
static void handle_idletime_for_event (const ClutterEvent *event) { #ifdef HAVE_NATIVE_BACKEND /* This is handled by XSync under X11. */ MetaBackend *backend = meta_get_backend (); if (META_IS_BACKEND_NATIVE (backend)) { ClutterInputDevice *device, *source_device; MetaIdleMonitor *core_monitor, *device_monitor; int device_id; device = clutter_event_get_device (event); if (device == NULL) return; if (event->any.flags & CLUTTER_EVENT_FLAG_SYNTHETIC || event->type == CLUTTER_ENTER || event->type == CLUTTER_LEAVE || event->type == CLUTTER_STAGE_STATE || event->type == CLUTTER_DESTROY_NOTIFY || event->type == CLUTTER_CLIENT_MESSAGE || event->type == CLUTTER_DELETE) return; device_id = clutter_input_device_get_device_id (device); core_monitor = meta_idle_monitor_get_core (); device_monitor = meta_idle_monitor_get_for_device (device_id); meta_idle_monitor_native_reset_idletime (core_monitor); meta_idle_monitor_native_reset_idletime (device_monitor); source_device = clutter_event_get_source_device (event); if (source_device != device) { device_id = clutter_input_device_get_device_id (device); device_monitor = meta_idle_monitor_get_for_device (device_id); meta_idle_monitor_native_reset_idletime (device_monitor); } } #endif /* HAVE_NATIVE_BACKEND */ }
static void on_device_removed (ClutterDeviceManager *device_manager, ClutterInputDevice *device, GDBusObjectManagerServer *manager) { int device_id; char *path; device_id = clutter_input_device_get_device_id (device); path = g_strdup_printf ("/org/gnome/Mutter/IdleMonitor/Device%d", device_id); g_dbus_object_manager_server_unexport (manager, path); g_free (path); }
/** * clutter_event_get_device_id: * @event: a clutter event * * Retrieves the events device id if set. * * Return value: A unique identifier for the device or -1 if the event has * no specific device set. */ gint clutter_event_get_device_id (const ClutterEvent *event) { ClutterInputDevice *device = NULL; g_return_val_if_fail (event != NULL, CLUTTER_POINTER_DEVICE); device = clutter_event_get_device (event); if (device != NULL) return clutter_input_device_get_device_id (device); return -1; }
static gboolean stage_button_event_cb (ClutterActor *actor, ClutterEvent *event, TestDevicesApp *app) { ClutterInputDevice *device; ClutterInputDevice *source_device; ClutterActor *hand = NULL; gdouble *axes; guint n_axes, i; device = clutter_event_get_device (event); source_device = clutter_event_get_source_device (event); hand = g_hash_table_lookup (app->devices, device); g_print ("Device: '%s' (id:%d, type: %s, source: '%s', axes: %d)\n", clutter_input_device_get_device_name (device), clutter_input_device_get_device_id (device), device_type_name (device), source_device != device ? clutter_input_device_get_device_name (source_device) : "<same>", clutter_input_device_get_n_axes (device)); if (hand != NULL) { gfloat event_x, event_y; clutter_event_get_coords (event, &event_x, &event_y); clutter_actor_set_position (hand, event_x, event_y); } axes = clutter_event_get_axes (event, &n_axes); for (i = 0; i < n_axes; i++) { ClutterInputAxis axis; axis = clutter_input_device_get_axis (device, i); if (axis == CLUTTER_INPUT_AXIS_IGNORE) continue; g_print ("\tAxis[%2d][%s].value: %.2f\n", i, axis_type_name (axis), axes[i]); } return FALSE; }
/* * _clutter_input_device_update: * @device: a #ClutterInputDevice * * Updates the input @device by determining the #ClutterActor underneath the * pointer's cursor * * This function calls _clutter_input_device_set_actor() if needed. * * This function only works for #ClutterInputDevice of type * %CLUTTER_POINTER_DEVICE. * * Since: 1.2 */ ClutterActor * _clutter_input_device_update (ClutterInputDevice *device, gboolean emit_crossing) { ClutterStage *stage; ClutterActor *new_cursor_actor; ClutterActor *old_cursor_actor; gint x, y; if (device->device_type == CLUTTER_KEYBOARD_DEVICE) return NULL; stage = device->stage; if (G_UNLIKELY (stage == NULL)) { CLUTTER_NOTE (EVENT, "No stage defined for device '%s'", clutter_input_device_get_device_name (device)); return NULL; } clutter_input_device_get_device_coords (device, &x, &y); old_cursor_actor = device->cursor_actor; new_cursor_actor = _clutter_do_pick (stage, x, y, CLUTTER_PICK_REACTIVE); /* if the pick could not find an actor then we do not update the * input device, to avoid ghost enter/leave events; the pick should * never fail, except for bugs in the glReadPixels() implementation * in which case this is the safest course of action anyway */ if (new_cursor_actor == NULL) return NULL; CLUTTER_NOTE (EVENT, "Actor under cursor (device %d, at %d, %d): %s", clutter_input_device_get_device_id (device), x, y, clutter_actor_get_name (new_cursor_actor) != NULL ? clutter_actor_get_name (new_cursor_actor) : G_OBJECT_TYPE_NAME (new_cursor_actor)); /* short-circuit here */ if (new_cursor_actor == old_cursor_actor) return old_cursor_actor; _clutter_input_device_set_actor (device, new_cursor_actor, emit_crossing); return device->cursor_actor; }
static void handle_idletime_for_event (const ClutterEvent *event) { ClutterInputDevice *device, *source_device; MetaIdleMonitor *core_monitor, *device_monitor; int device_id; device = clutter_event_get_device (event); if (device == NULL) return; if (event->any.flags & CLUTTER_EVENT_FLAG_SYNTHETIC || event->type == CLUTTER_ENTER || event->type == CLUTTER_LEAVE || event->type == CLUTTER_STAGE_STATE || event->type == CLUTTER_DESTROY_NOTIFY || event->type == CLUTTER_CLIENT_MESSAGE || event->type == CLUTTER_DELETE) return; device_id = clutter_input_device_get_device_id (device); core_monitor = meta_idle_monitor_get_core (); device_monitor = meta_idle_monitor_get_for_device (device_id); meta_idle_monitor_reset_idletime (core_monitor); meta_idle_monitor_reset_idletime (device_monitor); source_device = clutter_event_get_source_device (event); if (source_device != device) { device_id = clutter_input_device_get_device_id (device); device_monitor = meta_idle_monitor_get_for_device (device_id); meta_idle_monitor_reset_idletime (device_monitor); } }
ClutterInputDevice * clutter_seat_evdev_get_device (ClutterSeatEvdev *seat, gint id) { ClutterInputDevice *device; GSList *l; for (l = seat->devices; l; l = l->next) { device = l->data; if (clutter_input_device_get_device_id (device) == id) return device; } return NULL; }
static ClutterInputDevice * clutter_device_manager_win32_get_device (ClutterDeviceManager *manager, gint id) { ClutterDeviceManagerWin32 *manager_win32 = CLUTTER_DEVICE_MANAGER_WIN32 (manager); GSList *l; for (l = manager_win32->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 on_device_added (ClutterDeviceManager *device_manager, ClutterInputDevice *device, GDBusObjectManagerServer *manager) { MetaIdleMonitor *monitor; int device_id; char *path; device_id = clutter_input_device_get_device_id (device); monitor = meta_idle_monitor_get_for_device (device_id); path = g_strdup_printf ("/org/gnome/Mutter/IdleMonitor/Device%d", device_id); create_monitor_skeleton (manager, monitor, path); g_free (path); }
static void gdk_device_removed (GdkDeviceManager *gdk_manager, GdkDevice *device, ClutterDeviceManagerGdk *self) { ClutterInputDevice *clutter_device = g_object_get_data (G_OBJECT (device), "clutter-device"); if (clutter_device == NULL) return; self->device_cache = g_slist_remove (self->device_cache, clutter_device); g_object_unref (clutter_device); g_hash_table_remove (self->device_by_id, GINT_TO_POINTER (clutter_input_device_get_device_id (clutter_device))); _clutter_device_manager_remove_device (CLUTTER_DEVICE_MANAGER (self), clutter_device); }
static ClutterInputDevice * clutter_device_manager_wayland_get_device (ClutterDeviceManager *manager, gint id) { ClutterDeviceManagerWayland *manager_wayland = CLUTTER_DEVICE_MANAGER_WAYLAND (manager); GSList *l; for (l = manager_wayland->devices; l != NULL; l = l->next) { ClutterInputDevice *device = l->data; if (clutter_input_device_get_device_id (device) == id) return device; } return NULL; }
ClutterInputDevice * _clutter_device_manager_gdk_lookup_device (ClutterDeviceManager *manager, GdkDevice *device) { ClutterDeviceManagerGdk *manager_gdk = CLUTTER_DEVICE_MANAGER_GDK (manager); ClutterInputDevice *clutter_device; clutter_device = g_object_get_data (G_OBJECT (device), "clutter-device"); if (clutter_device != NULL) return clutter_device; clutter_device = _clutter_input_device_gdk_new (manager, device); g_object_set_data_full (G_OBJECT (device), "clutter-device", clutter_device, g_object_unref); manager_gdk->device_cache = g_slist_prepend (manager_gdk->device_cache, g_object_ref (clutter_device)); g_hash_table_replace (manager_gdk->device_by_id, GINT_TO_POINTER (clutter_input_device_get_device_id (clutter_device)), g_object_ref (clutter_device)); return clutter_device; }
static gboolean meta_display_handle_event (MetaDisplay *display, const ClutterEvent *event) { MetaWindow *window; gboolean bypass_clutter = FALSE; G_GNUC_UNUSED gboolean bypass_wayland = FALSE; MetaGestureTracker *tracker; ClutterEventSequence *sequence; ClutterInputDevice *source; sequence = clutter_event_get_event_sequence (event); /* Set the pointer emulating sequence on touch begin, if eligible */ if (event->type == CLUTTER_TOUCH_BEGIN) { if (sequence_is_pointer_emulated (display, event)) { /* This is the new pointer emulating sequence */ display->pointer_emulating_sequence = sequence; } else if (display->pointer_emulating_sequence == sequence) { /* This sequence was "pointer emulating" in a prior incarnation, * but now it isn't. We unset the pointer emulating sequence at * this point so the current sequence is not mistaken as pointer * emulating, while we've ensured that it's been deemed * "pointer emulating" throughout all of the event processing * of the previous incarnation. */ display->pointer_emulating_sequence = NULL; } } #ifdef HAVE_WAYLAND MetaWaylandCompositor *compositor = NULL; if (meta_is_wayland_compositor ()) { compositor = meta_wayland_compositor_get_default (); meta_wayland_compositor_update (compositor, event); } #endif if (!display->current_pad_osd && (event->type == CLUTTER_PAD_BUTTON_PRESS || event->type == CLUTTER_PAD_BUTTON_RELEASE)) { MetaBackend *backend = meta_get_backend (); if (meta_input_settings_handle_pad_button (meta_backend_get_input_settings (backend), clutter_event_get_source_device (event), event->type == CLUTTER_PAD_BUTTON_PRESS, event->pad_button.button)) { bypass_wayland = bypass_clutter = TRUE; goto out; } } source = clutter_event_get_source_device (event); if (source) { meta_backend_update_last_device (meta_get_backend (), clutter_input_device_get_device_id (source)); } #ifdef HAVE_WAYLAND if (meta_is_wayland_compositor () && event->type == CLUTTER_MOTION) { MetaWaylandCompositor *compositor; compositor = meta_wayland_compositor_get_default (); if (meta_wayland_tablet_manager_consumes_event (compositor->tablet_manager, event)) { meta_wayland_tablet_manager_update_cursor_position (compositor->tablet_manager, event); } else { MetaCursorTracker *tracker = meta_cursor_tracker_get_for_screen (NULL); meta_cursor_tracker_update_position (tracker, event->motion.x, event->motion.y); } display->monitor_cache_invalidated = TRUE; } #endif handle_idletime_for_event (event); window = get_window_for_event (display, event); display->current_time = event->any.time; if (window && !window->override_redirect && (event->type == CLUTTER_KEY_PRESS || event->type == CLUTTER_BUTTON_PRESS || event->type == CLUTTER_TOUCH_BEGIN)) { if (CurrentTime == display->current_time) { /* We can't use missing (i.e. invalid) timestamps to set user time, * nor do we want to use them to sanity check other timestamps. * See bug 313490 for more details. */ meta_warning ("Event has no timestamp! You may be using a broken " "program such as xse. Please ask the authors of that " "program to fix it.\n"); } else { meta_window_set_user_time (window, display->current_time); meta_display_sanity_check_timestamps (display, display->current_time); } } tracker = meta_display_get_gesture_tracker (display); if (meta_gesture_tracker_handle_event (tracker, event)) { bypass_wayland = bypass_clutter = TRUE; goto out; } if (display->event_route == META_EVENT_ROUTE_WINDOW_OP) { if (meta_window_handle_mouse_grab_op_event (window, event)) { bypass_clutter = TRUE; bypass_wayland = TRUE; goto out; } } /* For key events, it's important to enforce single-handling, or * we can get into a confused state. So if a keybinding is * handled (because it's one of our hot-keys, or because we are * in a keyboard-grabbed mode like moving a window, we don't * want to pass the key event to the compositor or Wayland at all. */ if (meta_keybindings_process_event (display, window, event)) { bypass_clutter = TRUE; bypass_wayland = TRUE; goto out; } /* Do not pass keyboard events to Wayland if key focus is not on the * stage in normal mode (e.g. during keynav in the panel) */ if (display->event_route == META_EVENT_ROUTE_NORMAL) { if (IS_KEY_EVENT (event) && !stage_has_key_focus ()) { bypass_wayland = TRUE; goto out; } } if (display->current_pad_osd) { bypass_wayland = TRUE; goto out; } if (window) { /* Events that are likely to trigger compositor gestures should * be known to clutter so they can propagate along the hierarchy. * Gesture-wise, there's two groups of events we should be getting * here: * - CLUTTER_TOUCH_* with a touch sequence that's not yet accepted * by the gesture tracker, these might trigger gesture actions * into recognition. Already accepted touch sequences are handled * directly by meta_gesture_tracker_handle_event(). * - CLUTTER_TOUCHPAD_* events over windows. These can likewise * trigger ::captured-event handlers along the way. */ bypass_clutter = !IS_GESTURE_EVENT (event); meta_window_handle_ungrabbed_event (window, event); /* This might start a grab op. If it does, then filter out the * event, and if it doesn't, replay the event to release our * own sync grab. */ if (display->event_route == META_EVENT_ROUTE_WINDOW_OP || display->event_route == META_EVENT_ROUTE_FRAME_BUTTON) { bypass_clutter = TRUE; bypass_wayland = TRUE; } else { /* Only replay button press events, since that's where we * have the synchronous grab. */ if (event->type == CLUTTER_BUTTON_PRESS) { MetaBackend *backend = meta_get_backend (); if (META_IS_BACKEND_X11 (backend)) { Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend)); meta_verbose ("Allowing events time %u\n", (unsigned int)event->button.time); XIAllowEvents (xdisplay, clutter_event_get_device_id (event), XIReplayDevice, event->button.time); } } } goto out; } out: /* If the compositor has a grab, don't pass that through to Wayland */ if (display->event_route == META_EVENT_ROUTE_COMPOSITOR_GRAB) bypass_wayland = TRUE; /* If a Wayland client has a grab, don't pass that through to Clutter */ if (display->event_route == META_EVENT_ROUTE_WAYLAND_POPUP) bypass_clutter = TRUE; #ifdef HAVE_WAYLAND if (compositor && !bypass_wayland) { if (meta_wayland_compositor_handle_event (compositor, event)) bypass_clutter = TRUE; } #endif display->current_time = CurrentTime; return bypass_clutter; }
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; }
//doc ClutterInputDevice deviceId IO_METHOD(IoClutterInputDevice, getId) { return IONUMBER(clutter_input_device_get_device_id(IOCIDEVICE(self))); }
static gboolean on_button_press_event(ClutterActor *actor, ClutterButtonEvent *event, CalibArea *area) { gint num_clicks; gboolean success; if (area->success) return FALSE; if (event->click_count > 1) return FALSE; /* Check matching device ID if a device ID was provided */ if (area->device_id > -1) { ClutterInputDevice *device; device = clutter_event_get_source_device ((ClutterEvent *) event); if (device != NULL && clutter_input_device_get_device_id (device) != area->device_id) { char *name; g_object_get (G_OBJECT (device), "name", &name, NULL); g_debug ("Ignoring input from device %s (%d)", name, clutter_input_device_get_device_id (device)); g_free (name); return FALSE; } } /* Handle click */ clutter_timeline_stop (CLUTTER_TIMELINE (area->clock_timeline)); clutter_timeline_start (CLUTTER_TIMELINE (area->clock_timeline)); success = add_click(&area->calibrator, (int) event->x, (int) event->y); num_clicks = area->calibrator.num_clicks; if (!success && num_clicks == 0) show_error_message (area); else { gboolean visible; g_object_get (area->error_text, "visible", &visible, NULL); if (visible) hide_error_message (area); } /* Are we done yet? */ if (num_clicks >= 4) { set_calibration_status (area); return FALSE; } cc_target_actor_move_center (CC_TARGET_ACTOR (area->target), area->X[num_clicks], area->Y[num_clicks]); return FALSE; }
G_MODULE_EXPORT int test_devices_main (int argc, char **argv) { ClutterActor *stage; TestDevicesApp *app; ClutterDeviceManager *manager; const GSList *stage_devices, *l; /* force enabling X11 support */ clutter_x11_enable_xinput (); clutter_init (&argc, &argv); app = g_new0 (TestDevicesApp, 1); app->devices = g_hash_table_new (g_direct_hash, g_direct_equal) ; stage = clutter_stage_new (); clutter_stage_set_color (CLUTTER_STAGE (stage), CLUTTER_COLOR_LightSkyBlue); clutter_stage_set_title (CLUTTER_STAGE (stage), "Devices"); clutter_stage_hide_cursor (CLUTTER_STAGE (stage)); g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL); g_signal_connect (stage, "motion-event", G_CALLBACK (stage_motion_event_cb), app); g_signal_connect (stage, "button-press-event", G_CALLBACK (stage_button_event_cb), app); app->stage = stage; clutter_actor_show_all (stage); manager = clutter_device_manager_get_default (); g_signal_connect (manager, "device-added", G_CALLBACK (manager_device_added_cb), app); g_signal_connect (manager, "device-removed", G_CALLBACK (manager_device_removed_cb), app); stage_devices = clutter_device_manager_peek_devices (manager); if (stage_devices == NULL) g_error ("No input devices found."); for (l = stage_devices; l != NULL; l = l->next) { ClutterInputDevice *device = l->data; ClutterInputDeviceType device_type; ClutterActor *hand = NULL; g_print ("got a %s device '%s' with id %d\n", device_type_name (device), clutter_input_device_get_device_name (device), clutter_input_device_get_device_id (device)); device_type = clutter_input_device_get_device_type (device); if (device_type == CLUTTER_POINTER_DEVICE || device_type == CLUTTER_PEN_DEVICE || device_type == CLUTTER_POINTER_DEVICE) { g_print ("*** enabling device '%s' ***\n", clutter_input_device_get_device_name (device)); clutter_input_device_set_enabled (device, TRUE); hand = clutter_texture_new_from_file (TESTS_DATADIR G_DIR_SEPARATOR_S "redhand.png", NULL); g_hash_table_insert (app->devices, device, hand); clutter_container_add_actor (CLUTTER_CONTAINER (stage), hand); } } clutter_main (); return EXIT_SUCCESS; }