2007-03-22 18:21:59 +00:00
|
|
|
/* Clutter.
|
|
|
|
* An OpenGL based 'interactive canvas' library.
|
|
|
|
* Authored By Matthew Allum <mallum@openedhand.com>
|
|
|
|
* Copyright (C) 2006-2007 OpenedHand
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
2010-03-01 12:56:10 +00:00
|
|
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*
|
|
|
|
*
|
2007-03-22 18:21:59 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "clutter-backend-glx.h"
|
|
|
|
#include "clutter-stage-glx.h"
|
|
|
|
#include "clutter-glx.h"
|
|
|
|
|
|
|
|
#include "../clutter-main.h"
|
|
|
|
#include "../clutter-feature.h"
|
|
|
|
#include "../clutter-color.h"
|
|
|
|
#include "../clutter-util.h"
|
|
|
|
#include "../clutter-event.h"
|
|
|
|
#include "../clutter-enum-types.h"
|
|
|
|
#include "../clutter-private.h"
|
|
|
|
#include "../clutter-debug.h"
|
2007-05-22 09:31:40 +00:00
|
|
|
#include "../clutter-units.h"
|
2007-12-03 16:29:18 +00:00
|
|
|
#include "../clutter-shader.h"
|
2008-01-21 11:39:23 +00:00
|
|
|
#include "../clutter-group.h"
|
|
|
|
#include "../clutter-container.h"
|
2008-03-28 22:50:55 +00:00
|
|
|
#include "../clutter-stage.h"
|
2008-04-04 15:02:11 +00:00
|
|
|
#include "../clutter-stage-window.h"
|
2007-03-22 18:21:59 +00:00
|
|
|
|
2008-04-25 13:37:36 +00:00
|
|
|
#include "cogl/cogl.h"
|
2007-04-27 21:13:06 +00:00
|
|
|
|
2007-03-22 18:21:59 +00:00
|
|
|
#include <GL/glx.h>
|
|
|
|
#include <GL/gl.h>
|
|
|
|
|
2008-04-04 15:02:11 +00:00
|
|
|
static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface);
|
|
|
|
|
2009-08-13 11:34:07 +00:00
|
|
|
static ClutterStageWindowIface *clutter_stage_glx_parent_iface = NULL;
|
|
|
|
|
2008-04-04 15:02:11 +00:00
|
|
|
G_DEFINE_TYPE_WITH_CODE (ClutterStageGLX,
|
|
|
|
clutter_stage_glx,
|
|
|
|
CLUTTER_TYPE_STAGE_X11,
|
|
|
|
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW,
|
|
|
|
clutter_stage_window_iface_init));
|
2007-03-22 18:21:59 +00:00
|
|
|
|
|
|
|
static void
|
2009-08-13 11:34:07 +00:00
|
|
|
clutter_stage_glx_unrealize (ClutterStageWindow *stage_window)
|
2007-03-22 18:21:59 +00:00
|
|
|
{
|
2009-08-03 13:50:10 +00:00
|
|
|
ClutterBackend *backend = clutter_get_default_backend ();
|
|
|
|
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
|
2009-08-13 11:34:07 +00:00
|
|
|
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
|
2010-01-14 14:03:23 +00:00
|
|
|
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (stage_window);
|
2007-03-22 18:21:59 +00:00
|
|
|
|
2008-04-04 15:02:11 +00:00
|
|
|
/* Note unrealize should free up any backend stage related resources */
|
2008-04-04 17:26:26 +00:00
|
|
|
CLUTTER_NOTE (BACKEND, "Unrealizing stage");
|
2007-03-22 18:21:59 +00:00
|
|
|
|
2007-11-15 14:45:27 +00:00
|
|
|
clutter_x11_trap_x_errors ();
|
2007-07-06 09:22:43 +00:00
|
|
|
|
2010-01-14 14:03:23 +00:00
|
|
|
if (stage_glx->glxwin != None)
|
|
|
|
{
|
|
|
|
glXDestroyWindow (backend_x11->xdpy, stage_glx->glxwin);
|
|
|
|
stage_glx->glxwin = None;
|
|
|
|
}
|
|
|
|
|
2009-07-31 17:34:51 +00:00
|
|
|
if (!stage_x11->is_foreign_xwin && stage_x11->xwin != None)
|
2007-03-22 18:21:59 +00:00
|
|
|
{
|
2009-08-03 13:50:10 +00:00
|
|
|
XDestroyWindow (backend_x11->xdpy, stage_x11->xwin);
|
2009-07-31 17:34:51 +00:00
|
|
|
stage_x11->xwin = None;
|
2007-03-22 18:21:59 +00:00
|
|
|
}
|
|
|
|
else
|
2009-07-31 17:34:51 +00:00
|
|
|
stage_x11->xwin = None;
|
2007-03-22 18:21:59 +00:00
|
|
|
|
2009-08-03 13:50:10 +00:00
|
|
|
XSync (backend_x11->xdpy, False);
|
2007-07-22 22:40:18 +00:00
|
|
|
|
2007-11-15 14:45:27 +00:00
|
|
|
clutter_x11_untrap_x_errors ();
|
2007-07-22 22:40:18 +00:00
|
|
|
|
|
|
|
CLUTTER_MARK ();
|
2007-03-22 18:21:59 +00:00
|
|
|
}
|
|
|
|
|
2009-08-13 11:34:07 +00:00
|
|
|
static gboolean
|
|
|
|
clutter_stage_glx_realize (ClutterStageWindow *stage_window)
|
2007-03-22 18:21:59 +00:00
|
|
|
{
|
2009-08-13 11:34:07 +00:00
|
|
|
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
|
2010-01-14 14:03:23 +00:00
|
|
|
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (stage_window);
|
2009-05-13 21:21:48 +00:00
|
|
|
ClutterBackend *backend;
|
2008-03-28 22:50:55 +00:00
|
|
|
ClutterBackendGLX *backend_glx;
|
2008-06-23 09:55:42 +00:00
|
|
|
ClutterBackendX11 *backend_x11;
|
2009-07-31 17:34:51 +00:00
|
|
|
GError *error;
|
2007-03-22 18:21:59 +00:00
|
|
|
|
2009-05-11 11:36:14 +00:00
|
|
|
CLUTTER_NOTE (ACTOR, "Realizing stage '%s' [%p]",
|
2009-08-13 11:34:07 +00:00
|
|
|
G_OBJECT_TYPE_NAME (stage_window),
|
|
|
|
stage_window);
|
2007-03-22 18:21:59 +00:00
|
|
|
|
2009-05-13 21:21:48 +00:00
|
|
|
backend = clutter_get_default_backend ();
|
|
|
|
backend_glx = CLUTTER_BACKEND_GLX (backend);
|
|
|
|
backend_x11 = CLUTTER_BACKEND_X11 (backend);
|
2008-03-28 22:50:55 +00:00
|
|
|
|
2009-07-31 17:34:51 +00:00
|
|
|
if (stage_x11->xwin == None)
|
|
|
|
{
|
|
|
|
XSetWindowAttributes xattr;
|
|
|
|
unsigned long mask;
|
2009-08-03 13:50:10 +00:00
|
|
|
XVisualInfo *xvisinfo;
|
2010-02-15 18:53:58 +00:00
|
|
|
gfloat width, height;
|
2009-07-31 17:34:51 +00:00
|
|
|
|
|
|
|
CLUTTER_NOTE (MISC, "Creating stage X window");
|
|
|
|
|
2009-12-01 16:18:39 +00:00
|
|
|
xvisinfo = clutter_backend_x11_get_visual_info (backend_x11);
|
2009-08-03 13:50:10 +00:00
|
|
|
if (xvisinfo == NULL)
|
|
|
|
{
|
|
|
|
g_critical ("Unable to find suitable GL visual.");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2009-07-31 17:34:51 +00:00
|
|
|
/* window attributes */
|
2009-08-03 13:50:10 +00:00
|
|
|
xattr.background_pixel = WhitePixel (backend_x11->xdpy,
|
|
|
|
backend_x11->xscreen_num);
|
2009-07-31 17:34:51 +00:00
|
|
|
xattr.border_pixel = 0;
|
2009-08-03 13:50:10 +00:00
|
|
|
xattr.colormap = XCreateColormap (backend_x11->xdpy,
|
|
|
|
backend_x11->xwin_root,
|
|
|
|
xvisinfo->visual,
|
2009-07-31 17:34:51 +00:00
|
|
|
AllocNone);
|
|
|
|
mask = CWBorderPixel | CWColormap;
|
2010-02-15 18:53:58 +00:00
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
2009-08-03 13:50:10 +00:00
|
|
|
stage_x11->xwin = XCreateWindow (backend_x11->xdpy,
|
|
|
|
backend_x11->xwin_root,
|
2009-07-31 17:34:51 +00:00
|
|
|
0, 0,
|
|
|
|
stage_x11->xwin_width,
|
|
|
|
stage_x11->xwin_height,
|
|
|
|
0,
|
2009-08-03 13:50:10 +00:00
|
|
|
xvisinfo->depth,
|
2009-07-31 17:34:51 +00:00
|
|
|
InputOutput,
|
2009-08-03 13:50:10 +00:00
|
|
|
xvisinfo->visual,
|
2009-07-31 17:34:51 +00:00
|
|
|
mask, &xattr);
|
2009-12-03 17:13:44 +00:00
|
|
|
|
2010-02-15 18:53:58 +00:00
|
|
|
CLUTTER_NOTE (BACKEND, "Stage [%p], window: 0x%x, size: %dx%d",
|
2009-12-03 17:13:44 +00:00
|
|
|
stage_window,
|
2010-02-15 18:53:58 +00:00
|
|
|
(unsigned int) stage_x11->xwin,
|
|
|
|
stage_x11->xwin_width,
|
|
|
|
stage_x11->xwin_height);
|
2009-12-03 17:13:44 +00:00
|
|
|
|
2009-08-03 13:50:10 +00:00
|
|
|
XFree (xvisinfo);
|
2009-07-31 17:34:51 +00:00
|
|
|
}
|
2008-01-31 23:10:30 +00:00
|
|
|
|
2010-01-14 14:03:23 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-01 16:18:39 +00:00
|
|
|
if (clutter_x11_has_event_retrieval ())
|
2009-07-31 17:34:51 +00:00
|
|
|
{
|
2009-12-01 16:18:39 +00:00
|
|
|
if (clutter_x11_has_xinput ())
|
2008-06-23 09:55:42 +00:00
|
|
|
{
|
2009-08-03 13:50:10 +00:00
|
|
|
XSelectInput (backend_x11->xdpy, stage_x11->xwin,
|
2009-07-31 17:34:51 +00:00
|
|
|
StructureNotifyMask |
|
|
|
|
FocusChangeMask |
|
|
|
|
ExposureMask |
|
|
|
|
KeyPressMask | KeyReleaseMask |
|
|
|
|
EnterWindowMask | LeaveWindowMask |
|
|
|
|
PropertyChangeMask);
|
|
|
|
#ifdef HAVE_XINPUT
|
|
|
|
_clutter_x11_select_events (stage_x11->xwin);
|
2008-06-23 09:55:42 +00:00
|
|
|
#endif
|
2008-01-31 23:10:30 +00:00
|
|
|
}
|
2009-07-31 17:34:51 +00:00
|
|
|
else
|
2009-08-03 13:50:10 +00:00
|
|
|
XSelectInput (backend_x11->xdpy, stage_x11->xwin,
|
2009-07-31 17:34:51 +00:00
|
|
|
StructureNotifyMask |
|
|
|
|
FocusChangeMask |
|
|
|
|
ExposureMask |
|
|
|
|
PointerMotionMask |
|
|
|
|
KeyPressMask | KeyReleaseMask |
|
|
|
|
ButtonPressMask | ButtonReleaseMask |
|
|
|
|
EnterWindowMask | LeaveWindowMask |
|
|
|
|
PropertyChangeMask);
|
2009-11-12 20:37:01 +00:00
|
|
|
|
|
|
|
#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 */
|
2007-03-22 18:21:59 +00:00
|
|
|
}
|
2009-05-13 21:21:48 +00:00
|
|
|
|
2009-07-31 17:34:51 +00:00
|
|
|
/* no user resize.. */
|
2010-02-07 18:17:43 +00:00
|
|
|
clutter_stage_x11_fix_window_size (stage_x11,
|
|
|
|
stage_x11->xwin_width,
|
|
|
|
stage_x11->xwin_height);
|
2009-07-31 17:34:51 +00:00
|
|
|
clutter_stage_x11_set_wm_protocols (stage_x11);
|
2007-03-22 18:21:59 +00:00
|
|
|
|
2009-07-31 17:34:51 +00:00
|
|
|
/* 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;
|
2007-03-22 18:21:59 +00:00
|
|
|
}
|
|
|
|
|
2009-07-31 17:34:51 +00:00
|
|
|
CLUTTER_NOTE (BACKEND, "Successfully realized stage");
|
|
|
|
|
2009-08-13 11:34:07 +00:00
|
|
|
/* chain up to the StageX11 implementation */
|
|
|
|
return clutter_stage_glx_parent_iface->realize (stage_window);
|
2007-03-22 18:21:59 +00:00
|
|
|
}
|
|
|
|
|
2009-11-12 20:37:01 +00:00
|
|
|
static int
|
|
|
|
clutter_stage_glx_get_pending_swaps (ClutterStageWindow *stage_window)
|
|
|
|
{
|
|
|
|
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (stage_window);
|
|
|
|
|
|
|
|
return stage_glx->pending_swaps;
|
|
|
|
}
|
|
|
|
|
2007-03-22 18:21:59 +00:00
|
|
|
static void
|
|
|
|
clutter_stage_glx_dispose (GObject *gobject)
|
|
|
|
{
|
|
|
|
G_OBJECT_CLASS (clutter_stage_glx_parent_class)->dispose (gobject);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2007-05-31 11:13:43 +00:00
|
|
|
clutter_stage_glx_class_init (ClutterStageGLXClass *klass)
|
2007-03-22 18:21:59 +00:00
|
|
|
{
|
|
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
|
|
|
|
|
|
gobject_class->dispose = clutter_stage_glx_dispose;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2007-05-31 11:13:43 +00:00
|
|
|
clutter_stage_glx_init (ClutterStageGLX *stage)
|
2007-03-22 18:21:59 +00:00
|
|
|
{
|
2008-04-04 15:02:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
|
|
|
|
{
|
2009-08-13 11:34:07 +00:00
|
|
|
clutter_stage_glx_parent_iface = g_type_interface_peek_parent (iface);
|
|
|
|
|
|
|
|
iface->realize = clutter_stage_glx_realize;
|
|
|
|
iface->unrealize = clutter_stage_glx_unrealize;
|
2009-11-12 20:37:01 +00:00
|
|
|
iface->get_pending_swaps = clutter_stage_glx_get_pending_swaps;
|
2009-08-13 11:34:07 +00:00
|
|
|
|
2008-04-04 15:02:11 +00:00
|
|
|
/* the rest is inherited from ClutterStageX11 */
|
2007-03-22 18:21:59 +00:00
|
|
|
}
|
2009-11-12 20:37:01 +00:00
|
|
|
|