2008-03-25 Neil Roberts <neil@o-hand.com>
Added a native Win32 WGL backend. * configure.ac: Added the 'win32' flavour. * clutter/cogl/gl/cogl.c (cogl_get_proc_address): Added an ifdef to use wglGetProcAddress with the Win32 backend. * clutter/Makefile.am (DIST_SUBDIRS): Added the win32 directory. * clutter/win32/clutter-win32.pc.in: * clutter/win32/clutter-win32.h: * clutter/win32/clutter-stage-win32.h: * clutter/win32/clutter-stage-win32.c: * clutter/win32/clutter-event-win32.c: * clutter/win32/clutter-backend-win32.h: * clutter/win32/Makefile.am: * clutter/win32/clutter-backend-win32.c: New files.
This commit is contained in:
parent
7c05499865
commit
051ed6b43b
20
ChangeLog
20
ChangeLog
@ -1,3 +1,23 @@
|
||||
2008-03-25 Neil Roberts <neil@o-hand.com>
|
||||
|
||||
Added a native Win32 WGL backend.
|
||||
|
||||
* configure.ac: Added the 'win32' flavour.
|
||||
|
||||
* clutter/cogl/gl/cogl.c (cogl_get_proc_address): Added an ifdef
|
||||
to use wglGetProcAddress with the Win32 backend.
|
||||
|
||||
* clutter/Makefile.am (DIST_SUBDIRS): Added the win32 directory.
|
||||
|
||||
* clutter/win32/clutter-win32.pc.in:
|
||||
* clutter/win32/clutter-win32.h:
|
||||
* clutter/win32/clutter-stage-win32.h:
|
||||
* clutter/win32/clutter-stage-win32.c:
|
||||
* clutter/win32/clutter-event-win32.c:
|
||||
* clutter/win32/clutter-backend-win32.h:
|
||||
* clutter/win32/Makefile.am:
|
||||
* clutter/win32/clutter-backend-win32.c: New files.
|
||||
|
||||
2008-03-19 Emmanuele Bassi <ebassi@openedhand.com>
|
||||
|
||||
* clutter/clutter-model.[ch]: Add a ::copy() virtual function
|
||||
|
@ -2,7 +2,7 @@ NULL =
|
||||
|
||||
SUBDIRS = cogl pango json $(clutterbackend) $(backendextra)
|
||||
|
||||
DIST_SUBDIRS = pango glx eglx eglnative cogl sdl json osx x11
|
||||
DIST_SUBDIRS = pango glx eglx eglnative cogl sdl json osx x11 win32
|
||||
|
||||
target = $(clutterbackend)
|
||||
|
||||
|
@ -109,7 +109,7 @@ cogl_get_proc_address (const gchar* name)
|
||||
/* Sucks to ifdef here but not other option..? would be nice to
|
||||
* split the code up for more reuse (once more backends use this
|
||||
*/
|
||||
#ifdef HAVE_CLUTTER_GLX
|
||||
#if defined(HAVE_CLUTTER_GLX)
|
||||
static GLXGetProcAddressProc get_proc_func = NULL;
|
||||
static void *dlhand = NULL;
|
||||
|
||||
@ -142,7 +142,11 @@ cogl_get_proc_address (const gchar* name)
|
||||
if (get_proc_func)
|
||||
return get_proc_func ((unsigned char*) name);
|
||||
|
||||
#else /* !HAVE_CLUTTER_GLX */
|
||||
#elif defined(HAVE_CLUTTER_WIN32)
|
||||
|
||||
return (CoglFuncPtr) wglGetProcAddress ((LPCSTR) name);
|
||||
|
||||
#else /* HAVE_CLUTTER_WIN32 */
|
||||
|
||||
/* this should find the right function if the program is linked against a
|
||||
* library providing it */
|
||||
@ -158,7 +162,7 @@ cogl_get_proc_address (const gchar* name)
|
||||
return symbol;
|
||||
}
|
||||
|
||||
#endif /* HAVE_CLUTTER_GLX */
|
||||
#endif /* HAVE_CLUTTER_WIN32 */
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
33
clutter/win32/Makefile.am
Normal file
33
clutter/win32/Makefile.am
Normal file
@ -0,0 +1,33 @@
|
||||
libclutterincludedir = $(includedir)/clutter-@CLUTTER_API_VERSION@/clutter
|
||||
libclutterinclude_HEADERS = clutter-win32.h
|
||||
|
||||
clutter-win32-$(CLUTTER_API_VERSION).pc: clutter-win32.pc
|
||||
@cp -f $< $(@F)
|
||||
|
||||
pkgconfig_DATA = clutter-win32-@CLUTTER_API_VERSION@.pc
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
|
||||
INCLUDES = \
|
||||
-DG_LOG_DOMAIN=\"ClutterWin32\" \
|
||||
-I$(top_srcdir) \
|
||||
-I$(top_srcdir)/clutter/cogl \
|
||||
-I$(top_srcdir)/clutter/cogl/@CLUTTER_COGL@ \
|
||||
$(CLUTTER_CFLAGS) \
|
||||
$(CLUTTER_DEBUG_CFLAGS) \
|
||||
$(GCC_FLAGS)
|
||||
|
||||
LDADD = $(CLUTTER_LIBS)
|
||||
|
||||
noinst_LTLIBRARIES = libclutter-win32.la
|
||||
|
||||
libclutter_win32_la_SOURCES = \
|
||||
clutter-backend-win32.h \
|
||||
clutter-backend-win32.c \
|
||||
clutter-event-win32.c \
|
||||
clutter-stage-win32.h \
|
||||
clutter-stage-win32.c \
|
||||
clutter-win32.h
|
||||
|
||||
CLEANFILES = clutter-win32-$(CLUTTER_API_VERSION).pc
|
||||
|
||||
EXTRA_DIST = clutter-win32.pc.in
|
302
clutter/win32/clutter-backend-win32.c
Normal file
302
clutter/win32/clutter-backend-win32.c
Normal file
@ -0,0 +1,302 @@
|
||||
/* 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
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "clutter-backend-win32.h"
|
||||
#include "clutter-stage-win32.h"
|
||||
#include "clutter-win32.h"
|
||||
|
||||
#include "../clutter-event.h"
|
||||
#include "../clutter-main.h"
|
||||
#include "../clutter-debug.h"
|
||||
#include "../clutter-private.h"
|
||||
|
||||
#include "cogl.h"
|
||||
|
||||
G_DEFINE_TYPE (ClutterBackendWin32, clutter_backend_win32,
|
||||
CLUTTER_TYPE_BACKEND);
|
||||
|
||||
typedef int (* SwapIntervalProc) (int interval);
|
||||
|
||||
/* singleton object */
|
||||
static ClutterBackendWin32 *backend_singleton = NULL;
|
||||
|
||||
static gchar *clutter_vblank_name = NULL;
|
||||
|
||||
gboolean
|
||||
clutter_backend_win32_pre_parse (ClutterBackend *backend,
|
||||
GError **error)
|
||||
{
|
||||
const gchar *env_string;
|
||||
|
||||
if ((env_string = g_getenv ("CLUTTER_VBLANK")))
|
||||
clutter_vblank_name = g_strdup (env_string);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_backend_win32_init_events (ClutterBackend *backend)
|
||||
{
|
||||
CLUTTER_NOTE (EVENT, "initialising the event loop");
|
||||
|
||||
_clutter_backend_win32_events_init (backend);
|
||||
}
|
||||
|
||||
ClutterActor *
|
||||
clutter_backend_win32_get_stage (ClutterBackend *backend)
|
||||
{
|
||||
ClutterBackendWin32 *backend_win32 = CLUTTER_BACKEND_WIN32 (backend);
|
||||
|
||||
return backend_win32->stage;
|
||||
}
|
||||
|
||||
static const GOptionEntry entries[] =
|
||||
{
|
||||
{
|
||||
"vblank", 0,
|
||||
0,
|
||||
G_OPTION_ARG_STRING, &clutter_vblank_name,
|
||||
"VBlank method to be used (none, default or wgl)", "METHOD"
|
||||
},
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
void
|
||||
clutter_backend_win32_add_options (ClutterBackend *backend,
|
||||
GOptionGroup *group)
|
||||
{
|
||||
g_option_group_add_entries (group, entries);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_backend_win32_finalize (GObject *gobject)
|
||||
{
|
||||
backend_singleton = NULL;
|
||||
|
||||
G_OBJECT_CLASS (clutter_backend_win32_parent_class)->finalize (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_backend_win32_dispose (GObject *gobject)
|
||||
{
|
||||
ClutterBackendWin32 *backend_win32 = CLUTTER_BACKEND_WIN32 (gobject);
|
||||
|
||||
if (backend_win32->stage)
|
||||
{
|
||||
CLUTTER_NOTE (BACKEND, "Disposing the main stage");
|
||||
|
||||
/* we unset the private flag on the stage so we can safely
|
||||
* destroy it without a warning from clutter_actor_destroy()
|
||||
*/
|
||||
CLUTTER_UNSET_PRIVATE_FLAGS (backend_win32->stage,
|
||||
CLUTTER_ACTOR_IS_TOPLEVEL);
|
||||
clutter_actor_destroy (backend_win32->stage);
|
||||
backend_win32->stage = NULL;
|
||||
}
|
||||
|
||||
CLUTTER_NOTE (BACKEND, "Removing the event source");
|
||||
_clutter_backend_win32_events_uninit (CLUTTER_BACKEND (backend_win32));
|
||||
|
||||
G_OBJECT_CLASS (clutter_backend_win32_parent_class)->dispose (gobject);
|
||||
}
|
||||
|
||||
static GObject *
|
||||
clutter_backend_win32_constructor (GType gtype,
|
||||
guint n_params,
|
||||
GObjectConstructParam *params)
|
||||
{
|
||||
GObjectClass *parent_class;
|
||||
GObject *retval;
|
||||
|
||||
if (!backend_singleton)
|
||||
{
|
||||
parent_class = G_OBJECT_CLASS (clutter_backend_win32_parent_class);
|
||||
retval = parent_class->constructor (gtype, n_params, params);
|
||||
|
||||
backend_singleton = CLUTTER_BACKEND_WIN32 (retval);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
g_warning ("Attempting to create a new backend object. This should "
|
||||
"never happen, so we return the singleton instance.");
|
||||
|
||||
return g_object_ref (backend_singleton);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
check_vblank_env (const char *name)
|
||||
{
|
||||
return clutter_vblank_name && !strcasecmp (clutter_vblank_name, name);
|
||||
}
|
||||
|
||||
ClutterFeatureFlags
|
||||
clutter_backend_win32_get_features (ClutterBackend *backend)
|
||||
{
|
||||
ClutterFeatureFlags flags;
|
||||
const gchar *extensions;
|
||||
SwapIntervalProc swap_interval;
|
||||
|
||||
/* FIXME: we really need to check if gl context is set */
|
||||
|
||||
extensions = glGetString (GL_EXTENSIONS);
|
||||
|
||||
CLUTTER_NOTE (BACKEND, "Checking features\n"
|
||||
"GL_VENDOR: %s\n"
|
||||
"GL_RENDERER: %s\n"
|
||||
"GL_VERSION: %s\n"
|
||||
"GL_EXTENSIONS: %s\n",
|
||||
glGetString (GL_VENDOR),
|
||||
glGetString (GL_RENDERER),
|
||||
glGetString (GL_VERSION),
|
||||
extensions);
|
||||
|
||||
flags = CLUTTER_FEATURE_STAGE_USER_RESIZE | CLUTTER_FEATURE_STAGE_CURSOR;
|
||||
|
||||
/* If the VBlank should be left at the default or it has been
|
||||
disabled elsewhere (eg NVIDIA) then don't bother trying to check
|
||||
for the swap control extension */
|
||||
if (getenv ("__GL_SYNC_TO_VBLANK") || check_vblank_env ("default"))
|
||||
CLUTTER_NOTE (BACKEND, "vblank sync: left at default at user request");
|
||||
else if (cogl_check_extension ("WGL_EXT_swap_control", extensions)
|
||||
&& (swap_interval = (SwapIntervalProc)
|
||||
cogl_get_proc_address ("wglSwapIntervalEXT")))
|
||||
{
|
||||
/* According to the specification for the WGL_EXT_swap_control
|
||||
extension the default swap interval is 1 anyway, so if no
|
||||
vblank is requested then we should explicitly set it to
|
||||
zero */
|
||||
if (check_vblank_env ("none"))
|
||||
{
|
||||
if (swap_interval (0))
|
||||
CLUTTER_NOTE (BACKEND, "vblank sync: successfully disabled");
|
||||
else
|
||||
CLUTTER_NOTE (BACKEND, "vblank sync: disabling failed");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (swap_interval (1))
|
||||
{
|
||||
flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;
|
||||
CLUTTER_NOTE (BACKEND, "vblank sync: wglSwapIntervalEXT "
|
||||
"vblank setup success");
|
||||
}
|
||||
else
|
||||
CLUTTER_NOTE (BACKEND, "vblank sync: wglSwapIntervalEXT "
|
||||
"vblank setup failed");
|
||||
}
|
||||
}
|
||||
else
|
||||
CLUTTER_NOTE (BACKEND, "no use-able vblank mechanism found");
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_backend_win32_redraw (ClutterBackend *backend)
|
||||
{
|
||||
ClutterBackendWin32 *backend_win32 = CLUTTER_BACKEND_WIN32 (backend);
|
||||
ClutterStageWin32 *stage_win32;
|
||||
|
||||
stage_win32 = CLUTTER_STAGE_WIN32 (backend_win32->stage);
|
||||
|
||||
clutter_actor_paint (CLUTTER_ACTOR (stage_win32));
|
||||
|
||||
if (stage_win32->client_dc)
|
||||
SwapBuffers (stage_win32->client_dc);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clutter_backend_win32_init_stage (ClutterBackend *backend,
|
||||
GError **error)
|
||||
{
|
||||
ClutterBackendWin32 *backend_win32 = CLUTTER_BACKEND_WIN32 (backend);
|
||||
|
||||
if (!backend_win32->stage)
|
||||
{
|
||||
ClutterStageWin32 *stage_win32;
|
||||
ClutterActor *stage;
|
||||
|
||||
stage = g_object_new (CLUTTER_TYPE_STAGE_WIN32, NULL);
|
||||
|
||||
/* copy backend data into the stage */
|
||||
stage_win32 = CLUTTER_STAGE_WIN32 (stage);
|
||||
stage_win32->backend = backend_win32;
|
||||
|
||||
g_object_set_data (G_OBJECT (stage), "clutter-backend", backend);
|
||||
|
||||
backend_win32->stage = g_object_ref_sink (stage);
|
||||
}
|
||||
|
||||
clutter_actor_realize (backend_win32->stage);
|
||||
|
||||
if (!CLUTTER_ACTOR_IS_REALIZED (backend_win32->stage))
|
||||
{
|
||||
g_set_error (error, CLUTTER_INIT_ERROR,
|
||||
CLUTTER_INIT_ERROR_INTERNAL,
|
||||
"Unable to realize the main stage");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_backend_win32_class_init (ClutterBackendWin32Class *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
ClutterBackendClass *backend_class = CLUTTER_BACKEND_CLASS (klass);
|
||||
|
||||
gobject_class->constructor = clutter_backend_win32_constructor;
|
||||
gobject_class->dispose = clutter_backend_win32_dispose;
|
||||
gobject_class->finalize = clutter_backend_win32_finalize;
|
||||
|
||||
backend_class->pre_parse = clutter_backend_win32_pre_parse;
|
||||
backend_class->init_events = clutter_backend_win32_init_events;
|
||||
backend_class->init_stage = clutter_backend_win32_init_stage;
|
||||
backend_class->get_stage = clutter_backend_win32_get_stage;
|
||||
backend_class->add_options = clutter_backend_win32_add_options;
|
||||
backend_class->get_features = clutter_backend_win32_get_features;
|
||||
backend_class->redraw = clutter_backend_win32_redraw;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_backend_win32_init (ClutterBackendWin32 *backend_win32)
|
||||
{
|
||||
ClutterBackend *backend = CLUTTER_BACKEND (backend_win32);
|
||||
|
||||
/* FIXME: get from GetSystemMetric? */
|
||||
clutter_backend_set_double_click_time (backend, 250);
|
||||
clutter_backend_set_double_click_distance (backend, 5);
|
||||
clutter_backend_set_resolution (backend, 96.0);
|
||||
}
|
||||
|
||||
GType
|
||||
_clutter_backend_impl_get_type (void)
|
||||
{
|
||||
return clutter_backend_win32_get_type ();
|
||||
}
|
76
clutter/win32/clutter-backend-win32.h
Normal file
76
clutter/win32/clutter-backend-win32.h
Normal file
@ -0,0 +1,76 @@
|
||||
/* 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
|
||||
* 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 __CLUTTER_BACKEND_WIN32_H__
|
||||
#define __CLUTTER_BACKEND_WIN32_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <clutter/clutter-event.h>
|
||||
#include <clutter/clutter-backend.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include "clutter-win32.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define CLUTTER_TYPE_BACKEND_WIN32 (clutter_backend_win32_get_type ())
|
||||
#define CLUTTER_BACKEND_WIN32(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BACKEND_WIN32, ClutterBackendWin32))
|
||||
#define CLUTTER_IS_BACKEND_WIN32(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BACKEND_WIN32))
|
||||
#define CLUTTER_BACKEND_WIN32_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_BACKEND_WIN32, ClutterBackendWin32Class))
|
||||
#define CLUTTER_IS_BACKEND_WIN32_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_BACKEND_WIN32))
|
||||
#define CLUTTER_BACKEND_WIN32_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_BACKEND_WIN32, ClutterBackendWin32Class))
|
||||
|
||||
typedef struct _ClutterBackendWin32 ClutterBackendWin32;
|
||||
typedef struct _ClutterBackendWin32Class ClutterBackendWin32Class;
|
||||
|
||||
struct _ClutterBackendWin32
|
||||
{
|
||||
ClutterBackend parent_instance;
|
||||
|
||||
/* main stage singleton */
|
||||
ClutterActor *stage;
|
||||
|
||||
GSource *event_source;
|
||||
};
|
||||
|
||||
struct _ClutterBackendWin32Class
|
||||
{
|
||||
ClutterBackendClass parent_class;
|
||||
};
|
||||
|
||||
void _clutter_backend_win32_events_init (ClutterBackend *backend);
|
||||
void _clutter_backend_win32_events_uninit (ClutterBackend *backend);
|
||||
|
||||
GType clutter_backend_win32_get_type (void) G_GNUC_CONST;
|
||||
|
||||
ClutterActor *
|
||||
clutter_backend_win32_get_stage (ClutterBackend *backend);
|
||||
|
||||
void
|
||||
clutter_backend_win32_add_options (ClutterBackend *backend,
|
||||
GOptionGroup *group);
|
||||
|
||||
ClutterFeatureFlags
|
||||
clutter_backend_win32_get_features (ClutterBackend *backend);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __CLUTTER_BACKEND_WIN32_H__ */
|
613
clutter/win32/clutter-event-win32.c
Normal file
613
clutter/win32/clutter-event-win32.c
Normal file
@ -0,0 +1,613 @@
|
||||
/* 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
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "clutter-stage-win32.h"
|
||||
#include "clutter-backend-win32.h"
|
||||
#include "clutter-win32.h"
|
||||
|
||||
#include "../clutter-backend.h"
|
||||
#include "../clutter-event.h"
|
||||
#include "../clutter-private.h"
|
||||
#include "../clutter-debug.h"
|
||||
#include "../clutter-main.h"
|
||||
#include "../clutter-keysyms.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <glib.h>
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
|
||||
typedef struct _ClutterEventSource ClutterEventSource;
|
||||
|
||||
struct _ClutterEventSource
|
||||
{
|
||||
GSource source;
|
||||
|
||||
ClutterBackend *backend;
|
||||
GPollFD event_poll_fd;
|
||||
};
|
||||
|
||||
static gboolean clutter_event_prepare (GSource *source,
|
||||
gint *timeout);
|
||||
static gboolean clutter_event_check (GSource *source);
|
||||
static gboolean clutter_event_dispatch (GSource *source,
|
||||
GSourceFunc callback,
|
||||
gpointer user_data);
|
||||
|
||||
static GSourceFuncs event_funcs = {
|
||||
clutter_event_prepare,
|
||||
clutter_event_check,
|
||||
clutter_event_dispatch,
|
||||
NULL
|
||||
};
|
||||
|
||||
/* Special mapping for some keys that don't have a direct Unicode
|
||||
value. Must be sorted by the numeric value of the Windows key
|
||||
virtual key code */
|
||||
static const struct
|
||||
{
|
||||
gushort win_sym, clutter_sym;
|
||||
} clutter_win32_key_map[] =
|
||||
{
|
||||
{ VK_CANCEL, CLUTTER_Cancel },
|
||||
{ VK_BACK, CLUTTER_BackSpace },
|
||||
{ VK_TAB, CLUTTER_Tab },
|
||||
{ VK_CLEAR, CLUTTER_Clear },
|
||||
{ VK_RETURN, CLUTTER_Return },
|
||||
{ VK_MENU, CLUTTER_Menu },
|
||||
{ VK_PAUSE, CLUTTER_Pause },
|
||||
{ VK_HANGUL, CLUTTER_Hangul },
|
||||
{ VK_KANJI, CLUTTER_Kanji },
|
||||
{ VK_ESCAPE, CLUTTER_Escape },
|
||||
{ VK_SPACE, CLUTTER_space },
|
||||
{ VK_PRIOR, CLUTTER_Prior },
|
||||
{ VK_NEXT, CLUTTER_Next },
|
||||
{ VK_END, CLUTTER_End },
|
||||
{ VK_HOME, CLUTTER_Home },
|
||||
{ VK_LEFT, CLUTTER_Left },
|
||||
{ VK_UP, CLUTTER_Up },
|
||||
{ VK_RIGHT, CLUTTER_Right },
|
||||
{ VK_DOWN, CLUTTER_Down },
|
||||
{ VK_SELECT, CLUTTER_Select },
|
||||
{ VK_PRINT, CLUTTER_Print },
|
||||
{ VK_EXECUTE, CLUTTER_Execute },
|
||||
{ VK_INSERT, CLUTTER_Insert },
|
||||
{ VK_DELETE, CLUTTER_Delete },
|
||||
{ VK_HELP, CLUTTER_Help },
|
||||
{ VK_MULTIPLY, CLUTTER_multiply },
|
||||
{ VK_F1, CLUTTER_F1 },
|
||||
{ VK_F2, CLUTTER_F2 },
|
||||
{ VK_F3, CLUTTER_F3 },
|
||||
{ VK_F4, CLUTTER_F4 },
|
||||
{ VK_F5, CLUTTER_F5 },
|
||||
{ VK_F6, CLUTTER_F6 },
|
||||
{ VK_F7, CLUTTER_F7 },
|
||||
{ VK_F8, CLUTTER_F8 },
|
||||
{ VK_F9, CLUTTER_F9 },
|
||||
{ VK_F10, CLUTTER_F10 },
|
||||
{ VK_F11, CLUTTER_F11 },
|
||||
{ VK_F12, CLUTTER_F12 },
|
||||
{ VK_F13, CLUTTER_F13 },
|
||||
{ VK_F14, CLUTTER_F14 },
|
||||
{ VK_F15, CLUTTER_F15 },
|
||||
{ VK_F16, CLUTTER_F16 },
|
||||
{ VK_F17, CLUTTER_F17 },
|
||||
{ VK_F18, CLUTTER_F18 },
|
||||
{ VK_F19, CLUTTER_F19 },
|
||||
{ VK_F20, CLUTTER_F20 },
|
||||
{ VK_F21, CLUTTER_F21 },
|
||||
{ VK_F22, CLUTTER_F22 },
|
||||
{ VK_F23, CLUTTER_F23 },
|
||||
{ VK_F24, CLUTTER_F24 },
|
||||
{ VK_LSHIFT, CLUTTER_Shift_L },
|
||||
{ VK_RSHIFT, CLUTTER_Shift_R },
|
||||
{ VK_LCONTROL, CLUTTER_Control_L },
|
||||
{ VK_RCONTROL, CLUTTER_Control_R }
|
||||
};
|
||||
#define CLUTTER_WIN32_KEY_MAP_SIZE (sizeof (clutter_win32_key_map) \
|
||||
/ sizeof (clutter_win32_key_map[0]))
|
||||
|
||||
static GSource *
|
||||
clutter_event_source_new (ClutterBackend *backend)
|
||||
{
|
||||
GSource *source = g_source_new (&event_funcs, sizeof (ClutterEventSource));
|
||||
ClutterEventSource *event_source = (ClutterEventSource *) source;
|
||||
|
||||
event_source->backend = backend;
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_backend_win32_events_init (ClutterBackend *backend)
|
||||
{
|
||||
ClutterBackendWin32 *backend_win32 = CLUTTER_BACKEND_WIN32 (backend);
|
||||
GSource *source;
|
||||
ClutterEventSource *event_source;
|
||||
|
||||
source = backend_win32->event_source = clutter_event_source_new (backend);
|
||||
event_source = (ClutterEventSource *) source;
|
||||
g_source_set_priority (source, CLUTTER_PRIORITY_EVENTS);
|
||||
|
||||
event_source->event_poll_fd.fd = G_WIN32_MSG_HANDLE;
|
||||
event_source->event_poll_fd.events = G_IO_IN;
|
||||
|
||||
g_source_add_poll (source, &event_source->event_poll_fd);
|
||||
g_source_set_can_recurse (source, TRUE);
|
||||
g_source_attach (source, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_backend_win32_events_uninit (ClutterBackend *backend)
|
||||
{
|
||||
ClutterBackendWin32 *backend_win32 = CLUTTER_BACKEND_WIN32 (backend);
|
||||
|
||||
if (backend_win32->event_source)
|
||||
{
|
||||
CLUTTER_NOTE (EVENT, "Destroying the event source");
|
||||
|
||||
g_source_destroy (backend_win32->event_source);
|
||||
g_source_unref (backend_win32->event_source);
|
||||
backend_win32->event_source = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
check_msg_pending ()
|
||||
{
|
||||
MSG msg;
|
||||
|
||||
return PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
static ClutterModifierType
|
||||
get_modifier_state (WPARAM wparam)
|
||||
{
|
||||
ClutterModifierType ret = 0;
|
||||
|
||||
if ((wparam & MK_SHIFT))
|
||||
ret |= CLUTTER_SHIFT_MASK;
|
||||
if ((wparam & MK_CONTROL))
|
||||
ret |= CLUTTER_CONTROL_MASK;
|
||||
if ((wparam & MK_LBUTTON))
|
||||
ret |= CLUTTER_BUTTON1_MASK;
|
||||
if ((wparam & MK_MBUTTON))
|
||||
ret |= CLUTTER_BUTTON2_MASK;
|
||||
if ((wparam & MK_RBUTTON))
|
||||
ret |= CLUTTER_BUTTON3_MASK;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
make_button_event (const MSG *msg, ClutterEvent *event,
|
||||
int button, int click_count, gboolean release)
|
||||
{
|
||||
event->type = release ? CLUTTER_BUTTON_RELEASE : CLUTTER_BUTTON_PRESS;
|
||||
event->button.time = msg->time;
|
||||
event->button.x = GET_X_LPARAM (msg->lParam);
|
||||
event->button.y = GET_Y_LPARAM (msg->lParam);
|
||||
event->button.modifier_state = get_modifier_state (msg->wParam);
|
||||
event->button.button = button;
|
||||
event->button.click_count = click_count;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clutter_event_prepare (GSource *source,
|
||||
gint *timeout)
|
||||
{
|
||||
gboolean retval;
|
||||
|
||||
clutter_threads_enter ();
|
||||
|
||||
*timeout = -1;
|
||||
retval = (clutter_events_pending () || check_msg_pending ());
|
||||
|
||||
clutter_threads_leave ();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clutter_event_check (GSource *source)
|
||||
{
|
||||
ClutterEventSource *event_source = (ClutterEventSource *) source;
|
||||
ClutterBackend *backend = event_source->backend;
|
||||
gboolean retval;
|
||||
|
||||
clutter_threads_enter ();
|
||||
|
||||
if ((event_source->event_poll_fd.revents & G_IO_IN))
|
||||
retval = (clutter_events_pending () || check_msg_pending (backend));
|
||||
else
|
||||
retval = FALSE;
|
||||
|
||||
clutter_threads_leave ();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clutter_event_dispatch (GSource *source,
|
||||
GSourceFunc callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
ClutterEvent *event;
|
||||
MSG msg;
|
||||
|
||||
clutter_threads_enter ();
|
||||
|
||||
/* Process Windows messages until we've got one that translates into
|
||||
the clutter event queue */
|
||||
while (!clutter_events_pending () && PeekMessageW (&msg, NULL,
|
||||
0, 0, PM_REMOVE))
|
||||
DispatchMessageW (&msg);
|
||||
|
||||
/* Pop an event off the queue if any */
|
||||
if ((event = clutter_event_get ()))
|
||||
{
|
||||
/* forward the event into clutter for emission etc. */
|
||||
clutter_do_event (event);
|
||||
clutter_event_free (event);
|
||||
}
|
||||
|
||||
clutter_threads_leave ();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static ClutterModifierType
|
||||
get_key_modifier_state (const BYTE *key_states)
|
||||
{
|
||||
ClutterModifierType ret = 0;
|
||||
|
||||
if ((key_states[VK_SHIFT] & 0x80)
|
||||
|| (key_states[VK_LSHIFT] & 0x80)
|
||||
|| (key_states[VK_RSHIFT] & 0x80))
|
||||
ret |= CLUTTER_SHIFT_MASK;
|
||||
if ((key_states[VK_CONTROL] & 0x80)
|
||||
|| (key_states[VK_LCONTROL] & 0x80)
|
||||
|| (key_states[VK_RCONTROL] & 0x80))
|
||||
ret |= CLUTTER_CONTROL_MASK;
|
||||
if ((key_states[VK_MENU] & 0x80)
|
||||
|| (key_states[VK_LMENU] & 0x80)
|
||||
|| (key_states[VK_RMENU] & 0x80))
|
||||
ret |= CLUTTER_MOD1_MASK;
|
||||
if (key_states[VK_CAPITAL])
|
||||
ret |= CLUTTER_LOCK_MASK;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
message_translate (ClutterBackend *backend,
|
||||
ClutterEvent *event,
|
||||
const MSG *msg)
|
||||
{
|
||||
ClutterBackendWin32 *backend_win32;
|
||||
ClutterStageWin32 *stage_win32;
|
||||
ClutterStage *stage;
|
||||
gboolean res;
|
||||
HWND stage_hwnd;
|
||||
|
||||
backend_win32 = CLUTTER_BACKEND_WIN32 (backend);
|
||||
stage = CLUTTER_STAGE (_clutter_backend_get_stage (backend));
|
||||
stage_win32 = CLUTTER_STAGE_WIN32 (stage);
|
||||
stage_hwnd = clutter_win32_get_stage_window (stage);
|
||||
|
||||
/* Do further processing only on events for the stage window */
|
||||
if (stage_hwnd != msg->hwnd)
|
||||
return FALSE;
|
||||
|
||||
res = TRUE;
|
||||
|
||||
switch (msg->message)
|
||||
{
|
||||
case WM_SIZE:
|
||||
{
|
||||
WORD new_width = LOWORD (msg->lParam);
|
||||
WORD new_height = HIWORD (msg->lParam);
|
||||
guint old_width, old_height;
|
||||
|
||||
clutter_actor_get_size (CLUTTER_ACTOR (stage),
|
||||
&old_width, &old_height);
|
||||
|
||||
if (new_width != old_width || new_height != old_height)
|
||||
clutter_actor_set_size (CLUTTER_ACTOR (stage),
|
||||
new_width, new_height);
|
||||
}
|
||||
res = FALSE;
|
||||
break;
|
||||
|
||||
case WM_MOVE:
|
||||
{
|
||||
WORD new_xpos = GET_X_LPARAM (msg->lParam);
|
||||
WORD new_ypos = GET_Y_LPARAM (msg->lParam);
|
||||
guint old_xpos, old_ypos;
|
||||
|
||||
clutter_actor_get_position (CLUTTER_ACTOR (stage),
|
||||
&old_xpos, &old_ypos);
|
||||
|
||||
if (new_xpos != old_xpos || new_ypos != old_ypos)
|
||||
clutter_actor_set_position (CLUTTER_ACTOR (stage),
|
||||
new_xpos, new_ypos);
|
||||
}
|
||||
res = FALSE;
|
||||
break;
|
||||
|
||||
case WM_SHOWWINDOW:
|
||||
if (msg->wParam)
|
||||
clutter_stage_win32_map (stage_win32);
|
||||
else
|
||||
clutter_stage_win32_unmap (stage_win32);
|
||||
res = FALSE;
|
||||
break;
|
||||
|
||||
case WM_ACTIVATE:
|
||||
if (msg->wParam == WA_INACTIVE)
|
||||
{
|
||||
if (stage_win32->state & CLUTTER_STAGE_STATE_ACTIVATED)
|
||||
{
|
||||
stage_win32->state &= ~CLUTTER_STAGE_STATE_ACTIVATED;
|
||||
|
||||
event->type = CLUTTER_STAGE_STATE;
|
||||
event->stage_state.changed_mask = CLUTTER_STAGE_STATE_ACTIVATED;
|
||||
event->stage_state.new_state = stage_win32->state;
|
||||
}
|
||||
else
|
||||
res = FALSE;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(stage_win32->state & CLUTTER_STAGE_STATE_ACTIVATED))
|
||||
{
|
||||
stage_win32->state |= CLUTTER_STAGE_STATE_ACTIVATED;
|
||||
|
||||
event->type = CLUTTER_STAGE_STATE;
|
||||
event->stage_state.changed_mask = CLUTTER_STAGE_STATE_ACTIVATED;
|
||||
event->stage_state.new_state = stage_win32->state;
|
||||
}
|
||||
else
|
||||
res = FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_PAINT:
|
||||
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage_win32));
|
||||
res = FALSE;
|
||||
break;
|
||||
|
||||
case WM_DESTROY:
|
||||
CLUTTER_NOTE (EVENT, "WM_DESTROY");
|
||||
event->type = CLUTTER_DESTROY_NOTIFY;
|
||||
break;
|
||||
|
||||
case WM_LBUTTONDOWN:
|
||||
make_button_event (msg, event, 1, 1, FALSE);
|
||||
break;
|
||||
|
||||
case WM_MBUTTONDOWN:
|
||||
make_button_event (msg, event, 2, 1, FALSE);
|
||||
break;
|
||||
|
||||
case WM_RBUTTONDOWN:
|
||||
make_button_event (msg, event, 3, 1, FALSE);
|
||||
break;
|
||||
|
||||
case WM_LBUTTONUP:
|
||||
make_button_event (msg, event, 1, 1, TRUE);
|
||||
break;
|
||||
|
||||
case WM_MBUTTONUP:
|
||||
make_button_event (msg, event, 2, 1, TRUE);
|
||||
break;
|
||||
|
||||
case WM_RBUTTONUP:
|
||||
make_button_event (msg, event, 3, 1, TRUE);
|
||||
break;
|
||||
|
||||
case WM_LBUTTONDBLCLK:
|
||||
make_button_event (msg, event, 1, 2, FALSE);
|
||||
break;
|
||||
|
||||
case WM_MBUTTONDBLCLK:
|
||||
make_button_event (msg, event, 2, 2, FALSE);
|
||||
break;
|
||||
|
||||
case WM_RBUTTONDBLCLK:
|
||||
make_button_event (msg, event, 3, 2, FALSE);
|
||||
break;
|
||||
|
||||
case WM_MOUSEWHEEL:
|
||||
stage_win32->scroll_pos += (SHORT) HIWORD (msg->wParam);
|
||||
|
||||
event->type = CLUTTER_SCROLL;
|
||||
event->scroll.time = msg->time;
|
||||
event->scroll.x = GET_X_LPARAM (msg->lParam);
|
||||
event->scroll.y = GET_Y_LPARAM (msg->lParam);
|
||||
event->scroll.modifier_state
|
||||
= get_modifier_state (LOWORD (msg->wParam));
|
||||
|
||||
if (stage_win32->scroll_pos >= WHEEL_DELTA)
|
||||
{
|
||||
event->scroll.direction = CLUTTER_SCROLL_UP;
|
||||
stage_win32->scroll_pos -= WHEEL_DELTA;
|
||||
}
|
||||
else if (stage_win32->scroll_pos <= -WHEEL_DELTA)
|
||||
{
|
||||
event->scroll.direction = CLUTTER_SCROLL_DOWN;
|
||||
stage_win32->scroll_pos += WHEEL_DELTA;
|
||||
}
|
||||
else
|
||||
res = FALSE;
|
||||
break;
|
||||
|
||||
case WM_MOUSEMOVE:
|
||||
event->type = CLUTTER_MOTION;
|
||||
event->motion.time = msg->time;
|
||||
event->motion.x = GET_X_LPARAM (msg->lParam);
|
||||
event->motion.y = GET_Y_LPARAM (msg->lParam);
|
||||
event->motion.modifier_state = get_modifier_state (msg->wParam);
|
||||
break;
|
||||
|
||||
case WM_KEYDOWN:
|
||||
case WM_KEYUP:
|
||||
case WM_SYSKEYDOWN:
|
||||
case WM_SYSKEYUP:
|
||||
{
|
||||
int scan_code = (msg->lParam >> 16) & 0xff;
|
||||
int min = 0, max = CLUTTER_WIN32_KEY_MAP_SIZE, mid;
|
||||
BYTE key_states[256];
|
||||
|
||||
/* Get the keyboard modifier states. GetKeyboardState
|
||||
conveniently gets the key state that was current when the
|
||||
last keyboard message read was generated */
|
||||
GetKeyboardState(key_states);
|
||||
|
||||
/* Binary chop to check if we have a direct mapping for this
|
||||
key code */
|
||||
while (min < max)
|
||||
{
|
||||
mid = (min + max) / 2;
|
||||
if (clutter_win32_key_map[mid].win_sym == msg->wParam)
|
||||
{
|
||||
event->key.keyval = clutter_win32_key_map[mid].clutter_sym;
|
||||
event->key.unicode_value = 0;
|
||||
break;
|
||||
}
|
||||
else if (clutter_win32_key_map[mid].win_sym < msg->wParam)
|
||||
min = mid + 1;
|
||||
else
|
||||
max = mid;
|
||||
}
|
||||
|
||||
/* If we don't have a direct mapping then try getting the
|
||||
unicode value of the key sym */
|
||||
if (min >= max)
|
||||
{
|
||||
WCHAR ch;
|
||||
BYTE shift_state[256];
|
||||
|
||||
/* Translate to a Unicode value, but only take into
|
||||
account the shift key. That way Ctrl+Shift+C will
|
||||
generate a capital C virtual key code with a zero
|
||||
unicode value for example */
|
||||
memset (shift_state, 0, 256);
|
||||
shift_state[VK_SHIFT] = key_states[VK_SHIFT];
|
||||
shift_state[VK_LSHIFT] = key_states[VK_LSHIFT];
|
||||
shift_state[VK_RSHIFT] = key_states[VK_RSHIFT];
|
||||
shift_state[VK_CAPITAL] = key_states[VK_CAPITAL];
|
||||
|
||||
if (ToUnicode (msg->wParam, scan_code,
|
||||
shift_state, &ch, 1, 0) == 1
|
||||
/* The codes in this range directly match the Latin 1
|
||||
codes so we can just use the Unicode value as the
|
||||
key sym */
|
||||
&& ch >= 0x20 && ch <= 0xff)
|
||||
event->key.keyval = ch;
|
||||
else
|
||||
/* Otherwise we don't know what the key means but the
|
||||
application might be able to do something with the
|
||||
scan code so we might as well still generate the
|
||||
event */
|
||||
event->key.keyval = CLUTTER_VoidSymbol;
|
||||
|
||||
/* Get the unicode value of the keypress again using the
|
||||
full modifier state */
|
||||
if (ToUnicode (msg->wParam, scan_code,
|
||||
key_states, &ch, 1, 0) == 1)
|
||||
event->key.unicode_value = ch;
|
||||
else
|
||||
event->key.unicode_value = 0;
|
||||
}
|
||||
|
||||
event->key.type = msg->message == WM_KEYDOWN
|
||||
|| msg->message == WM_SYSKEYDOWN
|
||||
? CLUTTER_KEY_PRESS : CLUTTER_KEY_RELEASE;
|
||||
event->key.time = msg->time;
|
||||
event->key.modifier_state = get_key_modifier_state (key_states);
|
||||
event->key.hardware_keycode = scan_code;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* ignore every other message */
|
||||
res = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
LRESULT CALLBACK
|
||||
_clutter_stage_win32_window_proc (HWND hwnd, UINT umsg,
|
||||
WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
ClutterStageWin32 *stage_win32
|
||||
= (ClutterStageWin32 *) GetWindowLongPtrW (hwnd, 0);
|
||||
|
||||
/* Ignore any messages before SetWindowLongPtr has been called to
|
||||
set the stage */
|
||||
if (stage_win32 != NULL)
|
||||
{
|
||||
ClutterBackendWin32 *backend_win32 = stage_win32->backend;
|
||||
MSG msg;
|
||||
ClutterEvent *event;
|
||||
ClutterMainContext *clutter_context;
|
||||
DWORD message_pos = GetMessagePos ();
|
||||
|
||||
clutter_context = clutter_context_get_default ();
|
||||
|
||||
msg.hwnd = hwnd;
|
||||
msg.message = umsg;
|
||||
msg.wParam = wparam;
|
||||
msg.lParam = lparam;
|
||||
msg.time = GetMessageTime ();
|
||||
/* Neither MAKE_POINTS nor GET_[XY]_LPARAM is defined in MinGW
|
||||
headers so we need to convert to a signed type explicitly */
|
||||
msg.pt.x = (SHORT) LOWORD (message_pos);
|
||||
msg.pt.y = (SHORT) HIWORD (message_pos);
|
||||
|
||||
/* Some messages are handled here specially outside of
|
||||
message_translate so that DefWindowProc can be overridden */
|
||||
if (umsg == WM_GETMINMAXINFO)
|
||||
{
|
||||
MINMAXINFO *min_max_info = (MINMAXINFO *) lparam;
|
||||
_clutter_stage_win32_get_min_max_info (stage_win32, min_max_info);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
event = clutter_event_new (CLUTTER_NOTHING);
|
||||
|
||||
if (message_translate (CLUTTER_BACKEND (backend_win32), event, &msg))
|
||||
/* push directly here to avoid copy of queue_put */
|
||||
g_queue_push_head (clutter_context->events_queue, event);
|
||||
else
|
||||
clutter_event_free (event);
|
||||
}
|
||||
}
|
||||
|
||||
return DefWindowProcW (hwnd, umsg, wparam, lparam);
|
||||
}
|
614
clutter/win32/clutter-stage-win32.c
Normal file
614
clutter/win32/clutter-stage-win32.c
Normal file
@ -0,0 +1,614 @@
|
||||
/* 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
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "clutter-backend-win32.h"
|
||||
#include "clutter-stage-win32.h"
|
||||
#include "clutter-win32.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"
|
||||
#include "../clutter-units.h"
|
||||
|
||||
#include "cogl.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
G_DEFINE_TYPE (ClutterStageWin32, clutter_stage_win32, CLUTTER_TYPE_STAGE);
|
||||
|
||||
static void
|
||||
clutter_stage_win32_show (ClutterActor *actor)
|
||||
{
|
||||
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (actor);
|
||||
|
||||
if (stage_win32->hwnd)
|
||||
ShowWindow (stage_win32->hwnd, SW_SHOW);
|
||||
|
||||
/* chain up */
|
||||
CLUTTER_ACTOR_CLASS (clutter_stage_win32_parent_class)->show (actor);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_win32_hide (ClutterActor *actor)
|
||||
{
|
||||
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (actor);
|
||||
|
||||
if (stage_win32->hwnd)
|
||||
ShowWindow (stage_win32->hwnd, SW_HIDE);
|
||||
|
||||
/* chain up */
|
||||
CLUTTER_ACTOR_CLASS (clutter_stage_win32_parent_class)->hide (actor);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_win32_query_coords (ClutterActor *self,
|
||||
ClutterActorBox *box)
|
||||
{
|
||||
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (self);
|
||||
|
||||
/* If we're in fullscreen mode then return the size of the screen
|
||||
instead */
|
||||
if ((stage_win32->state & CLUTTER_STAGE_STATE_FULLSCREEN))
|
||||
{
|
||||
box->x1 = CLUTTER_UNITS_FROM_INT (stage_win32->fullscreen_rect.left);
|
||||
box->y1 = CLUTTER_UNITS_FROM_INT (stage_win32->fullscreen_rect.top);
|
||||
box->x2 = CLUTTER_UNITS_FROM_INT (stage_win32->fullscreen_rect.right);
|
||||
box->y2 = CLUTTER_UNITS_FROM_INT (stage_win32->fullscreen_rect.bottom);
|
||||
}
|
||||
else
|
||||
{
|
||||
box->x1 = CLUTTER_UNITS_FROM_INT (stage_win32->win_xpos);
|
||||
box->y1 = CLUTTER_UNITS_FROM_INT (stage_win32->win_ypos);
|
||||
box->x2 = box->x1 + CLUTTER_UNITS_FROM_INT (stage_win32->win_width);
|
||||
box->y2 = box->y1 + CLUTTER_UNITS_FROM_INT (stage_win32->win_height);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
get_fullscreen_rect (ClutterStageWin32 *stage_win32)
|
||||
{
|
||||
HMONITOR monitor;
|
||||
MONITORINFO monitor_info;
|
||||
|
||||
/* If we already have a window then try to use the same monitor that
|
||||
is already on */
|
||||
if (stage_win32->hwnd)
|
||||
monitor = MonitorFromWindow (stage_win32->hwnd, MONITOR_DEFAULTTONEAREST);
|
||||
else
|
||||
{
|
||||
/* Otherwise just guess that they will want the monitor where
|
||||
the cursor is */
|
||||
POINT cursor;
|
||||
GetCursorPos (&cursor);
|
||||
monitor = MonitorFromPoint (cursor, MONITOR_DEFAULTTONEAREST);
|
||||
}
|
||||
|
||||
monitor_info.cbSize = sizeof (monitor_info);
|
||||
GetMonitorInfoW (monitor, &monitor_info);
|
||||
stage_win32->fullscreen_rect = monitor_info.rcMonitor;
|
||||
}
|
||||
|
||||
static void
|
||||
get_full_window_pos (ClutterStageWin32 *stage_win32,
|
||||
int xpos_in, int ypos_in,
|
||||
int *xpos_out, int *ypos_out)
|
||||
{
|
||||
gboolean resizable
|
||||
= clutter_stage_get_user_resizable (CLUTTER_STAGE (stage_win32));
|
||||
/* The window position passed to CreateWindow includes the window
|
||||
decorations */
|
||||
*xpos_out = xpos_in - GetSystemMetrics (resizable ? SM_CXSIZEFRAME
|
||||
: SM_CXFIXEDFRAME);
|
||||
*ypos_out = ypos_in - GetSystemMetrics (resizable ? SM_CYSIZEFRAME
|
||||
: SM_CYFIXEDFRAME)
|
||||
- GetSystemMetrics (SM_CYCAPTION);
|
||||
}
|
||||
|
||||
static void
|
||||
get_full_window_size (ClutterStageWin32 *stage_win32,
|
||||
int width_in, int height_in,
|
||||
int *width_out, int *height_out)
|
||||
{
|
||||
gboolean resizable
|
||||
= clutter_stage_get_user_resizable (CLUTTER_STAGE (stage_win32));
|
||||
/* The window size passed to CreateWindow includes the window
|
||||
decorations */
|
||||
*width_out = width_in + GetSystemMetrics (resizable ? SM_CXSIZEFRAME
|
||||
: SM_CXFIXEDFRAME) * 2;
|
||||
*height_out = height_in + GetSystemMetrics (resizable ? SM_CYSIZEFRAME
|
||||
: SM_CYFIXEDFRAME) * 2
|
||||
+ GetSystemMetrics (SM_CYCAPTION);
|
||||
}
|
||||
|
||||
void
|
||||
_clutter_stage_win32_get_min_max_info (ClutterStageWin32 *stage_win32,
|
||||
MINMAXINFO *min_max_info)
|
||||
{
|
||||
/* If the window isn't resizable then set the max and min size to
|
||||
the current size */
|
||||
if (!clutter_stage_get_user_resizable (CLUTTER_STAGE (stage_win32)))
|
||||
{
|
||||
int full_width, full_height;
|
||||
get_full_window_size (stage_win32,
|
||||
stage_win32->win_width, stage_win32->win_height,
|
||||
&full_width, &full_height);
|
||||
min_max_info->ptMaxTrackSize.x = full_width;
|
||||
min_max_info->ptMinTrackSize.x = full_width;
|
||||
min_max_info->ptMaxTrackSize.y = full_height;
|
||||
min_max_info->ptMinTrackSize.y = full_height;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_win32_request_coords (ClutterActor *self,
|
||||
ClutterActorBox *box)
|
||||
{
|
||||
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (self);
|
||||
|
||||
gint new_xpos, new_ypos, new_width, new_height;
|
||||
|
||||
new_xpos = CLUTTER_UNITS_TO_INT (MIN (box->x1, box->x2));
|
||||
new_ypos = CLUTTER_UNITS_TO_INT (MIN (box->y1, box->y2));
|
||||
new_width = ABS (CLUTTER_UNITS_TO_INT (box->x2 - box->x1));
|
||||
new_height = ABS (CLUTTER_UNITS_TO_INT (box->y2 - box->y1));
|
||||
|
||||
if ((new_width != stage_win32->win_width
|
||||
|| new_height != stage_win32->win_height
|
||||
|| new_xpos != stage_win32->win_xpos
|
||||
|| new_ypos != stage_win32->win_ypos)
|
||||
/* Ignore size requests if we are in full screen mode */
|
||||
&& (stage_win32->state & CLUTTER_STAGE_STATE_FULLSCREEN) == 0)
|
||||
{
|
||||
stage_win32->win_xpos = new_xpos;
|
||||
stage_win32->win_ypos = new_ypos;
|
||||
stage_win32->win_width = new_width;
|
||||
stage_win32->win_height = new_height;
|
||||
|
||||
if (stage_win32->hwnd != NULL)
|
||||
{
|
||||
int full_xpos, full_ypos, full_width, full_height;
|
||||
|
||||
get_full_window_pos (stage_win32,
|
||||
new_xpos, new_ypos,
|
||||
&full_xpos, &full_ypos);
|
||||
get_full_window_size (stage_win32,
|
||||
new_width, new_height,
|
||||
&full_width, &full_height);
|
||||
|
||||
SetWindowPos (stage_win32->hwnd, NULL,
|
||||
full_xpos, full_ypos,
|
||||
full_width, full_height,
|
||||
SWP_NOZORDER);
|
||||
}
|
||||
|
||||
CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_ACTOR_SYNC_MATRICES);
|
||||
}
|
||||
|
||||
CLUTTER_ACTOR_CLASS (clutter_stage_win32_parent_class)
|
||||
->request_coords (self, box);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_win32_set_title (ClutterStage *stage,
|
||||
const gchar *title)
|
||||
{
|
||||
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (stage);
|
||||
wchar_t *wtitle;
|
||||
|
||||
/* Empty window titles not allowed, so set it to just a period. */
|
||||
if (title == NULL || !title[0])
|
||||
title = ".";
|
||||
|
||||
wtitle = g_utf8_to_utf16 (title, -1, NULL, NULL, NULL);
|
||||
SetWindowTextW (stage_win32->hwnd, wtitle);
|
||||
g_free (wtitle);
|
||||
}
|
||||
|
||||
static LONG
|
||||
get_window_style (ClutterStageWin32 *stage_win32)
|
||||
{
|
||||
/* Fullscreen mode shouldn't have any borders */
|
||||
if ((stage_win32->state & CLUTTER_STAGE_STATE_FULLSCREEN))
|
||||
return WS_POPUP;
|
||||
/* Otherwise it's an overlapped window but if it isn't resizable
|
||||
then it shouldn't have a thick frame */
|
||||
else if (clutter_stage_get_user_resizable (CLUTTER_STAGE (stage_win32)))
|
||||
return WS_OVERLAPPEDWINDOW;
|
||||
else
|
||||
return WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_win32_set_user_resize (ClutterStage *stage,
|
||||
gboolean value)
|
||||
{
|
||||
HWND hwnd = CLUTTER_STAGE_WIN32 (stage)->hwnd;
|
||||
LONG old_style = GetWindowLongW (hwnd, GWL_STYLE);
|
||||
|
||||
/* Update the window style but preserve the visibility */
|
||||
SetWindowLongW (hwnd, GWL_STYLE,
|
||||
get_window_style (CLUTTER_STAGE_WIN32 (stage))
|
||||
| (old_style & WS_VISIBLE));
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_win32_set_fullscreen (ClutterStage *stage,
|
||||
gboolean value)
|
||||
{
|
||||
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (stage);
|
||||
HWND hwnd = CLUTTER_STAGE_WIN32 (stage)->hwnd;
|
||||
LONG old_style = GetWindowLongW (hwnd, GWL_STYLE);
|
||||
ClutterStageStateEvent event;
|
||||
|
||||
if (value)
|
||||
stage_win32->state |= CLUTTER_STAGE_STATE_FULLSCREEN;
|
||||
else
|
||||
stage_win32->state &= ~CLUTTER_STAGE_STATE_FULLSCREEN;
|
||||
|
||||
if (hwnd)
|
||||
{
|
||||
/* Update the window style but preserve the visibility */
|
||||
SetWindowLongW (hwnd, GWL_STYLE,
|
||||
get_window_style (stage_win32)
|
||||
| (old_style & WS_VISIBLE));
|
||||
/* Update the window size */
|
||||
if (value)
|
||||
{
|
||||
get_fullscreen_rect (stage_win32);
|
||||
SetWindowPos (hwnd, HWND_TOP,
|
||||
stage_win32->fullscreen_rect.left,
|
||||
stage_win32->fullscreen_rect.top,
|
||||
stage_win32->fullscreen_rect.right
|
||||
- stage_win32->fullscreen_rect.left,
|
||||
stage_win32->fullscreen_rect.bottom
|
||||
- stage_win32->fullscreen_rect.top,
|
||||
0);
|
||||
}
|
||||
else
|
||||
{
|
||||
int full_xpos, full_ypos, full_width, full_height;
|
||||
|
||||
get_full_window_pos (stage_win32,
|
||||
stage_win32->win_xpos,
|
||||
stage_win32->win_ypos,
|
||||
&full_xpos, &full_ypos);
|
||||
get_full_window_size (stage_win32,
|
||||
stage_win32->win_width,
|
||||
stage_win32->win_height,
|
||||
&full_width, &full_height);
|
||||
|
||||
SetWindowPos (stage_win32->hwnd, NULL,
|
||||
full_xpos, full_ypos,
|
||||
full_width, full_height,
|
||||
SWP_NOZORDER);
|
||||
}
|
||||
|
||||
CLUTTER_SET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_SYNC_MATRICES);
|
||||
}
|
||||
|
||||
/* Report the state change */
|
||||
memset (&event, 0, sizeof (event));
|
||||
event.type = CLUTTER_STAGE_STATE;
|
||||
event.new_state = stage_win32->state;
|
||||
event.changed_mask = CLUTTER_STAGE_STATE_FULLSCREEN;
|
||||
clutter_event_put ((ClutterEvent *) &event);
|
||||
}
|
||||
|
||||
static ATOM
|
||||
clutter_stage_win32_get_window_class ()
|
||||
{
|
||||
static ATOM klass = 0;
|
||||
|
||||
if (klass == 0)
|
||||
{
|
||||
WNDCLASSW wndclass;
|
||||
memset (&wndclass, 0, sizeof (wndclass));
|
||||
wndclass.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
|
||||
wndclass.lpfnWndProc = _clutter_stage_win32_window_proc;
|
||||
wndclass.cbWndExtra = sizeof (LONG_PTR);
|
||||
wndclass.hInstance = GetModuleHandleW (NULL);
|
||||
wndclass.hIcon = LoadIconW (NULL, (LPWSTR) IDI_APPLICATION);
|
||||
wndclass.hCursor = LoadCursorW (NULL, (LPWSTR) IDC_ARROW);
|
||||
wndclass.hbrBackground = NULL;
|
||||
wndclass.lpszMenuName = NULL;
|
||||
wndclass.lpszClassName = L"ClutterStageWin32";
|
||||
klass = RegisterClassW (&wndclass);
|
||||
}
|
||||
|
||||
return klass;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
clutter_stage_win32_check_gl_version ()
|
||||
{
|
||||
const char *version_string, *major_end, *minor_end;
|
||||
int major = 0, minor = 0;
|
||||
|
||||
/* Get the OpenGL version number */
|
||||
if ((version_string = (const char *) glGetString (GL_VERSION)) == NULL)
|
||||
return FALSE;
|
||||
|
||||
/* Extract the major number */
|
||||
for (major_end = version_string; *major_end >= '0'
|
||||
&& *major_end <= '9'; major_end++)
|
||||
major = (major * 10) + *major_end - '0';
|
||||
/* If there were no digits or the major number isn't followed by a
|
||||
dot then it is invalid */
|
||||
if (major_end == version_string || *major_end != '.')
|
||||
return FALSE;
|
||||
|
||||
/* Extract the minor number */
|
||||
for (minor_end = major_end + 1; *minor_end >= '0'
|
||||
&& *minor_end <= '9'; minor_end++)
|
||||
minor = (minor * 10) + *minor_end - '0';
|
||||
/* If there were no digits or there is an unexpected character then
|
||||
it is invalid */
|
||||
if (minor_end == major_end + 1
|
||||
|| (*minor_end && *minor_end != ' ' && *minor_end != '.'))
|
||||
return FALSE;
|
||||
|
||||
/* Accept OpenGL 1.2 or later */
|
||||
return major > 1 || (major == 1 && minor >= 2);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_win32_realize (ClutterActor *actor)
|
||||
{
|
||||
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (actor);
|
||||
PIXELFORMATDESCRIPTOR pfd;
|
||||
int pf;
|
||||
|
||||
CLUTTER_NOTE (MISC, "Realizing main stage");
|
||||
|
||||
if (stage_win32->hwnd == NULL)
|
||||
{
|
||||
ATOM window_class = clutter_stage_win32_get_window_class ();
|
||||
int win_xpos, win_ypos, win_width, win_height;
|
||||
RECT win_rect;
|
||||
POINT actual_pos;
|
||||
|
||||
if (window_class == 0)
|
||||
{
|
||||
g_critical ("Unable to register window class");
|
||||
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If we're in fullscreen mode then use the fullscreen rect
|
||||
instead */
|
||||
if ((stage_win32->state & CLUTTER_STAGE_STATE_FULLSCREEN))
|
||||
{
|
||||
get_fullscreen_rect (stage_win32);
|
||||
win_xpos = stage_win32->fullscreen_rect.left;
|
||||
win_ypos = stage_win32->fullscreen_rect.top;
|
||||
win_width = stage_win32->fullscreen_rect.right - win_xpos;
|
||||
win_height = stage_win32->fullscreen_rect.left - win_ypos;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (stage_win32->win_xpos == 0 && stage_win32->win_ypos == 0)
|
||||
win_xpos = win_ypos = CW_USEDEFAULT;
|
||||
else
|
||||
get_full_window_pos (stage_win32,
|
||||
stage_win32->win_xpos, stage_win32->win_ypos,
|
||||
&win_xpos, &win_ypos);
|
||||
get_full_window_size (stage_win32,
|
||||
stage_win32->win_width,
|
||||
stage_win32->win_height,
|
||||
&win_width, &win_height);
|
||||
}
|
||||
|
||||
stage_win32->hwnd = CreateWindowW ((LPWSTR) MAKEINTATOM (window_class),
|
||||
L".",
|
||||
get_window_style (stage_win32),
|
||||
win_xpos,
|
||||
win_ypos,
|
||||
win_width,
|
||||
win_height,
|
||||
NULL, NULL,
|
||||
GetModuleHandle (NULL),
|
||||
NULL);
|
||||
|
||||
if (stage_win32->hwnd == NULL)
|
||||
{
|
||||
g_critical ("Unable to create stage window");
|
||||
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the position in case CW_USEDEFAULT was specified */
|
||||
if ((stage_win32->state & CLUTTER_STAGE_STATE_FULLSCREEN) == 0)
|
||||
{
|
||||
GetClientRect (stage_win32->hwnd, &win_rect);
|
||||
actual_pos.x = win_rect.left;
|
||||
actual_pos.y = win_rect.top;
|
||||
ClientToScreen (stage_win32->hwnd, &actual_pos);
|
||||
stage_win32->win_xpos = actual_pos.x;
|
||||
stage_win32->win_ypos = actual_pos.y;
|
||||
}
|
||||
|
||||
/* Store a pointer to the actor in the extra bytes of the window
|
||||
so we can quickly access it in the window procedure */
|
||||
SetWindowLongPtrW (stage_win32->hwnd, 0, (LONG_PTR) stage_win32);
|
||||
}
|
||||
|
||||
if (stage_win32->gl_context)
|
||||
wglDeleteContext (stage_win32->gl_context);
|
||||
|
||||
if (stage_win32->client_dc)
|
||||
ReleaseDC (stage_win32->hwnd, stage_win32->client_dc);
|
||||
|
||||
stage_win32->client_dc = GetDC (stage_win32->hwnd);
|
||||
|
||||
memset (&pfd, 0, sizeof (pfd));
|
||||
pfd.nSize = sizeof (pfd);
|
||||
pfd.nVersion = 1;
|
||||
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
|
||||
pfd.iPixelType = PFD_TYPE_RGBA;
|
||||
pfd.cColorBits = 24;
|
||||
pfd.cAlphaBits = 8;
|
||||
pfd.cDepthBits = 32;
|
||||
pfd.cStencilBits = 8;
|
||||
pfd.iLayerType = PFD_MAIN_PLANE;
|
||||
|
||||
if ((pf = ChoosePixelFormat (stage_win32->client_dc, &pfd)) == 0
|
||||
|| !SetPixelFormat (stage_win32->client_dc, pf, &pfd))
|
||||
{
|
||||
g_critical ("Unable to find suitable GL pixel format");
|
||||
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
|
||||
return;
|
||||
}
|
||||
|
||||
stage_win32->gl_context = wglCreateContext (stage_win32->client_dc);
|
||||
|
||||
if (stage_win32->gl_context == NULL)
|
||||
{
|
||||
g_critical ("Unable to create suitable GL context");
|
||||
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
|
||||
return;
|
||||
}
|
||||
|
||||
CLUTTER_NOTE (GL, "wglMakeCurrent");
|
||||
wglMakeCurrent (stage_win32->client_dc, stage_win32->gl_context);
|
||||
|
||||
if (!clutter_stage_win32_check_gl_version ())
|
||||
{
|
||||
g_critical ("OpenGL version number is too low");
|
||||
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Make sure the viewport gets set up correctly */
|
||||
CLUTTER_SET_PRIVATE_FLAGS (actor, CLUTTER_ACTOR_SYNC_MATRICES);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_win32_unrealize (ClutterActor *actor)
|
||||
{
|
||||
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (actor);
|
||||
|
||||
wglMakeCurrent (NULL, NULL);
|
||||
|
||||
if (stage_win32->gl_context != NULL)
|
||||
{
|
||||
wglDeleteContext (stage_win32->gl_context);
|
||||
stage_win32->gl_context = NULL;
|
||||
}
|
||||
|
||||
if (stage_win32->client_dc)
|
||||
{
|
||||
ReleaseDC (stage_win32->hwnd, stage_win32->client_dc);
|
||||
stage_win32->client_dc = NULL;
|
||||
}
|
||||
|
||||
if (stage_win32->hwnd)
|
||||
{
|
||||
DestroyWindow (stage_win32->hwnd);
|
||||
stage_win32->hwnd = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_win32_dispose (GObject *gobject)
|
||||
{
|
||||
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (gobject);
|
||||
|
||||
if (stage_win32->hwnd)
|
||||
clutter_actor_unrealize (CLUTTER_ACTOR (gobject));
|
||||
|
||||
G_OBJECT_CLASS (clutter_stage_win32_parent_class)->dispose (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_win32_class_init (ClutterStageWin32Class *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
|
||||
ClutterStageClass *stage_class = CLUTTER_STAGE_CLASS (klass);
|
||||
|
||||
gobject_class->dispose = clutter_stage_win32_dispose;
|
||||
|
||||
actor_class->show = clutter_stage_win32_show;
|
||||
actor_class->hide = clutter_stage_win32_hide;
|
||||
actor_class->request_coords = clutter_stage_win32_request_coords;
|
||||
actor_class->query_coords = clutter_stage_win32_query_coords;
|
||||
actor_class->realize = clutter_stage_win32_realize;
|
||||
actor_class->unrealize = clutter_stage_win32_unrealize;
|
||||
|
||||
stage_class->set_title = clutter_stage_win32_set_title;
|
||||
stage_class->set_user_resize = clutter_stage_win32_set_user_resize;
|
||||
stage_class->set_fullscreen = clutter_stage_win32_set_fullscreen;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_stage_win32_init (ClutterStageWin32 *stage)
|
||||
{
|
||||
stage->hwnd = NULL;
|
||||
stage->client_dc = NULL;
|
||||
stage->gl_context = NULL;
|
||||
stage->win_xpos = 0;
|
||||
stage->win_ypos = 0;
|
||||
stage->win_width = 640;
|
||||
stage->win_height = 480;
|
||||
stage->backend = NULL;
|
||||
stage->scroll_pos = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* clutter_win32_get_stage_window:
|
||||
* @stage: a #ClutterStage
|
||||
*
|
||||
* Gets the stages window handle
|
||||
*
|
||||
* Return value: An HWND for the stage window.
|
||||
*
|
||||
* Since: 0.8
|
||||
*/
|
||||
HWND
|
||||
clutter_win32_get_stage_window (ClutterStage *stage)
|
||||
{
|
||||
g_return_val_if_fail (CLUTTER_IS_STAGE_WIN32 (stage), NULL);
|
||||
|
||||
return CLUTTER_STAGE_WIN32 (stage)->hwnd;
|
||||
}
|
||||
|
||||
void
|
||||
clutter_stage_win32_map (ClutterStageWin32 *stage_win32)
|
||||
{
|
||||
CLUTTER_ACTOR_SET_FLAGS (stage_win32, CLUTTER_ACTOR_MAPPED);
|
||||
|
||||
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage_win32));
|
||||
}
|
||||
|
||||
void
|
||||
clutter_stage_win32_unmap (ClutterStageWin32 *stage_win32)
|
||||
{
|
||||
CLUTTER_ACTOR_UNSET_FLAGS (stage_win32, CLUTTER_ACTOR_MAPPED);
|
||||
}
|
84
clutter/win32/clutter-stage-win32.h
Normal file
84
clutter/win32/clutter-stage-win32.h
Normal file
@ -0,0 +1,84 @@
|
||||
/* 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
|
||||
* 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 __CLUTTER_STAGE_WIN32_H__
|
||||
#define __CLUTTER_STAGE_WIN32_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <clutter/clutter-stage.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include "clutter-backend-win32.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define CLUTTER_TYPE_STAGE_WIN32 (clutter_stage_win32_get_type ())
|
||||
#define CLUTTER_STAGE_WIN32(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_STAGE_WIN32, ClutterStageWin32))
|
||||
#define CLUTTER_IS_STAGE_WIN32(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_STAGE_WIN32))
|
||||
#define CLUTTER_STAGE_WIN32_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_STAGE_WIN32, ClutterStageWin32Class))
|
||||
#define CLUTTER_IS_STAGE_WIN32_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_STAGE_WIN32))
|
||||
#define CLUTTER_STAGE_WIN32_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_STAGE_WIN32, ClutterStageWin32Class))
|
||||
|
||||
typedef struct _ClutterStageWin32 ClutterStageWin32;
|
||||
typedef struct _ClutterStageWin32Class ClutterStageWin32Class;
|
||||
|
||||
struct _ClutterStageWin32
|
||||
{
|
||||
ClutterStage parent_instance;
|
||||
|
||||
HWND hwnd;
|
||||
HDC client_dc;
|
||||
HGLRC gl_context;
|
||||
gint win_xpos;
|
||||
gint win_ypos;
|
||||
gint win_width;
|
||||
gint win_height;
|
||||
gint scroll_pos;
|
||||
RECT fullscreen_rect;
|
||||
|
||||
ClutterBackendWin32 *backend;
|
||||
ClutterStageState state;
|
||||
};
|
||||
|
||||
struct _ClutterStageWin32Class
|
||||
{
|
||||
ClutterStageClass parent_class;
|
||||
};
|
||||
|
||||
GType clutter_stage_win32_get_type (void) G_GNUC_CONST;
|
||||
|
||||
HWND clutter_win32_get_stage_window (ClutterStage *stage);
|
||||
|
||||
void clutter_stage_win32_map (ClutterStageWin32 *stage_win32);
|
||||
void clutter_stage_win32_unmap (ClutterStageWin32 *stage_win32);
|
||||
|
||||
/* Defined in clutter-event-win32.c */
|
||||
LRESULT CALLBACK _clutter_stage_win32_window_proc (HWND hwnd,
|
||||
UINT msg,
|
||||
WPARAM wparam,
|
||||
LPARAM lparam);
|
||||
|
||||
void _clutter_stage_win32_get_min_max_info (ClutterStageWin32 *stage_win32,
|
||||
MINMAXINFO *min_max_info);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __CLUTTER_STAGE_H__ */
|
39
clutter/win32/clutter-win32.h
Normal file
39
clutter/win32/clutter-win32.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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 __CLUTTER_WIN32_H__
|
||||
#define __CLUTTER_WIN32_H__
|
||||
|
||||
#include <glib.h>
|
||||
#include <clutter/clutter-stage.h>
|
||||
#include <windows.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
HWND clutter_win32_get_stage_window (ClutterStage *stage);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __CLUTTER_WIN32_H__ */
|
14
clutter/win32/clutter-win32.pc.in
Normal file
14
clutter/win32/clutter-win32.pc.in
Normal file
@ -0,0 +1,14 @@
|
||||
prefix=@prefix@
|
||||
exec_prefix=${prefix}
|
||||
libdir=${exec_prefix}/lib
|
||||
includedir=${prefix}/include
|
||||
backend=@clutterbackend@
|
||||
apiversion=@CLUTTER_API_VERSION@
|
||||
requires=@CLUTTER_REQUIRES@
|
||||
|
||||
Name: Clutter
|
||||
Description: Clutter Core Library (${backend} backend)
|
||||
Version: @VERSION@
|
||||
Libs: -L${libdir} -lclutter-${backend}-${apiversion}
|
||||
Cflags: -I${includedir}/clutter-${apiversion}
|
||||
Requires: ${requires}
|
31
configure.ac
31
configure.ac
@ -273,7 +273,30 @@ case $clutterbackend in
|
||||
[AC_MSG_ERROR([Unable to locate required GL headers])])
|
||||
;;
|
||||
|
||||
*) AC_MSG_ERROR([Invalid backend for Clutter: use glx,sdl,osx,eglx or eglnative])
|
||||
win32)
|
||||
|
||||
clutter_gl_header="GL/gl.h"
|
||||
CLUTTER_FLAVOUR="win32"
|
||||
AC_DEFINE([HAVE_CLUTTER_WIN32], 1, [Have the Win32 backend])
|
||||
|
||||
CLUTTER_COGL="gl"
|
||||
AC_DEFINE([HAVE_COGL_GL], 1, [Have GL for rendering])
|
||||
|
||||
AC_CHECK_HEADERS([$clutter_gl_header],,
|
||||
[AC_MSG_ERROR([Unable to locate required GL headers])])
|
||||
|
||||
dnl Use GLee under Windows instead of GL
|
||||
AC_CHECK_LIB(GLee, GLeeInit, HAVE_LIBGLEE=yes, HAVE_LIBGLEE=no, -lopengl32)
|
||||
if test "x$HAVE_LIBGLEE" = "xno"; then
|
||||
AC_MSG_ERROR([libGLee not found]);
|
||||
fi
|
||||
|
||||
WIN32_CFLAGS="-D_WIN32_WINNT=0x0500"
|
||||
WIN32_LIBS="-lGLee -lopengl32 -lgdi32"
|
||||
CLUTTER_LT_LDFLAGS="$CLUTTER_LT_LDFLAGS -no-undefined"
|
||||
;;
|
||||
|
||||
*) AC_MSG_ERROR([Invalid backend for Clutter: use glx,sdl,osx,win32,eglx or eglnative])
|
||||
;;
|
||||
|
||||
esac
|
||||
@ -380,8 +403,8 @@ dnl ========================================================================
|
||||
|
||||
AC_SUBST(GCC_FLAGS)
|
||||
|
||||
CLUTTER_CFLAGS="$SDL_CFLAGS $EGL_CFLAGS $GLX_CFLAGS $OSX_CFLAGS $CLUTTER_DEPS_CFLAGS "
|
||||
CLUTTER_LIBS="$SDL_LIBS $EGL_LIBS $GLX_LIBS $OSX_LIBS $CLUTTER_DEPS_LIBS"
|
||||
CLUTTER_CFLAGS="$SDL_CFLAGS $EGL_CFLAGS $GLX_CFLAGS $OSX_CFLAGS $WIN32_CFLAGS $CLUTTER_DEPS_CFLAGS "
|
||||
CLUTTER_LIBS="$SDL_LIBS $EGL_LIBS $GLX_LIBS $OSX_LIBS $WIN32_LIBS $CLUTTER_DEPS_LIBS"
|
||||
|
||||
AC_SUBST(CLUTTER_CFLAGS)
|
||||
AC_SUBST(CLUTTER_LIBS)
|
||||
@ -396,6 +419,8 @@ AC_CONFIG_FILES([
|
||||
clutter/eglx/Makefile
|
||||
clutter/eglnative/Makefile
|
||||
clutter/osx/Makefile
|
||||
clutter/win32/Makefile
|
||||
clutter/win32/clutter-win32.pc
|
||||
clutter/sdl/Makefile
|
||||
clutter/cogl/Makefile
|
||||
clutter/cogl/gl/Makefile
|
||||
|
Loading…
Reference in New Issue
Block a user