Beispiel #1
0
/*
 * _clutter_event_new_from_evdev: Create a new Clutter ClutterKeyEvent
 * @device: a ClutterInputDevice
 * @stage: the stage the event should be delivered to
 * @xkb: XKB rules to translate the event
 * @_time: timestamp of the event
 * @key: a key code coming from a Linux input device
 * @state: TRUE if a press event, FALSE if a release event
 * @modifer_state: in/out
 *
 * Translate @key to a #ClutterKeyEvent using rules from xbbcommon.
 *
 * Return value: the new #ClutterEvent
 */
ClutterEvent *
_clutter_key_event_new_from_evdev (ClutterInputDevice *device,
				   ClutterInputDevice *core_device,
                                   ClutterStage       *stage,
                                   struct xkb_state   *xkb_state,
				   uint32_t            button_state,
                                   uint32_t            _time,
                                   xkb_keycode_t       key,
                                   uint32_t            state)
{
  ClutterEvent *event;
  xkb_keysym_t sym;
  const xkb_keysym_t *syms;
  char buffer[8];
  int n;

  if (state)
    event = clutter_event_new (CLUTTER_KEY_PRESS);
  else
    event = clutter_event_new (CLUTTER_KEY_RELEASE);

  /* We use a fixed offset of 8 because evdev starts KEY_* numbering from
   * 0, whereas X11's minimum keycode, for really stupid reasons, is 8.
   * So the evdev XKB rules are based on the keycodes all being shifted
   * upwards by 8. */
  key += 8;

  n = xkb_key_get_syms (xkb_state, key, &syms);
  if (n == 1)
    sym = syms[0];
  else
    sym = XKB_KEY_NoSymbol;

  event->key.device = core_device;
  event->key.stage = stage;
  event->key.time = _time;
  _clutter_xkb_translate_state (event, xkb_state, button_state);
  event->key.hardware_keycode = key;
  event->key.keyval = sym;
  clutter_event_set_source_device (event, device);

  n = xkb_keysym_to_utf8 (sym, buffer, sizeof (buffer));

  if (n == 0)
    {
      /* not printable */
      event->key.unicode_value = (gunichar) '\0';
    }
  else
    {
      event->key.unicode_value = g_utf8_get_char_validated (buffer, n);
      if (event->key.unicode_value == -1 || event->key.unicode_value == -2)
        event->key.unicode_value = (gunichar) '\0';
    }

  return event;
}
Beispiel #2
0
IoClutterEvent *IoClutterEvent_newWithType(void *state, ClutterEventType type) {
  IoClutterEvent *self = IoClutterEvent_new(state);
  ClutterEvent *event  = clutter_event_new(type);
  IoObject_setDataPointer_(self, event);

  return self;
}
Beispiel #3
0
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 ();

  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);
        }
      else
        {
          clutter_event_free (event);
        }
    }
}
Beispiel #4
0
static void
events_queue (ClutterBackendX11 *backend_x11)
{
  ClutterBackend *backend = CLUTTER_BACKEND (backend_x11);
  Display *xdisplay = backend_x11->xdpy;
  ClutterEvent *event;
  XEvent xevent;

  while (!clutter_events_pending () && XPending (xdisplay))
    {
      XNextEvent (xdisplay, &xevent);

      event = clutter_event_new (CLUTTER_NOTHING);

#ifdef HAVE_XGE
      XGetEventData (xdisplay, &xevent.xcookie);
#endif

      if (_clutter_backend_translate_event (backend, &xevent, event))
        _clutter_event_push (event, FALSE);
      else
        clutter_event_free (event);

#ifdef HAVE_XGE
      XFreeEventData (xdisplay, &xevent.xcookie);
#endif
    }
}
static void
clutter_wayland_handle_pointer_leave (void *data,
                                      struct wl_pointer *pointer,
                                      uint32_t serial,
                                      struct wl_surface *surface)
{
  ClutterInputDeviceWayland *device = data;
  ClutterStageCogl          *stage_cogl;
  ClutterEvent              *event;

  stage_cogl = wl_surface_get_user_data (surface);
  g_assert (device->pointer_focus == stage_cogl);

  event = clutter_event_new (CLUTTER_LEAVE);
  event->crossing.stage = stage_cogl->wrapper;
  event->crossing.time = 0; /* ?! */
  event->crossing.x = device->x;
  event->crossing.y = device->y;
  event->crossing.source = CLUTTER_ACTOR (stage_cogl->wrapper);
  event->crossing.device = CLUTTER_INPUT_DEVICE (device);

  _clutter_event_push (event, FALSE);

  device->pointer_focus = NULL;
  _clutter_input_device_set_stage (CLUTTER_INPUT_DEVICE (device), NULL);
}
/**
 * clutter_event_copy:
 * @event: A #ClutterEvent.
 *
 * Copies @event.
 *
 * Return value: A newly allocated #ClutterEvent
 */
ClutterEvent *
clutter_event_copy (ClutterEvent *event)
{
  ClutterEvent *new_event;

  g_return_val_if_fail (event != NULL, NULL);

  new_event = clutter_event_new (CLUTTER_NOTHING);
  *new_event = *event;

  /* deep copies or references must be added here */
  switch (new_event->type)
    {
    case CLUTTER_ENTER:
    case CLUTTER_LEAVE:
      if (new_event->crossing.related)
        g_object_ref (new_event->crossing.related);
      break;

    default:
      break;
    }

  return new_event;
}
Beispiel #7
0
/**
 * clutter_x11_handle_event:
 * @xevent: pointer to XEvent structure
 *
 * This function processes a single X event; it can be used to hook
 * into external X11 event processing (for example, a GDK filter
 * function).
 *
 * If clutter_x11_disable_event_retrieval() has been called, you must
 * let this function process events to update Clutter's internal state.
 *
 * Return value: #ClutterX11FilterReturn. %CLUTTER_X11_FILTER_REMOVE
 *  indicates that Clutter has internally handled the event and the
 *  caller should do no further processing. %CLUTTER_X11_FILTER_CONTINUE
 *  indicates that Clutter is either not interested in the event,
 *  or has used the event to update internal state without taking
 *  any exclusive action. %CLUTTER_X11_FILTER_TRANSLATE will not
 *  occur.
 *
 * Since: 0.8
 */
