2007-01-23 Matthew Allum <mallum@openedhand.com>
* Makefile.am: * clutter.pc.in: * clutter/Makefile.am: * clutter/clutter-backend-glx.c: * clutter/clutter-backend-glx.h: * clutter/clutter-event.c: * clutter/clutter-feature.c: * clutter/clutter-group.c: * clutter/clutter-main.c: * clutter/clutter-main.h: * clutter/clutter-private.h: * clutter/clutter-stage-glx.c: * clutter/clutter-stage-glx.h: * clutter/clutter-stage.c: * clutter/clutter-stage.h: * clutter/clutter-util.c: * clutter/clutter-util.h: * clutter/pango/pangoclutter-render.c: * configure.ac: * examples/Makefile.am: Initial work in supporting different GL backends (ie. GLX/EGL/DirectFB etc). Currently just GLX supported and now mostly self contained. * TODO: Add a note about caching glenables
This commit is contained in:
parent
685c583d51
commit
244cacd14b
28
ChangeLog
28
ChangeLog
@ -1,3 +1,31 @@
|
||||
2007-01-23 Matthew Allum <mallum@openedhand.com>
|
||||
|
||||
* Makefile.am:
|
||||
* clutter.pc.in:
|
||||
* clutter/Makefile.am:
|
||||
* clutter/clutter-backend-glx.c:
|
||||
* clutter/clutter-backend-glx.h:
|
||||
* clutter/clutter-event.c:
|
||||
* clutter/clutter-feature.c:
|
||||
* clutter/clutter-group.c:
|
||||
* clutter/clutter-main.c:
|
||||
* clutter/clutter-main.h:
|
||||
* clutter/clutter-private.h:
|
||||
* clutter/clutter-stage-glx.c:
|
||||
* clutter/clutter-stage-glx.h:
|
||||
* clutter/clutter-stage.c:
|
||||
* clutter/clutter-stage.h:
|
||||
* clutter/clutter-util.c:
|
||||
* clutter/clutter-util.h:
|
||||
* clutter/pango/pangoclutter-render.c:
|
||||
* configure.ac:
|
||||
* examples/Makefile.am:
|
||||
Initial work in supporting different GL backends (ie. GLX/EGL/DirectFB etc).
|
||||
Currently just GLX supported and now mostly self contained.
|
||||
|
||||
* TODO:
|
||||
Add a note about caching glenables
|
||||
|
||||
2007-01-23 Tomas Frydrych <tf@openedhand.com>
|
||||
|
||||
* clutter/clutter-fixed.c:
|
||||
|
@ -1,8 +1,8 @@
|
||||
SUBDIRS=clutter doc examples
|
||||
|
||||
pcfiles = clutter-@CLUTTER_MAJORMINOR@.pc
|
||||
pcfiles = clutter-@CLUTTER_FLAVOUR@-@CLUTTER_MAJORMINOR@.pc
|
||||
|
||||
%-@CLUTTER_MAJORMINOR@.pc: %.pc
|
||||
%-@CLUTTER_FLAVOUR@-@CLUTTER_MAJORMINOR@.pc: %.pc
|
||||
cp $< $@
|
||||
|
||||
pkgconfig_DATA = $(pcfiles)
|
||||
|
2
TODO
2
TODO
@ -19,6 +19,8 @@ Optimisations
|
||||
- Display lists.
|
||||
- Custom source rather than idle handler for paints ?
|
||||
- General oprofiling.
|
||||
- GL state cache - avoid so much expensive glenable/disable calling
|
||||
during paint (Also GL does not check if a state is already set)
|
||||
|
||||
Other
|
||||
==
|
||||
|
@ -3,9 +3,9 @@ exec_prefix=${prefix}
|
||||
libdir=${exec_prefix}/lib
|
||||
includedir=${prefix}/include
|
||||
|
||||
Name: clutter-@CLUTTER_MAJORMINOR@
|
||||
Name: clutter-@CLUTTER_FLAVOUR@-@CLUTTER_MAJORMINOR@
|
||||
Description: Clutter library
|
||||
Version: @VERSION@
|
||||
Libs: -L${libdir} -lclutter-@CLUTTER_MAJORMINOR@
|
||||
Cflags: -I${includedir}/clutter-@CLUTTER_MAJORMINOR@
|
||||
Libs: -L${libdir} -lclutter-@CLUTTER_FLAVOUR@-@CLUTTER_MAJORMINOR@
|
||||
Cflags: -I${includedir}/clutter-@CLUTTER_FLAVOUR@-@CLUTTER_MAJORMINOR@
|
||||
Requires: pangoft2 glib-2.0 >= 2.8 gthread-2.0 gdk-pixbuf-2.0 gdk-pixbuf-xlib-2.0
|
||||
|
@ -32,6 +32,10 @@ source_h = \
|
||||
$(srcdir)/clutter-version.h \
|
||||
$(srcdir)/clutter-main.h
|
||||
|
||||
backend_h = \
|
||||
$(srcdir)/clutter-stage-glx.h \
|
||||
$(srcdir)/clutter-backend-glx.h
|
||||
|
||||
clutter-marshal.h: stamp-clutter-marshal.h
|
||||
@true
|
||||
stamp-clutter-marshal.h: clutter-marshal.list
|
||||
@ -113,11 +117,18 @@ source_c = clutter-main.c \
|
||||
clutter-media.c \
|
||||
clutter-enum-types.c
|
||||
|
||||
backend_c = \
|
||||
$(srcdir)/clutter-stage-glx.c \
|
||||
$(srcdir)/clutter-backend-glx.c
|
||||
|
||||
source_h_priv = clutter-debug.h clutter-private.h
|
||||
|
||||
libclutter_@CLUTTER_MAJORMINOR@_la_SOURCES = $(MARSHALFILES) \
|
||||
libclutter_@CLUTTER_FLAVOUR@_@CLUTTER_MAJORMINOR@_la_SOURCES = \
|
||||
$(MARSHALFILES) \
|
||||
$(source_c) \
|
||||
$(source_h) \
|
||||
$(backend_c) \
|
||||
$(backend_h) \
|
||||
$(source_h_priv)
|
||||
|
||||
INCLUDES = \
|
||||
@ -130,17 +141,23 @@ INCLUDES = \
|
||||
-DG_LOG_DOMAIN=\"Clutter\" \
|
||||
$(GCC_FLAGS) \
|
||||
$(CLUTTER_CFLAGS) \
|
||||
$(CLUTTER_DEBUG_CFLAGS)
|
||||
$(CLUTTER_DEBUG_CFLAGS) \
|
||||
-DCLUTTER_BACKEND_GLX
|
||||
|
||||
lib_LTLIBRARIES = libclutter-@CLUTTER_MAJORMINOR@.la
|
||||
lib_LTLIBRARIES = libclutter-@CLUTTER_FLAVOUR@-@CLUTTER_MAJORMINOR@.la
|
||||
|
||||
libclutter_@CLUTTER_MAJORMINOR@_la_LIBADD = \
|
||||
libclutter_@CLUTTER_FLAVOUR@_@CLUTTER_MAJORMINOR@_la_LIBADD = \
|
||||
@CLUTTER_LIBS@ $(top_builddir)/clutter/pango/libpangoclutter.la
|
||||
libclutter_@CLUTTER_MAJORMINOR@_la_LDFLAGS = @CLUTTER_LT_LDFLAGS@
|
||||
libclutter_@CLUTTER_MAJORMINOR@_la_DEPENDENCIES = \
|
||||
|
||||
libclutter_@CLUTTER_FLAVOUR@_@CLUTTER_MAJORMINOR@_la_LDFLAGS = \
|
||||
@CLUTTER_LT_LDFLAGS@
|
||||
|
||||
libclutter_@CLUTTER_FLAVOUR@_@CLUTTER_MAJORMINOR@_la_DEPENDENCIES = \
|
||||
$(top_builddir)/clutter/pango/libpangoclutter.la
|
||||
|
||||
clutterheadersdir = $(includedir)/clutter-@CLUTTER_MAJORMINOR@/clutter
|
||||
clutterheadersdir = \
|
||||
$(includedir)/clutter-@CLUTTER_FLAVOUR@-@CLUTTER_MAJORMINOR@/clutter
|
||||
|
||||
clutterheaders_HEADERS = $(source_h) \
|
||||
clutter-marshal.h \
|
||||
clutter-enum-types.h \
|
||||
|
173
clutter/clutter-backend-glx.c
Normal file
173
clutter/clutter-backend-glx.c
Normal file
@ -0,0 +1,173 @@
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <GL/glx.h>
|
||||
#include <GL/gl.h>
|
||||
#include <glib.h>
|
||||
|
||||
#include "clutter-main.h"
|
||||
|
||||
static Display *_xdpy = NULL;
|
||||
static Window _xwin_root;
|
||||
static int _xscreen;
|
||||
|
||||
static gchar *clutter_display_name = NULL;
|
||||
static int clutter_screen = 0;
|
||||
|
||||
static int TrappedErrorCode = 0;
|
||||
static int (*old_error_handler) (Display *, XErrorEvent *);
|
||||
|
||||
static int
|
||||
error_handler(Display *xdpy,
|
||||
XErrorEvent *error)
|
||||
{
|
||||
TrappedErrorCode = error->error_code;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_util_trap_x_errors:
|
||||
*
|
||||
* Trap X errors so they don't cause an abort.
|
||||
*/
|
||||
void
|
||||
clutter_glx_trap_x_errors(void)
|
||||
{
|
||||
TrappedErrorCode = 0;
|
||||
old_error_handler = XSetErrorHandler(error_handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_util_untrap_x_errors:
|
||||
*
|
||||
* Stop trapping X errors.
|
||||
*
|
||||
* Return value: 0 if there was no error, or the last X error that occurred.
|
||||
*/
|
||||
int
|
||||
clutter_glx_untrap_x_errors(void)
|
||||
{
|
||||
XSetErrorHandler(old_error_handler);
|
||||
return TrappedErrorCode;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* clutter_glx_display:
|
||||
*
|
||||
* Retrieves the X display that Clutter is using
|
||||
*
|
||||
* Return value: A pointer to an X Display structure.
|
||||
*/
|
||||
Display*
|
||||
clutter_glx_display (void)
|
||||
{
|
||||
return _xdpy;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_glx_screen:
|
||||
*
|
||||
* Retrieves the X screen that Clutter is using.
|
||||
*
|
||||
* Return value: the X screen ID
|
||||
*/
|
||||
int
|
||||
clutter_glx_screen (void)
|
||||
{
|
||||
return _xscreen;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_glx_root_window:
|
||||
*
|
||||
* FIXME
|
||||
*
|
||||
* Return value: FIXME
|
||||
*/
|
||||
Window
|
||||
clutter_glx_root_window (void)
|
||||
{
|
||||
return _xwin_root;
|
||||
}
|
||||
|
||||
static GOptionEntry clutter_glx_args[] = {
|
||||
{ "display", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_STRING, &clutter_display_name,
|
||||
"X display to use", "DISPLAY" },
|
||||
{ "screen", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_INT, &clutter_screen,
|
||||
"X screen to use", "SCREEN" },
|
||||
{ NULL, }
|
||||
};
|
||||
|
||||
|
||||
static gboolean
|
||||
pre_parse_hook (GOptionContext *context,
|
||||
GOptionGroup *group,
|
||||
gpointer data,
|
||||
GError **error)
|
||||
{
|
||||
const char *env_string;
|
||||
|
||||
env_string = g_getenv ("DISPLAY");
|
||||
if (env_string)
|
||||
{
|
||||
clutter_display_name = g_strdup (env_string);
|
||||
env_string = NULL;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
post_parse_hook (GOptionContext *context,
|
||||
GOptionGroup *group,
|
||||
gpointer data,
|
||||
GError **error)
|
||||
{
|
||||
_xdpy = XOpenDisplay (clutter_display_name);
|
||||
|
||||
if (_xdpy)
|
||||
{
|
||||
if (clutter_screen == 0)
|
||||
_xscreen = DefaultScreen (_xdpy);
|
||||
else
|
||||
{
|
||||
Screen *xscreen;
|
||||
|
||||
xscreen = ScreenOfDisplay (_xdpy, clutter_screen);
|
||||
_xscreen = XScreenNumberOfScreen (xscreen);
|
||||
}
|
||||
|
||||
_xwin_root = RootWindow (_xdpy, _xscreen);
|
||||
|
||||
/* we don't need it anymore */
|
||||
g_free (clutter_display_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_set_error (error,
|
||||
clutter_init_error_quark (),
|
||||
CLUTTER_INIT_ERROR_BACKEND,
|
||||
"Unable to connect to X Server DISPLAY.");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
clutter_backend_init (GOptionContext *context)
|
||||
{
|
||||
GOptionGroup *group;
|
||||
|
||||
group = g_option_group_new ("clutter-glx",
|
||||
"Clutter GLX Options",
|
||||
"Show Clutter GLX Options",
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
g_option_group_set_parse_hooks (group, pre_parse_hook, post_parse_hook);
|
||||
g_option_group_add_entries (group, clutter_glx_args);
|
||||
g_option_context_add_group (context, group);
|
||||
|
||||
return TRUE;
|
||||
}
|
54
clutter/clutter-backend-glx.h
Normal file
54
clutter/clutter-backend-glx.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Clutter.
|
||||
*
|
||||
* An OpenGL based 'interactive canvas' library.
|
||||
*
|
||||
* Authored By Matthew Allum <mallum@openedhand.com>
|
||||
*
|
||||
* Copyright (C) 2006 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
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _HAVE_CLUTTER_GLX_H
|
||||
#define _HAVE_CLUTTER_GLX_H
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
#include <GL/glx.h>
|
||||
#include <GL/gl.h>
|
||||
|
||||
gboolean
|
||||
clutter_backend_init (GOptionContext *context) G_GNUC_INTERNAL;
|
||||
|
||||
void
|
||||
clutter_glx_trap_x_errors(void);
|
||||
|
||||
int
|
||||
clutter_glx_untrap_x_errors(void);
|
||||
|
||||
Display*
|
||||
clutter_glx_display (void);
|
||||
|
||||
int
|
||||
clutter_glx_screen (void);
|
||||
|
||||
Window
|
||||
clutter_glx_root_window (void);
|
||||
|
||||
|
||||
#endif
|
@ -29,9 +29,6 @@
|
||||
|
||||
#include "clutter-event.h"
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
/**
|
||||
* clutter_event_type:
|
||||
* @event: a #ClutterEvent
|
||||
|
@ -249,15 +249,15 @@ clutter_feature_init (void)
|
||||
__features->features_set = FALSE; /* don't rely on zero-ing */
|
||||
}
|
||||
|
||||
if (!clutter_xdisplay ())
|
||||
if (!clutter_glx_display ())
|
||||
return;
|
||||
|
||||
if (__features->features_set)
|
||||
return;
|
||||
|
||||
gl_extensions = (const gchar*) glGetString (GL_EXTENSIONS);
|
||||
glx_extensions = glXQueryExtensionsString (clutter_xdisplay (),
|
||||
clutter_xscreen ());
|
||||
glx_extensions = glXQueryExtensionsString (clutter_glx_display (),
|
||||
clutter_glx_screen ());
|
||||
|
||||
if (check_gl_extension ("GL_ARB_texture_rectangle", gl_extensions)
|
||||
|| check_gl_extension ("GL_EXT_texture_rectangle", gl_extensions))
|
||||
|
@ -36,6 +36,7 @@
|
||||
|
||||
#include "clutter-group.h"
|
||||
#include "clutter-main.h"
|
||||
#include "clutter-private.h"
|
||||
#include "clutter-marshal.h"
|
||||
#include "clutter-enum-types.h"
|
||||
|
||||
|
@ -43,12 +43,16 @@
|
||||
#include "clutter-private.h"
|
||||
#include "clutter-debug.h"
|
||||
|
||||
#ifdef CLUTTER_BACKEND_GLX
|
||||
#include <clutter/clutter-backend-glx.h>
|
||||
#endif
|
||||
|
||||
static ClutterMainContext *ClutterCntx = NULL;
|
||||
|
||||
static gboolean clutter_is_initialized = FALSE;
|
||||
static gboolean clutter_show_fps = FALSE;
|
||||
static gboolean clutter_fatal_warnings = FALSE;
|
||||
static gchar *clutter_display_name = NULL;
|
||||
static gchar *clutter_vblank_name = NULL;
|
||||
static int clutter_screen = 0;
|
||||
|
||||
guint clutter_debug_flags = 0; /* global clutter debug flag */
|
||||
|
||||
@ -66,210 +70,8 @@ static const GDebugKey clutter_debug_keys[] = {
|
||||
};
|
||||
#endif /* CLUTTER_ENABLE_DEBUG */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GSource source;
|
||||
Display *display;
|
||||
GPollFD event_poll_fd;
|
||||
}
|
||||
ClutterXEventSource;
|
||||
|
||||
typedef void (*ClutterXEventFunc) (XEvent *xev, gpointer user_data);
|
||||
|
||||
static ClutterMainContext *ClutterCntx = NULL;
|
||||
|
||||
static gboolean
|
||||
x_event_prepare (GSource *source,
|
||||
gint *timeout)
|
||||
{
|
||||
Display *display = ((ClutterXEventSource*)source)->display;
|
||||
|
||||
*timeout = -1;
|
||||
|
||||
return XPending (display);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
x_event_check (GSource *source)
|
||||
{
|
||||
ClutterXEventSource *display_source = (ClutterXEventSource*)source;
|
||||
gboolean retval;
|
||||
|
||||
if (display_source->event_poll_fd.revents & G_IO_IN)
|
||||
retval = XPending (display_source->display);
|
||||
else
|
||||
retval = FALSE;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
x_event_dispatch (GSource *source,
|
||||
GSourceFunc callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
Display *display = ((ClutterXEventSource*)source)->display;
|
||||
ClutterXEventFunc event_func = (ClutterXEventFunc) callback;
|
||||
|
||||
XEvent xev;
|
||||
|
||||
if (XPending (display))
|
||||
{
|
||||
XNextEvent (display, &xev);
|
||||
|
||||
if (event_func)
|
||||
(*event_func) (&xev, user_data);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static const GSourceFuncs x_event_funcs = {
|
||||
x_event_prepare,
|
||||
x_event_check,
|
||||
x_event_dispatch,
|
||||
NULL
|
||||
};
|
||||
|
||||
static void
|
||||
translate_key_event (ClutterKeyEvent *event,
|
||||
XEvent *xevent)
|
||||
{
|
||||
event->type = xevent->xany.type == KeyPress ? CLUTTER_KEY_PRESS
|
||||
: CLUTTER_KEY_RELEASE;
|
||||
event->time = xevent->xkey.time;
|
||||
event->modifier_state = xevent->xkey.state; /* FIXME: handle modifiers */
|
||||
event->hardware_keycode = xevent->xkey.keycode;
|
||||
event->keyval = XKeycodeToKeysym(xevent->xkey.display,
|
||||
xevent->xkey.keycode,
|
||||
0 ); /* FIXME: index with modifiers */
|
||||
}
|
||||
|
||||
static void
|
||||
translate_button_event (ClutterButtonEvent *event,
|
||||
XEvent *xevent)
|
||||
{
|
||||
/* FIXME: catch double click */
|
||||
CLUTTER_NOTE (EVENT, " button event at %ix%i",
|
||||
xevent->xbutton.x,
|
||||
xevent->xbutton.y);
|
||||
|
||||
event->type = xevent->xany.type == ButtonPress ? CLUTTER_BUTTON_PRESS
|
||||
: CLUTTER_BUTTON_RELEASE;
|
||||
event->time = xevent->xbutton.time;
|
||||
event->x = xevent->xbutton.x;
|
||||
event->y = xevent->xbutton.y;
|
||||
event->modifier_state = xevent->xbutton.state; /* includes button masks */
|
||||
event->button = xevent->xbutton.button;
|
||||
}
|
||||
|
||||
static void
|
||||
translate_motion_event (ClutterMotionEvent *event,
|
||||
XEvent *xevent)
|
||||
{
|
||||
event->type = CLUTTER_MOTION;
|
||||
event->time = xevent->xbutton.time;
|
||||
event->x = xevent->xmotion.x;
|
||||
event->y = xevent->xmotion.y;
|
||||
event->modifier_state = xevent->xmotion.state;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_dispatch_x_event (XEvent *xevent,
|
||||
gpointer data)
|
||||
{
|
||||
ClutterMainContext *ctx = CLUTTER_CONTEXT ();
|
||||
ClutterEvent event;
|
||||
ClutterStage *stage = ctx->stage;
|
||||
gboolean emit_input_event = FALSE;
|
||||
|
||||
switch (xevent->type)
|
||||
{
|
||||
case Expose:
|
||||
{
|
||||
XEvent foo_xev;
|
||||
|
||||
/* Cheap compress */
|
||||
while (XCheckTypedWindowEvent(ctx->xdpy,
|
||||
xevent->xexpose.window,
|
||||
Expose,
|
||||
&foo_xev));
|
||||
|
||||
/* FIXME: need to make stage an 'actor' so can que
|
||||
* a paint direct from there rather than hack here...
|
||||
*/
|
||||
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
|
||||
}
|
||||
break;
|
||||
case KeyPress:
|
||||
translate_key_event ((ClutterKeyEvent *) &event, xevent);
|
||||
g_signal_emit_by_name (stage, "key-press-event", &event);
|
||||
emit_input_event = TRUE;
|
||||
break;
|
||||
case KeyRelease:
|
||||
translate_key_event ((ClutterKeyEvent *) &event, xevent);
|
||||
g_signal_emit_by_name (stage, "key-release-event", &event);
|
||||
emit_input_event = TRUE;
|
||||
break;
|
||||
case ButtonPress:
|
||||
translate_button_event ((ClutterButtonEvent *) &event, xevent);
|
||||
g_signal_emit_by_name (stage, "button-press-event", &event);
|
||||
emit_input_event = TRUE;
|
||||
break;
|
||||
case ButtonRelease:
|
||||
translate_button_event ((ClutterButtonEvent *) &event, xevent);
|
||||
g_signal_emit_by_name (stage, "button-release-event", &event);
|
||||
emit_input_event = TRUE;
|
||||
break;
|
||||
case MotionNotify:
|
||||
translate_motion_event ((ClutterMotionEvent *) &event, xevent);
|
||||
g_signal_emit_by_name (stage, "motion-event", &event);
|
||||
emit_input_event = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (emit_input_event)
|
||||
g_signal_emit_by_name (stage, "input-event", &event);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
events_init()
|
||||
{
|
||||
ClutterMainContext *clutter_context;
|
||||
GMainContext *gmain_context;
|
||||
int connection_number;
|
||||
GSource *source;
|
||||
ClutterXEventSource *display_source;
|
||||
|
||||
clutter_context = clutter_context_get_default ();
|
||||
gmain_context = g_main_context_default ();
|
||||
|
||||
g_main_context_ref (gmain_context);
|
||||
|
||||
connection_number = ConnectionNumber (clutter_context->xdpy);
|
||||
|
||||
source = g_source_new ((GSourceFuncs *)&x_event_funcs,
|
||||
sizeof (ClutterXEventSource));
|
||||
|
||||
display_source = (ClutterXEventSource *)source;
|
||||
|
||||
display_source->event_poll_fd.fd = connection_number;
|
||||
display_source->event_poll_fd.events = G_IO_IN;
|
||||
display_source->display = clutter_context->xdpy;
|
||||
|
||||
g_source_add_poll (source, &display_source->event_poll_fd);
|
||||
g_source_set_can_recurse (source, TRUE);
|
||||
|
||||
g_source_set_callback (source,
|
||||
(GSourceFunc) clutter_dispatch_x_event,
|
||||
NULL /* no userdata */, NULL);
|
||||
|
||||
g_source_attach (source, gmain_context);
|
||||
g_source_unref (source);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gboolean
|
||||
clutter_want_fps (void)
|
||||
{
|
||||
return clutter_show_fps;
|
||||
@ -291,60 +93,8 @@ clutter_redraw (void)
|
||||
{
|
||||
ClutterMainContext *ctx = CLUTTER_CONTEXT();
|
||||
ClutterStage *stage = ctx->stage;
|
||||
ClutterColor stage_color;
|
||||
|
||||
static GTimer *timer = NULL;
|
||||
static guint timer_n_frames = 0;
|
||||
|
||||
/* FIXME: Should move all this into stage...
|
||||
*/
|
||||
|
||||
CLUTTER_NOTE (PAINT, " Redraw enter");
|
||||
|
||||
if (clutter_want_fps ())
|
||||
{
|
||||
if (!timer)
|
||||
timer = g_timer_new ();
|
||||
}
|
||||
|
||||
clutter_stage_get_color (stage, &stage_color);
|
||||
|
||||
glClearColor(((float) stage_color.red / 0xff * 1.0),
|
||||
((float) stage_color.green / 0xff * 1.0),
|
||||
((float) stage_color.blue / 0xff * 1.0),
|
||||
0.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
|
||||
glDisable(GL_LIGHTING);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
clutter_actor_paint (CLUTTER_ACTOR (stage));
|
||||
|
||||
if (clutter_stage_get_xwindow (stage))
|
||||
{
|
||||
clutter_feature_wait_for_vblank ();
|
||||
glXSwapBuffers(ctx->xdpy, clutter_stage_get_xwindow (stage));
|
||||
}
|
||||
else
|
||||
{
|
||||
glXWaitGL();
|
||||
CLUTTER_GLERR();
|
||||
}
|
||||
|
||||
|
||||
if (clutter_want_fps ())
|
||||
{
|
||||
timer_n_frames++;
|
||||
|
||||
if (g_timer_elapsed (timer, NULL) >= 1.0)
|
||||
{
|
||||
g_print ("*** FPS: %i ***\n", timer_n_frames);
|
||||
timer_n_frames = 0;
|
||||
g_timer_start (timer);
|
||||
}
|
||||
}
|
||||
|
||||
CLUTTER_NOTE (PAINT, "Redraw leave");
|
||||
clutter_actor_paint (CLUTTER_ACTOR(stage));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -444,50 +194,6 @@ clutter_threads_leave (void)
|
||||
g_mutex_unlock (context->gl_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_xdisplay:
|
||||
*
|
||||
* Retrieves the X display that Clutter is using
|
||||
*
|
||||
* Return value: A pointer to an X Display structure.
|
||||
*/
|
||||
Display*
|
||||
clutter_xdisplay (void)
|
||||
{
|
||||
ClutterMainContext *context = CLUTTER_CONTEXT ();
|
||||
|
||||
return context->xdpy;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_xscreen:
|
||||
*
|
||||
* Retrieves the X screen that Clutter is using.
|
||||
*
|
||||
* Return value: the X screen ID
|
||||
*/
|
||||
int
|
||||
clutter_xscreen (void)
|
||||
{
|
||||
ClutterMainContext *context = CLUTTER_CONTEXT ();
|
||||
|
||||
return context->xscreen;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_root_xwindow:
|
||||
*
|
||||
* FIXME
|
||||
*
|
||||
* Return value: FIXME
|
||||
*/
|
||||
Window
|
||||
clutter_root_xwindow (void)
|
||||
{
|
||||
ClutterMainContext *context = CLUTTER_CONTEXT ();
|
||||
|
||||
return context->xwin_root;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_want_debug:
|
||||
@ -572,10 +278,6 @@ clutter_arg_no_debug_cb (const char *key,
|
||||
#endif /* CLUTTER_ENABLE_DEBUG */
|
||||
|
||||
static GOptionEntry clutter_args[] = {
|
||||
{ "display", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_STRING, &clutter_display_name,
|
||||
"X display to use", "DISPLAY" },
|
||||
{ "screen", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_INT, &clutter_screen,
|
||||
"X screen to use", "SCREEN" },
|
||||
{ "clutter-show-fps", 0, 0, G_OPTION_ARG_NONE, &clutter_show_fps,
|
||||
"Show frames per second", NULL },
|
||||
{ "clutter-vblank", 0, 0, G_OPTION_ARG_STRING, &clutter_vblank_name,
|
||||
@ -606,18 +308,6 @@ pre_parse_hook (GOptionContext *context,
|
||||
if (clutter_is_initialized)
|
||||
return TRUE;
|
||||
|
||||
#if 0
|
||||
/* XXX - this shows a warning with newer releases of GLib,
|
||||
* as we use GOption in order to get here, and GOption uses
|
||||
* the slice allocator and other GLib stuff. so, either we
|
||||
* move the thread init inside clutter_init() directly or
|
||||
* we remove this call altogether, and let the applications
|
||||
* deal with threading, as they are supposed to do anyway.
|
||||
*/
|
||||
if (!g_thread_supported ())
|
||||
g_thread_init (NULL);
|
||||
#endif
|
||||
|
||||
g_type_init ();
|
||||
|
||||
#ifdef CLUTTER_ENABLE_DEBUG
|
||||
@ -643,13 +333,6 @@ pre_parse_hook (GOptionContext *context,
|
||||
if (env_string)
|
||||
clutter_show_fps = TRUE;
|
||||
|
||||
env_string = g_getenv ("DISPLAY");
|
||||
if (env_string)
|
||||
{
|
||||
clutter_display_name = g_strdup (env_string);
|
||||
env_string = NULL;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -680,32 +363,6 @@ post_parse_hook (GOptionContext *context,
|
||||
clutter_context->main_loops = NULL;
|
||||
clutter_context->main_loop_level = 0;
|
||||
|
||||
/* either we got this with the DISPLAY envvar or via the
|
||||
* --display command line switch; if both failed, then
|
||||
* we'll fail later when we return in clutter_init()
|
||||
*/
|
||||
if (clutter_display_name)
|
||||
clutter_context->xdpy = XOpenDisplay (clutter_display_name);
|
||||
|
||||
if (clutter_context->xdpy)
|
||||
{
|
||||
if (clutter_screen == 0)
|
||||
clutter_context->xscreen = DefaultScreen (clutter_context->xdpy);
|
||||
else
|
||||
{
|
||||
Screen *xscreen;
|
||||
|
||||
xscreen = ScreenOfDisplay (clutter_context->xdpy, clutter_screen);
|
||||
clutter_context->xscreen = XScreenNumberOfScreen (xscreen);
|
||||
}
|
||||
|
||||
clutter_context->xwin_root = RootWindow (clutter_context->xdpy,
|
||||
clutter_context->xscreen);
|
||||
|
||||
/* we don't need it anymore */
|
||||
g_free (clutter_display_name);
|
||||
}
|
||||
|
||||
clutter_context->font_map = PANGO_FT2_FONT_MAP (pango_ft2_font_map_new ());
|
||||
pango_ft2_font_map_set_resolution (clutter_context->font_map, 96.0, 96.0);
|
||||
|
||||
@ -745,34 +402,6 @@ clutter_get_option_group (void)
|
||||
return group;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clutter_parse_args (int *argc,
|
||||
char ***argv)
|
||||
{
|
||||
GOptionContext *option_context;
|
||||
GOptionGroup *clutter_group;
|
||||
GError *error = NULL;
|
||||
|
||||
if (clutter_is_initialized)
|
||||
return TRUE;
|
||||
|
||||
option_context = g_option_context_new (NULL);
|
||||
g_option_context_set_ignore_unknown_options (option_context, TRUE);
|
||||
g_option_context_set_help_enabled (option_context, FALSE);
|
||||
|
||||
clutter_group = clutter_get_option_group ();
|
||||
g_option_context_set_main_group (option_context, clutter_group);
|
||||
if (!g_option_context_parse (option_context, argc, argv, &error))
|
||||
{
|
||||
g_warning ("%s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
g_option_context_free (option_context);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GQuark
|
||||
clutter_init_error_quark (void)
|
||||
{
|
||||
@ -855,17 +484,11 @@ clutter_init_with_args (int *argc,
|
||||
if (!g_thread_supported ())
|
||||
g_thread_init (NULL);
|
||||
|
||||
if (!XInitThreads())
|
||||
{
|
||||
g_set_error (error, clutter_init_error_quark (),
|
||||
CLUTTER_INIT_ERROR_THREADS,
|
||||
"Unable to initialise the X threading");
|
||||
return CLUTTER_INIT_ERROR_THREADS;
|
||||
}
|
||||
|
||||
group = clutter_get_option_group ();
|
||||
|
||||
group = clutter_get_option_group ();
|
||||
context = g_option_context_new (parameter_string);
|
||||
|
||||
clutter_backend_init (context);
|
||||
|
||||
g_option_context_add_group (context, group);
|
||||
|
||||
if (entries)
|
||||
@ -881,15 +504,6 @@ clutter_init_with_args (int *argc,
|
||||
return CLUTTER_INIT_ERROR_INTERNAL;
|
||||
|
||||
clutter_context = clutter_context_get_default ();
|
||||
if (!clutter_context->xdpy)
|
||||
{
|
||||
g_set_error (error, clutter_init_error_quark (),
|
||||
CLUTTER_INIT_ERROR_DISPLAY,
|
||||
"Unable to connect to X DISPLAY. You should either "
|
||||
"set the DISPLAY environment variable or use the "
|
||||
"--display command line switch");
|
||||
return CLUTTER_INIT_ERROR_DISPLAY;
|
||||
}
|
||||
|
||||
stage_error = NULL;
|
||||
if (!clutter_stage_init (clutter_context, &stage_error))
|
||||
@ -898,18 +512,42 @@ clutter_init_with_args (int *argc,
|
||||
return CLUTTER_INIT_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
/* At least GL 1.2 is needed for CLAMP_TO_EDGE */
|
||||
if (!is_gl_version_at_least_12 ())
|
||||
return CLUTTER_INIT_SUCCESS;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clutter_parse_args (int *argc,
|
||||
char ***argv)
|
||||
{
|
||||
GOptionContext *option_context;
|
||||
GOptionGroup *clutter_group;
|
||||
GError *error = NULL;
|
||||
gboolean ret = TRUE;
|
||||
|
||||
if (clutter_is_initialized)
|
||||
return TRUE;
|
||||
|
||||
option_context = g_option_context_new (NULL);
|
||||
g_option_context_set_ignore_unknown_options (option_context, TRUE);
|
||||
g_option_context_set_help_enabled (option_context, FALSE);
|
||||
|
||||
/* Initiate any command line options from the backend */
|
||||
clutter_backend_init (option_context);
|
||||
|
||||
clutter_group = clutter_get_option_group ();
|
||||
|
||||
g_option_context_set_main_group (option_context, clutter_group);
|
||||
|
||||
if (!g_option_context_parse (option_context, argc, argv, &error))
|
||||
{
|
||||
g_set_error (error, clutter_init_error_quark (),
|
||||
CLUTTER_INIT_ERROR_OPENGL,
|
||||
"Clutter needs at least version 1.2 of OpenGL");
|
||||
return CLUTTER_INIT_ERROR_OPENGL;
|
||||
g_warning ("%s", error->message);
|
||||
g_error_free (error);
|
||||
ret = FALSE;
|
||||
}
|
||||
|
||||
events_init ();
|
||||
g_option_context_free (option_context);
|
||||
|
||||
return CLUTTER_INIT_SUCCESS;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -937,20 +575,10 @@ clutter_init (int *argc,
|
||||
if (!g_thread_supported ())
|
||||
g_thread_init (NULL);
|
||||
|
||||
if (!XInitThreads())
|
||||
return CLUTTER_INIT_ERROR_THREADS;
|
||||
|
||||
clutter_parse_args (argc, argv);
|
||||
if (clutter_parse_args (argc, argv) == FALSE)
|
||||
return CLUTTER_INIT_ERROR_INTERNAL;
|
||||
|
||||
context = clutter_context_get_default ();
|
||||
if (!context->xdpy)
|
||||
{
|
||||
g_critical ("Unable to connect to X DISPLAY. You should either "
|
||||
"set the DISPLAY environment variable or use the "
|
||||
"--display command line switch");
|
||||
|
||||
return CLUTTER_INIT_ERROR_DISPLAY;
|
||||
}
|
||||
|
||||
stage_error = NULL;
|
||||
if (!clutter_stage_init (context, &stage_error))
|
||||
@ -960,14 +588,15 @@ clutter_init (int *argc,
|
||||
return CLUTTER_INIT_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* FIXME: move to backend */
|
||||
/* At least GL 1.2 is needed for CLAMP_TO_EDGE */
|
||||
if (!is_gl_version_at_least_12 ())
|
||||
{
|
||||
g_critical ("Clutter needs at least version 1.2 of OpenGL");
|
||||
return CLUTTER_INIT_ERROR_OPENGL;
|
||||
}
|
||||
|
||||
events_init ();
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -29,11 +29,6 @@
|
||||
#include <clutter/clutter-actor.h>
|
||||
#include <clutter/clutter-stage.h>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
#include <GL/glx.h>
|
||||
#include <GL/gl.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define CLUTTER_INIT_ERROR (clutter_init_error_quark ())
|
||||
@ -42,7 +37,7 @@ typedef enum {
|
||||
CLUTTER_INIT_SUCCESS = 1,
|
||||
CLUTTER_INIT_ERROR_UNKOWN = 0,
|
||||
CLUTTER_INIT_ERROR_THREADS = -1,
|
||||
CLUTTER_INIT_ERROR_DISPLAY = -2,
|
||||
CLUTTER_INIT_ERROR_BACKEND = -2,
|
||||
CLUTTER_INIT_ERROR_INTERNAL = -3,
|
||||
CLUTTER_INIT_ERROR_OPENGL = -4
|
||||
} ClutterInitError;
|
||||
@ -64,10 +59,8 @@ void clutter_main (void);
|
||||
void clutter_main_quit (void);
|
||||
gint clutter_main_level (void);
|
||||
void clutter_redraw (void);
|
||||
Display * clutter_xdisplay (void);
|
||||
gint clutter_xscreen (void);
|
||||
Window clutter_root_xwindow (void);
|
||||
gboolean clutter_want_debug (void);
|
||||
gboolean clutter_want_fps (void);
|
||||
void clutter_threads_enter (void);
|
||||
void clutter_threads_leave (void);
|
||||
|
||||
|
@ -32,12 +32,7 @@
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/keysym.h>
|
||||
|
||||
#include <GL/glx.h>
|
||||
#include <GL/gl.h>
|
||||
#include <GL/gl.h> /* Togo */
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
@ -49,11 +44,6 @@ typedef struct _ClutterMainContext ClutterMainContext;
|
||||
|
||||
struct _ClutterMainContext
|
||||
{
|
||||
Display *xdpy;
|
||||
Window xwin_root;
|
||||
int xscreen;
|
||||
GC xgc;
|
||||
|
||||
PangoFT2FontMap *font_map;
|
||||
|
||||
GMutex *gl_lock;
|
||||
|
898
clutter/clutter-stage-glx.c
Normal file
898
clutter/clutter-stage-glx.c
Normal file
@ -0,0 +1,898 @@
|
||||
/*
|
||||
* Clutter.
|
||||
*
|
||||
* An OpenGL based 'interactive canvas' library.
|
||||
*
|
||||
* Authored By Matthew Allum <mallum@openedhand.com>
|
||||
*
|
||||
* Copyright (C) 2006 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
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:clutter-stage
|
||||
* @short_description: Top level visual element to which actors are placed.
|
||||
*
|
||||
* #ClutterStage is a top level 'window' on which child actors are placed
|
||||
* and manipulated.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "clutter-stage.h"
|
||||
#include "clutter-main.h"
|
||||
#include "clutter-feature.h"
|
||||
#include "clutter-color.h"
|
||||
#include "clutter-util.h"
|
||||
#include "clutter-marshal.h"
|
||||
#include "clutter-enum-types.h"
|
||||
#include "clutter-private.h"
|
||||
#include "clutter-debug.h"
|
||||
|
||||
#include "clutter-stage-glx.h"
|
||||
#include "clutter-backend-glx.h"
|
||||
|
||||
#include <GL/glx.h>
|
||||
#include <GL/gl.h>
|
||||
|
||||
#include <gdk-pixbuf-xlib/gdk-pixbuf-xlib.h>
|
||||
|
||||
struct _ClutterStageBackend
|
||||
{
|
||||
XVisualInfo *xvisinfo;
|
||||
Window xwin;
|
||||
Pixmap xpixmap;
|
||||
gint xwin_width, xwin_height; /* FIXME target_width / height */
|
||||
GLXPixmap glxpixmap;
|
||||
GLXContext gl_context;
|
||||
gboolean is_foreign_xwin;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GSource source;
|
||||
Display *display;
|
||||
GPollFD event_poll_fd;
|
||||
}
|
||||
ClutterXEventSource;
|
||||
|
||||
typedef void (*ClutterXEventFunc) (XEvent *xev, gpointer user_data);
|
||||
|
||||
static gboolean
|
||||
x_event_prepare (GSource *source,
|
||||
gint *timeout)
|
||||
{
|
||||
Display *display = ((ClutterXEventSource*)source)->display;
|
||||
|
||||
*timeout = -1;
|
||||
|
||||
return XPending (display);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
x_event_check (GSource *source)
|
||||
{
|
||||
ClutterXEventSource *display_source = (ClutterXEventSource*)source;
|
||||
gboolean retval;
|
||||
|
||||
if (display_source->event_poll_fd.revents & G_IO_IN)
|
||||
retval = XPending (display_source->display);
|
||||
else
|
||||
retval = FALSE;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
x_event_dispatch (GSource *source,
|
||||
GSourceFunc callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
Display *display = ((ClutterXEventSource*)source)->display;
|
||||
ClutterXEventFunc event_func = (ClutterXEventFunc) callback;
|
||||
|
||||
XEvent xev;
|
||||
|
||||
if (XPending (display))
|
||||
{
|
||||
XNextEvent (display, &xev);
|
||||
|
||||
if (event_func)
|
||||
(*event_func) (&xev, user_data);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static const GSourceFuncs x_event_funcs = {
|
||||
x_event_prepare,
|
||||
x_event_check,
|
||||
x_event_dispatch,
|
||||
NULL
|
||||
};
|
||||
|
||||
static void
|
||||
translate_key_event (ClutterKeyEvent *event,
|
||||
XEvent *xevent)
|
||||
{
|
||||
event->type = xevent->xany.type == KeyPress ? CLUTTER_KEY_PRESS
|
||||
: CLUTTER_KEY_RELEASE;
|
||||
event->time = xevent->xkey.time;
|
||||
event->modifier_state = xevent->xkey.state; /* FIXME: handle modifiers */
|
||||
event->hardware_keycode = xevent->xkey.keycode;
|
||||
event->keyval = XKeycodeToKeysym(xevent->xkey.display,
|
||||
xevent->xkey.keycode,
|
||||
0 ); /* FIXME: index with modifiers */
|
||||
}
|
||||
|
||||
static void
|
||||
translate_button_event (ClutterButtonEvent *event,
|
||||
XEvent *xevent)
|
||||
{
|
||||
/* FIXME: catch double click */
|
||||
CLUTTER_NOTE (EVENT, " button event at %ix%i",
|
||||
xevent->xbutton.x,
|
||||
xevent->xbutton.y);
|
||||
|
||||
event->type = xevent->xany.type == ButtonPress ? CLUTTER_BUTTON_PRESS
|
||||
: CLUTTER_BUTTON_RELEASE;
|
||||
event->time = xevent->xbutton.time;
|
||||
event->x = xevent->xbutton.x;
|
||||
event->y = xevent->xbutton.y;
|
||||
event->modifier_state = xevent->xbutton.state; /* includes button masks */
|
||||
event->button = xevent->xbutton.button;
|
||||
}
|
||||
|
||||
static void
|
||||
translate_motion_event (ClutterMotionEvent *event,
|
||||
XEvent *xevent)
|
||||
{
|
||||
event->type = CLUTTER_MOTION;
|
||||
event->time = xevent->xbutton.time;
|
||||
event->x = xevent->xmotion.x;
|
||||
event->y = xevent->xmotion.y;
|
||||
event->modifier_state = xevent->xmotion.state;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_dispatch_x_event (XEvent *xevent,
|
||||
gpointer data)
|
||||
{
|
||||
ClutterMainContext *ctx = CLUTTER_CONTEXT ();
|
||||
ClutterEvent event;
|
||||
ClutterStage *stage = ctx->stage;
|
||||
gboolean emit_input_event = FALSE;
|
||||
|
||||
switch (xevent->type)
|
||||
{
|
||||
case Expose:
|
||||
{
|
||||
XEvent foo_xev;
|
||||
|
||||
/* Cheap compress */
|
||||
while (XCheckTypedWindowEvent(clutter_glx_display(),
|
||||
xevent->xexpose.window,
|
||||
Expose,
|
||||
&foo_xev));
|
||||
|
||||
/* FIXME: need to make stage an 'actor' so can que
|
||||
* a paint direct from there rather than hack here...
|
||||
*/
|
||||
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
|
||||
}
|
||||
break;
|
||||
case KeyPress:
|
||||
translate_key_event ((ClutterKeyEvent *) &event, xevent);
|
||||
g_signal_emit_by_name (stage, "key-press-event", &event);
|
||||
emit_input_event = TRUE;
|
||||
break;
|
||||
case KeyRelease:
|
||||
translate_key_event ((ClutterKeyEvent *) &event, xevent);
|
||||
g_signal_emit_by_name (stage, "key-release-event", &event);
|
||||
emit_input_event = TRUE;
|
||||
break;
|
||||
case ButtonPress:
|
||||
translate_button_event ((ClutterButtonEvent *) &event, xevent);
|
||||
g_signal_emit_by_name (stage, "button-press-event", &event);
|
||||
emit_input_event = TRUE;
|
||||
break;
|
||||
case ButtonRelease:
|
||||
translate_button_event ((ClutterButtonEvent *) &event, xevent);
|
||||
g_signal_emit_by_name (stage, "button-release-event", &event);
|
||||
emit_input_event = TRUE;
|
||||
break;
|
||||
case MotionNotify:
|
||||
translate_motion_event ((ClutterMotionEvent *) &event, xevent);
|
||||
g_signal_emit_by_name (stage, "motion-event", &event);
|
||||
emit_input_event = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (emit_input_event)
|
||||
g_signal_emit_by_name (stage, "input-event", &event);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
events_init()
|
||||
{
|
||||
ClutterMainContext *clutter_context;
|
||||
GMainContext *gmain_context;
|
||||
int connection_number;
|
||||
GSource *source;
|
||||
ClutterXEventSource *display_source;
|
||||
|
||||
clutter_context = clutter_context_get_default ();
|
||||
gmain_context = g_main_context_default ();
|
||||
|
||||
g_main_context_ref (gmain_context);
|
||||
|
||||
connection_number = ConnectionNumber (clutter_glx_display());
|
||||
|
||||
source = g_source_new ((GSourceFuncs *)&x_event_funcs,
|
||||
sizeof (ClutterXEventSource));
|
||||
|
||||
display_source = (ClutterXEventSource *)source;
|
||||
|
||||
display_source->event_poll_fd.fd = connection_number;
|
||||
display_source->event_poll_fd.events = G_IO_IN;
|
||||
display_source->display = clutter_glx_display();
|
||||
|
||||
g_source_add_poll (source, &display_source->event_poll_fd);
|
||||
g_source_set_can_recurse (source, TRUE);
|
||||
|
||||
g_source_set_callback (source,
|
||||
(GSourceFunc) clutter_dispatch_x_event,
|
||||
NULL /* no userdata */, NULL);
|
||||
|
||||
g_source_attach (source, gmain_context);
|
||||
g_source_unref (source);
|
||||
}
|
||||
|
||||
static void
|
||||
sync_fullscreen (ClutterStage *stage)
|
||||
{
|
||||
Atom atom_WINDOW_STATE, atom_WINDOW_STATE_FULLSCREEN;
|
||||
gboolean want_fullscreen;
|
||||
|
||||
atom_WINDOW_STATE
|
||||
= XInternAtom(clutter_glx_display(), "_NET_WM_STATE", False);
|
||||
atom_WINDOW_STATE_FULLSCREEN
|
||||
= XInternAtom(clutter_glx_display(), "_NET_WM_STATE_FULLSCREEN",False);
|
||||
|
||||
g_object_get (stage, "fullscreen", &want_fullscreen, NULL);
|
||||
|
||||
if (want_fullscreen)
|
||||
{
|
||||
clutter_actor_set_size (CLUTTER_ACTOR(stage),
|
||||
DisplayWidth(clutter_glx_display(),
|
||||
clutter_glx_screen()),
|
||||
DisplayHeight(clutter_glx_display(),
|
||||
clutter_glx_screen()));
|
||||
|
||||
if (stage->backend->xwin != None)
|
||||
XChangeProperty(clutter_glx_display(), stage->backend->xwin,
|
||||
atom_WINDOW_STATE, XA_ATOM, 32,
|
||||
PropModeReplace,
|
||||
(unsigned char *)&atom_WINDOW_STATE_FULLSCREEN, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (stage->backend->xwin != None)
|
||||
XDeleteProperty(clutter_glx_display(),
|
||||
stage->backend->xwin, atom_WINDOW_STATE);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sync_cursor (ClutterStage *stage)
|
||||
{
|
||||
gboolean hide_cursor;
|
||||
|
||||
if (stage->backend->xwin == None)
|
||||
return;
|
||||
|
||||
g_object_get (stage, "hide-cursor", &hide_cursor, NULL);
|
||||
|
||||
/* FIXME: Use XFixesHideCursor */
|
||||
|
||||
if (hide_cursor)
|
||||
{
|
||||
XColor col;
|
||||
Pixmap pix;
|
||||
Cursor curs;
|
||||
|
||||
pix = XCreatePixmap (clutter_glx_display(),
|
||||
stage->backend->xwin, 1, 1, 1);
|
||||
memset (&col, 0, sizeof (col));
|
||||
curs = XCreatePixmapCursor (clutter_glx_display(),
|
||||
pix, pix, &col, &col, 1, 1);
|
||||
XFreePixmap (clutter_glx_display(), pix);
|
||||
XDefineCursor(clutter_glx_display(), stage->backend->xwin, curs);
|
||||
}
|
||||
else
|
||||
{
|
||||
XUndefineCursor(clutter_glx_display(), stage->backend->xwin);
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME -> CGL */
|
||||
static void
|
||||
frustum (GLfloat left,
|
||||
GLfloat right,
|
||||
GLfloat bottom,
|
||||
GLfloat top,
|
||||
GLfloat nearval,
|
||||
GLfloat farval)
|
||||
{
|
||||
GLfloat x, y, a, b, c, d;
|
||||
GLfloat m[16];
|
||||
|
||||
x = (2.0 * nearval) / (right - left);
|
||||
y = (2.0 * nearval) / (top - bottom);
|
||||
a = (right + left) / (right - left);
|
||||
b = (top + bottom) / (top - bottom);
|
||||
c = -(farval + nearval) / ( farval - nearval);
|
||||
d = -(2.0 * farval * nearval) / (farval - nearval);
|
||||
|
||||
#define M(row,col) m[col*4+row]
|
||||
M(0,0) = x; M(0,1) = 0.0F; M(0,2) = a; M(0,3) = 0.0F;
|
||||
M(1,0) = 0.0F; M(1,1) = y; M(1,2) = b; M(1,3) = 0.0F;
|
||||
M(2,0) = 0.0F; M(2,1) = 0.0F; M(2,2) = c; M(2,3) = d;
|
||||
M(3,0) = 0.0F; M(3,1) = 0.0F; M(3,2) = -1.0F; M(3,3) = 0.0F;
|
||||
#undef M
|
||||
|
||||
glMultMatrixf (m);
|
||||
}
|
||||
|
||||
static void
|
||||
perspective (GLfloat fovy,
|
||||
GLfloat aspect,
|
||||
GLfloat zNear,
|
||||
GLfloat zFar)
|
||||
{
|
||||
GLfloat xmin, xmax, ymin, ymax;
|
||||
|
||||
ymax = zNear * tan (fovy * M_PI / 360.0);
|
||||
ymin = -ymax;
|
||||
xmin = ymin * aspect;
|
||||
xmax = ymax * aspect;
|
||||
|
||||
frustum (xmin, xmax, ymin, ymax, zNear, zFar);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
sync_viewport (ClutterStage *stage)
|
||||
{
|
||||
glViewport (0, 0, stage->backend->xwin_width, stage->backend->xwin_height);
|
||||
glMatrixMode (GL_PROJECTION);
|
||||
glLoadIdentity ();
|
||||
perspective (60.0f, 1.0f, 0.1f, 100.0f);
|
||||
glMatrixMode (GL_MODELVIEW);
|
||||
glLoadIdentity ();
|
||||
|
||||
/* Then for 2D like transform */
|
||||
|
||||
/* camera distance from screen, 0.5 * tan (FOV) */
|
||||
#define DEFAULT_Z_CAMERA 0.866025404f
|
||||
|
||||
glTranslatef (-0.5f, -0.5f, -DEFAULT_Z_CAMERA);
|
||||
glScalef (1.0f / stage->backend->xwin_width,
|
||||
-1.0f / stage->backend->xwin_height,
|
||||
1.0f / stage->backend->xwin_width);
|
||||
glTranslatef (0.0f, -stage->backend->xwin_height, 0.0f);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_glx_show (ClutterActor *self)
|
||||
{
|
||||
if (clutter_stage_glx_window (CLUTTER_STAGE(self)))
|
||||
XMapWindow (clutter_glx_display(),
|
||||
clutter_stage_glx_window (CLUTTER_STAGE(self)));
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_glx_hide (ClutterActor *self)
|
||||
{
|
||||
if (clutter_stage_glx_window (CLUTTER_STAGE(self)))
|
||||
XUnmapWindow (clutter_glx_display(),
|
||||
clutter_stage_glx_window (CLUTTER_STAGE(self)));
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_glx_unrealize (ClutterActor *actor)
|
||||
{
|
||||
ClutterStage *stage;
|
||||
ClutterStagePrivate *priv;
|
||||
ClutterStageBackend *backend;
|
||||
gboolean want_offscreen;
|
||||
|
||||
stage = CLUTTER_STAGE(actor);
|
||||
priv = stage->priv;
|
||||
backend = stage->backend;
|
||||
|
||||
CLUTTER_MARK();
|
||||
|
||||
g_object_get (stage, "offscreen", &want_offscreen, NULL);
|
||||
|
||||
if (want_offscreen)
|
||||
{
|
||||
if (backend->glxpixmap)
|
||||
{
|
||||
glXDestroyGLXPixmap (clutter_glx_display(), backend->glxpixmap);
|
||||
backend->glxpixmap = None;
|
||||
}
|
||||
|
||||
if (backend->xpixmap)
|
||||
{
|
||||
XFreePixmap (clutter_glx_display(), backend->xpixmap);
|
||||
backend->xpixmap = None;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!backend->is_foreign_xwin && backend->xwin != None)
|
||||
{
|
||||
XDestroyWindow (clutter_glx_display(), backend->xwin);
|
||||
backend->xwin = None;
|
||||
}
|
||||
else
|
||||
backend->xwin = None;
|
||||
}
|
||||
|
||||
glXMakeCurrent(clutter_glx_display(), None, NULL);
|
||||
if (backend->gl_context != None)
|
||||
{
|
||||
glXDestroyContext (clutter_glx_display(), backend->gl_context);
|
||||
backend->gl_context = None;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_glx_realize (ClutterActor *actor)
|
||||
{
|
||||
ClutterStage *stage;
|
||||
ClutterStagePrivate *priv;
|
||||
ClutterStageBackend *backend;
|
||||
gboolean want_offscreen;
|
||||
|
||||
stage = CLUTTER_STAGE(actor);
|
||||
|
||||
priv = stage->priv;
|
||||
backend = stage->backend;
|
||||
|
||||
CLUTTER_MARK();
|
||||
|
||||
g_object_get (stage, "offscreen", &want_offscreen, NULL);
|
||||
|
||||
if (want_offscreen)
|
||||
{
|
||||
int gl_attributes[] = {
|
||||
GLX_RGBA,
|
||||
GLX_RED_SIZE, 1,
|
||||
GLX_GREEN_SIZE, 1,
|
||||
GLX_BLUE_SIZE, 1,
|
||||
0
|
||||
};
|
||||
|
||||
if (backend->xvisinfo)
|
||||
XFree(backend->xvisinfo);
|
||||
|
||||
backend->xvisinfo = glXChooseVisual (clutter_glx_display(),
|
||||
clutter_glx_screen(),
|
||||
gl_attributes);
|
||||
if (!backend->xvisinfo)
|
||||
{
|
||||
g_critical ("Unable to find suitable GL visual.");
|
||||
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (backend->gl_context)
|
||||
glXDestroyContext (clutter_glx_display(), backend->gl_context);
|
||||
|
||||
backend->xpixmap = XCreatePixmap (clutter_glx_display(),
|
||||
clutter_glx_root_window(),
|
||||
backend->xwin_width,
|
||||
backend->xwin_height,
|
||||
backend->xvisinfo->depth);
|
||||
|
||||
backend->glxpixmap = glXCreateGLXPixmap(clutter_glx_display(),
|
||||
backend->xvisinfo,
|
||||
backend->xpixmap);
|
||||
sync_fullscreen (stage);
|
||||
|
||||
/* indirect */
|
||||
backend->gl_context = glXCreateContext (clutter_glx_display(),
|
||||
backend->xvisinfo,
|
||||
0,
|
||||
False);
|
||||
|
||||
glXMakeCurrent(clutter_glx_display(),
|
||||
backend->glxpixmap, backend->gl_context);
|
||||
|
||||
#if 0
|
||||
/* Debug code for monitoring a off screen pixmap via window */
|
||||
{
|
||||
Colormap cmap;
|
||||
XSetWindowAttributes swa;
|
||||
|
||||
cmap = XCreateColormap(clutter_glx_display(),
|
||||
clutter_glx_root_window(),
|
||||
backend->xvisinfo->visual, AllocNone);
|
||||
|
||||
/* create a window */
|
||||
swa.colormap = cmap;
|
||||
|
||||
foo_win = XCreateWindow(clutter_glx_display(),
|
||||
clutter_glx_root_window(),
|
||||
0, 0,
|
||||
backend->xwin_width, backend->xwin_height,
|
||||
0,
|
||||
backend->xvisinfo->depth,
|
||||
InputOutput,
|
||||
backend->xvisinfo->visual,
|
||||
CWColormap, &swa);
|
||||
|
||||
XMapWindow(clutter_glx_display(), foo_win);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
int gl_attributes[] =
|
||||
{
|
||||
GLX_RGBA,
|
||||
GLX_DOUBLEBUFFER,
|
||||
GLX_RED_SIZE, 1,
|
||||
GLX_GREEN_SIZE, 1,
|
||||
GLX_BLUE_SIZE, 1,
|
||||
GLX_STENCIL_SIZE, 1,
|
||||
0
|
||||
};
|
||||
|
||||
if (backend->xvisinfo)
|
||||
XFree(backend->xvisinfo);
|
||||
|
||||
if (backend->xvisinfo == None)
|
||||
backend->xvisinfo = glXChooseVisual (clutter_glx_display(),
|
||||
clutter_glx_screen(),
|
||||
gl_attributes);
|
||||
if (!backend->xvisinfo)
|
||||
{
|
||||
g_critical ("Unable to find suitable GL visual.");
|
||||
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (backend->xwin == None)
|
||||
backend->xwin = XCreateSimpleWindow(clutter_glx_display(),
|
||||
clutter_glx_root_window(),
|
||||
0, 0,
|
||||
backend->xwin_width, backend->xwin_height,
|
||||
0, 0,
|
||||
WhitePixel(clutter_glx_display(),
|
||||
clutter_glx_screen()));
|
||||
XSelectInput(clutter_glx_display(),
|
||||
backend->xwin,
|
||||
StructureNotifyMask
|
||||
|ExposureMask
|
||||
/* FIXME: we may want to eplicity enable MotionMask */
|
||||
|PointerMotionMask
|
||||
|KeyPressMask
|
||||
|KeyReleaseMask
|
||||
|ButtonPressMask
|
||||
|ButtonReleaseMask
|
||||
|PropertyChangeMask);
|
||||
|
||||
sync_fullscreen (stage);
|
||||
sync_cursor (stage);
|
||||
|
||||
if (backend->gl_context)
|
||||
glXDestroyContext (clutter_glx_display(), backend->gl_context);
|
||||
|
||||
backend->gl_context = glXCreateContext (clutter_glx_display(),
|
||||
backend->xvisinfo,
|
||||
0,
|
||||
True);
|
||||
|
||||
if (backend->gl_context == None)
|
||||
{
|
||||
g_critical ("Unable to create suitable GL context.");
|
||||
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
|
||||
return;
|
||||
}
|
||||
|
||||
glXMakeCurrent(clutter_glx_display(), backend->xwin, backend->gl_context);
|
||||
}
|
||||
|
||||
CLUTTER_NOTE (GL,
|
||||
"\n"
|
||||
"===========================================\n"
|
||||
"GL_VENDOR: %s\n"
|
||||
"GL_RENDERER: %s\n"
|
||||
"GL_VERSION: %s\n"
|
||||
"GL_EXTENSIONS: %s\n"
|
||||
"Is direct: %s\n"
|
||||
"===========================================\n",
|
||||
glGetString (GL_VENDOR),
|
||||
glGetString (GL_RENDERER),
|
||||
glGetString (GL_VERSION),
|
||||
glGetString (GL_EXTENSIONS),
|
||||
glXIsDirect(clutter_glx_display(), backend->gl_context) ? "yes" : "no"
|
||||
);
|
||||
|
||||
sync_viewport (stage);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_glx_paint (ClutterActor *self)
|
||||
{
|
||||
ClutterStage *stage = CLUTTER_STAGE(self);
|
||||
ClutterColor stage_color;
|
||||
static GTimer *timer = NULL;
|
||||
static guint timer_n_frames = 0;
|
||||
|
||||
static ClutterActorClass *parent_class = NULL;
|
||||
|
||||
CLUTTER_NOTE (PAINT, " Redraw enter");
|
||||
|
||||
if (parent_class == NULL)
|
||||
parent_class = g_type_class_peek_parent (CLUTTER_STAGE_GET_CLASS(stage));
|
||||
|
||||
if (clutter_want_fps ())
|
||||
{
|
||||
if (!timer)
|
||||
timer = g_timer_new ();
|
||||
}
|
||||
|
||||
clutter_stage_get_color (stage, &stage_color);
|
||||
|
||||
glClearColor(((float) stage_color.red / 0xff * 1.0),
|
||||
((float) stage_color.green / 0xff * 1.0),
|
||||
((float) stage_color.blue / 0xff * 1.0),
|
||||
0.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
glDisable(GL_LIGHTING);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
parent_class->paint (self);
|
||||
|
||||
if (clutter_stage_glx_window (stage))
|
||||
{
|
||||
clutter_feature_wait_for_vblank ();
|
||||
glXSwapBuffers(clutter_glx_display(), clutter_stage_glx_window (stage));
|
||||
}
|
||||
else
|
||||
{
|
||||
glXWaitGL();
|
||||
CLUTTER_GLERR();
|
||||
}
|
||||
|
||||
if (clutter_want_fps ())
|
||||
{
|
||||
timer_n_frames++;
|
||||
|
||||
if (g_timer_elapsed (timer, NULL) >= 1.0)
|
||||
{
|
||||
g_print ("*** FPS: %i ***\n", timer_n_frames);
|
||||
timer_n_frames = 0;
|
||||
g_timer_start (timer);
|
||||
}
|
||||
}
|
||||
|
||||
CLUTTER_NOTE (PAINT, " Redraw leave");
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_glx_allocate_coords (ClutterActor *self,
|
||||
ClutterActorBox *box)
|
||||
{
|
||||
/* Do nothing, just stop group_allocate getting called */
|
||||
|
||||
/* TODO: sync up with any configure events from WM ?? */
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_glx_request_coords (ClutterActor *self,
|
||||
ClutterActorBox *box)
|
||||
{
|
||||
ClutterStage *stage;
|
||||
ClutterStageBackend *backend;
|
||||
gint new_width, new_height;
|
||||
|
||||
stage = CLUTTER_STAGE (self);
|
||||
backend = stage->backend;
|
||||
|
||||
/* FIXME: some how have X configure_notfiys call this ?
|
||||
*/
|
||||
|
||||
new_width = ABS(box->x2 - box->x1);
|
||||
new_height = ABS(box->y2 - box->y1);
|
||||
|
||||
if (new_width != backend->xwin_width || new_height != backend->xwin_height)
|
||||
{
|
||||
backend->xwin_width = new_width;
|
||||
backend->xwin_height = new_height;
|
||||
|
||||
if (backend->xwin != None)
|
||||
XResizeWindow (clutter_glx_display(),
|
||||
backend->xwin,
|
||||
backend->xwin_width,
|
||||
backend->xwin_height);
|
||||
|
||||
if (backend->xpixmap != None)
|
||||
{
|
||||
/* Need to recreate to resize */
|
||||
clutter_actor_unrealize(self);
|
||||
clutter_actor_realize(self);
|
||||
}
|
||||
|
||||
sync_viewport (stage);
|
||||
}
|
||||
|
||||
if (backend->xwin != None) /* Do we want to bother ? */
|
||||
XMoveWindow (clutter_glx_display(),
|
||||
backend->xwin,
|
||||
box->x1,
|
||||
box->y1);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_glx_dispose (GObject *object)
|
||||
{
|
||||
#if 0
|
||||
ClutterStage *self = CLUTTER_STAGE (object);
|
||||
|
||||
if (self->backend->xwin)
|
||||
clutter_actor_unrealize (CLUTTER_ACTOR (self));
|
||||
|
||||
G_OBJECT_CLASS (clutter_stage_parent_class)->dispose (object);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_glx_finalize (GObject *object)
|
||||
{
|
||||
#if 0
|
||||
G_OBJECT_CLASS (clutter_stage_parent_class)->finalize (object);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
clutter_stage_backend_init_vtable (ClutterStageVTable *vtable)
|
||||
{
|
||||
vtable->show = clutter_stage_glx_show;
|
||||
vtable->hide = clutter_stage_glx_hide;
|
||||
vtable->realize = clutter_stage_glx_realize;
|
||||
vtable->unrealize = clutter_stage_glx_unrealize;
|
||||
vtable->paint = clutter_stage_glx_paint;
|
||||
vtable->request_coords = clutter_stage_glx_request_coords;
|
||||
vtable->allocate_coords = clutter_stage_glx_allocate_coords;
|
||||
|
||||
vtable->sync_fullscreen = sync_fullscreen;
|
||||
vtable->sync_cursor = sync_cursor;
|
||||
vtable->sync_viewport = sync_viewport;
|
||||
|
||||
}
|
||||
|
||||
ClutterStageBackend*
|
||||
clutter_stage_backend_init (ClutterStage *stage)
|
||||
{
|
||||
ClutterStageBackend *backend;
|
||||
|
||||
backend = g_new0(ClutterStageBackend, 1);
|
||||
|
||||
backend->xwin_width = 100;
|
||||
backend->xwin_height = 100;
|
||||
|
||||
/* Maybe better somewhere else */
|
||||
events_init ();
|
||||
|
||||
return backend;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_stage_glx_get_xwindow
|
||||
* @stage: A #ClutterStage
|
||||
*
|
||||
* Get the stage's underlying x window ID.
|
||||
*
|
||||
* Return Value: Stage X Window XID
|
||||
*
|
||||
* Since: 0.3
|
||||
**/
|
||||
Window
|
||||
clutter_stage_glx_window (ClutterStage *stage)
|
||||
{
|
||||
return stage->backend->xwin;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_stage_set_xwindow_foreign
|
||||
* @stage: A #ClutterStage
|
||||
* @xid: A preexisting X Window ID
|
||||
*
|
||||
* Target the #ClutterStage to use an existing external X Window.
|
||||
*
|
||||
* Return Value: TRUE if foreign window valid, FALSE otherwise
|
||||
*
|
||||
* Since: 0.3
|
||||
**/
|
||||
gboolean
|
||||
clutter_stage_glx_set_window_foreign (ClutterStage *stage,
|
||||
Window xid)
|
||||
{
|
||||
/* For screensavers via XSCREENSAVER_WINDOW env var.
|
||||
* Also for toolkit binding.
|
||||
*/
|
||||
gint x,y;
|
||||
guint width, height, border, depth;
|
||||
Window root_return;
|
||||
Status status;
|
||||
ClutterGeometry geom;
|
||||
|
||||
clutter_glx_trap_x_errors();
|
||||
|
||||
status = XGetGeometry (clutter_glx_display(),
|
||||
xid,
|
||||
&root_return,
|
||||
&x,
|
||||
&y,
|
||||
&width,
|
||||
&height,
|
||||
&border,
|
||||
&depth);
|
||||
|
||||
if (clutter_glx_untrap_x_errors() || !status
|
||||
|| width == 0 || height == 0 || depth != stage->backend->xvisinfo->depth)
|
||||
return FALSE;
|
||||
|
||||
clutter_actor_unrealize (CLUTTER_ACTOR(stage));
|
||||
|
||||
stage->backend->xwin = xid;
|
||||
|
||||
geom.x = x;
|
||||
geom.y = y;
|
||||
|
||||
geom.width = stage->backend->xwin_width = width;
|
||||
geom.height = stage->backend->xwin_height = height;
|
||||
|
||||
clutter_actor_set_geometry (CLUTTER_ACTOR(stage), &geom);
|
||||
|
||||
clutter_actor_realize (CLUTTER_ACTOR(stage));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_stage_glx_get_xvisual
|
||||
* @stage: A #ClutterStage
|
||||
*
|
||||
* Get the stage's XVisualInfo.
|
||||
*
|
||||
* Return Value: The stage's XVisualInfo
|
||||
*
|
||||
* Since: 0.3
|
||||
**/
|
||||
const XVisualInfo*
|
||||
clutter_stage_glx_get_visual (ClutterStage *stage)
|
||||
{
|
||||
return stage->backend->xvisinfo;
|
||||
}
|
58
clutter/clutter-stage-glx.h
Normal file
58
clutter/clutter-stage-glx.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Clutter.
|
||||
*
|
||||
* An OpenGL based 'interactive canvas' library.
|
||||
*
|
||||
* Authored By Matthew Allum <mallum@openedhand.com>
|
||||
*
|
||||
* Copyright (C) 2006 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
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _HAVE_CLUTTER_STAGE_GLX_H
|
||||
#define _HAVE_CLUTTER_STAGE_GLX_H
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
#include <GL/glx.h>
|
||||
#include <GL/gl.h>
|
||||
|
||||
#include <clutter/clutter-stage.h>
|
||||
|
||||
void
|
||||
clutter_stage_backend_init_vtable (ClutterStageVTable *vtable) G_GNUC_INTERNAL;
|
||||
|
||||
ClutterStageBackend*
|
||||
clutter_stage_backend_init (ClutterStage *stage) G_GNUC_INTERNAL;
|
||||
|
||||
Window
|
||||
clutter_stage_glx_window (ClutterStage *stage);
|
||||
|
||||
gboolean
|
||||
clutter_stage_glx_set_window_foreign (ClutterStage *stage,
|
||||
Window xid);
|
||||
|
||||
const XVisualInfo*
|
||||
clutter_stage_glx_get_xvisual (ClutterStage *stage);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
@ -42,14 +42,22 @@
|
||||
#include "clutter-private.h"
|
||||
#include "clutter-debug.h"
|
||||
|
||||
#include <GL/glx.h>
|
||||
#include <GL/gl.h>
|
||||
#ifdef CLUTTER_BACKEND_GLX
|
||||
#include <clutter/clutter-stage-glx.h>
|
||||
#endif
|
||||
|
||||
#ifdef CLUTTER_BACKEND_EGL
|
||||
#include <clutter/clutter-stage-egl.h>
|
||||
#endif
|
||||
|
||||
#include <gdk-pixbuf-xlib/gdk-pixbuf-xlib.h>
|
||||
|
||||
/* the stage is a singleton instance */
|
||||
static ClutterStage *stage_singleton = NULL;
|
||||
|
||||
/* Backend hooks */
|
||||
static ClutterStageVTable _vtable;
|
||||
|
||||
G_DEFINE_TYPE (ClutterStage, clutter_stage, CLUTTER_TYPE_GROUP);
|
||||
|
||||
#define CLUTTER_STAGE_GET_PRIVATE(obj) \
|
||||
@ -57,21 +65,11 @@ G_DEFINE_TYPE (ClutterStage, clutter_stage, CLUTTER_TYPE_GROUP);
|
||||
|
||||
struct _ClutterStagePrivate
|
||||
{
|
||||
XVisualInfo *xvisinfo;
|
||||
Window xwin;
|
||||
Pixmap xpixmap;
|
||||
gint xwin_width, xwin_height; /* FIXME target_width / height */
|
||||
|
||||
GLXPixmap glxpixmap;
|
||||
GLXContext gl_context;
|
||||
|
||||
|
||||
ClutterColor color;
|
||||
|
||||
guint want_fullscreen : 1;
|
||||
guint want_offscreen : 1;
|
||||
guint hide_cursor : 1;
|
||||
guint is_foreign_xwin : 1;
|
||||
};
|
||||
|
||||
enum
|
||||
@ -100,511 +98,6 @@ static guint stage_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
static ClutterActorClass *parent_class = NULL;
|
||||
|
||||
static void
|
||||
sync_fullscreen (ClutterStage *stage)
|
||||
{
|
||||
Atom atom_WINDOW_STATE, atom_WINDOW_STATE_FULLSCREEN;
|
||||
|
||||
atom_WINDOW_STATE
|
||||
= XInternAtom(clutter_xdisplay(), "_NET_WM_STATE", False);
|
||||
atom_WINDOW_STATE_FULLSCREEN
|
||||
= XInternAtom(clutter_xdisplay(), "_NET_WM_STATE_FULLSCREEN",False);
|
||||
|
||||
if (stage->priv->want_fullscreen)
|
||||
{
|
||||
clutter_actor_set_size (CLUTTER_ACTOR(stage),
|
||||
DisplayWidth(clutter_xdisplay(),
|
||||
clutter_xscreen()),
|
||||
DisplayHeight(clutter_xdisplay(),
|
||||
clutter_xscreen()));
|
||||
|
||||
if (stage->priv->xwin != None)
|
||||
XChangeProperty(clutter_xdisplay(), stage->priv->xwin,
|
||||
atom_WINDOW_STATE, XA_ATOM, 32,
|
||||
PropModeReplace,
|
||||
(unsigned char *)&atom_WINDOW_STATE_FULLSCREEN, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (stage->priv->xwin != None)
|
||||
XDeleteProperty(clutter_xdisplay(),
|
||||
stage->priv->xwin, atom_WINDOW_STATE);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sync_cursor_visible (ClutterStage *stage)
|
||||
{
|
||||
if (stage->priv->xwin == None)
|
||||
return;
|
||||
|
||||
if (stage->priv->hide_cursor)
|
||||
{
|
||||
XColor col;
|
||||
Pixmap pix;
|
||||
Cursor curs;
|
||||
|
||||
pix = XCreatePixmap (clutter_xdisplay(),
|
||||
stage->priv->xwin, 1, 1, 1);
|
||||
memset (&col, 0, sizeof (col));
|
||||
curs = XCreatePixmapCursor (clutter_xdisplay(),
|
||||
pix, pix, &col, &col, 1, 1);
|
||||
XFreePixmap (clutter_xdisplay(), pix);
|
||||
XDefineCursor(clutter_xdisplay(), stage->priv->xwin, curs);
|
||||
}
|
||||
else
|
||||
{
|
||||
XUndefineCursor(clutter_xdisplay(), stage->priv->xwin);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
frustum (GLfloat left,
|
||||
GLfloat right,
|
||||
GLfloat bottom,
|
||||
GLfloat top,
|
||||
GLfloat nearval,
|
||||
GLfloat farval)
|
||||
{
|
||||
GLfloat x, y, a, b, c, d;
|
||||
GLfloat m[16];
|
||||
|
||||
x = (2.0 * nearval) / (right - left);
|
||||
y = (2.0 * nearval) / (top - bottom);
|
||||
a = (right + left) / (right - left);
|
||||
b = (top + bottom) / (top - bottom);
|
||||
c = -(farval + nearval) / ( farval - nearval);
|
||||
d = -(2.0 * farval * nearval) / (farval - nearval);
|
||||
|
||||
#define M(row,col) m[col*4+row]
|
||||
M(0,0) = x; M(0,1) = 0.0F; M(0,2) = a; M(0,3) = 0.0F;
|
||||
M(1,0) = 0.0F; M(1,1) = y; M(1,2) = b; M(1,3) = 0.0F;
|
||||
M(2,0) = 0.0F; M(2,1) = 0.0F; M(2,2) = c; M(2,3) = d;
|
||||
M(3,0) = 0.0F; M(3,1) = 0.0F; M(3,2) = -1.0F; M(3,3) = 0.0F;
|
||||
#undef M
|
||||
|
||||
glMultMatrixf (m);
|
||||
}
|
||||
|
||||
static void
|
||||
perspective (GLfloat fovy,
|
||||
GLfloat aspect,
|
||||
GLfloat zNear,
|
||||
GLfloat zFar)
|
||||
{
|
||||
GLfloat xmin, xmax, ymin, ymax;
|
||||
|
||||
ymax = zNear * tan (fovy * M_PI / 360.0);
|
||||
ymin = -ymax;
|
||||
xmin = ymin * aspect;
|
||||
xmax = ymax * aspect;
|
||||
|
||||
frustum (xmin, xmax, ymin, ymax, zNear, zFar);
|
||||
}
|
||||
|
||||
static void
|
||||
sync_gl_viewport (ClutterStage *stage)
|
||||
{
|
||||
/* Set For 2D */
|
||||
#if 0
|
||||
glViewport (0, 0, stage->priv->xwin_width, stage->priv->xwin_height);
|
||||
glMatrixMode (GL_PROJECTION);
|
||||
glLoadIdentity ();
|
||||
glOrtho (0, stage->priv->xwin_width, stage->priv->xwin_height, 0, -1, 1);
|
||||
glMatrixMode (GL_MODELVIEW);
|
||||
glLoadIdentity ();
|
||||
|
||||
#endif
|
||||
/* For 3D */
|
||||
|
||||
glViewport (0, 0, stage->priv->xwin_width, stage->priv->xwin_height);
|
||||
glMatrixMode (GL_PROJECTION);
|
||||
glLoadIdentity ();
|
||||
perspective (60.0f, 1.0f, 0.1f, 100.0f);
|
||||
glMatrixMode (GL_MODELVIEW);
|
||||
glLoadIdentity ();
|
||||
|
||||
/* Then for 2D like transform */
|
||||
|
||||
/* camera distance from screen, 0.5 * tan (FOV) */
|
||||
#define DEFAULT_Z_CAMERA 0.866025404f
|
||||
|
||||
glTranslatef (-0.5f, -0.5f, -DEFAULT_Z_CAMERA);
|
||||
glScalef (1.0f / stage->priv->xwin_width,
|
||||
-1.0f / stage->priv->xwin_height, 1.0f / stage->priv->xwin_width);
|
||||
glTranslatef (0.0f, -stage->priv->xwin_height, 0.0f);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_show (ClutterActor *self)
|
||||
{
|
||||
ClutterActorClass *parent_class;
|
||||
|
||||
parent_class = CLUTTER_ACTOR_CLASS (clutter_stage_parent_class);
|
||||
if (parent_class->show)
|
||||
parent_class->show (self);
|
||||
|
||||
if (clutter_stage_get_xwindow (CLUTTER_STAGE (self)))
|
||||
XMapWindow (clutter_xdisplay (),
|
||||
clutter_stage_get_xwindow (CLUTTER_STAGE (self)));
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_hide (ClutterActor *self)
|
||||
{
|
||||
ClutterActorClass *parent_class;
|
||||
|
||||
parent_class = CLUTTER_ACTOR_CLASS (clutter_stage_parent_class);
|
||||
if (parent_class->hide)
|
||||
parent_class->hide (self);
|
||||
|
||||
if (clutter_stage_get_xwindow (CLUTTER_STAGE (self)))
|
||||
XUnmapWindow (clutter_xdisplay (),
|
||||
clutter_stage_get_xwindow (CLUTTER_STAGE (self)));
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_unrealize (ClutterActor *actor)
|
||||
{
|
||||
ClutterStage *stage;
|
||||
ClutterStagePrivate *priv;
|
||||
|
||||
stage = CLUTTER_STAGE(actor);
|
||||
priv = stage->priv;
|
||||
|
||||
CLUTTER_MARK();
|
||||
|
||||
if (priv->want_offscreen)
|
||||
{
|
||||
if (priv->glxpixmap)
|
||||
{
|
||||
glXDestroyGLXPixmap (clutter_xdisplay(), priv->glxpixmap);
|
||||
priv->glxpixmap = None;
|
||||
}
|
||||
|
||||
if (priv->xpixmap)
|
||||
{
|
||||
XFreePixmap (clutter_xdisplay(), priv->xpixmap);
|
||||
priv->xpixmap = None;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!priv->is_foreign_xwin && priv->xwin != None)
|
||||
{
|
||||
XDestroyWindow (clutter_xdisplay(), priv->xwin);
|
||||
priv->xwin = None;
|
||||
}
|
||||
else
|
||||
priv->xwin = None;
|
||||
}
|
||||
|
||||
glXMakeCurrent(clutter_xdisplay(), None, NULL);
|
||||
if (priv->gl_context != None)
|
||||
{
|
||||
glXDestroyContext (clutter_xdisplay(), priv->gl_context);
|
||||
priv->gl_context = None;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_realize (ClutterActor *actor)
|
||||
{
|
||||
ClutterStage *stage;
|
||||
ClutterStagePrivate *priv;
|
||||
|
||||
stage = CLUTTER_STAGE(actor);
|
||||
|
||||
priv = stage->priv;
|
||||
|
||||
CLUTTER_MARK();
|
||||
|
||||
if (priv->want_offscreen)
|
||||
{
|
||||
int gl_attributes[] = {
|
||||
GLX_RGBA,
|
||||
GLX_RED_SIZE, 1,
|
||||
GLX_GREEN_SIZE, 1,
|
||||
GLX_BLUE_SIZE, 1,
|
||||
0
|
||||
};
|
||||
|
||||
if (priv->xvisinfo)
|
||||
XFree(priv->xvisinfo);
|
||||
|
||||
priv->xvisinfo = glXChooseVisual (clutter_xdisplay(),
|
||||
clutter_xscreen(),
|
||||
gl_attributes);
|
||||
if (!priv->xvisinfo)
|
||||
{
|
||||
g_critical ("Unable to find suitable GL visual.");
|
||||
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (priv->gl_context != None)
|
||||
glXDestroyContext (clutter_xdisplay(), priv->gl_context);
|
||||
|
||||
priv->xpixmap = XCreatePixmap (clutter_xdisplay(),
|
||||
clutter_root_xwindow(),
|
||||
priv->xwin_width,
|
||||
priv->xwin_height,
|
||||
priv->xvisinfo->depth);
|
||||
|
||||
priv->glxpixmap = glXCreateGLXPixmap(clutter_xdisplay(),
|
||||
priv->xvisinfo,
|
||||
priv->xpixmap);
|
||||
sync_fullscreen (stage);
|
||||
|
||||
/* indirect */
|
||||
priv->gl_context = glXCreateContext (clutter_xdisplay(),
|
||||
priv->xvisinfo,
|
||||
0,
|
||||
False);
|
||||
|
||||
glXMakeCurrent(clutter_xdisplay(), priv->glxpixmap, priv->gl_context);
|
||||
|
||||
#if 0
|
||||
/* Debug code for monitoring a off screen pixmap via window */
|
||||
{
|
||||
Colormap cmap;
|
||||
XSetWindowAttributes swa;
|
||||
|
||||
cmap = XCreateColormap(clutter_xdisplay(),
|
||||
clutter_root_xwindow(),
|
||||
priv->xvisinfo->visual, AllocNone);
|
||||
|
||||
/* create a window */
|
||||
swa.colormap = cmap;
|
||||
|
||||
foo_win = XCreateWindow(clutter_xdisplay(),
|
||||
clutter_root_xwindow(),
|
||||
0, 0,
|
||||
priv->xwin_width, priv->xwin_height,
|
||||
0,
|
||||
priv->xvisinfo->depth,
|
||||
InputOutput,
|
||||
priv->xvisinfo->visual,
|
||||
CWColormap, &swa);
|
||||
|
||||
XMapWindow(clutter_xdisplay(), foo_win);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
int gl_attributes[] =
|
||||
{
|
||||
GLX_RGBA,
|
||||
GLX_DOUBLEBUFFER,
|
||||
GLX_RED_SIZE, 1,
|
||||
GLX_GREEN_SIZE, 1,
|
||||
GLX_BLUE_SIZE, 1,
|
||||
GLX_STENCIL_SIZE, 1,
|
||||
0
|
||||
};
|
||||
|
||||
if (priv->xvisinfo)
|
||||
{
|
||||
XFree(priv->xvisinfo);
|
||||
priv->xvisinfo = None;
|
||||
}
|
||||
#if 0
|
||||
/* Attempted fix at GTK 'white' textures - made no difference :( */
|
||||
if (priv->is_foreign_xwin && priv->xwin != None)
|
||||
{
|
||||
XWindowAttributes win_attr;
|
||||
XVisualInfo vis_info;
|
||||
int n;
|
||||
|
||||
XGetWindowAttributes (clutter_xdisplay(), priv->xwin, &win_attr);
|
||||
vis_info.screen = clutter_xscreen();
|
||||
vis_info.visualid = XVisualIDFromVisual (win_attr.visual);
|
||||
priv->xvisinfo = XGetVisualInfo (clutter_xdisplay(),
|
||||
VisualScreenMask|VisualIDMask,
|
||||
&vis_info, &n);
|
||||
|
||||
printf("made %li\n", priv->xvisinfo);
|
||||
}
|
||||
#endif
|
||||
if (priv->xvisinfo == None)
|
||||
priv->xvisinfo = glXChooseVisual (clutter_xdisplay(),
|
||||
clutter_xscreen(),
|
||||
gl_attributes);
|
||||
if (!priv->xvisinfo)
|
||||
{
|
||||
g_critical ("Unable to find suitable GL visual.");
|
||||
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
|
||||
return;
|
||||
}
|
||||
|
||||
CLUTTER_NOTE(GL, "visual id's %li vs %li",
|
||||
priv->xvisinfo->visualid,
|
||||
XVisualIDFromVisual(DefaultVisual(clutter_xdisplay(),
|
||||
clutter_xscreen())));
|
||||
|
||||
|
||||
if (priv->xwin == None)
|
||||
{
|
||||
XSetWindowAttributes swa;
|
||||
|
||||
if (priv->xvisinfo->visualid
|
||||
== XVisualIDFromVisual(DefaultVisual(clutter_xdisplay(),
|
||||
clutter_xscreen())))
|
||||
{
|
||||
swa.colormap = DefaultColormap(clutter_xdisplay(),
|
||||
clutter_xscreen());
|
||||
}
|
||||
else
|
||||
{
|
||||
swa.colormap = XCreateColormap(clutter_xdisplay(),
|
||||
clutter_root_xwindow(),
|
||||
priv->xvisinfo->visual,
|
||||
AllocNone);
|
||||
}
|
||||
|
||||
priv->xwin = XCreateWindow(clutter_xdisplay(),
|
||||
clutter_root_xwindow(),
|
||||
0, 0,
|
||||
priv->xwin_width, priv->xwin_height,
|
||||
0,
|
||||
priv->xvisinfo->depth,
|
||||
InputOutput,
|
||||
priv->xvisinfo->visual,
|
||||
CWColormap, &swa);
|
||||
}
|
||||
|
||||
XSelectInput(clutter_xdisplay(),
|
||||
priv->xwin,
|
||||
StructureNotifyMask
|
||||
|ExposureMask
|
||||
/* FIXME: we may want to eplicity enable MotionMask */
|
||||
|PointerMotionMask
|
||||
|KeyPressMask
|
||||
|KeyReleaseMask
|
||||
|ButtonPressMask
|
||||
|ButtonReleaseMask
|
||||
|PropertyChangeMask);
|
||||
|
||||
sync_fullscreen (stage);
|
||||
sync_cursor_visible (stage);
|
||||
|
||||
if (priv->gl_context != None)
|
||||
glXDestroyContext (clutter_xdisplay(), priv->gl_context);
|
||||
|
||||
priv->gl_context = glXCreateContext (clutter_xdisplay(),
|
||||
priv->xvisinfo,
|
||||
0,
|
||||
True);
|
||||
if (priv->gl_context == None)
|
||||
{
|
||||
g_critical ("Unable to create suitable GL context.");
|
||||
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
|
||||
return;
|
||||
}
|
||||
|
||||
glXMakeCurrent(clutter_xdisplay(), priv->xwin, priv->gl_context);
|
||||
}
|
||||
|
||||
CLUTTER_NOTE (GL,
|
||||
"\n"
|
||||
"==========================================="
|
||||
"GL_VENDOR: %s\n"
|
||||
"GL_RENDERER: %s\n"
|
||||
"GL_VERSION: %s\n"
|
||||
"GL_EXTENSIONS: %s\n"
|
||||
"Is direct: %s\n"
|
||||
"===========================================",
|
||||
glGetString (GL_VENDOR),
|
||||
glGetString (GL_RENDERER),
|
||||
glGetString (GL_VERSION),
|
||||
glGetString (GL_EXTENSIONS),
|
||||
glXIsDirect(clutter_xdisplay(), priv->gl_context) ? "yes" : "no"
|
||||
);
|
||||
|
||||
sync_gl_viewport (stage);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_paint (ClutterActor *self)
|
||||
{
|
||||
parent_class->paint (self);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_allocate_coords (ClutterActor *self,
|
||||
ClutterActorBox *box)
|
||||
{
|
||||
/* Do nothing, just stop group_allocate getting called */
|
||||
|
||||
/* TODO: sync up with any configure events from WM ?? */
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_request_coords (ClutterActor *self,
|
||||
ClutterActorBox *box)
|
||||
{
|
||||
ClutterStage *stage;
|
||||
ClutterStagePrivate *priv;
|
||||
gint new_width, new_height;
|
||||
|
||||
stage = CLUTTER_STAGE (self);
|
||||
priv = stage->priv;
|
||||
|
||||
/* FIXME: some how have X configure_notfiys call this ?
|
||||
*/
|
||||
|
||||
new_width = ABS(box->x2 - box->x1);
|
||||
new_height = ABS(box->y2 - box->y1);
|
||||
|
||||
if (new_width != priv->xwin_width || new_height != priv->xwin_height)
|
||||
{
|
||||
priv->xwin_width = new_width;
|
||||
priv->xwin_height = new_height;
|
||||
|
||||
if (priv->xwin != None)
|
||||
XResizeWindow (clutter_xdisplay(),
|
||||
priv->xwin,
|
||||
priv->xwin_width,
|
||||
priv->xwin_height);
|
||||
|
||||
if (priv->xpixmap)
|
||||
{
|
||||
/* Need to recreate to resize */
|
||||
clutter_actor_unrealize(self);
|
||||
clutter_actor_realize(self);
|
||||
}
|
||||
|
||||
sync_gl_viewport (stage);
|
||||
}
|
||||
|
||||
if (priv->xwin != None) /* Do we want to bother ? */
|
||||
XMoveWindow (clutter_xdisplay(),
|
||||
priv->xwin,
|
||||
box->x1,
|
||||
box->y1);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_dispose (GObject *object)
|
||||
{
|
||||
ClutterStage *self = CLUTTER_STAGE (object);
|
||||
|
||||
if (self->priv->xwin != None)
|
||||
clutter_stage_unrealize (CLUTTER_ACTOR (self));
|
||||
|
||||
G_OBJECT_CLASS (clutter_stage_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_finalize (GObject *object)
|
||||
{
|
||||
G_OBJECT_CLASS (clutter_stage_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
clutter_stage_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
@ -640,14 +133,14 @@ clutter_stage_set_property (GObject *object,
|
||||
if (priv->want_fullscreen != g_value_get_boolean (value))
|
||||
{
|
||||
priv->want_fullscreen = g_value_get_boolean (value);
|
||||
sync_fullscreen (stage);
|
||||
_vtable.sync_fullscreen (stage);
|
||||
}
|
||||
break;
|
||||
case PROP_HIDE_CURSOR:
|
||||
if (priv->hide_cursor != g_value_get_boolean (value))
|
||||
{
|
||||
priv->hide_cursor = g_value_get_boolean (value);
|
||||
sync_cursor_visible (stage);
|
||||
_vtable.sync_cursor (stage);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -698,17 +191,22 @@ clutter_stage_class_init (ClutterStageClass *klass)
|
||||
|
||||
parent_class = g_type_class_peek_parent (klass);
|
||||
|
||||
actor_class->realize = clutter_stage_realize;
|
||||
actor_class->unrealize = clutter_stage_unrealize;
|
||||
actor_class->show = clutter_stage_show;
|
||||
actor_class->hide = clutter_stage_hide;
|
||||
actor_class->paint = clutter_stage_paint;
|
||||
clutter_stage_backend_init_vtable (&_vtable);
|
||||
|
||||
actor_class->request_coords = clutter_stage_request_coords;
|
||||
actor_class->allocate_coords = clutter_stage_allocate_coords;
|
||||
actor_class->realize = _vtable.realize;
|
||||
actor_class->unrealize = _vtable.unrealize;
|
||||
actor_class->show = _vtable.show;
|
||||
actor_class->hide = _vtable.hide;
|
||||
actor_class->paint = _vtable.paint;
|
||||
|
||||
actor_class->request_coords = _vtable.request_coords;
|
||||
actor_class->allocate_coords = _vtable.allocate_coords;
|
||||
|
||||
/*
|
||||
gobject_class->dispose = _vtable.stage_dispose;
|
||||
gobject_class->finalize = _vtable.stage_finalize;
|
||||
*/
|
||||
|
||||
gobject_class->dispose = clutter_stage_dispose;
|
||||
gobject_class->finalize = clutter_stage_finalize;
|
||||
gobject_class->set_property = clutter_stage_set_property;
|
||||
gobject_class->get_property = clutter_stage_get_property;
|
||||
|
||||
@ -867,16 +365,11 @@ clutter_stage_init (ClutterStage *self)
|
||||
|
||||
self->priv = priv = CLUTTER_STAGE_GET_PRIVATE (self);
|
||||
|
||||
self->backend = clutter_stage_backend_init (self);
|
||||
|
||||
priv->want_offscreen = FALSE;
|
||||
priv->want_fullscreen = FALSE;
|
||||
priv->hide_cursor = FALSE;
|
||||
priv->is_foreign_xwin = FALSE;
|
||||
|
||||
priv->xwin = None;
|
||||
priv->gl_context = None;
|
||||
|
||||
priv->xwin_width = 100;
|
||||
priv->xwin_height = 100;
|
||||
|
||||
priv->color.red = 0xff;
|
||||
priv->color.green = 0xff;
|
||||
@ -928,98 +421,6 @@ clutter_stage_get_default (void)
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_stage_get_xwindow
|
||||
* @stage: A #ClutterStage
|
||||
*
|
||||
* Get the stage's underlying x window ID.
|
||||
*
|
||||
* Return Value: Stage X Window XID
|
||||
**/
|
||||
Window
|
||||
clutter_stage_get_xwindow (ClutterStage *stage)
|
||||
{
|
||||
return stage->priv->xwin;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_stage_set_xwindow_foreign
|
||||
* @stage: A #ClutterStage
|
||||
* @xid: A preexisting X Window ID
|
||||
*
|
||||
* Target the #ClutterStage to use an existing external X Window.
|
||||
*
|
||||
* Return value: TRUE if foreign window valid, FALSE otherwise
|
||||
**/
|
||||
gboolean
|
||||
clutter_stage_set_xwindow_foreign (ClutterStage *stage,
|
||||
Window xid)
|
||||
{
|
||||
/* For screensavers via XSCREENSAVER_WINDOW env var.
|
||||
* Also for toolkit binding.
|
||||
*/
|
||||
gint x,y;
|
||||
guint width, height, border, depth;
|
||||
Window root_return;
|
||||
Status status;
|
||||
ClutterGeometry geom;
|
||||
ClutterStagePrivate *priv;
|
||||
|
||||
g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE);
|
||||
g_return_val_if_fail (xid != None, FALSE);
|
||||
|
||||
priv = stage->priv;
|
||||
|
||||
clutter_util_trap_x_errors();
|
||||
|
||||
status = XGetGeometry (clutter_xdisplay(),
|
||||
xid,
|
||||
&root_return,
|
||||
&x,
|
||||
&y,
|
||||
&width,
|
||||
&height,
|
||||
&border,
|
||||
&depth);
|
||||
|
||||
if (clutter_util_untrap_x_errors() || !status ||
|
||||
width == 0 || height == 0 ||
|
||||
depth != priv->xvisinfo->depth)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
clutter_actor_unrealize (CLUTTER_ACTOR (stage));
|
||||
|
||||
priv->xwin = xid;
|
||||
priv->is_foreign_xwin = TRUE;
|
||||
|
||||
geom.x = x;
|
||||
geom.y = y;
|
||||
geom.width = priv->xwin_width = width;
|
||||
geom.height = priv->xwin_height = height;
|
||||
|
||||
clutter_actor_set_geometry (CLUTTER_ACTOR (stage), &geom);
|
||||
|
||||
clutter_actor_realize (CLUTTER_ACTOR (stage));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_stage_get_xvisual
|
||||
* @stage: A #ClutterStage
|
||||
*
|
||||
* Get the stage's XVisualInfo.
|
||||
*
|
||||
* Return Value: The stage's XVisualInfo
|
||||
**/
|
||||
const XVisualInfo*
|
||||
clutter_stage_get_xvisual (ClutterStage *stage)
|
||||
{
|
||||
return stage->priv->xvisinfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_stage_set_color
|
||||
* @stage: A #ClutterStage
|
||||
@ -1072,12 +473,14 @@ clutter_stage_get_color (ClutterStage *stage,
|
||||
color->alpha = priv->color.alpha;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void
|
||||
snapshot_pixbuf_free (guchar *pixels,
|
||||
gpointer data)
|
||||
{
|
||||
g_free(pixels);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* clutter_stage_snapshot
|
||||
@ -1100,6 +503,7 @@ clutter_stage_snapshot (ClutterStage *stage,
|
||||
gint width,
|
||||
gint height)
|
||||
{
|
||||
#if 0
|
||||
guchar *data;
|
||||
GdkPixbuf *pixb, *fpixb;
|
||||
ClutterActor *actor;
|
||||
@ -1158,8 +562,56 @@ clutter_stage_snapshot (ClutterStage *stage,
|
||||
|
||||
return fpixb;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME -> CGL */
|
||||
static void
|
||||
frustum (GLfloat left,
|
||||
GLfloat right,
|
||||
GLfloat bottom,
|
||||
GLfloat top,
|
||||
GLfloat nearval,
|
||||
GLfloat farval)
|
||||
{
|
||||
GLfloat x, y, a, b, c, d;
|
||||
GLfloat m[16];
|
||||
|
||||
x = (2.0 * nearval) / (right - left);
|
||||
y = (2.0 * nearval) / (top - bottom);
|
||||
a = (right + left) / (right - left);
|
||||
b = (top + bottom) / (top - bottom);
|
||||
c = -(farval + nearval) / ( farval - nearval);
|
||||
d = -(2.0 * farval * nearval) / (farval - nearval);
|
||||
|
||||
#define M(row,col) m[col*4+row]
|
||||
M(0,0) = x; M(0,1) = 0.0F; M(0,2) = a; M(0,3) = 0.0F;
|
||||
M(1,0) = 0.0F; M(1,1) = y; M(1,2) = b; M(1,3) = 0.0F;
|
||||
M(2,0) = 0.0F; M(2,1) = 0.0F; M(2,2) = c; M(2,3) = d;
|
||||
M(3,0) = 0.0F; M(3,1) = 0.0F; M(3,2) = -1.0F; M(3,3) = 0.0F;
|
||||
#undef M
|
||||
|
||||
glMultMatrixf (m);
|
||||
}
|
||||
|
||||
static void
|
||||
perspective (GLfloat fovy,
|
||||
GLfloat aspect,
|
||||
GLfloat zNear,
|
||||
GLfloat zFar)
|
||||
{
|
||||
GLfloat xmin, xmax, ymin, ymax;
|
||||
|
||||
ymax = zNear * tan (fovy * M_PI / 360.0);
|
||||
ymin = -ymax;
|
||||
xmin = ymin * aspect;
|
||||
xmax = ymax * aspect;
|
||||
|
||||
frustum (xmin, xmax, ymin, ymax, zNear, zFar);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* clutter_stage_get_actor_at_pos:
|
||||
* @stage: a #ClutterStage
|
||||
@ -1220,7 +672,7 @@ clutter_stage_get_actor_at_pos (ClutterStage *stage,
|
||||
buff[(hits-1) * 4 + 3]);
|
||||
}
|
||||
|
||||
sync_gl_viewport (stage);
|
||||
_vtable.sync_viewport (stage);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
@ -34,10 +34,6 @@
|
||||
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <GL/glx.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define CLUTTER_TYPE_STAGE (clutter_stage_get_type())
|
||||
@ -72,10 +68,14 @@ G_BEGIN_DECLS
|
||||
typedef struct _ClutterStagePrivate ClutterStagePrivate;
|
||||
typedef struct _ClutterStage ClutterStage;
|
||||
typedef struct _ClutterStageClass ClutterStageClass;
|
||||
typedef struct _ClutterStageBackend ClutterStageBackend;
|
||||
typedef struct _ClutterStageVTable ClutterStageVTable;
|
||||
|
||||
|
||||
struct _ClutterStage
|
||||
{
|
||||
ClutterGroup parent;
|
||||
ClutterStageBackend *backend;
|
||||
|
||||
/*< private >*/
|
||||
ClutterStagePrivate *priv;
|
||||
@ -107,11 +107,27 @@ struct _ClutterStageClass
|
||||
void (*_clutter_stage6) (void);
|
||||
};
|
||||
|
||||
struct _ClutterStageVTable
|
||||
{
|
||||
void (* show) (ClutterActor *actor);
|
||||
void (* hide) (ClutterActor *actor);
|
||||
void (* realize) (ClutterActor *actor);
|
||||
void (* unrealize) (ClutterActor *actor);
|
||||
void (* paint) (ClutterActor *actor);
|
||||
void (* request_coords) (ClutterActor *actor,
|
||||
ClutterActorBox *box);
|
||||
void (* allocate_coords) (ClutterActor *actor,
|
||||
ClutterActorBox *box);
|
||||
|
||||
void (* sync_fullscreen) (ClutterStage *stage);
|
||||
void (* sync_cursor) (ClutterStage *stage);
|
||||
void (* sync_viewport) (ClutterStage *stage);
|
||||
|
||||
};
|
||||
|
||||
|
||||
GType clutter_stage_get_type (void) G_GNUC_CONST;
|
||||
ClutterActor *clutter_stage_get_default (void);
|
||||
Window clutter_stage_get_xwindow (ClutterStage *stage);
|
||||
gboolean clutter_stage_set_xwindow_foreign (ClutterStage *stage,
|
||||
Window xid);
|
||||
void clutter_stage_set_color (ClutterStage *stage,
|
||||
const ClutterColor *color);
|
||||
void clutter_stage_get_color (ClutterStage *stage,
|
||||
@ -124,7 +140,6 @@ GdkPixbuf * clutter_stage_snapshot (ClutterStage *stage,
|
||||
gint y,
|
||||
gint width,
|
||||
gint height);
|
||||
const XVisualInfo * clutter_stage_get_xvisual (ClutterStage *stage);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@ -34,43 +34,6 @@
|
||||
#include "clutter-util.h"
|
||||
#include "clutter-main.h"
|
||||
|
||||
static int TrappedErrorCode = 0;
|
||||
static int (*old_error_handler) (Display *, XErrorEvent *);
|
||||
|
||||
static int
|
||||
error_handler(Display *xdpy,
|
||||
XErrorEvent *error)
|
||||
{
|
||||
TrappedErrorCode = error->error_code;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_util_trap_x_errors:
|
||||
*
|
||||
* Trap X errors so they don't cause an abort.
|
||||
*/
|
||||
void
|
||||
clutter_util_trap_x_errors(void)
|
||||
{
|
||||
TrappedErrorCode = 0;
|
||||
old_error_handler = XSetErrorHandler(error_handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_util_untrap_x_errors:
|
||||
*
|
||||
* Stop trapping X errors.
|
||||
*
|
||||
* Return value: 0 if there was no error, or the last X error that occurred.
|
||||
*/
|
||||
int
|
||||
clutter_util_untrap_x_errors(void)
|
||||
{
|
||||
XSetErrorHandler(old_error_handler);
|
||||
return TrappedErrorCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_util_next_p2:
|
||||
* @a: Value to get the next power
|
||||
|
@ -30,12 +30,6 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
void
|
||||
clutter_util_trap_x_errors(void);
|
||||
|
||||
int
|
||||
clutter_util_untrap_x_errors(void);
|
||||
|
||||
int
|
||||
clutter_util_next_p2 (int a);
|
||||
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <GL/gl.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "pangoclutter.h"
|
||||
@ -553,14 +554,15 @@ draw_begin (PangoRenderer *renderer_)
|
||||
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
glEnable (GL_BLEND);
|
||||
#if 0
|
||||
/* How to handle in ES ? */
|
||||
gl_BlendFuncSeparate (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
|
||||
GL_ONE , GL_ONE_MINUS_SRC_ALPHA);
|
||||
#endif
|
||||
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
#if 0
|
||||
|
||||
glEnable (GL_ALPHA_TEST);
|
||||
glAlphaFunc (GL_GREATER, 0.01f);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -97,6 +97,9 @@ fi
|
||||
|
||||
GLX_CFLAGS="$X11_CFLAGS"
|
||||
|
||||
CLUTTER_FLAVOUR="glx"
|
||||
AC_SUBST(CLUTTER_FLAVOUR)
|
||||
|
||||
dnl ========================================================================
|
||||
|
||||
pkg_modules="pangoft2 glib-2.0 >= 2.8 gthread-2.0 gdk-pixbuf-2.0 gdk-pixbuf-xlib-2.0"
|
||||
|
@ -1,7 +1,7 @@
|
||||
noinst_PROGRAMS = test super-oh behave
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/
|
||||
LDADD = $(top_builddir)/clutter/libclutter-@CLUTTER_MAJORMINOR@.la
|
||||
LDADD = $(top_builddir)/clutter/libclutter-@CLUTTER_FLAVOUR@-@CLUTTER_MAJORMINOR@.la
|
||||
|
||||
test_SOURCES = test.c
|
||||
test_CFLAGS = $(CLUTTER_CFLAGS) $(GCONF_CFLAGS)
|
||||
|
Loading…
Reference in New Issue
Block a user