Пример #1
0
/**
 * clutter_win32_get_stage_from_window:
 * @hwnd: a window handle
 *
 * Gets the stage for a particular window.
 *
 * Return value: The stage or NULL if a stage does not exist for the
 * window.
 *
 * Since: 0.8
 */
ClutterStage *
clutter_win32_get_stage_from_window (HWND hwnd)
{
  /* Check whether the window handle is an instance of the stage
     window class */
  if ((ATOM) GetClassLongPtrW (hwnd, GCW_ATOM)
      == clutter_stage_win32_get_window_class ())
    /* If it is there should be a pointer to the stage in the window
       extra data */
    return CLUTTER_STAGE_WIN32 (GetWindowLongPtrW (hwnd, 0))->wrapper;
  else
    {
      /* Otherwise it might be a foreign window so we should check the
	 stage list */
      ClutterStageManager *stage_manager;
      const GSList        *stages, *l;

      stage_manager = clutter_stage_manager_get_default ();
      stages = clutter_stage_manager_peek_stages (stage_manager);

      for (l = stages; l != NULL; l = l->next)
	{
	  ClutterStage *stage = l->data;
	  ClutterStageWindow *impl;

	  impl = _clutter_stage_get_window (stage);
	  g_assert (CLUTTER_IS_STAGE_WIN32 (impl));

	  if (CLUTTER_STAGE_WIN32 (impl)->hwnd == hwnd)
	    return stage;
	}
    }

  return NULL;
}
Пример #2
0
static void
clutter_backend_win32_ensure_context (ClutterBackend *backend, 
				      ClutterStage   *stage)
{
  ClutterStageWin32 *stage_win32 =
    CLUTTER_STAGE_WIN32 (_clutter_stage_get_window (stage));

  cogl_set_framebuffer (COGL_FRAMEBUFFER (stage_win32->onscreen));
}
Пример #3
0
/**
 * clutter_win32_set_stage_foreign:
 * @stage: a #ClutterStage
 * @hwnd: an existing window handle
 *
 * Target the #ClutterStage to use an existing external window handle.
 *
 * Return value: %TRUE if foreign window is valid
 *
 * Since: 0.8
 */
gboolean
clutter_win32_set_stage_foreign (ClutterStage *stage,
                                 HWND          hwnd)
{
    ClutterStageWin32 *stage_win32;
    ClutterStageWindow *impl;
    ClutterActor *actor;
    RECT client_rect;
    ForeignWindowData fwd;

    g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE);
    g_return_val_if_fail (hwnd != NULL, FALSE);

    actor = CLUTTER_ACTOR (stage);

    impl = _clutter_stage_get_window (stage);
    stage_win32 = CLUTTER_STAGE_WIN32 (impl);

    if (!GetClientRect (hwnd, &client_rect))
    {
        g_warning ("Unable to retrieve the new window geometry");
        return FALSE;
    }

    fwd.stage_win32 = stage_win32;
    fwd.hwnd = hwnd;

    /* destroy the old HWND, if we have one and it's ours */
    if (stage_win32->hwnd != NULL && !stage_win32->is_foreign_win)
        fwd.destroy_old_hwnd = TRUE;
    else
        fwd.destroy_old_hwnd = FALSE;

    fwd.geom.x = 0;
    fwd.geom.y = 0;
    fwd.geom.width = client_rect.right - client_rect.left;
    fwd.geom.height = client_rect.bottom - client_rect.top;

    _clutter_actor_rerealize (actor,
                              set_foreign_window_callback,
                              &fwd);

    /* Queue a relayout - so the stage will be allocated the new
     * window size.
     *
     * Note also that when the stage gets allocated the new
     * window size that will result in the stage's
     * priv->viewport being changed, which will in turn result
     * in the Cogl viewport changing when _clutter_do_redraw
     * calls _clutter_stage_maybe_setup_viewport().
     */
    clutter_actor_queue_relayout (CLUTTER_ACTOR (stage));

    return TRUE;
}
Пример #4
0
/**
 * clutter_x11_get_stage_window: (skip)
 * @stage: a #ClutterStage
 *
 * Gets the stages X Window.
 *
 * Return value: An XID for the stage window.
 *
 *
 */
Window
clutter_x11_get_stage_window (ClutterStage *stage)
{
  ClutterStageWindow *impl;

  g_return_val_if_fail (CLUTTER_IS_STAGE (stage), None);

  impl = _clutter_stage_get_window (stage);
  g_assert (CLUTTER_IS_STAGE_X11 (impl));

  return CLUTTER_STAGE_X11 (impl)->xwin;
}
Пример #5
0
/**
 * clutter_win32_get_stage_window:
 * @stage: a #ClutterStage
 *
 * Gets the stage's window handle
 *
 * Return value: An HWND for the stage window.
 *
 * Since: 0.8
 */
HWND
clutter_win32_get_stage_window (ClutterStage *stage)
{
  ClutterStageWindow *impl;

  g_return_val_if_fail (CLUTTER_IS_STAGE (stage), NULL);

  impl = _clutter_stage_get_window (stage);

  g_return_val_if_fail (CLUTTER_IS_STAGE_WIN32 (impl), NULL);

  return CLUTTER_STAGE_WIN32 (impl)->hwnd;
}
/**
 * clutter_wayland_stage_get_wl_shell_surface: (skip)
 *
 * @stage: a #ClutterStage
 *
 * Access the underlying data structure representing the shell surface that is
 * backing the #ClutterStage
 *
 * Note: this function can only be called when running on the Wayland
 * platform. Calling this function at any other time will return %NULL.
 *
 * Returns: (transfer non): the Wayland shell surface associated with
 * @stage
 *
 * Since: 1.10
 */
struct wl_shell_surface *
clutter_wayland_stage_get_wl_shell_surface (ClutterStage *stage)
{
    ClutterStageWindow *stage_window = _clutter_stage_get_window (stage);
    ClutterStageWayland *stage_wayland;

    if (!CLUTTER_IS_STAGE_WAYLAND (stage_window))
        return NULL;

    stage_wayland = CLUTTER_STAGE_WAYLAND (stage_window);

    return stage_wayland->wayland_shell_surface;
}
Пример #7
0
/**
 * clutter_win32_set_stage_foreign:
 * @stage: a #ClutterStage
 * @hwnd: an existing window handle
 *
 * Target the #ClutterStage to use an existing external window handle.
 *
 * Return value: %TRUE if foreign window is valid
 *
 * Since: 0.8
 */