ClutterX11FilterReturn
clutter_x11_handle_event (XEvent *xevent)
{
  ClutterX11FilterReturn result;
  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
   * generated for the event. This mostly, but not entirely,
   * corresponds to whether other event processing should be
   * excluded. As long as the stage window is not shared with another
   * toolkit it should be safe, and never return
   * %CLUTTER_X11_FILTER_REMOVE when more processing is needed.
   */

  result = CLUTTER_X11_FILTER_CONTINUE;

  clutter_threads_enter ();

  backend = clutter_get_default_backend ();

  event = clutter_event_new (CLUTTER_NOTHING);

  if (_clutter_backend_translate_event (backend, xevent, event))
    {
      _clutter_event_push (event, FALSE);

      result = CLUTTER_X11_FILTER_REMOVE;
    }
  else
    {
      clutter_event_free (event);
      goto out;
    }

  /*
   * Motion events can generate synthetic enter and leave events, so if we
   * are processing a motion event, we need to spin the event loop at least
   * two extra times to pump the enter/leave events through (otherwise they
   * just get pushed down the queue and never processed).
   */
  if (event->type == CLUTTER_MOTION)
    spin += 2;

  while (spin > 0 && (event = clutter_event_get ()))
    {
      /* forward the event into clutter for emission etc. */
      clutter_do_event (event);
      clutter_event_free (event);
      --spin;
    }

out:
  clutter_threads_leave ();

  return result;
}
Beispiel #8
0
static ClutterEvent *
new_absolute_motion_event (ClutterSeatEvdev   *seat,
                           ClutterInputDevice *input_device,
                           guint64             time_us,
                           gfloat              x,
                           gfloat              y,
                           gdouble            *axes)
{
  ClutterStage *stage = _clutter_input_device_get_stage (input_device);
  ClutterEvent *event;

  event = clutter_event_new (CLUTTER_MOTION);

  if (clutter_input_device_get_device_type (input_device) != CLUTTER_TABLET_DEVICE)
    _clutter_device_manager_evdev_constrain_pointer (seat->manager_evdev,
                                                     seat->core_pointer,
                                                     time_us,
                                                     seat->pointer_x,
                                                     seat->pointer_y,
                                                     &x, &y);

  _clutter_evdev_event_set_time_usec (event, time_us);
  event->motion.time = us2ms (time_us);
  event->motion.stage = stage;
  _clutter_xkb_translate_state (event, seat->xkb, seat->button_state);
  event->motion.x = x;
  event->motion.y = y;
  event->motion.axes = axes;
  clutter_event_set_device (event, seat->core_pointer);
  clutter_event_set_source_device (event, input_device);

  if (clutter_input_device_get_device_type (input_device) == CLUTTER_TABLET_DEVICE)
    {
      ClutterInputDeviceEvdev *device_evdev =
        CLUTTER_INPUT_DEVICE_EVDEV (input_device);

      clutter_event_set_device_tool (event, device_evdev->last_tool);
      clutter_event_set_device (event, input_device);
    }
  else
    {
      clutter_event_set_device (event, seat->core_pointer);
    }

  _clutter_input_device_set_stage (seat->core_pointer, stage);

  if (clutter_input_device_get_device_type (input_device) != CLUTTER_TABLET_DEVICE)
    {
      seat->pointer_x = x;
      seat->pointer_y = y;
    }

  return event;
}
static void
clutter_wayland_handle_pointer_enter (void *data,
                                      struct wl_pointer *pointer,
                                      uint32_t serial,
                                      struct wl_surface *surface,
                                      wl_fixed_t x, wl_fixed_t y)
{
  ClutterInputDeviceWayland *device = data;
  ClutterStageCogl          *stage_cogl;
  ClutterEvent              *event;
  ClutterBackend            *backend;
  ClutterBackendWayland     *backend_wayland;

  stage_cogl = wl_surface_get_user_data (surface);

  device->pointer_focus = stage_cogl;
  _clutter_input_device_set_stage (CLUTTER_INPUT_DEVICE (device),
       stage_cogl->wrapper);

  event = clutter_event_new (CLUTTER_ENTER);
  event->crossing.stage = stage_cogl->wrapper;
  event->crossing.time = 0; /* ?! */
  event->crossing.x = wl_fixed_to_double(x);
  event->crossing.y = wl_fixed_to_double(y);
  event->crossing.source = CLUTTER_ACTOR (stage_cogl->wrapper);
  event->crossing.device = CLUTTER_INPUT_DEVICE (device);

  device->x = event->crossing.x;
  device->y = event->crossing.y;

  _clutter_event_push (event, FALSE);

  /* Set the cursor to the cursor loaded at backend initialisation */
  backend = clutter_get_default_backend ();
  backend_wayland = CLUTTER_BACKEND_WAYLAND (backend);

  wl_pointer_set_cursor (pointer,
                         serial,
                         backend_wayland->cursor_surface,
                         backend_wayland->cursor_x,
                         backend_wayland->cursor_y);
  wl_surface_attach (backend_wayland->cursor_surface,
                     backend_wayland->cursor_buffer,
                     0,
                     0);
  wl_surface_damage (backend_wayland->cursor_surface,
                     0,
                     0,
                     32, /* XXX: FFS */
                     32);

  wl_surface_commit (backend_wayland->cursor_surface);
}
Beispiel #10
0
static void
notify_scroll (ClutterInputDevice       *input_device,
               guint64                   time_us,
               gdouble                   dx,
               gdouble                   dy,
               ClutterScrollSource       scroll_source,
               ClutterScrollFinishFlags  flags,
               gboolean                  emulated)
{
  ClutterInputDeviceEvdev *device_evdev;
  ClutterSeatEvdev *seat;
  ClutterStage *stage;
  ClutterEvent *event = NULL;
  gdouble scroll_factor;

  /* We can drop the event on the floor if no stage has been
   * associated with the device yet. */
  stage = _clutter_input_device_get_stage (input_device);
  if (stage == NULL)
    return;

  device_evdev = CLUTTER_INPUT_DEVICE_EVDEV (input_device);
  seat = _clutter_input_device_evdev_get_seat (device_evdev);

  event = clutter_event_new (CLUTTER_SCROLL);

  _clutter_evdev_event_set_time_usec (event, time_us);
  event->scroll.time = us2ms (time_us);
  event->scroll.stage = CLUTTER_STAGE (stage);
  _clutter_xkb_translate_state (event, seat->xkb, seat->button_state);

  /* libinput pointer axis events are in pointer motion coordinate space.
   * To convert to Xi2 discrete step coordinate space, multiply the factor
   * 1/10. */
  event->scroll.direction = CLUTTER_SCROLL_SMOOTH;
  scroll_factor = 1.0 / DISCRETE_SCROLL_STEP;
  clutter_event_set_scroll_delta (event,
                                  scroll_factor * dx,
                                  scroll_factor * dy);

  event->scroll.x = seat->pointer_x;
  event->scroll.y = seat->pointer_y;
  clutter_event_set_device (event, seat->core_pointer);
  clutter_event_set_source_device (event, input_device);
  event->scroll.scroll_source = scroll_source;
  event->scroll.finish_flags = flags;

  _clutter_event_set_pointer_emulated (event, emulated);

  queue_event (event);
}
LRESULT CALLBACK
_clutter_stage_win32_window_proc (HWND hwnd, UINT umsg,
				  WPARAM wparam, LPARAM lparam)
{
  ClutterStageWin32 *stage_win32
    = (ClutterStageWin32 *) GetWindowLongPtrW (hwnd, 0);
  gboolean call_def_window_proc = TRUE;

  /* Ignore any messages before SetWindowLongPtr has been called to
     set the stage */
  if (stage_win32 != NULL)
    {
      ClutterBackendWin32 *backend_win32 = stage_win32->backend;
      MSG msg;
      ClutterEvent *event;
      ClutterMainContext *clutter_context;
      DWORD message_pos = GetMessagePos ();

      clutter_context = clutter_context_get_default ();

      msg.hwnd = hwnd;
      msg.message = umsg;
      msg.wParam = wparam;
      msg.lParam = lparam;
      msg.time = GetMessageTime ();
      /* Neither MAKE_POINTS nor GET_[XY]_LPARAM is defined in MinGW
	 headers so we need to convert to a signed type explicitly */
      msg.pt.x = (SHORT) LOWORD (message_pos);
      msg.pt.y = (SHORT) HIWORD (message_pos);

      event = clutter_event_new (CLUTTER_NOTHING);
	  
      if (message_translate (CLUTTER_BACKEND (backend_win32), event,
			     &msg, &call_def_window_proc))
	/* push directly here to avoid copy of queue_put */
	g_queue_push_head (clutter_context->events_queue, event);
      else
	clutter_event_free (event);
    }

  if (call_def_window_proc)
    return DefWindowProcW (hwnd, umsg, wparam, lparam);
  else
    return 0;
}
Beispiel #12
0
/* This is an IBus workaround. The flow of events with IBus is that every time
 * it gets gets a key event, it:
 *
 *  Sends it to the daemon via D-Bus asynchronously
 *  When it gets an reply, synthesizes a new GdkEvent and puts it into the
 *   GDK event queue with gdk_event_put(), including
 *   IBUS_FORWARD_MASK = 1 << 25 in the state to prevent a loop.
 *
 * (Normally, IBus uses the GTK+ key snooper mechanism to get the key
 * events early, but since our key events aren't visible to GTK+ key snoopers,
 * IBus will instead get the events via the standard
 * GtkIMContext.filter_keypress() mechanism.)
 *
 * There are a number of potential problems here; probably the worst
 * problem is that IBus doesn't forward the timestamp with the event
 * so that every key event that gets delivered ends up with
 * GDK_CURRENT_TIME.  This creates some very subtle bugs; for example
 * if you have IBus running and a keystroke is used to trigger
 * launching an application, focus stealing prevention won't work
 * right. http://code.google.com/p/ibus/issues/detail?id=1184
 *
 * In any case, our normal flow of key events is:
 *
 *  GDK filter function => clutter_x11_handle_event => clutter actor
 *
 * So, if we see a key event that gets delivered via the GDK event handler
 * function - then we know it must be one of these synthesized events, and
 * we should push it back to clutter.
 *
 * To summarize, the full key event flow with IBus is:
 *
 *   GDK filter function
 *     => Mutter
 *     => gnome_cinnamon_plugin_xevent_filter()
 *     => clutter_x11_handle_event()
 *     => clutter event delivery to actor
 *     => gtk_im_context_filter_event()
 *     => sent to IBus daemon
 *     => response received from IBus daemon
 *     => gdk_event_put()
 *     => GDK event handler
 *     => <this function>
 *     => clutter_event_put()
 *     => clutter event delivery to actor
 *
 * Anything else we see here we just pass on to the normal GDK event handler
 * gtk_main_do_event().
 */
