Пример #1
0
static void
clutter_stage_x11_get_geometry (ClutterStageWindow    *stage_window,
                                cairo_rectangle_int_t *geometry)
{
  ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
  ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_x11);
  ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (stage_cogl->backend);

  geometry->x = geometry->y = 0;

  /* If we're fullscreen, return the size of the display.
   *
   * FIXME - this is utterly broken for anything that is not a single
   * head set up; the window manager will give us the right size in a
   * ConfigureNotify, but between the fullscreen signal emission on the
   * stage and the following frame, the size returned by the stage will
   * be wrong.
   */
  if (_clutter_stage_is_fullscreen (stage_cogl->wrapper) &&
      stage_x11->fullscreening)
    {
      geometry->width = DisplayWidth (backend_x11->xdpy, backend_x11->xscreen_num);
      geometry->height = DisplayHeight (backend_x11->xdpy, backend_x11->xscreen_num);

      return;
    }

  geometry->width = stage_x11->xwin_width;
  geometry->height = stage_x11->xwin_height;
}
Пример #2
0
static ClutterStageWindow *
clutter_backend_glx_create_stage (ClutterBackend  *backend,
                                  ClutterStage    *wrapper,
                                  GError         **error)
{
  ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
  ClutterStageWindow *stage_window;
  ClutterStageX11 *stage_x11;

  CLUTTER_NOTE (BACKEND, "Creating stage of type '%s'",
                g_type_name (CLUTTER_STAGE_TYPE));

  stage_window = g_object_new (CLUTTER_TYPE_STAGE_GLX, NULL);

  /* copy backend data into the stage */
  stage_x11 = CLUTTER_STAGE_X11 (stage_window);
  stage_x11->wrapper = wrapper;

  CLUTTER_NOTE (BACKEND,
                "GLX stage created[%p] (dpy:%p, screen:%d, root:%u, wrap:%p)",
                stage_window,
                backend_x11->xdpy,
                backend_x11->xscreen_num,
                (unsigned int) backend_x11->xwin_root,
                wrapper);

  return stage_window;
}
Пример #3
0
static void
clutter_stage_glx_unrealize (ClutterStageWindow *stage_window)
{
  ClutterBackend *backend = clutter_get_default_backend ();
  ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
  ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
  ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (stage_window);

  /* Note unrealize should free up any backend stage related resources */
  CLUTTER_NOTE (BACKEND, "Unrealizing stage");

  clutter_x11_trap_x_errors ();

  if (stage_glx->glxwin != None)
    {
      glXDestroyWindow (backend_x11->xdpy, stage_glx->glxwin);
      stage_glx->glxwin = None;
    }

  if (!stage_x11->is_foreign_xwin && stage_x11->xwin != None)
    {
      XDestroyWindow (backend_x11->xdpy, stage_x11->xwin);
      stage_x11->xwin = None;
    }
  else
    stage_x11->xwin = None;

  XSync (backend_x11->xdpy, False);

  clutter_x11_untrap_x_errors ();

  CLUTTER_MARK ();
}
Пример #4
0
static ClutterStageWindow *
clutter_backend_egl_create_stage (ClutterBackend  *backend,
                                  ClutterStage    *wrapper,
                                  GError         **error)
{
  ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
  ClutterStageX11 *stage_x11;
  ClutterStageWindow *stage;

  CLUTTER_NOTE (BACKEND, "Creating stage of type '%s'",
                g_type_name (CLUTTER_STAGE_TYPE));
  
  stage = g_object_new (CLUTTER_TYPE_STAGE_EGL, NULL);
  
  /* copy backend data into the stage */
  stage_x11 = CLUTTER_STAGE_X11 (stage);
  stage_x11->wrapper = wrapper;
  
  CLUTTER_NOTE (MISC, "EGLX stage created (display:%p, screen:%d, root:%u)",
                backend_x11->xdpy,
                backend_x11->xscreen_num,
                (unsigned int) backend_x11->xwin_root);
  
  return stage;
}
Пример #5
0
static gboolean
clutter_stage_glx_realize (ClutterStageWindow *stage_window)
{
  ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
  ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (stage_window);
  ClutterBackendX11 *backend_x11;
  ClutterBackendGLX *backend_glx;

  CLUTTER_NOTE (ACTOR, "Realizing stage '%s' [%p]",
                G_OBJECT_TYPE_NAME (stage_window),
                stage_window);

  if (!_clutter_stage_x11_create_window (stage_x11))
    return FALSE;

  backend_x11 = stage_x11->backend;
  backend_glx = CLUTTER_BACKEND_GLX (backend_x11);

  if (stage_glx->glxwin == None)
    {
      int major;
      int minor;
      GLXFBConfig config;

      /* Try and create a GLXWindow to use with extensions dependent on
       * GLX versions >= 1.3 that don't accept regular X Windows as GLX
       * drawables.
       */
      if (glXQueryVersion (backend_x11->xdpy, &major, &minor) &&
          major == 1 && minor >= 3 &&
          _clutter_backend_glx_get_fbconfig (backend_glx, &config))
        {
          stage_glx->glxwin = glXCreateWindow (backend_x11->xdpy,
                                               config,
                                               stage_x11->xwin,
                                               NULL);
        }
    }

#ifdef GLX_INTEL_swap_event
  if (clutter_feature_available (CLUTTER_FEATURE_SWAP_EVENTS))
    {
      GLXDrawable drawable = stage_glx->glxwin
                           ? stage_glx->glxwin
                           : stage_x11->xwin;

      /* we unconditionally select this event because we rely on it to
       * advance the master clock, and drive redraw/relayout, animations
       * and event handling.
       */
      glXSelectEvent (backend_x11->xdpy,
                      drawable,
                      GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK);
    }
#endif /* GLX_INTEL_swap_event */

  /* chain up to the StageX11 implementation */
  return clutter_stage_window_parent_iface->realize (stage_window);
}
Пример #6
0
static void
clutter_stage_x11_finalize (GObject *gobject)
{
  ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (gobject);

  g_free (stage_x11->title);

  G_OBJECT_CLASS (clutter_stage_x11_parent_class)->finalize (gobject);
}
Пример #7
0
static void
clutter_stage_x11_set_cursor_visible (ClutterStageWindow *stage_window,
                                      gboolean            cursor_visible)
{
  ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);

  stage_x11->is_cursor_visible = !!cursor_visible;
  set_cursor_visible (stage_x11);
}
Пример #8
0
static void
clutter_stage_x11_set_accept_focus (ClutterStageWindow *stage_window,
                                    gboolean            accept_focus)
{
  ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);

  stage_x11->accept_focus = !!accept_focus;
  update_wm_hints (stage_x11);
}
Пример #9
0
static void
clutter_stage_x11_set_title (ClutterStageWindow *stage_window,
                             const gchar        *title)
{
  ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);

  g_free (stage_x11->title);
  stage_x11->title = g_strdup (title);
  set_wm_title (stage_x11);
}
Пример #10
0
static void
clutter_stage_x11_set_user_resizable (ClutterStageWindow *stage_window,
                                      gboolean            is_resizable)
{
  ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);

  clutter_stage_x11_fix_window_size (stage_x11,
                                     stage_x11->xwin_width,
                                     stage_x11->xwin_height);
}
Пример #11
0
static gboolean
clutter_stage_x11_can_clip_redraws (ClutterStageWindow *stage_window)
{
  ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);

  /* while resizing a window, clipped redraws are disabled in order to
   * avoid artefacts. see clutter-event-x11.c:event_translate for a more
   * detailed explanation
   */
  return stage_x11->clipped_redraws_cool_off == 0;
}
Пример #12
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;
}
Пример #13
0
static void
clutter_stage_x11_unrealize (ClutterStageWindow *stage_window)
{
  ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);

  if (clutter_stages_by_xid != NULL)
    {
      CLUTTER_NOTE (BACKEND, "Removing X11 stage 0x%x [%p]",
                    (unsigned int) stage_x11->xwin,
                    stage_x11);

      g_hash_table_remove (clutter_stages_by_xid,
                           GINT_TO_POINTER (stage_x11->xwin));
    }

  clutter_stage_window_parent_iface->unrealize (stage_window);
}
Пример #14
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 ();
    }
}
Пример #15
0
static void
clutter_stage_x11_hide (ClutterStageWindow *stage_window)
{
  ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
  ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_x11);
  ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (stage_cogl->backend);

  if (stage_x11->xwin != None)
    {
      if (STAGE_X11_IS_MAPPED (stage_x11))
        set_stage_x11_state (stage_x11, 0, STAGE_X11_WITHDRAWN);

      g_assert (!STAGE_X11_IS_MAPPED (stage_x11));

      clutter_actor_unmap (CLUTTER_ACTOR (stage_cogl->wrapper));

      if (!stage_x11->is_foreign_xwin)
        XWithdrawWindow (backend_x11->xdpy, stage_x11->xwin, 0);
    }
}
Пример #16
0
static void
clutter_stage_x11_show (ClutterStageWindow *stage_window,
                        gboolean            do_raise)
{
  ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
  ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_x11);
  ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (stage_cogl->backend);

  if (stage_x11->xwin != None)
    {
      if (do_raise && !stage_x11->is_foreign_xwin)
        {
          CLUTTER_NOTE (BACKEND, "Raising stage[%lu]",
                        (unsigned long) stage_x11->xwin);
          XRaiseWindow (backend_x11->xdpy, stage_x11->xwin);
        }

      if (!STAGE_X11_IS_MAPPED (stage_x11))
        {
          CLUTTER_NOTE (BACKEND, "Mapping stage[%lu]",
                        (unsigned long) stage_x11->xwin);

          set_stage_x11_state (stage_x11, STAGE_X11_WITHDRAWN, 0);

          update_wm_hints (stage_x11);

          if (stage_x11->fullscreening)
            clutter_stage_x11_set_fullscreen (stage_window, TRUE);
          else
            clutter_stage_x11_set_fullscreen (stage_window, FALSE);
        }

      g_assert (STAGE_X11_IS_MAPPED (stage_x11));

      clutter_actor_map (CLUTTER_ACTOR (stage_cogl->wrapper));

      if (!stage_x11->is_foreign_xwin)
        XMapWindow (backend_x11->xdpy, stage_x11->xwin);
    }
}
Пример #17
0
static ClutterTranslateReturn
clutter_stage_glx_translate_event (ClutterEventTranslator *translator,
                                   gpointer                native,
                                   ClutterEvent           *event)
{
#ifdef GLX_INTEL_swap_event
  ClutterBackendGLX *backend_glx;
  XEvent *xevent = native;

  backend_glx = CLUTTER_BACKEND_GLX (clutter_get_default_backend ());

  if (xevent->type == (backend_glx->event_base + GLX_BufferSwapComplete))
    {
      ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (translator);
      ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (translator);
      GLXBufferSwapComplete *swap_complete_event;

      swap_complete_event = (GLXBufferSwapComplete *) xevent;

      if (stage_x11->xwin == swap_complete_event->drawable)
        {
	  /* Early versions of the swap_event implementation in Mesa
	   * deliver BufferSwapComplete event when not selected for,
	   * so if we get a swap event we aren't expecting, just ignore it.
	   *
	   * https://bugs.freedesktop.org/show_bug.cgi?id=27962
	   */
          if (stage_glx->pending_swaps > 0)
            stage_glx->pending_swaps--;

          return CLUTTER_TRANSLATE_REMOVE;
        }
    }
#endif

  /* chain up to the common X11 implementation */
  return clutter_event_translator_parent_iface->translate_event (translator,
                                                                 native,
                                                                 event);
}
Пример #18
0
static void
clutter_stage_glx_unrealize (ClutterStageWindow *stage_window)
{
  ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
  ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (stage_window);
  ClutterBackendX11 *backend_x11 = stage_x11->backend;

  /* Note unrealize should free up any backend stage related resources */
  CLUTTER_NOTE (BACKEND, "Unrealizing GLX stage [%p]", stage_glx);

  clutter_x11_trap_x_errors ();

  if (stage_glx->glxwin != None)
    {
      glXDestroyWindow (backend_x11->xdpy, stage_glx->glxwin);
      stage_glx->glxwin = None;
    }

  _clutter_stage_x11_destroy_window_untrapped (stage_x11);

  XSync (backend_x11->xdpy, False);

  clutter_x11_untrap_x_errors ();
}
Пример #19
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);
    }
}
Пример #20
0
static gboolean
clutter_stage_glx_realize (ClutterStageWindow *stage_window)
{
  ClutterStageX11   *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
  ClutterStageGLX   *stage_glx = CLUTTER_STAGE_GLX (stage_window);
  ClutterBackend    *backend;
  ClutterBackendGLX *backend_glx;
  ClutterBackendX11 *backend_x11;
  GError            *error;

  CLUTTER_NOTE (ACTOR, "Realizing stage '%s' [%p]",
                G_OBJECT_TYPE_NAME (stage_window),
                stage_window);

  backend     = clutter_get_default_backend ();
  backend_glx = CLUTTER_BACKEND_GLX (backend);
  backend_x11 = CLUTTER_BACKEND_X11 (backend);

  if (stage_x11->xwin == None)
    {
      XSetWindowAttributes xattr;
      unsigned long mask;
      XVisualInfo *xvisinfo;
      gfloat width, height;

      CLUTTER_NOTE (MISC, "Creating stage X window");

      xvisinfo = clutter_backend_x11_get_visual_info (backend_x11);
      if (xvisinfo == NULL)
        {
          g_critical ("Unable to find suitable GL visual.");
          return FALSE;
        }

      /* window attributes */
      xattr.background_pixel = WhitePixel (backend_x11->xdpy,
                                           backend_x11->xscreen_num);
      xattr.border_pixel = 0;
      xattr.colormap = XCreateColormap (backend_x11->xdpy,
                                        backend_x11->xwin_root,
                                        xvisinfo->visual,
                                        AllocNone);
      mask = CWBorderPixel | CWColormap;

      /* Call get_size - this will either get the geometry size (which
       * before we create the window is set to 640x480), or if a size
       * is set, it will get that. This lets you set a size on the
       * stage before it's realized.
       */
      clutter_actor_get_size (CLUTTER_ACTOR (stage_x11->wrapper),
                              &width,
                              &height);
      stage_x11->xwin_width = (gint)width;
      stage_x11->xwin_height = (gint)height;

      stage_x11->xwin = XCreateWindow (backend_x11->xdpy,
                                       backend_x11->xwin_root,
                                       0, 0,
                                       stage_x11->xwin_width,
                                       stage_x11->xwin_height,
                                       0,
                                       xvisinfo->depth,
                                       InputOutput,
                                       xvisinfo->visual,
                                       mask, &xattr);

      CLUTTER_NOTE (BACKEND, "Stage [%p], window: 0x%x, size: %dx%d",
                    stage_window,
                    (unsigned int) stage_x11->xwin,
                    stage_x11->xwin_width,
                    stage_x11->xwin_height);

      XFree (xvisinfo);
    }

  if (stage_glx->glxwin == None)
    {
      int major;
      int minor;
      GLXFBConfig config;

      /* Try and create a GLXWindow to use with extensions dependent on
       * GLX versions >= 1.3 that don't accept regular X Windows as GLX
       * drawables. */
      if (glXQueryVersion (backend_x11->xdpy, &major, &minor) &&
          major == 1 && minor >= 3 &&
          _clutter_backend_glx_get_fbconfig (backend_glx, &config))
        {
          stage_glx->glxwin = glXCreateWindow (backend_x11->xdpy,
                                               config,
                                               stage_x11->xwin,
                                               NULL);
        }
    }

  if (clutter_x11_has_event_retrieval ())
    {
      if (clutter_x11_has_xinput ())
        {
          XSelectInput (backend_x11->xdpy, stage_x11->xwin,
                        StructureNotifyMask |
                        FocusChangeMask |
                        ExposureMask |
                        KeyPressMask | KeyReleaseMask |
                        EnterWindowMask | LeaveWindowMask |
                        PropertyChangeMask);
#ifdef HAVE_XINPUT
          _clutter_x11_select_events (stage_x11->xwin);
#endif
        }
      else
        XSelectInput (backend_x11->xdpy, stage_x11->xwin,
                      StructureNotifyMask |
                      FocusChangeMask |
                      ExposureMask |
                      PointerMotionMask |
                      KeyPressMask | KeyReleaseMask |
                      ButtonPressMask | ButtonReleaseMask |
                      EnterWindowMask | LeaveWindowMask |
                      PropertyChangeMask);

#ifdef GLX_INTEL_swap_event
      if (clutter_feature_available (CLUTTER_FEATURE_SWAP_EVENTS))
        {
          GLXDrawable drawable =
            stage_glx->glxwin ? stage_glx->glxwin : stage_x11->xwin;
          glXSelectEvent (backend_x11->xdpy,
                          drawable,
                          GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK);
        }
#endif /* GLX_INTEL_swap_event */
    }

  /* no user resize.. */
  clutter_stage_x11_fix_window_size (stage_x11,
                                     stage_x11->xwin_width,
                                     stage_x11->xwin_height);
  clutter_stage_x11_set_wm_protocols (stage_x11);

  /* ask for a context; a no-op, if a context already exists */
  error = NULL;
  _clutter_backend_create_context (backend, &error);
  if (error)
    {
      g_critical ("Unable to realize stage: %s", error->message);
      g_error_free (error);
      return FALSE;
    }

  CLUTTER_NOTE (BACKEND, "Successfully realized stage");

  /* chain up to the StageX11 implementation */
  return clutter_stage_glx_parent_iface->realize (stage_window);
}
Пример #21
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;
}
Пример #22
0
static void
clutter_stage_glx_redraw (ClutterStageWindow *stage_window)
{
  ClutterBackendX11 *backend_x11;
  ClutterBackendGLX *backend_glx;
  ClutterStageX11 *stage_x11;
  ClutterStageGLX *stage_glx;
  GLXDrawable drawable;
  unsigned int video_sync_count;
  gboolean may_use_clipped_redraw;
  gboolean use_clipped_redraw;

  CLUTTER_STATIC_TIMER (painting_timer,
                        "Redrawing", /* parent */
                        "Painting actors",
                        "The time spent painting actors",
                        0 /* no application private data */);
  CLUTTER_STATIC_TIMER (swapbuffers_timer,
                        "Redrawing", /* parent */
                        "glXSwapBuffers",
                        "The time spent blocked by glXSwapBuffers",
                        0 /* no application private data */);
  CLUTTER_STATIC_TIMER (blit_sub_buffer_timer,
                        "Redrawing", /* parent */
                        "glx_blit_sub_buffer",
                        "The time spent in _glx_blit_sub_buffer",
                        0 /* no application private data */);

  stage_x11 = CLUTTER_STAGE_X11 (stage_window);
  if (stage_x11->xwin == None)
    return;

  stage_glx = CLUTTER_STAGE_GLX (stage_window);

  backend_x11 = stage_x11->backend;
  backend_glx = CLUTTER_BACKEND_GLX (backend_x11);

  CLUTTER_TIMER_START (_clutter_uprof_context, painting_timer);

  if (G_LIKELY (backend_glx->can_blit_sub_buffer) &&
      /* NB: a zero width redraw clip == full stage redraw */
      stage_glx->bounding_redraw_clip.width != 0 &&
      /* some drivers struggle to get going and produce some junk
       * frames when starting up... */
      G_LIKELY (stage_glx->frame_count > 3) &&
      /* While resizing a window clipped redraws are disabled to avoid
       * artefacts. See clutter-event-x11.c:event_translate for a
       * detailed explanation */
      G_LIKELY (stage_x11->clipped_redraws_cool_off == 0))
    {
      may_use_clipped_redraw = TRUE;
    }
  else
    may_use_clipped_redraw = FALSE;

  if (may_use_clipped_redraw &&
      G_LIKELY (!(clutter_paint_debug_flags &
                  CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
    use_clipped_redraw = TRUE;
  else
    use_clipped_redraw = FALSE;

  if (use_clipped_redraw)
    {
      CLUTTER_NOTE (CLIPPING,
                    "Stage clip pushed: x=%d, y=%d, width=%d, height=%d\n",
                    stage_glx->bounding_redraw_clip.x,
                    stage_glx->bounding_redraw_clip.y,
                    stage_glx->bounding_redraw_clip.width,
                    stage_glx->bounding_redraw_clip.height);
      cogl_clip_push_window_rectangle (stage_glx->bounding_redraw_clip.x,
                                       stage_glx->bounding_redraw_clip.y,
                                       stage_glx->bounding_redraw_clip.width,
                                       stage_glx->bounding_redraw_clip.height);
      _clutter_stage_do_paint (stage_x11->wrapper,
                               &stage_glx->bounding_redraw_clip);
      cogl_clip_pop ();
    }
  else
    {
      CLUTTER_NOTE (CLIPPING, "Unclipped stage paint\n");
      _clutter_stage_do_paint (stage_x11->wrapper, NULL);
    }

  if (may_use_clipped_redraw &&
      G_UNLIKELY ((clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS)))
    {
      static CoglMaterial *outline = NULL;
      ClutterGeometry *clip = &stage_glx->bounding_redraw_clip;
      ClutterActor *actor = CLUTTER_ACTOR (stage_x11->wrapper);
      CoglHandle vbo;
      float x_1 = clip->x;
      float x_2 = clip->x + clip->width;
      float y_1 = clip->y;
      float y_2 = clip->y + clip->height;
      float quad[8] = {
        x_1, y_1,
        x_2, y_1,
        x_2, y_2,
        x_1, y_2
      };
      CoglMatrix modelview;

      if (outline == NULL)
        {
          outline = cogl_material_new ();
          cogl_material_set_color4ub (outline, 0xff, 0x00, 0x00, 0xff);
        }

      vbo = cogl_vertex_buffer_new (4);
      cogl_vertex_buffer_add (vbo,
                              "gl_Vertex",
                              2, /* n_components */
                              COGL_ATTRIBUTE_TYPE_FLOAT,
                              FALSE, /* normalized */
                              0, /* stride */
                              quad);
      cogl_vertex_buffer_submit (vbo);

      cogl_push_matrix ();
      cogl_matrix_init_identity (&modelview);
      _clutter_actor_apply_modelview_transform (actor, &modelview);
      cogl_set_modelview_matrix (&modelview);
      cogl_set_source (outline);
      cogl_vertex_buffer_draw (vbo, COGL_VERTICES_MODE_LINE_LOOP,
                               0 , 4);
      cogl_pop_matrix ();
      cogl_object_unref (vbo);
    }

  cogl_flush ();
  CLUTTER_TIMER_STOP (_clutter_uprof_context, painting_timer);

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

  /* If we might ever use _clutter_backend_glx_blit_sub_buffer then we
   * always need to keep track of the video_sync_count so that we can
   * throttle blits.
   *
   * Note: we get the count *before* we issue any glXCopySubBuffer or
   * blit_sub_buffer request in case the count would go up before
   * returning control to us.
   */
  if (backend_glx->can_blit_sub_buffer && backend_glx->get_video_sync)
    backend_glx->get_video_sync (&video_sync_count);

  /* push on the screen */
  if (use_clipped_redraw)
    {
      ClutterGeometry *clip = &stage_glx->bounding_redraw_clip;
      ClutterGeometry copy_area;
      ClutterActor *actor;

      CLUTTER_NOTE (BACKEND,
                    "_glx_blit_sub_buffer (window: 0x%lx, "
                                          "x: %d, y: %d, "
                                          "width: %d, height: %d)",
                    (unsigned long) drawable,
                    stage_glx->bounding_redraw_clip.x,
                    stage_glx->bounding_redraw_clip.y,
                    stage_glx->bounding_redraw_clip.width,
                    stage_glx->bounding_redraw_clip.height);

      /* XXX: It seems there will be a race here in that the stage
       * window may be resized before glXCopySubBufferMESA is handled
       * and so we may copy the wrong region. I can't really see how
       * we can handle this with the current state of X but at least
       * in this case a full redraw should be queued by the resize
       * anyway so it should only exhibit temporary artefacts.
       */
      actor = CLUTTER_ACTOR (stage_x11->wrapper);
      copy_area.y = clutter_actor_get_height (actor)
                  - clip->y
                  - clip->height;
      copy_area.x = clip->x;
      copy_area.width = clip->width;
      copy_area.height = clip->height;

      /* glXCopySubBufferMESA and glBlitFramebuffer are not integrated
       * with the glXSwapIntervalSGI mechanism which we usually use to
       * throttle the Clutter framerate to the vertical refresh and so
       * we have to manually wait for the vblank period...
       */

      /* Here 'is_synchronized' only means that the blit won't cause a
       * tear, ie it won't prevent multiple blits per retrace if they
       * can all be performed in the blanking period. If that's the
       * case then we still want to use the vblank sync menchanism but
       * we only need it to throttle redraws.
       */
      if (!backend_glx->blit_sub_buffer_is_synchronized)
        {
          /* XXX: note that glXCopySubBuffer, at least for Intel, is
           * synchronized with the vblank but glBlitFramebuffer may
           * not be so we use the same scheme we do when calling
           * glXSwapBuffers without the swap_control extension and
           * call glFinish () before waiting for the vblank period.
           *
           * See where we call glXSwapBuffers for more details.
           */
          glFinish ();
          wait_for_vblank (backend_glx);
        }
      else if (backend_glx->get_video_sync)
        {
          /* If we have the GLX_SGI_video_sync extension then we can
           * be a bit smarter about how we throttle blits by avoiding
           * any waits if we can see that the video sync count has
           * already progressed. */
          if (backend_glx->last_video_sync_count == video_sync_count)
            wait_for_vblank (backend_glx);
        }
      else
        wait_for_vblank (backend_glx);

      CLUTTER_TIMER_START (_clutter_uprof_context, blit_sub_buffer_timer);
      _clutter_backend_glx_blit_sub_buffer (backend_glx,
                                            drawable,
                                            copy_area.x,
                                            copy_area.y,
                                            copy_area.width,
                                            copy_area.height);
      CLUTTER_TIMER_STOP (_clutter_uprof_context, blit_sub_buffer_timer);
    }
  else
    {
      CLUTTER_NOTE (BACKEND, "glXSwapBuffers (display: %p, window: 0x%lx)",
                    backend_x11->xdpy,
                    (unsigned long) drawable);

      /* If we have GLX swap buffer events then glXSwapBuffers will return
       * immediately and we need to track that there is a swap in
       * progress... */
      if (clutter_feature_available (CLUTTER_FEATURE_SWAP_EVENTS))
        stage_glx->pending_swaps++;

      if (backend_glx->vblank_type != CLUTTER_VBLANK_GLX_SWAP &&
          backend_glx->vblank_type != CLUTTER_VBLANK_NONE)
        {
          /* If we are going to wait for VBLANK manually, we not only
           * need to flush out pending drawing to the GPU before we
           * sleep, we need to wait for it to finish. Otherwise, we
           * may end up with the situation:
           *
           *        - We finish drawing      - GPU drawing continues
           *        - We go to sleep         - GPU drawing continues
           * VBLANK - We call glXSwapBuffers - GPU drawing continues
           *                                 - GPU drawing continues
           *                                 - Swap buffers happens
           *
           * Producing a tear. Calling glFinish() first will cause us
           * to properly wait for the next VBLANK before we swap. This
           * obviously does not happen when we use _GLX_SWAP and let
           * the driver do the right thing
           */
          glFinish ();

          wait_for_vblank (backend_glx);
        }

      CLUTTER_TIMER_START (_clutter_uprof_context, swapbuffers_timer);
      glXSwapBuffers (backend_x11->xdpy, drawable);
      CLUTTER_TIMER_STOP (_clutter_uprof_context, swapbuffers_timer);

      _cogl_swap_buffers_notify ();
    }

  backend_glx->last_video_sync_count = video_sync_count;

  /* reset the redraw clipping for the next paint... */
  stage_glx->initialized_redraw_clip = FALSE;

  stage_glx->frame_count++;
}
Пример #23
0
static gboolean
clutter_stage_x11_realize (ClutterStageWindow *stage_window)
{
  ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
  ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
  ClutterBackend *backend = CLUTTER_BACKEND (stage_cogl->backend);
  ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
  ClutterDeviceManager *device_manager;
  int event_flags;
  gfloat width, height;

  clutter_actor_get_size (CLUTTER_ACTOR (stage_cogl->wrapper),
			  &width, &height);

  stage_cogl->onscreen = cogl_onscreen_new (backend->cogl_context,
                                            width, height);

  /* We just created a window of the size of the actor. No need to fix
     the size of the stage, just update it. */
  stage_x11->xwin_width = width;
  stage_x11->xwin_height = height;

  if (stage_x11->xwin != None)
    {
      cogl_x11_onscreen_set_foreign_window_xid (stage_cogl->onscreen,
                                                stage_x11->xwin,
                                                _clutter_stage_x11_update_foreign_event_mask,
                                                stage_x11);

    }

  /* Chain to the parent class now. ClutterStageCogl will call cogl_framebuffer_allocate,
     which will create the X Window we need */

  if (!(clutter_stage_window_parent_iface->realize (stage_window)))
    return FALSE;

  if (stage_x11->xwin == None)
    stage_x11->xwin = cogl_x11_onscreen_get_window_xid (stage_cogl->onscreen);

  if (clutter_stages_by_xid == NULL)
    clutter_stages_by_xid = g_hash_table_new (NULL, NULL);

  g_hash_table_insert (clutter_stages_by_xid,
                       GINT_TO_POINTER (stage_x11->xwin),
                       stage_x11);

  set_wm_pid (stage_x11);
  set_wm_title (stage_x11);
  set_cursor_visible (stage_x11);


  /* the masks for the events we want to select on a stage window;
   * KeyPressMask and KeyReleaseMask are necessary even with XI1
   * because key events are broken with that extension, and will
   * be fixed by XI2
   */
  event_flags = CLUTTER_STAGE_X11_EVENT_MASK;

  /* we unconditionally select input events even with event retrieval
   * disabled because we need to guarantee that the Clutter internal
   * state is maintained when calling clutter_x11_handle_event() without
   * requiring applications or embedding toolkits to select events
   * themselves. if we did that, we'd have to document the events to be
   * selected, and also update applications and embedding toolkits each
   * time we added a new mask, or a new class of events.
   *
   * see: http://bugzilla.clutter-project.org/show_bug.cgi?id=998
   * for the rationale of why we did conditional selection. it is now
   * clear that a compositor should clear out the input region, since
   * it cannot assume a perfectly clean slate coming from us.
   *
   * see: http://bugzilla.clutter-project.org/show_bug.cgi?id=2228
   * for an example of things that break if we do conditional event
   * selection.
   */
  XSelectInput (backend_x11->xdpy, stage_x11->xwin, event_flags);

  /* input events also depent on the actual device, so we need to
   * use the device manager to let every device select them, using
   * the event mask we passed to XSelectInput as the template
   */
  device_manager = clutter_device_manager_get_default ();
  if (G_UNLIKELY (device_manager != NULL))
    {
      _clutter_device_manager_select_stage_events (device_manager,
                                                   stage_cogl->wrapper,
                                                   event_flags);

      g_signal_connect (device_manager, "device-added",
                        G_CALLBACK (stage_events_device_added),
                        stage_window);
    }

  clutter_stage_x11_fix_window_size (stage_x11,
                                     stage_x11->xwin_width,
                                     stage_x11->xwin_height);
  clutter_stage_x11_set_wm_protocols (stage_x11);

  if (stage_x11->fullscreen_on_realize)
    {
      stage_x11->fullscreen_on_realize = FALSE;

      clutter_stage_x11_set_fullscreen (stage_window, TRUE);
    }

  CLUTTER_NOTE (BACKEND, "Successfully realized stage");

  return TRUE;
}
Пример #24
0
static void
clutter_stage_x11_set_fullscreen (ClutterStageWindow *stage_window,
                                  gboolean            is_fullscreen)
{
  ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
  ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_x11);
  ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (stage_cogl->backend);
  ClutterStage *stage = stage_cogl->wrapper;
  gboolean was_fullscreen;

  if (stage == NULL || CLUTTER_ACTOR_IN_DESTRUCTION (stage))
    return;

  was_fullscreen = _clutter_stage_is_fullscreen (stage);
  is_fullscreen = !!is_fullscreen;

  if (was_fullscreen == is_fullscreen)
    return;

  CLUTTER_NOTE (BACKEND, "%ssetting fullscreen", is_fullscreen ? "" : "un");

  if (is_fullscreen)
    {
#if 0
      int width, height;

      /* FIXME: this will do the wrong thing for dual-headed
         displays. This will return the size of the combined display
         but Metacity (at least) will fullscreen to only one of the
         displays. This will cause the actor to report the wrong size
         until the ConfigureNotify for the correct size is received */
      width  = DisplayWidth (backend_x11->xdpy, backend_x11->xscreen_num);
      height = DisplayHeight (backend_x11->xdpy, backend_x11->xscreen_num);
#endif

      /* Set the fullscreen hint so we can retain the old size of the window. */
      stage_x11->fullscreening = TRUE;

      if (stage_x11->xwin != None)
        {
          /* if the actor is not mapped we resize the stage window to match
           * the size of the screen; this is useful for e.g. EGLX to avoid
           * a resize when calling clutter_stage_fullscreen() before showing
           * the stage
           */
          if (!STAGE_X11_IS_MAPPED (stage_x11))
            {
              CLUTTER_NOTE (BACKEND, "Fullscreening unmapped stage");

              update_state (stage_x11, backend_x11,
                            &backend_x11->atom_NET_WM_STATE_FULLSCREEN,
                            TRUE);
            }
          else
            {
              CLUTTER_NOTE (BACKEND, "Fullscreening mapped stage");

              /* We need to fix the window size so that it will remove
                 the maximum and minimum window hints. Otherwise
                 metacity will honour the restrictions and not
                 fullscreen correctly. */
              clutter_stage_x11_fix_window_size (stage_x11, -1, -1);

              send_wmspec_change_state (backend_x11, stage_x11->xwin,
                                        backend_x11->atom_NET_WM_STATE_FULLSCREEN,
                                        TRUE);
            }
        }
      else
        stage_x11->fullscreen_on_realize = TRUE;
    }
  else
    {
      stage_x11->fullscreening = FALSE;

      if (stage_x11->xwin != None)
        {
          if (!STAGE_X11_IS_MAPPED (stage_x11))
            {
              CLUTTER_NOTE (BACKEND, "Un-fullscreening unmapped stage");

              update_state (stage_x11, backend_x11,
                            &backend_x11->atom_NET_WM_STATE_FULLSCREEN,
                            FALSE);
            }
          else
            {
              CLUTTER_NOTE (BACKEND, "Un-fullscreening mapped stage");

              send_wmspec_change_state (backend_x11,
                                        stage_x11->xwin,
                                        backend_x11->atom_NET_WM_STATE_FULLSCREEN,
                                        FALSE);

              /* Fix the window size to restore the minimum/maximum
                 restriction */
              clutter_stage_x11_fix_window_size (stage_x11,
                                                 stage_x11->xwin_width,
                                                 stage_x11->xwin_height);
            }
        }
      else
        stage_x11->fullscreen_on_realize = FALSE;
    }

  /* XXX: Note we rely on the ConfigureNotify mechanism as the common
   * mechanism to handle notifications of new X window sizes from the
   * X server so we don't actively change the stage viewport here or
   * queue a relayout etc. */
}
Пример #25
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;
}
Пример #26
0
static ClutterTranslateReturn
clutter_stage_x11_translate_event (ClutterEventTranslator *translator,
                                   gpointer                native,
                                   ClutterEvent           *event)
{
  ClutterStageX11 *stage_x11;
  ClutterStageCogl *stage_cogl;
  ClutterTranslateReturn res = CLUTTER_TRANSLATE_CONTINUE;
  ClutterBackendX11 *backend_x11;
  Window stage_xwindow;
  XEvent *xevent = native;
  ClutterStage *stage;

  stage_cogl = clutter_x11_get_stage_window_from_window (xevent->xany.window);
  if (stage_cogl == NULL)
    return CLUTTER_TRANSLATE_CONTINUE;

  stage = stage_cogl->wrapper;
  stage_x11 = CLUTTER_STAGE_X11 (stage_cogl);
  backend_x11 = CLUTTER_BACKEND_X11 (stage_cogl->backend);
  stage_xwindow = stage_x11->xwin;

  switch (xevent->type)
    {
    case ConfigureNotify:
      if (!stage_x11->is_foreign_xwin)
        {
          gboolean size_changed = FALSE;

          CLUTTER_NOTE (BACKEND, "ConfigureNotify[%x] (%d, %d)",
                        (unsigned int) stage_x11->xwin,
                        xevent->xconfigure.width,
                        xevent->xconfigure.height);

          /* When fullscreen, we'll keep the xwin_width/height
             variables to track the old size of the window and we'll
             assume all ConfigureNotifies constitute a size change */
          if (_clutter_stage_is_fullscreen (stage))
            size_changed = TRUE;
          else if ((stage_x11->xwin_width != xevent->xconfigure.width) ||
                   (stage_x11->xwin_height != xevent->xconfigure.height))
            {
              size_changed = TRUE;
              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_cogl->wrapper, CLUTTER_IN_RESIZE);

          if (size_changed)
            {
              /* XXX: This is a workaround for a race condition when
               * resizing windows while there are in-flight
               * glXCopySubBuffer blits happening.
               *
               * The problem stems from the fact that rectangles for the
               * blits are described relative to the bottom left of the
               * window and because we can't guarantee control over the X
               * window gravity used when resizing so the gravity is
               * typically NorthWest not SouthWest.
               *
               * This means if you grow a window vertically the server
               * will make sure to place the old contents of the window
               * at the top-left/north-west of your new larger window, but
               * that may happen asynchronous to GLX preparing to do a
               * blit specified relative to the bottom-left/south-west of
               * the window (based on the old smaller window geometry).
               *
               * When the GLX issued blit finally happens relative to the
               * new bottom of your window, the destination will have
               * shifted relative to the top-left where all the pixels you
               * care about are so it will result in a nasty artefact
               * making resizing look very ugly!
               *
               * We can't currently fix this completely, in-part because
               * the window manager tends to trample any gravity we might
               * set.  This workaround instead simply disables blits for a
               * while if we are notified of any resizes happening so if
               * the user is resizing a window via the window manager then
               * they may see an artefact for one frame but then we will
               * fallback to redrawing the full stage until the cooling
               * off period is over.
               */
              if (stage_x11->clipped_redraws_cool_off)
                g_source_remove (stage_x11->clipped_redraws_cool_off);

              stage_x11->clipped_redraws_cool_off =
                clutter_threads_add_timeout (1000,
                                             clipped_redraws_cool_off_cb,
                                             stage_x11);

              /* Queue a relayout - we want glViewport to be called
               * with the correct values, and this is done in ClutterStage
               * via cogl_onscreen_clutter_backend_set_size ().
               *
               * We queue a relayout, because if this ConfigureNotify is
               * in response to a size we set in the application, the
               * set_size() call 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.
               */
              clutter_actor_queue_relayout (CLUTTER_ACTOR (stage));

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

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

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

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

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

              is_fullscreen = _clutter_stage_is_fullscreen (stage_cogl->wrapper);

              if (fullscreen_set != is_fullscreen)
                {
                  if (fullscreen_set)
                    _clutter_stage_update_state (stage_cogl->wrapper,
                                                 0,
                                                 CLUTTER_STAGE_STATE_FULLSCREEN);
                  else
                    _clutter_stage_update_state (stage_cogl->wrapper,
                                                 CLUTTER_STAGE_STATE_FULLSCREEN,
                                                 0);
                }

              XFree (data);
            }
        }
      break;

    case FocusIn:
      if (!_clutter_stage_is_activated (stage_cogl->wrapper))
        {
          _clutter_stage_update_state (stage_cogl->wrapper,
                                       0,
                                       CLUTTER_STAGE_STATE_ACTIVATED);
        }
      break;

    case FocusOut:
      if (_clutter_stage_is_activated (stage_cogl->wrapper))
        {
          _clutter_stage_update_state (stage_cogl->wrapper,
                                       CLUTTER_STAGE_STATE_ACTIVATED,
                                       0);
        }
      break;

    case EnterNotify:
#if HAVE_XFIXES
      if (!stage_x11->is_cursor_visible && !stage_x11->cursor_hidden_xfixes)
        {
          XFixesHideCursor (backend_x11->xdpy, stage_x11->xwin);
          stage_x11->cursor_hidden_xfixes = TRUE;
        }
#endif
      break;

    case LeaveNotify:
#if HAVE_XFIXES
      if (stage_x11->cursor_hidden_xfixes)
        {
          XFixesShowCursor (backend_x11->xdpy, stage_x11->xwin);
          stage_x11->cursor_hidden_xfixes = FALSE;
        }
#endif
      break;

    case Expose:
      {
        XExposeEvent *expose = (XExposeEvent *) xevent;
        cairo_rectangle_int_t clip;

        CLUTTER_NOTE (EVENT,
                      "expose for stage: %s[%p], win:0x%x - "
                      "redrawing area (x: %d, y: %d, width: %d, height: %d)",
                      _clutter_actor_get_debug_name (CLUTTER_ACTOR (stage)),
                      stage,
                      (unsigned int) stage_xwindow,
                      expose->x,
                      expose->y,
                      expose->width,
                      expose->height);

        clip.x = expose->x;
        clip.y = expose->y;
        clip.width = expose->width;
        clip.height = expose->height;
        clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stage), &clip);
      }
      break;

    case DestroyNotify:
      CLUTTER_NOTE (EVENT,
                    "Destroy notification received for stage %s[%p], win:0x%x",
                    _clutter_actor_get_debug_name (CLUTTER_ACTOR (stage)),
                    stage,
                    (unsigned int) stage_xwindow);
      event->any.type = CLUTTER_DESTROY_NOTIFY;
      event->any.stage = stage;
      res = CLUTTER_TRANSLATE_QUEUE;
      break;

    case ClientMessage:
      CLUTTER_NOTE (EVENT, "Client message for stage %s[%p], win:0x%x",
                    _clutter_actor_get_debug_name (CLUTTER_ACTOR (stage)),
                    stage,
                    (unsigned int) stage_xwindow);
      if (handle_wm_protocols_event (backend_x11, stage_x11, xevent))
        {
          event->any.type = CLUTTER_DELETE;
          event->any.stage = stage;
          res = CLUTTER_TRANSLATE_QUEUE;
        }
      break;

    case MappingNotify:
      CLUTTER_NOTE (EVENT, "Refresh keyboard mapping");
      XRefreshKeyboardMapping (&xevent->xmapping);
      backend_x11->keymap_serial += 1;
      res = CLUTTER_TRANSLATE_REMOVE;
      break;

    default:
      res = CLUTTER_TRANSLATE_CONTINUE;
      break;
    }

  return res;
}
Пример #27
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);
    }
}
Пример #28
0
static void
clutter_stage_x11_resize (ClutterStageWindow *stage_window,
                          gint                width,
                          gint                height)
{
  ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
  ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_x11);
  ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (stage_cogl->backend);

  if (stage_x11->is_foreign_xwin)
    {
      /* If this is a foreign window we won't get a ConfigureNotify,
       * so we need to manually set the size and queue a relayout on the
       * stage here (as is normally done in response to ConfigureNotify).
       */
      stage_x11->xwin_width = width;
      stage_x11->xwin_height = height;
      clutter_actor_queue_relayout (CLUTTER_ACTOR (stage_cogl->wrapper));
      return;
    }

  /* If we're going fullscreen, don't mess with the size */
  if (stage_x11->fullscreening)
    return;

  if (width == 0 || height == 0)
    {
      /* Should not happen, if this turns up we need to debug it and
       * determine the cleanest way to fix.
       */
      g_warning ("X11 stage not allowed to have 0 width or height");
      width = 1;
      height = 1;
    }

  CLUTTER_NOTE (BACKEND, "New size received: (%d, %d)", width, height);

  if (stage_x11->xwin != None)
    {
      clutter_stage_x11_fix_window_size (stage_x11, width, height);

      if (width != stage_x11->xwin_width ||
          height != stage_x11->xwin_height)
        {
          CLUTTER_NOTE (BACKEND, "%s: XResizeWindow[%x] (%d, %d)",
                        G_STRLOC,
                        (unsigned int) stage_x11->xwin,
                        width,
                        height);

          CLUTTER_SET_PRIVATE_FLAGS (stage_cogl->wrapper,
                                     CLUTTER_IN_RESIZE);

          /* XXX: in this case we can rely on a subsequent
           * ConfigureNotify that will result in the stage
           * being reallocated so we don't actively do anything
           * to affect the stage allocation here. */
          XResizeWindow (backend_x11->xdpy,
                         stage_x11->xwin,
                         width,
                         height);
        }
    }
}
Пример #29
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);
    }
}