gboolean
clutter_win32_set_stage_foreign (ClutterStage *stage,
				 HWND          hwnd)
{
  ClutterStageWin32 *stage_win32;
  ClutterStageWindow *impl;
  ClutterActor *actor;
  RECT client_rect;
  POINT window_pos;
  ClutterGeometry geom;

  g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE);
  g_return_val_if_fail (hwnd != NULL, FALSE);

  actor = CLUTTER_ACTOR (stage);

  impl = _clutter_stage_get_window (stage);
  stage_win32 = CLUTTER_STAGE_WIN32 (impl);

  /* FIXME this needs updating to use _clutter_actor_rerealize(),
   * see the analogous code in x11 backend. Probably best if
   * win32 maintainer does it so they can be sure it compiles
   * and works.
   */

  clutter_actor_unrealize (actor);

  if (!GetClientRect (hwnd, &client_rect))
    {
      g_warning ("Unable to retrieve the new window geometry");
      return FALSE;
    }
  window_pos.x = client_rect.left;
  window_pos.y = client_rect.right;
  ClientToScreen (hwnd, &window_pos);

  CLUTTER_NOTE (BACKEND, "Setting foreign window (0x%x)", (int) hwnd);

  stage_win32->hwnd = hwnd;
  stage_win32->is_foreign_win = TRUE;

  geom.x = 0;
  geom.y = 0;
  geom.width = client_rect.right - client_rect.left;
  geom.height = client_rect.bottom - client_rect.top;

  clutter_actor_set_geometry (actor, &geom);
  clutter_actor_realize (actor);

  return TRUE;
}
Пример #8
0
/**
 * clutter_gdk_set_stage_foreign:
 * @stage: a #ClutterStage
 * @window: an existing #GdkWindow
 *
 * Target the #ClutterStage to use an existing external #GdkWindow
 *
 * Return value: %TRUE if foreign window is valid
 *
 * Since: 1.10
 */
gboolean
clutter_gdk_set_stage_foreign (ClutterStage *stage,
                               GdkWindow    *window)
{
  ForeignWindowClosure closure;
  ClutterStageGdk *stage_gdk;
  ClutterStageWindow *impl;
  ClutterActor *actor;

  g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE);
  g_return_val_if_fail (!CLUTTER_ACTOR_IN_DESTRUCTION (stage), FALSE);
  g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE);

  impl = _clutter_stage_get_window (stage);
  if (!CLUTTER_IS_STAGE_GDK (impl))
    {
      g_critical ("The Clutter backend is not a GDK backend");
      return FALSE;
    }

  stage_gdk = CLUTTER_STAGE_GDK (impl);

  if (g_object_get_data (G_OBJECT (window), "clutter-stage-window") != NULL)
    {
      g_critical ("The provided GdkWindow is already in use by another ClutterStage");
      return FALSE;
    }

  closure.stage_gdk = stage_gdk;
  closure.window = g_object_ref (window);

  actor = CLUTTER_ACTOR (stage);

  _clutter_actor_rerealize (actor,
                            set_foreign_window_callback,
                            &closure);

  /* Queue a relayout - so the stage will be allocated the new
   * window size.
   *
   * Note also that when the stage gets allocated the new
   * window size that will result in the stage's
   * priv->viewport being changed, which will in turn result
   * in the Cogl viewport changing when _clutter_do_redraw
   * calls _clutter_stage_maybe_setup_viewport().
   */
  clutter_actor_queue_relayout (actor);

  return TRUE;
}
Пример #9
0
static void
clutter_backend_egl_redraw (ClutterBackend *backend,
                            ClutterStage   *stage)
{
  ClutterStageWindow *impl;

  impl = _clutter_stage_get_window (stage);
  if (!impl)
    return;

  g_assert (CLUTTER_IS_STAGE_EGL (impl));

  clutter_stage_egl_redraw (CLUTTER_STAGE_EGL (impl), stage);
}
Пример #10
0
/**
 * clutter_gdk_get_stage_window:
 * @stage: a #ClutterStage
 *
 * Gets the stages GdkWindow.
 *
 * Return value: (transfer none): A GdkWindow* for the stage window.
 *
 * Since: 1.10
 */
GdkWindow *
clutter_gdk_get_stage_window (ClutterStage *stage)
{
  ClutterStageWindow *impl;

  g_return_val_if_fail (CLUTTER_IS_STAGE (stage), NULL);

  impl = _clutter_stage_get_window (stage);
  if (!CLUTTER_IS_STAGE_GDK (impl))
    {
      g_critical ("The Clutter backend is not a GDK backend");
      return NULL;
    }

  return CLUTTER_STAGE_GDK (impl)->window;
}
Пример #11
0
/*
 * FIXME: we should remove backend_class->redraw() and just
 * have stage_window_iface->redraw()
 */