static void
gnome_cinnamon_gdk_event_handler (GdkEvent *event_gdk,
                               gpointer  data)
{
  if (event_gdk->type == GDK_KEY_PRESS || event_gdk->type == GDK_KEY_RELEASE)
    {
      ClutterActor *stage;
      Window stage_xwindow;

      stage = clutter_stage_get_default ();
      stage_xwindow = clutter_x11_get_stage_window (CLUTTER_STAGE (stage));

      if (GDK_WINDOW_XID (event_gdk->key.window) == stage_xwindow)
        {
          ClutterDeviceManager *device_manager = clutter_device_manager_get_default ();
          ClutterInputDevice *keyboard = clutter_device_manager_get_core_device (device_manager,
                                                                                 CLUTTER_KEYBOARD_DEVICE);

          ClutterEvent *event_clutter = clutter_event_new ((event_gdk->type == GDK_KEY_PRESS) ?
                                                           CLUTTER_KEY_PRESS : CLUTTER_KEY_RELEASE);
          event_clutter->key.time = event_gdk->key.time;
          event_clutter->key.flags = CLUTTER_EVENT_NONE;
          event_clutter->key.stage = CLUTTER_STAGE (stage);
          event_clutter->key.source = NULL;

          /* This depends on ClutterModifierType and GdkModifierType being
           * identical, which they are currently. (They both match the X
           * modifier state in the low 16-bits and have the same extensions.) */
          event_clutter->key.modifier_state = event_gdk->key.state;

          event_clutter->key.keyval = event_gdk->key.keyval;
          event_clutter->key.hardware_keycode = event_gdk->key.hardware_keycode;
          event_clutter->key.unicode_value = gdk_keyval_to_unicode (event_clutter->key.keyval);
          event_clutter->key.device = keyboard;

          clutter_event_put (event_clutter);
          clutter_event_free (event_clutter);

          return;
        }
    }

  gtk_main_do_event (event_gdk);
}
Beispiel #13
0
static void
notify_discrete_scroll (ClutterInputDevice     *input_device,
                        uint64_t                time_us,
                        ClutterScrollDirection  direction,
                        ClutterScrollSource     scroll_source,
                        gboolean                emulated)
{
  ClutterInputDeviceEvdev *device_evdev;
  ClutterSeatEvdev *seat;
  ClutterStage *stage;
  ClutterEvent *event = NULL;

  if (direction == CLUTTER_SCROLL_SMOOTH)
    return;

  /* We can drop the event on the floor if no stage has been
   * associated with the device yet. */
  stage = _clutter_input_device_get_stage (input_device);
  if (stage == NULL)
    return;

  device_evdev = CLUTTER_INPUT_DEVICE_EVDEV (input_device);
  seat = _clutter_input_device_evdev_get_seat (device_evdev);

  event = clutter_event_new (CLUTTER_SCROLL);

  _clutter_evdev_event_set_time_usec (event, time_us);
  event->scroll.time = us2ms (time_us);
  event->scroll.stage = CLUTTER_STAGE (stage);
  _clutter_xkb_translate_state (event, seat->xkb, seat->button_state);

  event->scroll.direction = direction;

  event->scroll.x = seat->pointer_x;
  event->scroll.y = seat->pointer_y;
  clutter_event_set_device (event, seat->core_pointer);
  clutter_event_set_source_device (event, input_device);
  event->scroll.scroll_source = scroll_source;

  _clutter_event_set_pointer_emulated (event, emulated);

  queue_event (event);
}
Beispiel #14
0
void
clutter_seat_evdev_notify_touch_event (ClutterSeatEvdev   *seat,
                                       ClutterInputDevice *input_device,
                                       ClutterEventType    evtype,
                                       uint64_t            time_us,
                                       int                 slot,
                                       double              x,
                                       double              y)
{
  ClutterStage *stage;
  ClutterEvent *event = NULL;

  /* We can drop the event on the floor if no stage has been
   * associated with the device yet. */
  stage = _clutter_input_device_get_stage (input_device);
  if (stage == NULL)
    return;

  event = clutter_event_new (evtype);

  _clutter_evdev_event_set_time_usec (event, time_us);
  event->touch.time = us2ms (time_us);
  event->touch.stage = CLUTTER_STAGE (stage);
  event->touch.x = x;
  event->touch.y = y;
  clutter_input_device_evdev_translate_coordinates (input_device, stage,
                                                    &event->touch.x,
                                                    &event->touch.y);

  /* "NULL" sequences are special cased in clutter */
  event->touch.sequence = GINT_TO_POINTER (MAX (1, slot + 1));
  _clutter_xkb_translate_state (event, seat->xkb, seat->button_state);

  if (evtype == CLUTTER_TOUCH_BEGIN ||
      evtype == CLUTTER_TOUCH_UPDATE)
    event->touch.modifier_state |= CLUTTER_BUTTON1_MASK;

  clutter_event_set_device (event, seat->core_pointer);
  clutter_event_set_source_device (event, input_device);

  queue_event (event);
}
Beispiel #15
0
static void
events_queue (ClutterBackend *backend)
{
  ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
  Display *xdisplay = backend_x11->xdpy;
  ClutterEvent *event;
  XEvent xevent;

  while (!clutter_events_pending () && XPending (xdisplay))
    {
      XNextEvent (xdisplay, &xevent);

      event = clutter_event_new (CLUTTER_NOTHING);

      if (_clutter_backend_translate_event (backend, &xevent, event))
        _clutter_event_push (event, FALSE);
      else
        clutter_event_free (event);
    }
}
static void
clutter_wayland_handle_button (void *data,
                               struct wl_pointer *pointer,
                               uint32_t serial, uint32_t _time,
                               uint32_t button, uint32_t state)
{
  ClutterInputDeviceWayland *device = data;
  ClutterStageCogl          *stage_cogl = device->pointer_focus;
  ClutterEvent              *event;
  ClutterEventType           type;

  if (state)
    type = CLUTTER_BUTTON_PRESS;
  else
    type = CLUTTER_BUTTON_RELEASE;

  event = clutter_event_new (type);
  event->button.stage = stage_cogl->wrapper;
  event->button.device = CLUTTER_INPUT_DEVICE (device);
  event->button.time = /*_time*/ serial;
  event->button.x = device->x;
  event->button.y = device->y;
  event->button.modifier_state =
    xkb_state_serialize_mods (device->xkb, XKB_STATE_EFFECTIVE);

  /* evdev button codes */
  switch (button) {
  case 272:
    event->button.button = 1;
    break;
  case 273:
    event->button.button = 3;
    break;
  case 274:
    event->button.button = 2;
    break;
  }

  _clutter_event_push (event, FALSE);
}
Beispiel #17
0
static void
_method_cb (GDBusConnection       *connection,
            const gchar           *sender,
            const gchar           *object_path,
            const gchar           *interface_name,
            const gchar           *method_name,
            GVariant              *parameters,
            GDBusMethodInvocation *invocation,
            DbusInput             *self)
{

  if (g_strcmp0 (method_name, "ControlKey") == 0)
    {
      guint keyflag;
      ClutterEvent *event;
      ClutterKeyEvent *kevent;

      g_variant_get (parameters, "(u)", &keyflag);

      event = clutter_event_new (CLUTTER_KEY_PRESS);
      kevent = (ClutterKeyEvent *)event;

      kevent->flags = 0;
      kevent->source = NULL;
      kevent->stage = CLUTTER_STAGE (self->stage);
      kevent->keyval = keyflag;
      kevent->time = time (NULL);

      /* KEY PRESS */
      clutter_event_put (event);
      /* KEY RELEASE */
      kevent->type = CLUTTER_KEY_RELEASE;
      clutter_event_put (event);

      clutter_event_free (event);
    }

  g_dbus_method_invocation_return_value (invocation, NULL);
}
static void
clutter_wayland_handle_motion (void *data,
                               struct wl_pointer *pointer,
                               uint32_t _time,
                               wl_fixed_t x, wl_fixed_t y)
{
  ClutterInputDeviceWayland *device = data;
  ClutterStageCogl          *stage_cogl = device->pointer_focus;
  ClutterEvent              *event;

  event = clutter_event_new (CLUTTER_MOTION);
  event->motion.stage = stage_cogl->wrapper;
  event->motion.device = CLUTTER_INPUT_DEVICE (device);
  event->motion.time = _time;
  event->motion.modifier_state = 0;
  event->motion.x = wl_fixed_to_double(x);
  event->motion.y = wl_fixed_to_double(y);

  device->x = event->motion.x;
  device->y = event->motion.y;

  _clutter_event_push (event, FALSE);
}
static void
clutter_wayland_handle_axis (void *data,
                             struct wl_pointer *pointer,
                             uint32_t time,
                             uint32_t axis,
                             wl_fixed_t value)
{
  ClutterInputDeviceWayland *device = data;
  ClutterStageCogl          *stage_cogl = device->pointer_focus;
  ClutterEvent              *event;
  gdouble                    delta_x, delta_y;

  event = clutter_event_new (CLUTTER_SCROLL);
  event->scroll.time = time;
  event->scroll.stage = stage_cogl->wrapper;
  event->scroll.direction = CLUTTER_SCROLL_SMOOTH;
  event->scroll.x = device->x;
  event->scroll.y = device->y;

  if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL)
    {
      delta_x = -wl_fixed_to_double(value) * 23;
      delta_y = 0;
    }
  else
    {
      delta_x = 0;
      delta_y = -wl_fixed_to_double(value) * 23; /* XXX: based on my bcm5794 */
    }
  clutter_event_set_scroll_delta (event, delta_x, delta_y);

  event->scroll.modifier_state =
    xkb_state_serialize_mods(device->xkb, XKB_STATE_EFFECTIVE);

  _clutter_event_push (event, FALSE);
}
Beispiel #20
0
static inline void
make_button_event (const MSG *msg,
                   ClutterStage *stage,
		   int button,
                   int click_count,
                   gboolean release,
                   ClutterInputDevice *device)
{
  ClutterEvent *event = clutter_event_new (release ?
                                           CLUTTER_BUTTON_RELEASE :
                                           CLUTTER_BUTTON_PRESS);

  event->any.stage = stage;

  event->button.time = msg->time;
  event->button.x = GET_X_LPARAM (msg->lParam);
  event->button.y = GET_Y_LPARAM (msg->lParam);
  event->button.modifier_state = get_modifier_state (msg->wParam);
  event->button.button = button;
  event->button.click_count = click_count;
  clutter_event_set_device (event, device);

  take_and_queue_event (event);
}
Beispiel #21
0
/*< private >
 * clutter_input_device_set_actor:
 * @device: a #ClutterInputDevice
 * @actor: a #ClutterActor
 * @emit_crossing: %TRUE to emit crossing events
 *
 * Sets the actor under the pointer coordinates of @device
 *
 * This function is called by _clutter_input_device_update()
 * and it will:
 *
 *   - queue a %CLUTTER_LEAVE event on the previous pointer actor
 *     of @device, if any
 *   - set to %FALSE the :has-pointer property of the previous
 *     pointer actor of @device, if any
 *   - queue a %CLUTTER_ENTER event on the new pointer actor
 *   - set to %TRUE the :has-pointer property of the new pointer
 *     actor
 */
void
_clutter_input_device_set_actor (ClutterInputDevice *device,
                                 ClutterActor       *actor,
                                 gboolean            emit_crossing)
{
  ClutterActor *old_actor;

  if (device->cursor_actor == actor)
    return;

  old_actor = device->cursor_actor;

  if (old_actor != NULL)
    {
      if (emit_crossing)
        {
          ClutterEvent *event;

          event = clutter_event_new (CLUTTER_LEAVE);
          event->crossing.time = device->current_time;
          event->crossing.flags = 0;
          event->crossing.stage = device->stage;
          event->crossing.source = device->cursor_actor;
          event->crossing.x = device->current_x;
          event->crossing.y = device->current_y;
          event->crossing.related = actor;
          clutter_event_set_device (event, device);

          /* we need to make sure that this event is processed
           * before any other event we might have queued up until
           * now, so we go on, and synthesize the event emission
           * ourselves
           */
          _clutter_process_event (event);

          clutter_event_free (event);
        }

      /* processing the event might have destroyed the actor */
      if (device->cursor_actor != NULL)
        {
          _clutter_actor_set_has_pointer (device->cursor_actor, FALSE);
          g_object_weak_unref (G_OBJECT (device->cursor_actor),
                               cursor_weak_unref,
                               device);

          device->cursor_actor = NULL;
        }
    }

  if (actor != NULL)
    {
      if (emit_crossing)
        {
          ClutterEvent *event;

          event = clutter_event_new (CLUTTER_ENTER);
          event->crossing.time = device->current_time;
          event->crossing.flags = 0;
          event->crossing.stage = device->stage;
          event->crossing.x = device->current_x;
          event->crossing.y = device->current_y;
          event->crossing.source = actor;
          event->crossing.related = old_actor;
          clutter_event_set_device (event, device);

          /* see above */
          _clutter_process_event (event);

          clutter_event_free (event);
        }
    }

  device->cursor_actor = actor;
  if (device->cursor_actor != NULL)
    {
      g_object_weak_ref (G_OBJECT (device->cursor_actor),
                         cursor_weak_unref,
                         device);
      _clutter_actor_set_has_pointer (device->cursor_actor, TRUE);
    }
}
Beispiel #22
0
void
clutter_seat_evdev_notify_button (ClutterSeatEvdev   *seat,
                                  ClutterInputDevice *input_device,
                                  uint64_t            time_us,
                                  uint32_t            button,
                                  uint32_t            state)
{
  ClutterInputDeviceEvdev *device_evdev = (ClutterInputDeviceEvdev *) input_device;
  ClutterStage *stage;
  ClutterEvent *event = NULL;
  gint button_nr;
  static gint maskmap[8] =
    {
      CLUTTER_BUTTON1_MASK, CLUTTER_BUTTON3_MASK, CLUTTER_BUTTON2_MASK,
      CLUTTER_BUTTON4_MASK, CLUTTER_BUTTON5_MASK, 0, 0, 0
    };
  int button_count;

  /* Drop any repeated button press (for example from virtual devices. */
  button_count = update_button_count (seat, button, state);
  if (state && button_count > 1)
    return;
  if (!state && button_count != 0)
    return;

  /* We can drop the event on the floor if no stage has been
   * associated with the device yet. */
  stage = _clutter_input_device_get_stage (input_device);
  if (stage == NULL)
    return;

  /* The evdev button numbers don't map sequentially to clutter button
   * numbers (the right and middle mouse buttons are in the opposite
   * order) so we'll map them directly with a switch statement */
  switch (button)
    {
    case BTN_LEFT:
    case BTN_TOUCH:
      button_nr = CLUTTER_BUTTON_PRIMARY;
      break;

    case BTN_RIGHT:
    case BTN_STYLUS:
      button_nr = CLUTTER_BUTTON_SECONDARY;
      break;

    case BTN_MIDDLE:
    case BTN_STYLUS2:
      button_nr = CLUTTER_BUTTON_MIDDLE;
      break;

    case 0x149: /* BTN_STYLUS3 */
      button_nr = 8;
      break;

    default:
      /* For compatibility reasons, all additional buttons go after the old 4-7 scroll ones */
      if (clutter_input_device_get_device_type (input_device) == CLUTTER_TABLET_DEVICE)
        button_nr = button - BTN_TOOL_PEN + 4;
      else
        button_nr = button - (BTN_LEFT - 1) + 4;
      break;
    }

  if (button_nr < 1 || button_nr > 12)
    {
      g_warning ("Unhandled button event 0x%x", button);
      return;
    }

  if (state)
    event = clutter_event_new (CLUTTER_BUTTON_PRESS);
  else
    event = clutter_event_new (CLUTTER_BUTTON_RELEASE);

  if (button_nr < G_N_ELEMENTS (maskmap))
    {
      /* Update the modifiers */
      if (state)
        seat->button_state |= maskmap[button_nr - 1];
      else
        seat->button_state &= ~maskmap[button_nr - 1];
    }

  _clutter_evdev_event_set_time_usec (event, time_us);
  event->button.time = us2ms (time_us);
  event->button.stage = CLUTTER_STAGE (stage);
  _clutter_xkb_translate_state (event, seat->xkb, seat->button_state);
  event->button.button = button_nr;

  if (clutter_input_device_get_device_type (input_device) == CLUTTER_TABLET_DEVICE)
    {
      ClutterPoint point;

      clutter_input_device_get_coords (input_device, NULL, &point);
      event->button.x = point.x;
      event->button.y = point.y;
    }
  else
    {
      event->button.x = seat->pointer_x;
      event->button.y = seat->pointer_y;
    }

  clutter_event_set_device (event, seat->core_pointer);
  clutter_event_set_source_device (event, input_device);

  if (device_evdev->last_tool)
    {
      /* Apply the button event code as per the tool mapping */
      guint mapped_button;

      mapped_button = clutter_input_device_tool_evdev_get_button_code (device_evdev->last_tool,
                                                                       button_nr);
      if (mapped_button != 0)
        button = mapped_button;
    }

  _clutter_evdev_event_set_event_code (event, button);

  if (clutter_input_device_get_device_type (input_device) == CLUTTER_TABLET_DEVICE)
    {
      clutter_event_set_device_tool (event, device_evdev->last_tool);
      clutter_event_set_device (event, input_device);
    }
  else
    {
      clutter_event_set_device (event, seat->core_pointer);
    }

  _clutter_input_device_set_stage (seat->core_pointer, stage);

  queue_event (event);
}
/**
 * clutter_event_copy:
 * @event: A #ClutterEvent.
 *
 * Copies @event.
 *
 * Return value: (transfer full): A newly allocated #ClutterEvent
 */
ClutterEvent *
clutter_event_copy (const ClutterEvent *event)
{
  ClutterEvent *new_event;
  ClutterEventPrivate *new_real_event;
  ClutterInputDevice *device;
  gint n_axes = 0;

  g_return_val_if_fail (event != NULL, NULL);

  new_event = clutter_event_new (CLUTTER_NOTHING);
  new_real_event = (ClutterEventPrivate *) new_event;

  *new_event = *event;

  if (is_event_allocated (event))
    {
      ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;

      new_real_event->device = real_event->device;
      new_real_event->source_device = real_event->source_device;
      new_real_event->delta_x = real_event->delta_x;
      new_real_event->delta_y = real_event->delta_y;
    }

  device = clutter_event_get_device (event);
  if (device != NULL)
    n_axes = clutter_input_device_get_n_axes (device);

  switch (event->type)
    {
    case CLUTTER_BUTTON_PRESS:
    case CLUTTER_BUTTON_RELEASE:
      if (event->button.axes != NULL)
        new_event->button.axes = g_memdup (event->button.axes,
                                           sizeof (gdouble) * n_axes);
      break;

    case CLUTTER_SCROLL:
      if (event->scroll.axes != NULL)
        new_event->scroll.axes = g_memdup (event->scroll.axes,
                                           sizeof (gdouble) * n_axes);
      break;

    case CLUTTER_MOTION:
      if (event->motion.axes != NULL)
        new_event->motion.axes = g_memdup (event->motion.axes,
                                           sizeof (gdouble) * n_axes);
      break;

    case CLUTTER_TOUCH_BEGIN:
    case CLUTTER_TOUCH_UPDATE:
    case CLUTTER_TOUCH_END:
    case CLUTTER_TOUCH_CANCEL:
      if (event->touch.axes != NULL)
        new_event->touch.axes = g_memdup (event->touch.axes,
                                          sizeof (gdouble) * n_axes);
      break;

    default:
      break;
    }

  if (is_event_allocated (event))
    _clutter_backend_copy_event_data (clutter_get_default_backend (),
                                      event,
                                      new_event);

  return new_event;
}
/**
 * clutter_gdk_handle_event:
 * @event: a #GdkEvent
 *
 * This function processes a single GDK event; it can be used to hook
 * into external event processing
 *
 * Return value: #GdkFilterReturn. %GDK_FILTER_REMOVE indicates that
 *  Clutter has internally handled the event and the caller should do
 *  no further processing. %GDK_FILTER_CONTINUE indicates that Clutter
 *  is either not interested in the event, or has used the event to
 *  update internal state without taking any exclusive action.
 *  %GDK_FILTER_TRANSLATE will not occur.
 *
 */