static void
clutter_backend_glx_redraw (ClutterBackend *backend,
                            ClutterStage   *stage)
{
  ClutterStageWindow *impl = _clutter_stage_get_window (stage);

  if (G_UNLIKELY (impl == NULL))
    {
      CLUTTER_NOTE (BACKEND, "Stage [%p] has no implementation", stage);
      return;
    }

  g_assert (CLUTTER_IS_STAGE_GLX (impl));

  clutter_stage_glx_redraw (CLUTTER_STAGE_GLX (impl),
                            stage);
}
Пример #12
0
static void
clutter_backend_glx_redraw (ClutterBackend *backend,
                            ClutterStage   *stage)
{
  ClutterStageGLX *stage_glx;
  ClutterStageX11 *stage_x11;
  ClutterStageWindow *impl;

  impl = _clutter_stage_get_window (stage);
  if (G_UNLIKELY (impl == NULL))
    {
      CLUTTER_NOTE (BACKEND, "Stage [%p] has no implementation", stage);
      return;
    }

  g_assert (CLUTTER_IS_STAGE_GLX (impl));

  stage_x11 = CLUTTER_STAGE_X11 (impl);
  stage_glx = CLUTTER_STAGE_GLX (impl);

  /* this will cause the stage implementation to be painted */
  clutter_actor_paint (CLUTTER_ACTOR (stage));
  cogl_flush ();

  if (stage_x11->xwin != None)
    {
      /* wait for the next vblank */
      CLUTTER_NOTE (BACKEND, "Waiting for vblank");
      glx_wait_for_vblank (CLUTTER_BACKEND_GLX (backend));

      /* push on the screen */
      CLUTTER_NOTE (BACKEND, "glXSwapBuffers (display: %p, window: 0x%lx)",
                    stage_x11->xdpy,
                    (unsigned long) stage_x11->xwin);
      glXSwapBuffers (stage_x11->xdpy, stage_x11->xwin);
    }
  else
    {
      /* offscreen */
      glXWaitGL ();

      CLUTTER_GLERR ();
    }
}
Пример #13
0
static void
clutter_backend_real_ensure_context (ClutterBackend *backend,
                                     ClutterStage   *stage)
{
  ClutterStageWindow *stage_impl;
  CoglFramebuffer *framebuffer;

  if (stage == NULL)
    return;

  stage_impl = _clutter_stage_get_window (stage);
  if (stage_impl == NULL)
    return;

  framebuffer = _clutter_stage_window_get_active_framebuffer (stage_impl);
  if (framebuffer == NULL)
    return;

  cogl_set_framebuffer (framebuffer);
}
Пример #14
0
static void
clutter_backend_egl_redraw (ClutterBackend *backend,
                            ClutterStage   *stage)
{
    ClutterBackendEGL  *backend_egl = CLUTTER_BACKEND_EGL (backend);
    ClutterStageEGL    *stage_egl;
    ClutterStageWindow *impl;

    impl = _clutter_stage_get_window (stage);
    if (!impl)
        return;

    g_assert (CLUTTER_IS_STAGE_EGL (impl));
    stage_egl = CLUTTER_STAGE_EGL (impl);

    eglWaitNative (EGL_CORE_NATIVE_ENGINE);
    clutter_actor_paint (CLUTTER_ACTOR (stage));
    cogl_flush ();
    eglWaitGL();
    eglSwapBuffers (backend_egl->edpy,  stage_egl->egl_surface);
}
Пример #15
0
/* TODO: remove this interface in favour of
 * _clutter_stage_window_make_current () */
static void
clutter_backend_glx_ensure_context (ClutterBackend *backend,
                                    ClutterStage   *stage)
{
  ClutterStageWindow *impl;

  /* if there is no stage, the stage is being destroyed or it has no
   * implementation attached to it then we clear the GL context
   */
  if (stage == NULL ||
      (CLUTTER_PRIVATE_FLAGS (stage) & CLUTTER_ACTOR_IN_DESTRUCTION) ||
      ((impl = _clutter_stage_get_window (stage)) == NULL))
    {
      ClutterBackendX11 *backend_x11;

      backend_x11 = CLUTTER_BACKEND_X11 (backend);
      CLUTTER_NOTE (MULTISTAGE, "Clearing all context");

      glXMakeContextCurrent (backend_x11->xdpy, None, None, NULL);
    }
  else
    {
      ClutterBackendGLX *backend_glx;
      ClutterBackendX11 *backend_x11;
      ClutterStageGLX   *stage_glx;
      ClutterStageX11   *stage_x11;
      GLXDrawable        drawable;

      g_assert (impl != NULL);

      stage_glx = CLUTTER_STAGE_GLX (impl);
      stage_x11 = CLUTTER_STAGE_X11 (impl);
      backend_glx = CLUTTER_BACKEND_GLX (backend);
      backend_x11 = CLUTTER_BACKEND_X11 (backend);

      drawable = stage_glx->glxwin ? stage_glx->glxwin : stage_x11->xwin;

      CLUTTER_NOTE (BACKEND,
                    "Setting context for stage of type %s, window: 0x%x",
                    G_OBJECT_TYPE_NAME (impl),
                    (unsigned int) drawable);

      /* no GL context to set */
      if (backend_glx->gl_context == None)
        return;

      clutter_x11_trap_x_errors ();

      /* we might get here inside the final dispose cycle, so we
       * need to handle this gracefully
       */
      if (drawable == None)
        {
          GLXDrawable dummy_drawable;

          CLUTTER_NOTE (BACKEND,
                        "Received a stale stage, clearing all context");

          if (backend_glx->dummy_glxwin)
            dummy_drawable = backend_glx->dummy_glxwin;
          else
            dummy_drawable = backend_glx->dummy_xwin;

          if (dummy_drawable == None)
            glXMakeContextCurrent (backend_x11->xdpy, None, None, NULL);
          else
            {
              glXMakeContextCurrent (backend_x11->xdpy,
                                     dummy_drawable,
                                     dummy_drawable,
                                     backend_glx->gl_context);
            }
        }
      else
        {
          CLUTTER_NOTE (BACKEND,
                        "MakeContextCurrent dpy: %p, window: 0x%x (%s), context: %p",
                        backend_x11->xdpy,
                        (unsigned int) drawable,
                        stage_x11->is_foreign_xwin ? "foreign" : "native",
                        backend_glx->gl_context);

          glXMakeContextCurrent (backend_x11->xdpy,
                                 drawable,
                                 drawable,
                                 backend_glx->gl_context);
          /*
           * In case we are using GLX_SGI_swap_control for vblank syncing we need call
           * glXSwapIntervalSGI here to make sure that it affects the current drawable.
           */
          if (backend_glx->vblank_type == CLUTTER_VBLANK_GLX_SWAP && backend_glx->swap_interval != NULL)
            backend_glx->swap_interval (1);
        }

      if (clutter_x11_untrap_x_errors ())
        g_critical ("Unable to make the stage window 0x%x the current "
                    "GLX drawable",
                    (unsigned int) drawable);
    }
}
Пример #16
0
/**
 * clutter_x11_set_stage_foreign:
 * @stage: a #ClutterStage
 * @xwindow: an existing X Window id
 *
 * Target the #ClutterStage to use an existing external X Window
 *
 * Return value: %TRUE if foreign window is valid
 *
 *
 */