GdkFilterReturn
clutter_gdk_handle_event (GdkEvent *gdk_event)
{
  ClutterDeviceManager *device_manager;
  ClutterBackendGdk *backend_gdk;
  ClutterBackend *backend;
  ClutterStage *stage = NULL;
  ClutterEvent *event = NULL;
  gint spin = 0;
  GdkFilterReturn result = GDK_FILTER_CONTINUE;
  ClutterInputDevice *device, *source_device;
  GdkDevice *gdk_device;

  backend = clutter_get_default_backend ();
  if (!CLUTTER_IS_BACKEND_GDK (backend))
    return GDK_FILTER_CONTINUE;

  if (gdk_event->any.window == NULL)
    return GDK_FILTER_CONTINUE;

  device_manager = clutter_device_manager_get_default ();
  if (G_UNLIKELY (device_manager == NULL))
    return GDK_FILTER_CONTINUE;

  backend_gdk = CLUTTER_BACKEND_GDK (backend);
  stage = clutter_gdk_get_stage_from_window (gdk_event->any.window);

  gdk_device = gdk_event_get_device (gdk_event);
  if (gdk_device != NULL)
    device = _clutter_device_manager_gdk_lookup_device (device_manager,
                                                        gdk_device);
  else
    device = NULL;

  gdk_device = gdk_event_get_source_device (gdk_event);
  if (gdk_device != NULL)
    source_device = _clutter_device_manager_gdk_lookup_device (device_manager,
                                                               gdk_device);
  else
    source_device = NULL;

  if (stage == NULL)
    return GDK_FILTER_CONTINUE;

  _clutter_threads_acquire_lock ();

  switch (gdk_event->type)
    {
    case GDK_DELETE:
      event = clutter_event_new (CLUTTER_DELETE);
      break;

    case GDK_DESTROY:
      event = clutter_event_new (CLUTTER_DESTROY_NOTIFY);
      break;

    case GDK_EXPOSE:
      {
        ClutterPaintVolume clip;
        ClutterVertex origin;

        CLUTTER_NOTE (EVENT, "Expose for stage '%s' [%p] { %d, %d - %d x %d }",
                      _clutter_actor_get_debug_name (CLUTTER_ACTOR (stage)),
                      stage,
                      gdk_event->expose.area.x,
                      gdk_event->expose.area.y,
                      gdk_event->expose.area.width,
                      gdk_event->expose.area.height);

        origin.x = gdk_event->expose.area.x;
        origin.y = gdk_event->expose.area.y;
        origin.z = 0;

        _clutter_paint_volume_init_static (&clip, CLUTTER_ACTOR (stage));

        clutter_paint_volume_set_origin (&clip, &origin);
        clutter_paint_volume_set_width (&clip, gdk_event->expose.area.width);
        clutter_paint_volume_set_height (&clip, gdk_event->expose.area.height);

        _clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stage), 0, &clip);

        clutter_paint_volume_free (&clip);
      }
      break;

    case GDK_DAMAGE:
      /* This is handled by cogl */
      break;

    case GDK_MOTION_NOTIFY:
      event = clutter_event_new (CLUTTER_MOTION);
      event->motion.time = gdk_event->motion.time;
      event->motion.x = gdk_event->motion.x;
      event->motion.y = gdk_event->motion.y;
      event->motion.axes = NULL;
      /* It's all X in the end, right? */
      event->motion.modifier_state = gdk_event->motion.state;
      clutter_event_set_device (event, device);
      clutter_event_set_source_device (event, source_device);
      CLUTTER_NOTE (EVENT, "Motion notifiy [%.2f, %.2f]",
                    event->motion.x,
                    event->motion.y);
      break;

    case GDK_BUTTON_PRESS:
    case GDK_BUTTON_RELEASE:
      event = clutter_event_new (gdk_event->type == GDK_BUTTON_PRESS ?
                                 CLUTTER_BUTTON_PRESS :
                                 CLUTTER_BUTTON_RELEASE);
      event->button.time = gdk_event->button.time;
      event->button.x = gdk_event->button.x;
      event->button.y = gdk_event->button.y;
      event->button.axes = NULL;
      event->button.modifier_state = gdk_event->button.state;
      event->button.button = gdk_event->button.button;
      event->button.click_count = 1;
      clutter_event_set_device (event, device);
      clutter_event_set_source_device (event, source_device);
      CLUTTER_NOTE (EVENT, "Button %d %s [%.2f, %.2f]",
                    event->button.button,
                    event->type == CLUTTER_BUTTON_PRESS ? "press" : "release",
                    event->button.x,
                    event->button.y);
      break;

    case GDK_2BUTTON_PRESS:
    case GDK_3BUTTON_PRESS:
      /* these are handled by clutter-main.c updating click_count */
      break;

    case GDK_KEY_PRESS:
    case GDK_KEY_RELEASE:
      event = clutter_event_new (gdk_event->type == GDK_KEY_PRESS ?
                                 CLUTTER_KEY_PRESS :
                                 CLUTTER_KEY_RELEASE);
      event->key.time = gdk_event->key.time;
      event->key.modifier_state = gdk_event->key.state;
      event->key.keyval = gdk_event->key.keyval;
      event->key.hardware_keycode = gdk_event->key.hardware_keycode;
      event->key.unicode_value = g_utf8_get_char (gdk_event->key.string);
      clutter_event_set_device (event, device);
      clutter_event_set_source_device (event, source_device);
      CLUTTER_NOTE (EVENT, "Key %d %s",
                    event->key.keyval,
                    event->type == CLUTTER_KEY_PRESS ? "press" : "release");
      break;

    case GDK_ENTER_NOTIFY:
    case GDK_LEAVE_NOTIFY:
      event = clutter_event_new (gdk_event->type == GDK_ENTER_NOTIFY ?
                                 CLUTTER_ENTER :
                                 CLUTTER_LEAVE);
      event->crossing.source = CLUTTER_ACTOR (stage);
      event->crossing.time = gdk_event_get_time (gdk_event);
      event->crossing.x = gdk_event->crossing.x;
      event->crossing.y = gdk_event->crossing.y;

      /* XXX: no better fallback here? */
      clutter_event_set_device (event, device);
      clutter_event_set_source_device (event, source_device);
      if (gdk_event->type == GDK_ENTER_NOTIFY)
        _clutter_input_device_set_stage (clutter_event_get_device (event), stage);
      else
        _clutter_input_device_set_stage (clutter_event_get_device (event), NULL);
      CLUTTER_NOTE (EVENT, "Crossing %s [%.2f, %.2f]",
                    event->type == CLUTTER_ENTER ? "enter" : "leave",
                    event->crossing.x,
                    event->crossing.y);
      break;

    case GDK_FOCUS_CHANGE:
      if (gdk_event->focus_change.in)
        _clutter_stage_update_state (stage, 0, CLUTTER_STAGE_STATE_ACTIVATED);
      else
        _clutter_stage_update_state (stage, CLUTTER_STAGE_STATE_ACTIVATED, 0);
      break;

    case GDK_CONFIGURE:
      {
        gfloat w, h;

        clutter_actor_get_size (CLUTTER_ACTOR (stage), &w, &h);

        if (w != gdk_event->configure.width ||
            h != gdk_event->configure.height)
          {
            clutter_actor_set_size (CLUTTER_ACTOR (stage),
                                    gdk_event->configure.width,
                                    gdk_event->configure.height);
          }
      }
      break;

    case GDK_SCROLL:
      event = clutter_event_new (CLUTTER_SCROLL);
      event->scroll.time = gdk_event->scroll.time;
      event->scroll.x = gdk_event->scroll.x;
      event->scroll.y = gdk_event->scroll.y;
      event->scroll.modifier_state = gdk_event->scroll.state;
      event->scroll.axes = NULL;
      /* XXX: must keep ClutterScrollDirection compatible with GdkScrollDirection */
      event->scroll.direction = (ClutterScrollDirection) gdk_event->scroll.direction;
      clutter_event_set_device (event, device);
      clutter_event_set_source_device (event, source_device);
      clutter_event_set_scroll_delta (event,
                                      gdk_event->scroll.delta_x,
                                      gdk_event->scroll.delta_y);
      break;

    case GDK_WINDOW_STATE:
      if (gdk_event->window_state.changed_mask & GDK_WINDOW_STATE_FULLSCREEN)
        {
          gboolean is_fullscreen;

          is_fullscreen = (gdk_event->window_state.new_window_state & GDK_WINDOW_STATE_FULLSCREEN) != 0;
          if (is_fullscreen)
            _clutter_stage_update_state (stage, 0, CLUTTER_STAGE_STATE_FULLSCREEN);
          else
            _clutter_stage_update_state (stage, CLUTTER_STAGE_STATE_FULLSCREEN, 0);
        }
      break;

    case GDK_SETTING:
      _clutter_backend_gdk_update_setting (backend_gdk, gdk_event->setting.name);
      break;

    default:
      break;
    }

  if (event != NULL)
    {
      event->any.stage = stage;

      if (gdk_event->any.send_event)
	event->any.flags = CLUTTER_EVENT_FLAG_SYNTHETIC;

      _clutter_event_push (event, FALSE);

      spin = 1;

      CLUTTER_NOTE (EVENT, "Translated one event from Gdk");

      /* handle also synthetic enter/leave events */
      if (event->type == CLUTTER_MOTION)
	spin += 2;

      while (spin > 0 && (event = clutter_event_get ()))
	{
	  /* forward the event into clutter for emission etc. */
	  clutter_do_event (event);
	  clutter_event_free (event);
	  --spin;
	}

      result = GDK_FILTER_REMOVE;
    }

  _clutter_threads_release_lock ();

  return result;
}
Beispiel #25
0
/**
 * clutter_x11_handle_event:
 * @xevent: pointer to XEvent structure
 *
 * This function processes a single X event; it can be used to hook
 * into external X11 event processing (for example, a GDK filter
 * function).
 *
 * If clutter_x11_disable_event_retrieval() has been called, you must
 * let this function process events to update Clutter's internal state.
 *
 * Return value: #ClutterX11FilterReturn. %CLUTTER_X11_FILTER_REMOVE
 *  indicates that Clutter has internally handled the event and the
 *  caller should do no further processing. %CLUTTER_X11_FILTER_CONTINUE
 *  indicates that Clutter is either not interested in the event,
 *  or has used the event to update internal state without taking
 *  any exclusive action. %CLUTTER_X11_FILTER_TRANSLATE will not
 *  occur.
 *
 * Since: 0.8
 */
ClutterX11FilterReturn
clutter_x11_handle_event (XEvent *xevent)
{
  ClutterX11FilterReturn result;
  ClutterBackend *backend;
  ClutterEvent *event;
  gint spin = 1;
#ifdef HAVE_XGE
  ClutterBackendX11 *backend_x11;
  Display *xdisplay;
  gboolean allocated_event;
#endif

  /* The return values here are someone approximate; we return
   * CLUTTER_X11_FILTER_REMOVE if a clutter event is
   * generated for the event. This mostly, but not entirely,
   * corresponds to whether other event processing should be
   * excluded. As long as the stage window is not shared with another
   * toolkit it should be safe, and never return
   * %CLUTTER_X11_FILTER_REMOVE when more processing is needed.
   */

  result = CLUTTER_X11_FILTER_CONTINUE;

  _clutter_threads_acquire_lock ();

  backend = clutter_get_default_backend ();

  event = clutter_event_new (CLUTTER_NOTHING);

#ifdef HAVE_XGE
  backend_x11 = CLUTTER_BACKEND_X11 (backend);
  xdisplay = backend_x11->xdpy;

  allocated_event = XGetEventData (xdisplay, &xevent->xcookie);
#endif

  if (_clutter_backend_translate_event (backend, xevent, event))
    {
      _clutter_event_push (event, FALSE);

      result = CLUTTER_X11_FILTER_REMOVE;
    }
  else
    {
      clutter_event_free (event);
      goto out;
    }

  /*
   * Motion events can generate synthetic enter and leave events, so if we
   * are processing a motion event, we need to spin the event loop at least
   * two extra times to pump the enter/leave events through (otherwise they
   * just get pushed down the queue and never processed).
   */
  if (event->type == CLUTTER_MOTION)
    spin += 2;

  while (spin > 0 && (event = clutter_event_get ()))
    {
      /* forward the event into clutter for emission etc. */
      _clutter_stage_queue_event (event->any.stage, event, FALSE);
      --spin;
    }

out:
#ifdef HAVE_XGE
  if (allocated_event)
    XFreeEventData (xdisplay, &xevent->xcookie);
#endif

  _clutter_threads_release_lock ();

  return result;
}
/* Dragged actor moved */
static void _xfdashboard_drag_action_drag_motion(ClutterDragAction *inAction,
													ClutterActor *inActor,
													gfloat inDeltaX,
													gfloat inDeltaY)
{
	XfdashboardDragAction				*self;
	XfdashboardDragActionPrivate		*priv;
	ClutterDragActionClass				*dragActionClass;
	gfloat								stageX, stageY;
	XfdashboardDropAction				*dropTarget;
	gfloat								dropX, dropY;
	const ClutterEvent					*event;

	g_return_if_fail(XFDASHBOARD_IS_DRAG_ACTION(inAction));

	self=XFDASHBOARD_DRAG_ACTION(inAction);
	priv=self->priv;
	dragActionClass=CLUTTER_DRAG_ACTION_CLASS(xfdashboard_drag_action_parent_class);

	/* Call parent's class method */
	if(dragActionClass->drag_motion) dragActionClass->drag_motion(inAction, inActor, inDeltaX, inDeltaY);

	/* Remember motion delta coordinates */
	priv->lastDeltaX=inDeltaX;
	priv->lastDeltaY=inDeltaY;

	/* Get event coordinates relative to stage */
	clutter_drag_action_get_motion_coords(inAction, &stageX, &stageY);

	/* Find drop target at stage coordinate */
	dropTarget=_xfdashboard_drag_action_find_drop_traget_at_coord(self, stageX, stageY);

	/* If found drop target is not the same as the last one emit "drag-leave"
	 * signal at last drop target and "drag-enter" in new drop target
	 */
	if(priv->lastDropTarget!=dropTarget)
	{
		/* Emit "drag-leave" signal on last drop target */
		if(priv->lastDropTarget)
		{
			g_signal_emit_by_name(priv->lastDropTarget, "drag-leave", self, NULL);
			priv->lastDropTarget=NULL;
		}

		/* Check if new drop target is active and emit "drag-enter" signal */
		if(dropTarget)
		{
			ClutterActorMeta			*actorMeta=CLUTTER_ACTOR_META(dropTarget);
			ClutterActor				*dropActor=clutter_actor_meta_get_actor(actorMeta);

			if(clutter_actor_meta_get_enabled(actorMeta) &&
				clutter_actor_is_visible(dropActor) &&
				clutter_actor_get_reactive(dropActor))
			{
				g_signal_emit_by_name(dropTarget, "drag-enter", self, NULL);
				priv->lastDropTarget=dropTarget;
			}
		}
	}

	/* Transform event coordinates relative to last drop target which
	 * should be the drop target under pointer device if it is active
	 * and emit "drag-motion" signal
	 */
	if(priv->lastDropTarget)
	{
		dropX=dropY=0.0f;
		_xfdashboard_drag_action_transform_stage_point(priv->lastDropTarget,
														stageX, stageY,
														&dropX, &dropY);
		g_signal_emit_by_name(priv->lastDropTarget, "drag-motion", self, dropX, dropY, NULL);
	}

	/* We are derived from ClutterDragAction and this one disables stage motion
	 * so no "enter-event", "motion-event" and "leave-event" will be emitted while
	 * dragging. We need to do it on our own.
	 */
	event=clutter_get_current_event();
	if(event && clutter_event_type(event)==CLUTTER_MOTION)
	{
		GSList							*list, *next;
		ClutterStage					*stage;
		ClutterActor					*motionActor;
		gboolean						newMotionActor;
		ClutterActor					*actor;
		gfloat							x, y, w, h;
		gboolean						result;
		ClutterEvent					*actorEvent;

		/* Get stage where event happened */
		stage=clutter_event_get_stage(event);
		if(stage)
		{
			/* Get actor under pointer */
			newMotionActor=TRUE;
			motionActor=clutter_stage_get_actor_at_pos(stage,
														CLUTTER_PICK_REACTIVE,
														stageX, stageY);

			/* Iterate through list of crossed actors so far and check if pointer
			 * is still inside. If pointer is outside of an actor emit "leave-event".
			 * For each actor the pointer is still inside emit this "motion-event".
			 * Also check if actor under pointer is already is list to prevent
			 * "enter-event" to be emitted more than once.
			 */
			list=priv->lastMotionActors;
			while(list)
			{
				/* Get next entry now as this entry might get deleted */
				next=g_slist_next(list);

				/* Get actor from entry */
				actor=CLUTTER_ACTOR(list->data);

				/* Actor must be one same stage where event happened */
				if(clutter_actor_get_stage(actor)!=CLUTTER_ACTOR(stage)) continue;

				/* Get position and size of actor in stage coordinates */
				clutter_actor_get_transformed_position(actor, &x, &y);
				clutter_actor_get_transformed_size(actor, &w, &h);

				/* Check if pointer is still inside actor */
				if(stageX>=x && stageX<(x+w) &&
					stageY>=y && stageY<(y+h))
				{

					/* Check if actor is the "new" motion actor. If so set flag. */
					if(actor==motionActor) newMotionActor=FALSE;

					/* Emit "motion-event" */
					actorEvent=clutter_event_copy(event);
					actorEvent->motion.source=actor;

					g_signal_emit_by_name(actor, "motion-event", actorEvent, &result);

					clutter_event_free(actorEvent);
				}
					/* Pointer is not inside actor anymore so remove actor from list
					 * of last known "motion actors" and send "leave-event"
					 */
					else
					{
						/* Disconnect signal */
						g_signal_handlers_disconnect_by_func(actor, G_CALLBACK(_xfdashboard_drag_action_on_motion_actor_destroyed), self);

						/* Remove from list */
						priv->lastMotionActors=g_slist_remove_link(priv->lastMotionActors, list);
						g_slist_free_1(list);

						/* Create and emit "leave-event" */
						actorEvent=clutter_event_new(CLUTTER_LEAVE);
						actorEvent->crossing.time=event->motion.time;
						actorEvent->crossing.flags=event->motion.flags;
						actorEvent->crossing.stage=event->motion.stage;
						actorEvent->crossing.source=actor;

						actorEvent->crossing.x=event->motion.x;
						actorEvent->crossing.y=event->motion.y;
						actorEvent->crossing.device=event->motion.device;
						actorEvent->crossing.related=event->motion.source;

						g_signal_emit_by_name(actor, "leave-event", actorEvent, &result);

						clutter_event_free(actorEvent);
					}

				/* Proceed with next actor */
				list=next;
			}

			/* We have an actor under pointer and was not seen while iterating
			 * through list of all last known "motion actors" then add this actor
			 * to list and emit "enter-event" and also all parent actors because
			 * if pointer is inside their child then it is also inside them.
			 */
			if(motionActor && newMotionActor)
			{
				while(motionActor)
				{
					/* Avoid duplicates */
					if(!g_slist_find(priv->lastMotionActors, motionActor))
					{
						/* Add to list */
						priv->lastMotionActors=g_slist_append(priv->lastMotionActors, motionActor);

						/* Create and emit "enter-event" */
						actorEvent=clutter_event_new(CLUTTER_ENTER);
						actorEvent->crossing.time=event->motion.time;
						actorEvent->crossing.flags=event->motion.flags;
						actorEvent->crossing.stage=event->motion.stage;
						actorEvent->crossing.source=event->motion.source;

						actorEvent->crossing.x=event->motion.x;
						actorEvent->crossing.y=event->motion.y;
						actorEvent->crossing.device=event->motion.device;
						actorEvent->crossing.related=motionActor;

						g_signal_emit_by_name(motionActor, "enter-event", actorEvent, &result);

						clutter_event_free(actorEvent);

						/* To prevent emiting these motion events on actors being
						 * destroyed while drag is in progress we connect to 'destroy'
						 * signal of each "motion actor" added to list. The signal
						 * handler will be removed either on actor's destruction by
						 * signal handler's callback, when pointer leaves actor or on
						 * end of drag.
						 */
						g_signal_connect(motionActor, "destroy", G_CALLBACK(_xfdashboard_drag_action_on_motion_actor_destroyed), self);
					}

					/* Get parent */
					motionActor=clutter_actor_get_parent(motionActor);
				}
			}
		}
	}
}
Beispiel #27
0
/**
 * clutter_win32_handle_event:
 * @msg: A pointer to a structure describing a Win32 message.
 *
 * This function processes a single Win32 message. It can be used to
 * hook into external windows message processing (for example, a GDK
 * filter function).
 *
 * If clutter_win32_disable_event_retrieval() has been called, you must
 * let this function process events to update Clutter's internal state.
 *
 * Return value: %TRUE if the message was handled entirely by Clutter
 * and no further processing (such as calling the default window
 * procedure) should take place. %FALSE is returned if is the message
 * was not handled at all or if Clutter expects processing to take
 * place.
 *
 * Since: 1.6
 */