gboolean
clutter_x11_set_stage_foreign (ClutterStage *stage,
                               Window        xwindow)
{
  ClutterBackendX11 *backend_x11;
  ClutterStageX11 *stage_x11;
  ClutterStageCogl *stage_cogl;
  ClutterStageWindow *impl;
  ClutterActor *actor;
  gint x, y;
  guint width, height, border, depth;
  Window root_return;
  Status status;
  ForeignWindowData fwd;
  XVisualInfo *xvisinfo;

  g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE);
  g_return_val_if_fail (!CLUTTER_ACTOR_IN_DESTRUCTION (stage), FALSE);
  g_return_val_if_fail (xwindow != None, FALSE);

  impl = _clutter_stage_get_window (stage);
  stage_x11 = CLUTTER_STAGE_X11 (impl);
  stage_cogl = CLUTTER_STAGE_COGL (impl);
  backend_x11 = CLUTTER_BACKEND_X11 (stage_cogl->backend);

  xvisinfo = _clutter_backend_x11_get_visual_info (backend_x11);
  g_return_val_if_fail (xvisinfo != NULL, FALSE);

  clutter_x11_trap_x_errors ();

  status = XGetGeometry (backend_x11->xdpy, xwindow,
                         &root_return,
                         &x, &y,
                         &width, &height,
                         &border,
                         &depth);

  if (clutter_x11_untrap_x_errors () || !status)
    {
      g_critical ("Unable to retrieve the geometry of the foreign window: "
                  "XGetGeometry() failed (status code: %d)", status);
      return FALSE;
    }

  if (width == 0 || height == 0)
    {
      g_warning ("The size of the foreign window is 0x0");
      return FALSE;
    }

  if (depth != xvisinfo->depth)
    {
      g_warning ("The depth of the visual of the foreign window is %d, but "
                 "Clutter has been initialized to require a visual depth "
                 "of %d",
                 depth,
                 xvisinfo->depth);
      return FALSE;
    }

  fwd.stage_x11 = stage_x11;
  fwd.xwindow = xwindow;

  /* destroy the old Window, if we have one and it's ours */
  if (stage_x11->xwin != None && !stage_x11->is_foreign_xwin)
    fwd.destroy_old_xwindow = TRUE;
  else
    fwd.destroy_old_xwindow = FALSE;

  fwd.geom.x = x;
  fwd.geom.y = y;
  fwd.geom.width = width;
  fwd.geom.height = height;

  actor = CLUTTER_ACTOR (stage);

  _clutter_actor_rerealize (actor,
                            set_foreign_window_callback,
                            &fwd);

  /* Queue a relayout - so the stage will be allocated the new
   * window size.
   *
   * Note also that when the stage gets allocated the new
   * window size that will result in the stage's
   * priv->viewport being changed, which will in turn result
   * in the Cogl viewport changing when _clutter_do_redraw
   * calls _clutter_stage_maybe_setup_viewport().
   */
  clutter_actor_queue_relayout (actor);

  return TRUE;
}
Пример #17
0
static void
clutter_backend_glx_ensure_context (ClutterBackend *backend, 
                                    ClutterStage   *stage)
{
  ClutterStageWindow *impl;

  /* if there is no stage, the stage is being destroyed or it has no
   * implementation attached to it then we clear the GL context
   */
  if (stage == NULL ||
      (CLUTTER_PRIVATE_FLAGS (stage) & CLUTTER_ACTOR_IN_DESTRUCTION) ||
      ((impl = _clutter_stage_get_window (stage)) == NULL))
    {
      ClutterBackendX11 *backend_x11;

      backend_x11 = CLUTTER_BACKEND_X11 (backend);
      CLUTTER_NOTE (MULTISTAGE, "Clearing all context");

      glXMakeCurrent (backend_x11->xdpy, None, NULL);
    }
  else
    {
      ClutterBackendGLX *backend_glx;
      ClutterStageGLX   *stage_glx;
      ClutterStageX11   *stage_x11;

      g_assert (impl != NULL);

      CLUTTER_NOTE (MULTISTAGE, "Setting context for stage of type %s [%p]",
                    g_type_name (G_OBJECT_TYPE (impl)),
                    impl);

      stage_glx = CLUTTER_STAGE_GLX (impl);
      stage_x11 = CLUTTER_STAGE_X11 (impl);
      backend_glx = CLUTTER_BACKEND_GLX (backend);

      /* no GL context to set */
      if (backend_glx->gl_context == None)
        return;

      clutter_x11_trap_x_errors ();

      /* we might get here inside the final dispose cycle, so we
       * need to handle this gracefully
       */
      if (stage_x11->xwin == None)
        {
          ClutterBackendX11 *backend_x11;

          backend_x11 = CLUTTER_BACKEND_X11 (backend);
          CLUTTER_NOTE (MULTISTAGE,
                        "Received a stale stage, clearing all context");

          glXMakeCurrent (backend_x11->xdpy, None, NULL);
        }
      else
        {
          CLUTTER_NOTE (BACKEND,
                        "MakeCurrent dpy: %p, window: 0x%x (%s), context: %p",
                        stage_x11->xdpy,
                        (int) stage_x11->xwin,
                        stage_x11->is_foreign_xwin ? "foreign" : "native",
                        backend_glx->gl_context);

          glXMakeCurrent (stage_x11->xdpy,
                          stage_x11->xwin,
                          backend_glx->gl_context);
        }

      if (clutter_x11_untrap_x_errors ())
        g_critical ("Unable to make the stage window 0x%x the current "
                    "GLX drawable",
                    (int) stage_x11->xwin);
    }
}
Пример #18
0
static gboolean
event_translate (ClutterBackend *backend,
                 ClutterEvent   *event,
                 XEvent         *xevent)
{
  ClutterBackendX11 *backend_x11;
  ClutterStageX11 *stage_x11;
  ClutterStage *stage;
  ClutterStageWindow *impl;
  ClutterDeviceManager *manager;
  gboolean res, not_yet_handled = FALSE;
  Window xwindow, stage_xwindow;
  ClutterInputDevice *device;

  backend_x11 = CLUTTER_BACKEND_X11 (backend);

  xwindow = xevent->xany.window;

  if (backend_x11->event_filters)
    {
      GSList *node;

      node = backend_x11->event_filters;

      while (node)
        {
          ClutterX11EventFilter *filter = node->data;

          switch (filter->func (xevent, event, filter->data))
            {
            case CLUTTER_X11_FILTER_CONTINUE:
              break;
            case CLUTTER_X11_FILTER_TRANSLATE:
              return TRUE;
            case CLUTTER_X11_FILTER_REMOVE:
              return FALSE;
            default:
              break;
            }

          node = node->next;
        }
    }

  /* Do further processing only on events for the stage window (the x11
   * filters might be getting events for other windows, so do not mess
   * them about.
   */
  stage = clutter_x11_get_stage_from_window (xwindow);
  if (stage == NULL)
    return FALSE;

  impl = _clutter_stage_get_window (stage);
  stage_x11 = CLUTTER_STAGE_X11 (impl);
  stage_xwindow = xwindow; /* clutter_x11_get_stage_window (stage); */

  event->any.stage = stage;

  res = TRUE;

  update_last_event_time (backend_x11, xevent);

  manager = clutter_device_manager_get_default ();

  switch (xevent->type)
    {
    case ConfigureNotify:
      if (!stage_x11->is_foreign_xwin)
        {
          CLUTTER_NOTE (BACKEND, "%s: ConfigureNotify[%x] (%d, %d)",
                        G_STRLOC,
                        (unsigned int) stage_x11->xwin,
                        xevent->xconfigure.width,
                        xevent->xconfigure.height);

          /* Queue a relayout - we want glViewport to be called
           * with the correct values, and this is done in ClutterStage
           * via _cogl_onscreen_clutter_backend_set_size ().
           *
           * We queue a relayout, because if this ConfigureNotify is
           * in response to a size we set in the application, the
           * set_size above is essentially a null-op.
           *
           * Make sure we do this only when the size has changed,
           * otherwise we end up relayouting on window moves.
           */
          if ((stage_x11->state & CLUTTER_STAGE_STATE_FULLSCREEN) ||
              (stage_x11->xwin_width != xevent->xconfigure.width) ||
              (stage_x11->xwin_height != xevent->xconfigure.height))
          clutter_actor_queue_relayout (CLUTTER_ACTOR (stage));

          /* If we're fullscreened, we want these variables to
           * represent the size of the window before it was set
           * to fullscreen.
           */
          if (!(stage_x11->state & CLUTTER_STAGE_STATE_FULLSCREEN))
            {
              stage_x11->xwin_width = xevent->xconfigure.width;
              stage_x11->xwin_height = xevent->xconfigure.height;
            }

          clutter_actor_set_size (CLUTTER_ACTOR (stage),
                                  xevent->xconfigure.width,
                                  xevent->xconfigure.height);

          CLUTTER_UNSET_PRIVATE_FLAGS (stage_x11->wrapper,
                                       CLUTTER_STAGE_IN_RESIZE);

          /* the resize process is complete, so we can ask the stage
           * to set up the GL viewport with the new size
           */
          clutter_stage_ensure_viewport (stage);
        }
      res = FALSE;
      break;

    case PropertyNotify:
      if (xevent->xproperty.atom == backend_x11->atom_NET_WM_STATE &&
          xevent->xproperty.window == stage_xwindow &&
          !stage_x11->is_foreign_xwin)
        {
          Atom     type;
          gint     format;
          gulong   n_items, bytes_after;
          guchar  *data = NULL;
          gboolean fullscreen_set = FALSE;

          clutter_x11_trap_x_errors ();
          XGetWindowProperty (backend_x11->xdpy, stage_xwindow,
                              backend_x11->atom_NET_WM_STATE,
                              0, G_MAXLONG,
                              False, XA_ATOM,
                              &type, &format, &n_items,
                              &bytes_after, &data);
          clutter_x11_untrap_x_errors ();

          if (type != None && data != NULL)
            {
              Atom *atoms = (Atom *) data;
              gulong i;
              gboolean is_fullscreen = FALSE;

              for (i = 0; i < n_items; i++)
                {
                  if (atoms[i] == backend_x11->atom_NET_WM_STATE_FULLSCREEN)
                    fullscreen_set = TRUE;
                }

              is_fullscreen =
                (stage_x11->state & CLUTTER_STAGE_STATE_FULLSCREEN);

              if (fullscreen_set != is_fullscreen)
                {
                  if (fullscreen_set)
                    stage_x11->state |= CLUTTER_STAGE_STATE_FULLSCREEN;
                  else
                    stage_x11->state &= ~CLUTTER_STAGE_STATE_FULLSCREEN;

                  stage_x11->fullscreening = fullscreen_set;

                  event->type = CLUTTER_STAGE_STATE;
                  event->stage_state.changed_mask =
                    CLUTTER_STAGE_STATE_FULLSCREEN;
                  event->stage_state.new_state = stage_x11->state;
                }
              else
                res = FALSE;

              XFree (data);
            }
          else
            res = FALSE;
        }
      else
        res = FALSE;
      break;

    case MapNotify:
      res = FALSE;
      break;

    case UnmapNotify:
      res = FALSE;
      break;

    case FocusIn:
      if (!(stage_x11->state & CLUTTER_STAGE_STATE_ACTIVATED))
        {
          /* TODO: check xevent->xfocus.detail ? */
          stage_x11->state |= CLUTTER_STAGE_STATE_ACTIVATED;

          event->type = CLUTTER_STAGE_STATE;
          event->stage_state.changed_mask = CLUTTER_STAGE_STATE_ACTIVATED;
          event->stage_state.new_state = stage_x11->state;
        }
      else
        res = FALSE;
      break;

    case FocusOut:
      if (stage_x11->state & CLUTTER_STAGE_STATE_ACTIVATED)
        {
          stage_x11->state &= ~CLUTTER_STAGE_STATE_ACTIVATED;

          event->type = CLUTTER_STAGE_STATE;
          event->stage_state.changed_mask = CLUTTER_STAGE_STATE_ACTIVATED;
          event->stage_state.new_state = stage_x11->state;
        }
      else
        res = FALSE;
      break;

    case Expose:
      {
        CLUTTER_NOTE (MULTISTAGE, "expose for stage: %p, redrawing", stage);
        clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
        res = FALSE;
      }
      break;
    case DestroyNotify:
      CLUTTER_NOTE (EVENT, "destroy notify:\txid: %ld",
                    xevent->xdestroywindow.window);
      if (xevent->xdestroywindow.window == stage_xwindow &&
          !stage_x11->is_foreign_xwin)
        event->type = event->any.type = CLUTTER_DESTROY_NOTIFY;
      else
        res = FALSE;
      break;

    case ClientMessage:
      CLUTTER_NOTE (EVENT, "client message");

      event->type = event->any.type = CLUTTER_CLIENT_MESSAGE;

      if (xevent->xclient.message_type == backend_x11->atom_XEMBED)
        res = handle_xembed_event (backend_x11, xevent);
      else if (xevent->xclient.message_type == backend_x11->atom_WM_PROTOCOLS)
        {
          res = handle_wm_protocols_event (backend_x11, stage_xwindow, xevent);
          event->type = event->any.type = CLUTTER_DELETE;
        }
      break;

    case KeyPress:
      event->key.type = event->type = CLUTTER_KEY_PRESS;
      event->key.device =
        clutter_device_manager_get_core_device (manager,
                                                CLUTTER_KEYBOARD_DEVICE);

      translate_key_event (backend, event, xevent);

      set_user_time (backend_x11, &xwindow, xevent->xkey.time);
      break;
              
    case KeyRelease:
      /* old-style X11 terminals require that even modern X11 send
       * KeyPress/KeyRelease pairs when auto-repeating. for this
       * reason modern(-ish) API like XKB has a way to detect
       * auto-repeat and do a single KeyRelease at the end of a
       * KeyPress sequence.
       *
       * this check emulates XKB's detectable auto-repeat; we peek
       * the next event and check if it's a KeyPress for the same key
       * and timestamp - and then ignore it if it matches the
       * KeyRelease
       */
      if (XPending (xevent->xkey.display))
        {
          XEvent next_event;

          XPeekEvent (xevent->xkey.display, &next_event);

          if (next_event.type == KeyPress &&
              next_event.xkey.keycode == xevent->xkey.keycode &&
              next_event.xkey.time == xevent->xkey.time)
            {
              res = FALSE;
              break;
            }
        }

      event->key.type = event->type = CLUTTER_KEY_RELEASE;
      event->key.device =
        clutter_device_manager_get_core_device (manager,
                                                CLUTTER_KEYBOARD_DEVICE);

      translate_key_event (backend, event, xevent);
      break;

    default:
      /* ignore every other event */
      not_yet_handled = TRUE;
      break;
    }

  /* Input device event handling.. */
  if (not_yet_handled)
    {
      device = clutter_device_manager_get_core_device (manager,
                                                       CLUTTER_POINTER_DEVICE);

      /* Regular X event */
      switch (xevent->type)
        {
        case ButtonPress:
          switch (xevent->xbutton.button)
            {
            case 4: /* up */
            case 5: /* down */
            case 6: /* left */
            case 7: /* right */
              event->scroll.type = event->type = CLUTTER_SCROLL;

              if (xevent->xbutton.button == 4)
                event->scroll.direction = CLUTTER_SCROLL_UP;
              else if (xevent->xbutton.button == 5)
                event->scroll.direction = CLUTTER_SCROLL_DOWN;
              else if (xevent->xbutton.button == 6)
                event->scroll.direction = CLUTTER_SCROLL_LEFT;
              else
                event->scroll.direction = CLUTTER_SCROLL_RIGHT;

              event->scroll.time = xevent->xbutton.time;
              event->scroll.x = xevent->xbutton.x;
              event->scroll.y = xevent->xbutton.y;
              event->scroll.modifier_state = xevent->xbutton.state;
              event->scroll.device = device;
              break;

            default:
              event->button.type = event->type = CLUTTER_BUTTON_PRESS;
              event->button.time = xevent->xbutton.time;
              event->button.x = xevent->xbutton.x;
              event->button.y = xevent->xbutton.y;
              event->button.modifier_state = xevent->xbutton.state;
              event->button.button = xevent->xbutton.button;
              event->button.device = device;
              break;
            }

          set_user_time (backend_x11, &xwindow, event->button.time);

          res = TRUE;
          break;

        case ButtonRelease:
          /* scroll events don't have a corresponding release */
          if (xevent->xbutton.button == 4 ||
              xevent->xbutton.button == 5 ||
              xevent->xbutton.button == 6 ||
              xevent->xbutton.button == 7)
            {
              res = FALSE;
              goto out;
            }

          event->button.type = event->type = CLUTTER_BUTTON_RELEASE;
          event->button.time = xevent->xbutton.time;
          event->button.x = xevent->xbutton.x;
          event->button.y = xevent->xbutton.y;
          event->button.modifier_state = xevent->xbutton.state;
          event->button.button = xevent->xbutton.button;
          event->button.device = device;

          res = TRUE;
          break;

        case MotionNotify:
          event->motion.type = event->type = CLUTTER_MOTION;
          event->motion.time = xevent->xmotion.time;
          event->motion.x = xevent->xmotion.x;
          event->motion.y = xevent->xmotion.y;
          event->motion.modifier_state = xevent->xmotion.state;
          event->motion.device = device;

          res = TRUE;
          break;

        case EnterNotify:
          /* we know that we are entering the stage here */
          _clutter_input_device_set_stage (device, stage);
          CLUTTER_NOTE (EVENT, "Entering the stage");

          /* Convert enter notifies to motion events because X
             doesn't emit the corresponding motion notify */
          event->motion.type = event->type = CLUTTER_MOTION;
          event->motion.time = xevent->xcrossing.time;
          event->motion.x = xevent->xcrossing.x;
          event->motion.y = xevent->xcrossing.y;
          event->motion.modifier_state = xevent->xcrossing.state;
          event->motion.source = CLUTTER_ACTOR (stage);
          event->motion.device = device;

          res = TRUE;
          break;

        case LeaveNotify:
          if (device->stage == NULL)
            {
              CLUTTER_NOTE (EVENT,
                            "Discarding LeaveNotify for ButtonRelease "
                            "event off-stage");
              res = FALSE;
              goto out;
            }

          /* we know that we are leaving the stage here */
          _clutter_input_device_set_stage (device, NULL);
          CLUTTER_NOTE (EVENT, "Leaving the stage (time:%u)",
                        event->crossing.time);

          event->crossing.type = event->type = CLUTTER_LEAVE;
          event->crossing.time = xevent->xcrossing.time;
          event->crossing.x = xevent->xcrossing.x;
          event->crossing.y = xevent->xcrossing.y;
          event->crossing.source = CLUTTER_ACTOR (stage);
          event->crossing.device = device;
          res = TRUE;
          break;

        default:
          res = FALSE;
          break;
        }
    }

    /* XInput fun...*/
  if (!res && clutter_x11_has_xinput ())
    {
#ifdef HAVE_XINPUT
      int *ev_types = backend_x11->event_types;
      int button_press, button_release;
      int key_press, key_release;
      int motion_notify;

      button_press   = ev_types[CLUTTER_X11_XINPUT_BUTTON_PRESS_EVENT];
      button_release = ev_types[CLUTTER_X11_XINPUT_BUTTON_RELEASE_EVENT];
      motion_notify  = ev_types[CLUTTER_X11_XINPUT_MOTION_NOTIFY_EVENT];
      key_press      = ev_types[CLUTTER_X11_XINPUT_KEY_PRESS_EVENT];
      key_release    = ev_types[CLUTTER_X11_XINPUT_KEY_RELEASE_EVENT];

      CLUTTER_NOTE (EVENT, "XInput event type: %d", xevent->type);

      if (xevent->type == button_press)
        {
          XDeviceButtonEvent *xbev = (XDeviceButtonEvent *) xevent;

          device = _clutter_x11_get_device_for_xid (xbev->deviceid);
          _clutter_input_device_set_stage (device, stage);

          CLUTTER_NOTE (EVENT,
                        "XI ButtonPress for %li ('%s') at %d, %d",
                        xbev->deviceid,
                        device->device_name,
                        xbev->x,
                        xbev->y);

          switch (xbev->button)
            {
            case 4:
            case 5:
            case 6:
            case 7:
              event->scroll.type = event->type = CLUTTER_SCROLL;

              if (xbev->button == 4)
                event->scroll.direction = CLUTTER_SCROLL_UP;
              else if (xbev->button == 5)
                event->scroll.direction = CLUTTER_SCROLL_DOWN;
              else if (xbev->button == 6)
                event->scroll.direction = CLUTTER_SCROLL_LEFT;
              else
                event->scroll.direction = CLUTTER_SCROLL_RIGHT;

              event->scroll.time = xbev->time;
              event->scroll.x = xbev->x;
              event->scroll.y = xbev->y;
              event->scroll.modifier_state = xbev->state;
              event->scroll.device = device;
              break;

            default:
              event->button.type = event->type = CLUTTER_BUTTON_PRESS;
              event->button.time = xbev->time;
              event->button.x = xbev->x;
              event->button.y = xbev->y;
              event->button.modifier_state = xbev->state;
              event->button.button = xbev->button;
              event->button.device = device;
              break;
            }

          set_user_time (backend_x11, &xwindow, xbev->time);

          res = TRUE;
        }
      else if (xevent->type == button_release)
        {
          XDeviceButtonEvent *xbev = (XDeviceButtonEvent *)xevent;

          device = _clutter_x11_get_device_for_xid (xbev->deviceid);
          _clutter_input_device_set_stage (device, stage);

          CLUTTER_NOTE (EVENT, "XI ButtonRelease for %li ('%s') at %d, %d",
                        xbev->deviceid,
                        device->device_name,
                        xbev->x,
                        xbev->y);

          /* scroll events don't have a corresponding release */
          if (xbev->button == 4 ||
              xbev->button == 5 ||
              xbev->button == 6 ||
              xbev->button == 7)
            {
              res = FALSE;
              goto out;
            }

          event->button.type = event->type = CLUTTER_BUTTON_RELEASE;
          event->button.time = xbev->time;
          event->button.x = xbev->x;
          event->button.y = xbev->y;
          event->button.modifier_state = xbev->state;
          event->button.button = xbev->button;
          event->button.device = device;

          res = TRUE;
        }
      else if (xevent->type == motion_notify)
        {
          XDeviceMotionEvent *xmev = (XDeviceMotionEvent *)xevent;

          device = _clutter_x11_get_device_for_xid (xmev->deviceid);
          _clutter_input_device_set_stage (device, stage);

          CLUTTER_NOTE (EVENT, "XI Motion for %li ('%s') at %d, %d",
                        xmev->deviceid,
                        device->device_name,
                        xmev->x,
                        xmev->y);

          event->motion.type = event->type = CLUTTER_MOTION;
          event->motion.time = xmev->time;
          event->motion.x = xmev->x;
          event->motion.y = xmev->y;
          event->motion.modifier_state = xmev->state;
          event->motion.device = device;

          res = TRUE;
        }
      else if (xevent->type == key_press || xevent->type == key_release)
        {
          /* the XInput 1.x handling of key presses/releases is broken:
           * it makes key repeat, key presses and releases outside the
           * window not generate events even when the window has focus
           */
          XDeviceKeyEvent *xkev = (XDeviceKeyEvent *) xevent;
          XEvent xevent_converted;

          convert_xdevicekey_to_xkey (xkev, &xevent_converted);

          event->key.type = event->type = (xevent->type == key_press)
                                          ? CLUTTER_KEY_PRESS
                                          : CLUTTER_KEY_RELEASE;

          translate_key_event (backend, event, &xevent_converted);

          if (xevent->type == key_press)
            set_user_time (backend_x11, &xwindow, xkev->time);
        }
      else
#endif /* HAVE_XINPUT */
        {
          CLUTTER_NOTE (EVENT, "Uknown Event");
          res = FALSE;
        }
    }

out:
  return res;
}
Пример #19
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;
}
static gboolean
message_translate (ClutterBackend *backend,
		   ClutterEvent   *event,
		   const MSG      *msg,
		   gboolean       *call_def_window_proc)
{
  ClutterBackendWin32 *backend_win32;
  ClutterStageWin32   *stage_win32;
  ClutterStage        *stage;
  ClutterStageWindow  *impl;
  gboolean            res;

  backend_win32 = CLUTTER_BACKEND_WIN32 (backend);

  /* Do further processing only on events for the stage window */
  stage = clutter_win32_get_stage_from_window (msg->hwnd);

  if (stage == NULL)
    return FALSE;
  impl        = _clutter_stage_get_window (stage);
  stage_win32 = CLUTTER_STAGE_WIN32 (impl);

  event->any.stage = stage;

  res = TRUE;

  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);
	  guint 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);
	}
      res = FALSE;
      break;

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

    case WM_ACTIVATE:
      if (msg->wParam == WA_INACTIVE)
	{
	  if (stage_win32->state & CLUTTER_STAGE_STATE_ACTIVATED)
	    {
	      stage_win32->state &= ~CLUTTER_STAGE_STATE_ACTIVATED;

	      event->type = CLUTTER_STAGE_STATE;
	      event->stage_state.changed_mask = CLUTTER_STAGE_STATE_ACTIVATED;
	      event->stage_state.new_state = stage_win32->state;
	    }
	  else
	    res = FALSE;
	  break;
	}
      else
	{
	  if (!(stage_win32->state & CLUTTER_STAGE_STATE_ACTIVATED))
	    {
	      stage_win32->state |= CLUTTER_STAGE_STATE_ACTIVATED;

	      event->type = CLUTTER_STAGE_STATE;
	      event->stage_state.changed_mask = CLUTTER_STAGE_STATE_ACTIVATED;
	      event->stage_state.new_state = stage_win32->state;
	    }
	  else
	    res = FALSE;
	}
      break;

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

    case WM_DESTROY:
      CLUTTER_NOTE (EVENT, "WM_DESTROY");
      event->type = CLUTTER_DESTROY_NOTIFY;
      break;

    case WM_CLOSE:
      CLUTTER_NOTE (EVENT, "WM_CLOSE");
      event->type = CLUTTER_DELETE;
      /* The default window proc will destroy the window so we want to
	 prevent this to allow applications to optionally destroy the
	 window themselves */
      if (call_def_window_proc)
	*call_def_window_proc = FALSE;
      break;

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

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

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

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

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

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

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

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

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

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

      event->type = CLUTTER_SCROLL;
      event->scroll.time = msg->time;
      event->scroll.modifier_state
	= get_modifier_state (LOWORD (msg->wParam));

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

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

    case WM_MOUSEMOVE:
      event->type = 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);
      break;

    case WM_KEYDOWN:
    case WM_KEYUP:
    case WM_SYSKEYDOWN:
    case WM_SYSKEYUP:
      {
	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_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;
      }
      break;

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

    default:
      /* ignore every other message */
      res = FALSE;
      break;
    }

  return res;
}
Пример #21
0
static void
clutter_backend_egl_ensure_context (ClutterBackend *backend,
                                    ClutterStage   *stage)
{
  ClutterBackendEGL  *backend_egl = CLUTTER_BACKEND_EGL (backend);
  ClutterStageWindow *impl;

  if (stage == NULL ||
      (CLUTTER_PRIVATE_FLAGS (stage) & CLUTTER_ACTOR_IN_DESTRUCTION) ||
      ((impl = _clutter_stage_get_window (stage)) == NULL))
    {
      CLUTTER_NOTE (BACKEND, "Clearing EGL context");
      eglMakeCurrent (backend_egl->edpy,
                      EGL_NO_SURFACE,
                      EGL_NO_SURFACE,
                      EGL_NO_CONTEXT);
    }
  else
    {
      ClutterStageEGL    *stage_egl;
      ClutterStageX11    *stage_x11;

      g_assert (impl != NULL);

      CLUTTER_NOTE (MULTISTAGE, "Setting context for stage of type %s [%p]",
                    g_type_name (G_OBJECT_TYPE (impl)),
                    impl);

      stage_egl = CLUTTER_STAGE_EGL (impl);
      stage_x11 = CLUTTER_STAGE_X11 (impl);

      if (backend_egl->egl_context == EGL_NO_CONTEXT)
        return;

      clutter_x11_trap_x_errors ();

      /* we might get here inside the final dispose cycle, so we
       * need to handle this gracefully
       */
      if (stage_x11->xwin == None ||
          stage_egl->egl_surface == EGL_NO_SURFACE)
        {
          CLUTTER_NOTE (MULTISTAGE,
                        "Received a stale stage, clearing all context");

          if (backend_egl->dummy_surface == EGL_NO_SURFACE)
            eglMakeCurrent (backend_egl->edpy,
                            EGL_NO_SURFACE,
                            EGL_NO_SURFACE,
                            EGL_NO_CONTEXT);
          else
            eglMakeCurrent (backend_egl->edpy,
                            backend_egl->dummy_surface,
                            backend_egl->dummy_surface,
                            backend_egl->egl_context);
        }
      else
        {
          CLUTTER_NOTE (MULTISTAGE, "Setting real surface current");
          eglMakeCurrent (backend_egl->edpy,
                          stage_egl->egl_surface,
                          stage_egl->egl_surface,
                          backend_egl->egl_context);
        }

      if (clutter_x11_untrap_x_errors ())
        g_critical ("Unable to make the stage window 0x%x the current "
                    "EGLX drawable",
                    (int) stage_x11->xwin);
    }
}