gboolean
clutter_win32_handle_event (const MSG *msg)
{
  ClutterBackendWin32  *backend_win32;
  ClutterStageWin32    *stage_win32;
  ClutterDeviceManager *manager;
  ClutterInputDevice   *core_pointer, *core_keyboard;
  ClutterStage         *stage;
  ClutterStageWindow   *impl;
  gboolean              return_value = FALSE;

  stage = clutter_win32_get_stage_from_window (msg->hwnd);

  /* Ignore any messages for windows which we don't have a stage for */
  if (stage == NULL)
    return FALSE;

  impl = _clutter_stage_get_window (stage);
  stage_win32 = CLUTTER_STAGE_WIN32 (impl);
  backend_win32 = stage_win32->backend;

  manager = clutter_device_manager_get_default ();
  core_pointer =
    clutter_device_manager_get_core_device (manager, CLUTTER_POINTER_DEVICE);
  core_keyboard =
    clutter_device_manager_get_core_device (manager, CLUTTER_KEYBOARD_DEVICE);

  switch (msg->message)
    {
    case WM_SIZE:
      if (!stage_win32->is_foreign_win
	  /* Ignore size changes resulting from the stage being
	     minimized - otherwise the window size will be set to
	     0,0 */
	  && msg->wParam != SIZE_MINIMIZED)
	{
	  WORD new_width = LOWORD (msg->lParam);
	  WORD new_height = HIWORD (msg->lParam);
	  gfloat old_width, old_height;

	  clutter_actor_get_size (CLUTTER_ACTOR (stage),
				  &old_width, &old_height);

	  if (new_width != old_width || new_height != old_height)
	    clutter_actor_set_size (CLUTTER_ACTOR (stage),
				    new_width, new_height);
	}
      break;

    case WM_SHOWWINDOW:
      if (msg->wParam)
	clutter_stage_win32_map (stage_win32);
      else
	clutter_stage_win32_unmap (stage_win32);
      break;

    case WM_ACTIVATE:
      if (msg->wParam == WA_INACTIVE)
        {
          if (stage_win32->state & CLUTTER_STAGE_STATE_ACTIVATED)
            {
              ClutterEvent *event = clutter_event_new (CLUTTER_STAGE_STATE);

              stage_win32->state &= ~CLUTTER_STAGE_STATE_ACTIVATED;

              event->any.stage = stage;
              event->stage_state.changed_mask = CLUTTER_STAGE_STATE_ACTIVATED;
              event->stage_state.new_state = stage_win32->state;

              take_and_queue_event (event);
            }
        }
      else if (!(stage_win32->state & CLUTTER_STAGE_STATE_ACTIVATED))
        {
          ClutterEvent *event = clutter_event_new (CLUTTER_STAGE_STATE);

          stage_win32->state |= CLUTTER_STAGE_STATE_ACTIVATED;

          event->any.stage = stage;
          event->stage_state.changed_mask = CLUTTER_STAGE_STATE_ACTIVATED;
          event->stage_state.new_state = stage_win32->state;

          take_and_queue_event (event);
        }
      break;

    case WM_PAINT:
      CLUTTER_NOTE (MULTISTAGE, "expose for stage:%p, redrawing", stage);
      clutter_redraw (stage);
      break;

    case WM_DESTROY:
      {
        ClutterEvent *event = clutter_event_new (CLUTTER_DESTROY_NOTIFY);

        CLUTTER_NOTE (EVENT, "WM_DESTROY");

        event->any.stage = stage;

        take_and_queue_event (event);
      }
      break;

    case WM_CLOSE:
      {
        ClutterEvent *event = clutter_event_new (CLUTTER_DELETE);

        CLUTTER_NOTE (EVENT, "WM_CLOSE");

        event->any.stage = stage;

        take_and_queue_event (event);

        /* The default window proc will destroy the window so we want to
           prevent this to allow applications to optionally destroy the
           window themselves */
        return_value = TRUE;
      }
      break;

    case WM_LBUTTONDOWN:
      make_button_event (msg, stage, 1, 1, FALSE, core_pointer);
      break;

    case WM_MBUTTONDOWN:
      make_button_event (msg, stage, 2, 1, FALSE, core_pointer);
      break;

    case WM_RBUTTONDOWN:
      make_button_event (msg, stage, 3, 1, FALSE, core_pointer);
      break;

    case WM_LBUTTONUP:
      make_button_event (msg, stage, 1, 1, TRUE, core_pointer);
      break;

    case WM_MBUTTONUP:
      make_button_event (msg, stage, 2, 1, TRUE, core_pointer);
      break;

    case WM_RBUTTONUP:
      make_button_event (msg, stage, 3, 1, TRUE, core_pointer);
      break;

    case WM_LBUTTONDBLCLK:
      make_button_event (msg, stage, 1, 2, FALSE, core_pointer);
      break;

    case WM_MBUTTONDBLCLK:
      make_button_event (msg, stage, 2, 2, FALSE, core_pointer);
      break;

    case WM_RBUTTONDBLCLK:
      make_button_event (msg, stage, 3, 2, FALSE, core_pointer);
      break;

    case WM_MOUSEWHEEL:
      stage_win32->scroll_pos += (SHORT) HIWORD (msg->wParam);

      while (abs (stage_win32->scroll_pos) >= WHEEL_DELTA)
        {
          ClutterEvent *event = clutter_event_new (CLUTTER_SCROLL);
          POINT pt;

          event->scroll.time = msg->time;
          event->scroll.modifier_state =
            get_modifier_state (LOWORD (msg->wParam));
          event->any.stage = stage;

          clutter_event_set_device (event, core_pointer);

          /* conversion to window coordinates is required */
          pt.x = GET_X_LPARAM (msg->lParam);
          pt.y = GET_Y_LPARAM (msg->lParam);
          ScreenToClient (msg->hwnd, &pt);
          event->scroll.x = pt.x;
          event->scroll.y = pt.y;

          if (stage_win32->scroll_pos > 0)
            {
              event->scroll.direction = CLUTTER_SCROLL_UP;
              stage_win32->scroll_pos -= WHEEL_DELTA;
            }
          else
            {
              event->scroll.direction = CLUTTER_SCROLL_DOWN;
              stage_win32->scroll_pos += WHEEL_DELTA;
            }

          take_and_queue_event (event);
        }
      break;

    case WM_MOUSEMOVE:
      {
        ClutterEvent *event = clutter_event_new (CLUTTER_MOTION);

        event->motion.time = msg->time;
        event->motion.x = GET_X_LPARAM (msg->lParam);
        event->motion.y = GET_Y_LPARAM (msg->lParam);
        event->motion.modifier_state = get_modifier_state (msg->wParam);
        event->any.stage = stage;

        clutter_event_set_device (event, core_pointer);

        /* We need to start tracking when the mouse enters the stage if
           we're not already */
        if (!stage_win32->tracking_mouse)
          {
            ClutterEvent *crossing = clutter_event_new (CLUTTER_ENTER);
            TRACKMOUSEEVENT tmevent;

            tmevent.cbSize = sizeof (tmevent);
            tmevent.dwFlags = TME_LEAVE;
            tmevent.hwndTrack = stage_win32->hwnd;
            TrackMouseEvent (&tmevent);

            event->crossing.time = msg->time;
            event->crossing.x = event->motion.x;
            event->crossing.y = event->motion.y;
            event->crossing.stage = stage;
            event->crossing.source = CLUTTER_ACTOR (stage);
            event->crossing.related = NULL;

            clutter_event_set_device (event, core_pointer);

            /* we entered the stage */
            _clutter_stage_add_device (stage, event->crossing.device);

            take_and_queue_event (crossing);

            stage_win32->tracking_mouse = TRUE;
          }

        take_and_queue_event (event);
      }
      break;

    case WM_MOUSELEAVE:
      {
        ClutterEvent *event = clutter_event_new (CLUTTER_LEAVE);

        event->crossing.time = msg->time;
        event->crossing.x = msg->pt.x;
        event->crossing.y = msg->pt.y;
        event->crossing.stage = stage;
        event->crossing.source = CLUTTER_ACTOR (stage);
        event->crossing.related = NULL;

        clutter_event_set_device (event, core_pointer);

        /* we left the stage */
        _clutter_stage_remove_device (stage, core_pointer);

        /* When we get a leave message the mouse tracking is
           automatically cancelled so we'll need to start it again when
           the mouse next enters the window */
        stage_win32->tracking_mouse = FALSE;

        take_and_queue_event (event);
      }
      break;

    case WM_KEYDOWN:
    case WM_KEYUP:
    case WM_SYSKEYDOWN:
    case WM_SYSKEYUP:
      {
        ClutterEvent *event = clutter_event_new (CLUTTER_EVENT_NONE);
	int scan_code = (msg->lParam >> 16) & 0xff;
	int min = 0, max = CLUTTER_WIN32_KEY_MAP_SIZE, mid;
	BYTE key_states[256];

	/* Get the keyboard modifier states. GetKeyboardState
	   conveniently gets the key state that was current when the
	   last keyboard message read was generated */
	GetKeyboardState(key_states);

	/* Binary chop to check if we have a direct mapping for this
	   key code */
	while (min < max)
	  {
	    mid = (min + max) / 2;
	    if (clutter_win32_key_map[mid].win_sym == msg->wParam)
	      {
		event->key.keyval = clutter_win32_key_map[mid].clutter_sym;
		event->key.unicode_value = 0;
		break;
	      }
	    else if (clutter_win32_key_map[mid].win_sym < msg->wParam)
	      min = mid + 1;
	    else
	      max = mid;
	  }

	/* If we don't have a direct mapping then try getting the
	   unicode value of the key sym */
	if (min >= max)
	  {
	    WCHAR ch;
	    BYTE shift_state[256];

	    /* Translate to a Unicode value, but only take into
	       account the shift key. That way Ctrl+Shift+C will
	       generate a capital C virtual key code with a zero
	       unicode value for example */
	    memset (shift_state, 0, 256);
	    shift_state[VK_SHIFT] = key_states[VK_SHIFT];
	    shift_state[VK_LSHIFT] = key_states[VK_LSHIFT];
	    shift_state[VK_RSHIFT] = key_states[VK_RSHIFT];
	    shift_state[VK_CAPITAL] = key_states[VK_CAPITAL];

	    if (ToUnicode (msg->wParam, scan_code,
			   shift_state, &ch, 1, 0) == 1
		/* The codes in this range directly match the Latin 1
		   codes so we can just use the Unicode value as the
		   key sym */
		&& ch >= 0x20 && ch <= 0xff)
	      event->key.keyval = ch;
	    else
	      /* Otherwise we don't know what the key means but the
		 application might be able to do something with the
		 scan code so we might as well still generate the
		 event */
	      event->key.keyval = CLUTTER_KEY_VoidSymbol;

	    /* Get the unicode value of the keypress again using the
	       full modifier state */
	    if (ToUnicode (msg->wParam, scan_code,
			   key_states, &ch, 1, 0) == 1)
		event->key.unicode_value = ch;
	    else
		event->key.unicode_value = 0;
	  }

	event->key.type = msg->message == WM_KEYDOWN
	  || msg->message == WM_SYSKEYDOWN
	  ? CLUTTER_KEY_PRESS : CLUTTER_KEY_RELEASE;
	event->key.time = msg->time;
	event->key.modifier_state = get_key_modifier_state (key_states);
	event->key.hardware_keycode = scan_code;
        event->any.stage = stage;

        clutter_event_set_device (event, core_keyboard);

        take_and_queue_event (event);
      }
      break;

    case WM_GETMINMAXINFO:
      {
	MINMAXINFO *min_max_info = (MINMAXINFO *) msg->lParam;
	_clutter_stage_win32_get_min_max_info (stage_win32, min_max_info);
        return_value = TRUE;
      }
      break;

    case WM_SETCURSOR:
      /* If the cursor is in the window's client area and the stage's
         cursor should be invisible then we'll set a blank cursor
         instead */
      if (LOWORD (msg->lParam) == HTCLIENT && !stage_win32->is_cursor_visible)
        {
          return_value = TRUE;
          _clutter_stage_win32_update_cursor (stage_win32);
        }
      break;
    }

  return return_value;
}
Beispiel #28
0
/**
 * clutter_x11_handle_event:
 * @xevent: pointer to XEvent structure
 *
 * This function processes a single X event; it can be used to hook
 * into external X event retrieval (for example that done by GDK).
 *
 * Return value: #ClutterX11FilterReturn. %CLUTTER_X11_FILTER_REMOVE
 *  indicates that Clutter has internally handled the event and the
 *  caller should do no further processing. %CLUTTER_X11_FILTER_CONTINUE
 *  indicates that Clutter is either not interested in the event,
 *  or has used the event to update internal state without taking
 *  any exclusive action. %CLUTTER_X11_FILTER_TRANSLATE will not
 *  occur.
 *
 * Since:  0.8
 */
ClutterX11FilterReturn
clutter_x11_handle_event (XEvent *xevent)
{
  ClutterBackend      *backend;
  ClutterBackendX11Class *backend_x11_class;
  ClutterEvent        *event;
  ClutterMainContext  *clutter_context;
  ClutterX11FilterReturn result;
  gint                 spin = 1;

  /* The return values here are someone approximate; we return
   * CLUTTER_X11_FILTER_REMOVE if a clutter event is
   * generated for the event. This mostly, but not entirely,
   * corresponds to whether other event processing should be
   * excluded. As long as the stage window is not shared with another
   * toolkit it should be safe, and never return
   * %CLUTTER_X11_FILTER_REMOVE when more processing is needed.
   */

  result = CLUTTER_X11_FILTER_CONTINUE;

  clutter_threads_enter ();

  clutter_context = _clutter_context_get_default ();
  backend = clutter_context->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))
    {
      /* push directly here to avoid copy of queue_put */
      result = CLUTTER_X11_FILTER_REMOVE;
      g_queue_push_head (clutter_context->events_queue, event);
    }
  else
    {
      clutter_event_free (event);
      goto out;
    }

  /*
   * Motion events can generate synthetic enter and leave events, so if we
   * are processing a motion event, we need to spin the event loop at least
   * two extra times to pump the enter/leave events through (otherwise they
   * just get pushed down the queue and never processed).
   */
  if (event->type == CLUTTER_MOTION)
    spin += 2;

  while (spin > 0 && (event = clutter_event_get ()))
    {
      /* forward the event into clutter for emission etc. */
      clutter_do_event (event);
      clutter_event_free (event);
      --spin;
    }

 out:
  clutter_threads_leave ();

  return result;
}
Beispiel #29
0
static void
mex_mmkeys_control (MexMMkeys *self, const gchar *key)
{
  MexMMkeysPrivate *priv = MEX_MMKEYS (self)->priv;

  ClutterEvent *event;
  ClutterKeyEvent *kevent;

  event = clutter_event_new (CLUTTER_KEY_PRESS);
  kevent = (ClutterKeyEvent *)event;

  /* These don't change */
  kevent->flags = 0;
  kevent->source = priv->stage;
  kevent->stage = CLUTTER_STAGE (priv->stage);

  if (g_strcmp0 (key, "Play") == 0)
    {
      kevent->keyval = CLUTTER_KEY_AudioPlay;
      goto end;
    }

  if (g_strcmp0 (key, "Pause") == 0)
    {
      kevent->keyval = CLUTTER_KEY_AudioPause;
      goto end;
    }

  if (g_strcmp0 (key, "Stop") == 0)
    {
      kevent->keyval = CLUTTER_KEY_AudioStop;
      goto end;
    }

  if (g_strcmp0 (key, "FastForward") == 0)
    {
      kevent->keyval = CLUTTER_KEY_AudioForward;
      goto end;
    }

  if (g_strcmp0 (key, "Rewind") == 0)
    {
      kevent->keyval = CLUTTER_KEY_AudioRewind;
      goto end;
    }

  if (g_strcmp0 (key, "Next") == 0)
    {
      kevent->keyval = CLUTTER_KEY_AudioNext;
      goto end;
    }

  if (g_strcmp0 (key, "Previous") == 0)
    {
      kevent->keyval = CLUTTER_KEY_AudioPrev;
      goto end;
    }

  /* One day we might be able to get volume keys from gnome setting daemon:
   * https://bugzilla.gnome.org/show_bug.cgi?id=647166
   * In the meantime you can get these keys by unbinding them
   */

  if (g_strcmp0 (key, "VolumeUp") == 0)
    {
      kevent->keyval = CLUTTER_KEY_AudioRaiseVolume;
      goto end;
    }

  if (g_strcmp0 (key, "VolumeDown") == 0)
    {
      kevent->keyval = CLUTTER_KEY_AudioLowerVolume;
      goto end;
    }

  if (g_strcmp0 (key, "VolumeMute") == 0)
    {
      kevent->keyval = CLUTTER_KEY_AudioMute;
      goto end;
    }

  return;

end:
  kevent->time = time (NULL);
  clutter_event_put (event);
  clutter_event_free (event);
}