2008-03-25 11:42:50 -04:00
|
|
|
/* Clutter.
|
|
|
|
* An OpenGL based 'interactive canvas' library.
|
|
|
|
* Authored By Matthew Allum <mallum@openedhand.com>
|
|
|
|
* Copyright (C) 2006-2007 OpenedHand
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* 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"
|
|
|
|
|
2008-04-13 04:43:32 -04:00
|
|
|
#include "../clutter-stage-window.h"
|
2008-03-25 11:42:50 -04:00
|
|
|
#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"
|
2008-04-13 04:43:32 -04:00
|
|
|
#include "../clutter-shader.h"
|
2008-03-30 12:51:01 -04:00
|
|
|
#include "../clutter-stage.h"
|
2008-03-25 11:42:50 -04:00
|
|
|
|
2008-04-25 09:37:36 -04:00
|
|
|
#include "cogl/cogl.h"
|
2008-03-25 11:42:50 -04:00
|
|
|
|
|
|
|
#include <windows.h>
|
|
|
|
|
2008-04-13 04:43:32 -04:00
|
|
|
static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface);
|
|
|
|
|
|
|
|
G_DEFINE_TYPE_WITH_CODE (ClutterStageWin32,
|
|
|
|
clutter_stage_win32,
|
|
|
|
CLUTTER_TYPE_GROUP,
|
|
|
|
G_IMPLEMENT_INTERFACE
|
|
|
|
(CLUTTER_TYPE_STAGE_WINDOW,
|
|
|
|
clutter_stage_window_iface_init));
|
2008-03-25 11:42:50 -04:00
|
|
|
|
|
|
|
static void
|
|
|
|
clutter_stage_win32_show (ClutterActor *actor)
|
|
|
|
{
|
|
|
|
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (actor);
|
|
|
|
|
|
|
|
if (stage_win32->hwnd)
|
2008-06-12 08:12:25 -04:00
|
|
|
{
|
|
|
|
/* Force a redraw so that the layout will be run and the correct
|
|
|
|
size will be allocated to the window before it is
|
|
|
|
shown. Otherwise a WM_SIZE message will be sent which will
|
|
|
|
override the user's chosen size */
|
|
|
|
clutter_redraw (stage_win32->wrapper);
|
2008-03-25 11:42:50 -04:00
|
|
|
|
2008-06-12 08:12:25 -04:00
|
|
|
ShowWindow (stage_win32->hwnd, SW_SHOW);
|
|
|
|
}
|
2008-03-25 11:42:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2008-06-12 08:12:25 -04:00
|
|
|
clutter_stage_win32_get_preferred_width (ClutterActor *self,
|
Remove Units from the public API
With the recent change to internal floating point values, ClutterUnit
has become a redundant type, defined to be a float. All integer entry
points are being internally converted to floating point values to be
passed to the GL pipeline with the least amount of conversion.
ClutterUnit is thus exposed as just a "pixel with fractionary bits",
and not -- as users might think -- as generic, resolution and device
independent units. not that it was the case, but a definitive amount
of people was convinced it did provide this "feature", and was flummoxed
about the mere existence of this type.
So, having ClutterUnit exposed in the public API doubles the entry
points and has the following disadvantages:
- we have to maintain twice the amount of entry points in ClutterActor
- we still do an integer-to-float implicit conversion
- we introduce a weird impedance between pixels and "pixels with
fractionary bits"
- language bindings will have to choose what to bind, and resort
to manually overriding the API
+ *except* for language bindings based on GObject-Introspection, as
they cannot do manual overrides, thus will replicate the entire
set of entry points
For these reason, we should coalesces every Actor entry point for
pixels and for ClutterUnit into a single entry point taking a float,
like:
void clutter_actor_set_x (ClutterActor *self,
gfloat x);
void clutter_actor_get_size (ClutterActor *self,
gfloat *width,
gfloat *height);
gfloat clutter_actor_get_height (ClutterActor *self);
etc.
The issues I have identified are:
- we'll have a two cases of compiler warnings:
- printf() format of the return values from %d to %f
- clutter_actor_get_size() taking floats instead of unsigned ints
- we'll have a problem with varargs when passing an integer instead
of a floating point value, except on 64bit platforms where the
size of a float is the same as the size of an int
To be clear: the *intent* of the API should not change -- we still use
pixels everywhere -- but:
- we remove ambiguity in the API with regard to pixels and units
- we remove entry points we get to maintain for the whole 1.0
version of the API
- we make things simpler to bind for both manual language bindings
and automatic (gobject-introspection based) ones
- we have the simplest API possible while still exposing the
capabilities of the underlying GL implementation
2009-05-06 11:44:47 -04:00
|
|
|
gfloat for_height,
|
|
|
|
gfloat *min_width_p,
|
|
|
|
gfloat *natural_width_p)
|
2008-03-25 11:42:50 -04:00
|
|
|
{
|
|
|
|
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (self);
|
2008-06-12 08:12:25 -04:00
|
|
|
int width;
|
2008-03-25 11:42:50 -04:00
|
|
|
|
|
|
|
/* If we're in fullscreen mode then return the size of the screen
|
|
|
|
instead */
|
|
|
|
if ((stage_win32->state & CLUTTER_STAGE_STATE_FULLSCREEN))
|
2009-07-13 12:04:05 -04:00
|
|
|
width = stage_win32->fullscreen_rect.right
|
|
|
|
- stage_win32->fullscreen_rect.left;
|
2008-03-25 11:42:50 -04:00
|
|
|
else
|
2009-07-13 12:04:05 -04:00
|
|
|
width = stage_win32->win_width;
|
2008-06-12 08:12:25 -04:00
|
|
|
|
|
|
|
if (min_width_p)
|
|
|
|
*min_width_p = width;
|
|
|
|
|
|
|
|
if (natural_width_p)
|
|
|
|
*natural_width_p = width;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
clutter_stage_win32_get_preferred_height (ClutterActor *self,
|
Remove Units from the public API
With the recent change to internal floating point values, ClutterUnit
has become a redundant type, defined to be a float. All integer entry
points are being internally converted to floating point values to be
passed to the GL pipeline with the least amount of conversion.
ClutterUnit is thus exposed as just a "pixel with fractionary bits",
and not -- as users might think -- as generic, resolution and device
independent units. not that it was the case, but a definitive amount
of people was convinced it did provide this "feature", and was flummoxed
about the mere existence of this type.
So, having ClutterUnit exposed in the public API doubles the entry
points and has the following disadvantages:
- we have to maintain twice the amount of entry points in ClutterActor
- we still do an integer-to-float implicit conversion
- we introduce a weird impedance between pixels and "pixels with
fractionary bits"
- language bindings will have to choose what to bind, and resort
to manually overriding the API
+ *except* for language bindings based on GObject-Introspection, as
they cannot do manual overrides, thus will replicate the entire
set of entry points
For these reason, we should coalesces every Actor entry point for
pixels and for ClutterUnit into a single entry point taking a float,
like:
void clutter_actor_set_x (ClutterActor *self,
gfloat x);
void clutter_actor_get_size (ClutterActor *self,
gfloat *width,
gfloat *height);
gfloat clutter_actor_get_height (ClutterActor *self);
etc.
The issues I have identified are:
- we'll have a two cases of compiler warnings:
- printf() format of the return values from %d to %f
- clutter_actor_get_size() taking floats instead of unsigned ints
- we'll have a problem with varargs when passing an integer instead
of a floating point value, except on 64bit platforms where the
size of a float is the same as the size of an int
To be clear: the *intent* of the API should not change -- we still use
pixels everywhere -- but:
- we remove ambiguity in the API with regard to pixels and units
- we remove entry points we get to maintain for the whole 1.0
version of the API
- we make things simpler to bind for both manual language bindings
and automatic (gobject-introspection based) ones
- we have the simplest API possible while still exposing the
capabilities of the underlying GL implementation
2009-05-06 11:44:47 -04:00
|
|
|
gfloat for_width,
|
|
|
|
gfloat *min_height_p,
|
|
|
|
gfloat *natural_height_p)
|
2008-06-12 08:12:25 -04:00
|
|
|
{
|
|
|
|
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (self);
|
|
|
|
int height;
|
|
|
|
|
|
|
|
/* If we're in fullscreen mode then return the size of the screen
|
|
|
|
instead */
|
|
|
|
if ((stage_win32->state & CLUTTER_STAGE_STATE_FULLSCREEN))
|
2009-07-13 12:04:05 -04:00
|
|
|
height = stage_win32->fullscreen_rect.bottom
|
|
|
|
- stage_win32->fullscreen_rect.top;
|
2008-06-12 08:12:25 -04:00
|
|
|
else
|
2009-07-13 12:04:05 -04:00
|
|
|
height = stage_win32->win_height;
|
2008-06-12 08:12:25 -04:00
|
|
|
|
|
|
|
if (min_height_p)
|
|
|
|
*min_height_p = height;
|
|
|
|
|
|
|
|
if (natural_height_p)
|
|
|
|
*natural_height_p = height;
|
2008-03-25 11:42:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
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_size (ClutterStageWin32 *stage_win32,
|
|
|
|
int width_in, int height_in,
|
|
|
|
int *width_out, int *height_out)
|
|
|
|
{
|
|
|
|
gboolean resizable
|
2008-04-13 04:43:32 -04:00
|
|
|
= clutter_stage_get_user_resizable (stage_win32->wrapper);
|
2008-03-25 11:42:50 -04:00
|
|
|
/* 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 */
|
2008-04-13 04:43:32 -04:00
|
|
|
if (!clutter_stage_get_user_resizable (CLUTTER_STAGE (stage_win32->wrapper)))
|
2008-03-25 11:42:50 -04:00
|
|
|
{
|
|
|
|
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
|
2009-06-03 09:02:06 -04:00
|
|
|
clutter_stage_win32_allocate (ClutterActor *self,
|
|
|
|
const ClutterActorBox *box,
|
|
|
|
ClutterAllocationFlags flags)
|
2008-03-25 11:42:50 -04:00
|
|
|
{
|
|
|
|
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (self);
|
2008-06-12 08:12:25 -04:00
|
|
|
gint new_width, new_height;
|
2008-03-25 11:42:50 -04:00
|
|
|
|
2009-06-03 09:02:06 -04:00
|
|
|
new_width = ABS (box->x2 - box->x1);
|
|
|
|
new_height = ABS (box->y2 - box->y1);
|
2008-03-25 11:42:50 -04:00
|
|
|
|
2009-06-03 09:02:06 -04:00
|
|
|
if (new_width != stage_win32->win_width ||
|
|
|
|
new_height != stage_win32->win_height)
|
2008-03-25 11:42:50 -04:00
|
|
|
{
|
2008-06-12 08:12:25 -04:00
|
|
|
/* Ignore size requests if we are in full screen mode */
|
|
|
|
if ((stage_win32->state & CLUTTER_STAGE_STATE_FULLSCREEN) == 0)
|
2008-03-25 11:42:50 -04:00
|
|
|
{
|
2008-06-12 08:12:25 -04:00
|
|
|
stage_win32->win_width = new_width;
|
|
|
|
stage_win32->win_height = new_height;
|
|
|
|
|
|
|
|
if (stage_win32->hwnd != NULL && !stage_win32->is_foreign_win)
|
|
|
|
{
|
|
|
|
int full_width, full_height;
|
|
|
|
|
|
|
|
get_full_window_size (stage_win32,
|
|
|
|
new_width, new_height,
|
|
|
|
&full_width, &full_height);
|
|
|
|
|
|
|
|
SetWindowPos (stage_win32->hwnd, NULL,
|
|
|
|
0, 0,
|
|
|
|
full_width, full_height,
|
|
|
|
SWP_NOZORDER | SWP_NOMOVE);
|
|
|
|
}
|
2008-03-25 11:42:50 -04:00
|
|
|
}
|
|
|
|
|
2008-04-13 04:43:32 -04:00
|
|
|
CLUTTER_SET_PRIVATE_FLAGS (stage_win32->wrapper,
|
|
|
|
CLUTTER_ACTOR_SYNC_MATRICES);
|
2008-03-25 11:42:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
CLUTTER_ACTOR_CLASS (clutter_stage_win32_parent_class)
|
2009-06-03 09:02:06 -04:00
|
|
|
->allocate (self, box, flags);
|
2008-03-25 11:42:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2008-04-13 04:43:32 -04:00
|
|
|
clutter_stage_win32_set_title (ClutterStageWindow *stage_window,
|
|
|
|
const gchar *title)
|
2008-03-25 11:42:50 -04:00
|
|
|
{
|
2008-04-13 04:43:32 -04:00
|
|
|
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (stage_window);
|
2008-03-25 11:42:50 -04:00
|
|
|
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)
|
|
|
|
{
|
2008-04-13 04:43:32 -04:00
|
|
|
ClutterStage *wrapper = stage_win32->wrapper;
|
|
|
|
|
2008-03-25 11:42:50 -04:00
|
|
|
/* 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 */
|
2008-04-13 04:43:32 -04:00
|
|
|
else if (clutter_stage_get_user_resizable (wrapper))
|
2008-03-25 11:42:50 -04:00
|
|
|
return WS_OVERLAPPEDWINDOW;
|
|
|
|
else
|
2008-09-16 12:00:31 -04:00
|
|
|
return WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX;
|
2008-03-25 11:42:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2008-04-13 04:43:32 -04:00
|
|
|
clutter_stage_win32_set_user_resize (ClutterStageWindow *stage_window,
|
|
|
|
gboolean value)
|
2008-03-25 11:42:50 -04:00
|
|
|
{
|
2008-04-13 04:43:32 -04:00
|
|
|
HWND hwnd = CLUTTER_STAGE_WIN32 (stage_window)->hwnd;
|
2008-03-25 11:42:50 -04:00
|
|
|
LONG old_style = GetWindowLongW (hwnd, GWL_STYLE);
|
|
|
|
|
|
|
|
/* Update the window style but preserve the visibility */
|
|
|
|
SetWindowLongW (hwnd, GWL_STYLE,
|
2008-04-13 04:43:32 -04:00
|
|
|
get_window_style (CLUTTER_STAGE_WIN32 (stage_window))
|
2008-03-25 11:42:50 -04:00
|
|
|
| (old_style & WS_VISIBLE));
|
2008-09-16 12:00:31 -04:00
|
|
|
/* Queue a redraw of the frame */
|
|
|
|
RedrawWindow (hwnd, NULL, NULL, RDW_FRAME | RDW_INVALIDATE);
|
2008-03-25 11:42:50 -04:00
|
|
|
}
|
|
|
|
|
2008-04-13 04:43:32 -04:00
|
|
|
static ClutterActor *
|
|
|
|
clutter_stage_win32_get_wrapper (ClutterStageWindow *stage_window)
|
|
|
|
{
|
|
|
|
return CLUTTER_ACTOR (CLUTTER_STAGE_WIN32 (stage_window)->wrapper);
|
|
|
|
}
|
|
|
|
|
2008-03-25 11:42:50 -04:00
|
|
|
static void
|
2008-04-13 04:43:32 -04:00
|
|
|
clutter_stage_win32_set_fullscreen (ClutterStageWindow *stage_window,
|
|
|
|
gboolean value)
|
2008-03-25 11:42:50 -04:00
|
|
|
{
|
2008-04-13 04:43:32 -04:00
|
|
|
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (stage_window);
|
|
|
|
HWND hwnd = CLUTTER_STAGE_WIN32 (stage_window)->hwnd;
|
2008-03-25 11:42:50 -04:00
|
|
|
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
|
|
|
|
{
|
2008-06-12 08:12:25 -04:00
|
|
|
int full_width, full_height;
|
2008-03-25 11:42:50 -04:00
|
|
|
|
|
|
|
get_full_window_size (stage_win32,
|
|
|
|
stage_win32->win_width,
|
|
|
|
stage_win32->win_height,
|
|
|
|
&full_width, &full_height);
|
|
|
|
|
|
|
|
SetWindowPos (stage_win32->hwnd, NULL,
|
2008-06-12 08:12:25 -04:00
|
|
|
0, 0,
|
2008-03-25 11:42:50 -04:00
|
|
|
full_width, full_height,
|
2008-06-12 08:12:25 -04:00
|
|
|
SWP_NOZORDER | SWP_NOMOVE);
|
2008-03-25 11:42:50 -04:00
|
|
|
}
|
|
|
|
|
2008-04-13 04:43:32 -04:00
|
|
|
CLUTTER_SET_PRIVATE_FLAGS (stage_win32->wrapper,
|
|
|
|
CLUTTER_ACTOR_SYNC_MATRICES);
|
2008-03-25 11:42:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Report the state change */
|
|
|
|
memset (&event, 0, sizeof (event));
|
|
|
|
event.type = CLUTTER_STAGE_STATE;
|
2008-04-13 04:43:32 -04:00
|
|
|
event.stage = CLUTTER_STAGE (stage_win32->wrapper);
|
2008-03-25 11:42:50 -04:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2008-06-25 08:25:43 -04:00
|
|
|
static gboolean
|
|
|
|
clutter_stage_win32_pixel_format_is_better (const PIXELFORMATDESCRIPTOR *pfa,
|
|
|
|
const PIXELFORMATDESCRIPTOR *pfb)
|
|
|
|
{
|
|
|
|
/* Always prefer a format with a stencil buffer */
|
|
|
|
if (pfa->cStencilBits == 0)
|
|
|
|
{
|
|
|
|
if (pfb->cStencilBits > 0)
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else if (pfb->cStencilBits == 0)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
/* Prefer a bigger color buffer */
|
|
|
|
if (pfb->cColorBits > pfa->cColorBits)
|
|
|
|
return TRUE;
|
|
|
|
else if (pfb->cColorBits < pfa->cColorBits)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
/* Prefer a bigger depth buffer */
|
|
|
|
return pfb->cDepthBits > pfa->cDepthBits;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
clutter_stage_win32_choose_pixel_format (HDC dc, PIXELFORMATDESCRIPTOR *pfd)
|
|
|
|
{
|
|
|
|
int i, num_formats, best_pf = 0;
|
|
|
|
PIXELFORMATDESCRIPTOR best_pfd;
|
|
|
|
|
|
|
|
num_formats = DescribePixelFormat (dc, 0, sizeof (best_pfd), NULL);
|
|
|
|
|
|
|
|
for (i = 1; i <= num_formats; i++)
|
|
|
|
{
|
|
|
|
memset (pfd, 0, sizeof (*pfd));
|
|
|
|
|
|
|
|
if (DescribePixelFormat (dc, i, sizeof (best_pfd), pfd)
|
|
|
|
/* Check whether this format is useable by Clutter */
|
|
|
|
&& ((pfd->dwFlags & (PFD_SUPPORT_OPENGL
|
|
|
|
| PFD_DRAW_TO_WINDOW
|
|
|
|
| PFD_DOUBLEBUFFER
|
|
|
|
| PFD_GENERIC_FORMAT))
|
|
|
|
== (PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW))
|
|
|
|
&& pfd->iPixelType == PFD_TYPE_RGBA
|
|
|
|
&& pfd->cColorBits >= 16 && pfd->cColorBits <= 32
|
|
|
|
&& pfd->cDepthBits >= 16 && pfd->cDepthBits <= 32
|
|
|
|
/* Check whether this is a better format than one we've
|
|
|
|
already found */
|
|
|
|
&& (best_pf == 0
|
|
|
|
|| clutter_stage_win32_pixel_format_is_better (&best_pfd, pfd)))
|
|
|
|
{
|
|
|
|
best_pf = i;
|
|
|
|
best_pfd = *pfd;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*pfd = best_pfd;
|
|
|
|
|
|
|
|
return best_pf;
|
|
|
|
}
|
|
|
|
|
2008-03-25 11:42:50 -04:00
|
|
|
static void
|
|
|
|
clutter_stage_win32_realize (ClutterActor *actor)
|
|
|
|
{
|
|
|
|
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (actor);
|
2008-03-30 12:51:01 -04:00
|
|
|
ClutterBackendWin32 *backend_win32;
|
2008-03-25 11:42:50 -04:00
|
|
|
PIXELFORMATDESCRIPTOR pfd;
|
|
|
|
int pf;
|
|
|
|
|
|
|
|
CLUTTER_NOTE (MISC, "Realizing main stage");
|
|
|
|
|
2008-03-30 12:51:01 -04:00
|
|
|
backend_win32 = CLUTTER_BACKEND_WIN32 (clutter_get_default_backend ());
|
|
|
|
|
2008-03-25 11:42:50 -04:00
|
|
|
if (stage_win32->hwnd == NULL)
|
|
|
|
{
|
|
|
|
ATOM window_class = clutter_stage_win32_get_window_class ();
|
|
|
|
int win_xpos, win_ypos, win_width, win_height;
|
|
|
|
|
|
|
|
if (window_class == 0)
|
|
|
|
{
|
|
|
|
g_critical ("Unable to register window class");
|
2008-05-15 18:03:22 -04:00
|
|
|
goto fail;
|
2008-03-25 11:42:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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
|
|
|
|
{
|
2008-06-12 08:12:25 -04:00
|
|
|
win_xpos = win_ypos = CW_USEDEFAULT;
|
|
|
|
|
2008-03-25 11:42:50 -04:00
|
|
|
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");
|
2008-05-15 18:03:22 -04:00
|
|
|
goto fail;
|
2008-03-25 11:42:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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->client_dc)
|
|
|
|
ReleaseDC (stage_win32->hwnd, stage_win32->client_dc);
|
|
|
|
|
|
|
|
stage_win32->client_dc = GetDC (stage_win32->hwnd);
|
|
|
|
|
2008-06-25 08:25:43 -04:00
|
|
|
pf = clutter_stage_win32_choose_pixel_format (stage_win32->client_dc, &pfd);
|
|
|
|
|
|
|
|
if (pf == 0 || !SetPixelFormat (stage_win32->client_dc, pf, &pfd))
|
2008-03-25 11:42:50 -04:00
|
|
|
{
|
|
|
|
g_critical ("Unable to find suitable GL pixel format");
|
2008-05-15 18:03:22 -04:00
|
|
|
goto fail;
|
2008-03-25 11:42:50 -04:00
|
|
|
}
|
|
|
|
|
2008-03-30 12:51:01 -04:00
|
|
|
if (backend_win32->gl_context == NULL)
|
2008-03-25 11:42:50 -04:00
|
|
|
{
|
2008-03-30 12:51:01 -04:00
|
|
|
backend_win32->gl_context = wglCreateContext (stage_win32->client_dc);
|
|
|
|
|
|
|
|
if (backend_win32->gl_context == NULL)
|
|
|
|
{
|
|
|
|
g_critical ("Unable to create suitable GL context");
|
2008-05-15 18:03:22 -04:00
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Make the context current so we can check the GL version */
|
|
|
|
wglMakeCurrent (stage_win32->client_dc, backend_win32->gl_context);
|
|
|
|
|
|
|
|
if (!clutter_stage_win32_check_gl_version ())
|
|
|
|
{
|
|
|
|
g_critical ("OpenGL version number is too low");
|
|
|
|
goto fail;
|
2008-03-30 12:51:01 -04:00
|
|
|
}
|
2008-03-25 11:42:50 -04:00
|
|
|
}
|
|
|
|
|
2009-06-06 09:55:00 -04:00
|
|
|
CLUTTER_NOTE (BACKEND, "Successfully realized stage");
|
2008-03-25 11:42:50 -04:00
|
|
|
|
2008-05-15 18:03:22 -04:00
|
|
|
return;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
|
2008-03-25 11:42:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
clutter_stage_win32_unrealize (ClutterActor *actor)
|
|
|
|
{
|
|
|
|
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (actor);
|
|
|
|
|
2008-04-13 04:43:32 -04:00
|
|
|
CLUTTER_NOTE (BACKEND, "Unrealizing stage");
|
|
|
|
|
Enforce invariants on mapped, realized, visibility states
Bug 1138 - No trackable "mapped" state
* Add a VISIBLE flag tracking application programmer's
expected showing-state for the actor, allowing us to
always ensure we keep what the app wants while tracking
internal implementation state separately.
* Make MAPPED reflect whether the actor will be painted;
add notification on a ClutterActor::mapped property.
Keep MAPPED state updated as the actor is shown,
ancestors are shown, actor is reparented, etc.
* Require a stage and realized parents to realize; this means
at realization time the correct window system and GL resources
are known. But unparented actors can no longer be realized.
* Allow children to be unrealized even if parent is realized.
Otherwise in effect either all actors or no actors are realized,
i.e. it becomes a stage-global flag.
* Allow clutter_actor_realize() to "fail" if not inside a toplevel
* Rework clutter_actor_unrealize() so internally we have
a flavor that does not mess with visibility flag
* Add _clutter_actor_rerealize() to encapsulate a somewhat
tricky operation we were doing in a couple of places
* Do not realize/unrealize children in ClutterGroup,
ClutterActor already does it
* Do not realize impl by hand in clutter_stage_show(),
since showing impl already does that
* Do not unrealize in various dispose() methods, since
ClutterActor dispose implementation already does it
and chaining up is mandatory
* ClutterTexture uses COGL while unrealizable (before it's
added to a stage). Previously this breakage was affecting
ClutterActor because we had to allow realize outside
a stage. Move the breakage to ClutterTexture, by making
ClutterTexture just use COGL while not realized.
* Unrealize before we set parent to NULL in clutter_actor_unparent().
This means unrealize() implementations can get to the stage.
Because actors need the stage in order to detach from stage.
* Update clutter-actor-invariants.txt to reflect latest changes
* Remove explicit hide/unrealize from ClutterActor::dispose since
unparent already forces those
Instead just assert that unparent() occurred and did the right thing.
* Check whether parent implements unrealize before chaining up
Needed because ClutterGroup no longer has to implement unrealize.
* Perform unrealize in the default handler for the signal.
This allows non-containers that have children to work properly,
and allows containers to override how it's done.
* Add map/unmap virtual methods and set MAPPED flag on self and
children in there. This allows subclasses to hook map/unmap.
These are not signals, because notify::mapped is better for
anything it's legitimate for a non-subclass to do.
Signed-off-by: Emmanuele Bassi <ebassi@linux.intel.com>
2009-04-02 09:16:43 -04:00
|
|
|
if (CLUTTER_ACTOR_CLASS (clutter_stage_win32_parent_class)->unrealize != NULL)
|
|
|
|
CLUTTER_ACTOR_CLASS (clutter_stage_win32_parent_class)->unrealize (actor);
|
2008-04-13 04:43:32 -04:00
|
|
|
|
2008-03-25 11:42:50 -04:00
|
|
|
if (stage_win32->client_dc)
|
|
|
|
{
|
|
|
|
ReleaseDC (stage_win32->hwnd, stage_win32->client_dc);
|
|
|
|
stage_win32->client_dc = NULL;
|
|
|
|
}
|
|
|
|
|
2008-04-15 12:12:37 -04:00
|
|
|
if (!stage_win32->is_foreign_win && stage_win32->hwnd)
|
2008-03-25 11:42:50 -04:00
|
|
|
{
|
2008-04-13 04:43:32 -04:00
|
|
|
/* Drop the pointer to this stage in the window so that any
|
|
|
|
further messages won't be processed. The stage might be being
|
|
|
|
destroyed so otherwise the messages would be handled with an
|
|
|
|
invalid stage instance */
|
|
|
|
SetWindowLongPtrW (stage_win32->hwnd, 0, (LONG_PTR) 0);
|
2008-03-25 11:42:50 -04:00
|
|
|
DestroyWindow (stage_win32->hwnd);
|
|
|
|
stage_win32->hwnd = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
clutter_stage_win32_dispose (GObject *gobject)
|
|
|
|
{
|
|
|
|
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (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);
|
|
|
|
|
|
|
|
gobject_class->dispose = clutter_stage_win32_dispose;
|
|
|
|
|
|
|
|
actor_class->show = clutter_stage_win32_show;
|
|
|
|
actor_class->hide = clutter_stage_win32_hide;
|
2008-06-12 08:12:25 -04:00
|
|
|
actor_class->get_preferred_width = clutter_stage_win32_get_preferred_width;
|
|
|
|
actor_class->get_preferred_height = clutter_stage_win32_get_preferred_height;
|
|
|
|
actor_class->allocate = clutter_stage_win32_allocate;
|
2008-03-25 11:42:50 -04:00
|
|
|
actor_class->realize = clutter_stage_win32_realize;
|
|
|
|
actor_class->unrealize = clutter_stage_win32_unrealize;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
clutter_stage_win32_init (ClutterStageWin32 *stage)
|
|
|
|
{
|
|
|
|
stage->hwnd = NULL;
|
|
|
|
stage->client_dc = NULL;
|
|
|
|
stage->win_width = 640;
|
|
|
|
stage->win_height = 480;
|
|
|
|
stage->backend = NULL;
|
|
|
|
stage->scroll_pos = 0;
|
2008-04-15 12:12:37 -04:00
|
|
|
stage->is_foreign_win = FALSE;
|
2008-04-13 04:43:32 -04:00
|
|
|
|
|
|
|
stage->wrapper = NULL;
|
|
|
|
|
|
|
|
CLUTTER_SET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_IS_TOPLEVEL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
|
|
|
|
{
|
|
|
|
iface->get_wrapper = clutter_stage_win32_get_wrapper;
|
|
|
|
iface->set_title = clutter_stage_win32_set_title;
|
|
|
|
iface->set_fullscreen = clutter_stage_win32_set_fullscreen;
|
|
|
|
iface->set_user_resizable = clutter_stage_win32_set_user_resize;
|
2008-03-25 11:42:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* clutter_win32_get_stage_window:
|
|
|
|
* @stage: a #ClutterStage
|
|
|
|
*
|
2008-03-26 18:22:32 -04:00
|
|
|
* Gets the stage's window handle
|
2008-03-25 11:42:50 -04:00
|
|
|
*
|
|
|
|
* Return value: An HWND for the stage window.
|
|
|
|
*
|
|
|
|
* Since: 0.8
|
|
|
|
*/
|
|
|
|
HWND
|
|
|
|
clutter_win32_get_stage_window (ClutterStage *stage)
|
|
|
|
{
|
2008-04-13 04:43:32 -04:00
|
|
|
ClutterStageWindow *impl;
|
|
|
|
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_STAGE (stage), NULL);
|
|
|
|
|
|
|
|
impl = _clutter_stage_get_window (stage);
|
|
|
|
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_STAGE_WIN32 (impl), NULL);
|
2008-03-25 11:42:50 -04:00
|
|
|
|
2008-04-13 04:43:32 -04:00
|
|
|
return CLUTTER_STAGE_WIN32 (impl)->hwnd;
|
2008-03-25 11:42:50 -04:00
|
|
|
}
|
|
|
|
|
2008-03-30 12:51:01 -04:00
|
|
|
/**
|
|
|
|
* clutter_win32_get_stage_from_window:
|
|
|
|
* @hwnd: a window handle
|
|
|
|
*
|
|
|
|
* Gets the stage for a particular window.
|
|
|
|
*
|
|
|
|
* Return value: The stage or NULL if a stage does not exist for the
|
|
|
|
* window.
|
|
|
|
*
|
|
|
|
* Since: 0.8
|
|
|
|
*/
|
|
|
|
ClutterStage *
|
|
|
|
clutter_win32_get_stage_from_window (HWND hwnd)
|
|
|
|
{
|
|
|
|
/* Check whether the window handle is an instance of the stage
|
|
|
|
window class */
|
|
|
|
if ((ATOM) GetClassLongPtrW (hwnd, GCW_ATOM)
|
|
|
|
== clutter_stage_win32_get_window_class ())
|
|
|
|
/* If it is there should be a pointer to the stage in the window
|
|
|
|
extra data */
|
2008-04-13 04:43:32 -04:00
|
|
|
return CLUTTER_STAGE_WIN32 (GetWindowLongPtrW (hwnd, 0))->wrapper;
|
2008-03-30 12:51:01 -04:00
|
|
|
else
|
2008-04-15 12:12:37 -04:00
|
|
|
{
|
|
|
|
/* Otherwise it might be a foreign window so we should check the
|
|
|
|
stage list */
|
2009-07-13 12:04:05 -04:00
|
|
|
ClutterStageManager *stage_manager;
|
2009-06-17 12:59:54 -04:00
|
|
|
const GSList *stages, *l;
|
2008-04-15 12:12:37 -04:00
|
|
|
|
2009-06-17 12:59:54 -04:00
|
|
|
stage_manager = clutter_stage_manager_get_default ();
|
|
|
|
stages = clutter_stage_manager_peek_stages (stage_manager);
|
|
|
|
|
|
|
|
for (l = stages; l != NULL; l = l->next)
|
2008-04-15 12:12:37 -04:00
|
|
|
{
|
|
|
|
ClutterStage *stage = l->data;
|
|
|
|
ClutterStageWindow *impl;
|
|
|
|
|
|
|
|
impl = _clutter_stage_get_window (stage);
|
|
|
|
g_assert (CLUTTER_IS_STAGE_WIN32 (impl));
|
|
|
|
|
|
|
|
if (CLUTTER_STAGE_WIN32 (impl)->hwnd == hwnd)
|
|
|
|
return stage;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
2008-03-30 12:51:01 -04:00
|
|
|
}
|
|
|
|
|
2008-04-15 12:12:37 -04:00
|
|
|
/**
|
|
|
|
* clutter_win32_set_stage_foreign:
|
|
|
|
* @stage: a #ClutterStage
|
|
|
|
* @hwnd: an existing window handle
|
|
|
|
*
|
|
|
|
* Target the #ClutterStage to use an existing external window handle.
|
|
|
|
*
|
|
|
|
* Return value: %TRUE if foreign window is valid
|
|
|
|
*
|
|
|
|
* Since: 0.8
|
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
clutter_win32_set_stage_foreign (ClutterStage *stage,
|
|
|
|
HWND hwnd)
|
|
|
|
{
|
|
|
|
ClutterStageWin32 *stage_win32;
|
|
|
|
ClutterStageWindow *impl;
|
|
|
|
ClutterActor *actor;
|
|
|
|
RECT client_rect;
|
|
|
|
POINT window_pos;
|
|
|
|
ClutterGeometry geom;
|
|
|
|
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE);
|
|
|
|
g_return_val_if_fail (hwnd != NULL, FALSE);
|
|
|
|
|
|
|
|
actor = CLUTTER_ACTOR (stage);
|
|
|
|
|
|
|
|
impl = _clutter_stage_get_window (stage);
|
|
|
|
stage_win32 = CLUTTER_STAGE_WIN32 (impl);
|
|
|
|
|
Enforce invariants on mapped, realized, visibility states
Bug 1138 - No trackable "mapped" state
* Add a VISIBLE flag tracking application programmer's
expected showing-state for the actor, allowing us to
always ensure we keep what the app wants while tracking
internal implementation state separately.
* Make MAPPED reflect whether the actor will be painted;
add notification on a ClutterActor::mapped property.
Keep MAPPED state updated as the actor is shown,
ancestors are shown, actor is reparented, etc.
* Require a stage and realized parents to realize; this means
at realization time the correct window system and GL resources
are known. But unparented actors can no longer be realized.
* Allow children to be unrealized even if parent is realized.
Otherwise in effect either all actors or no actors are realized,
i.e. it becomes a stage-global flag.
* Allow clutter_actor_realize() to "fail" if not inside a toplevel
* Rework clutter_actor_unrealize() so internally we have
a flavor that does not mess with visibility flag
* Add _clutter_actor_rerealize() to encapsulate a somewhat
tricky operation we were doing in a couple of places
* Do not realize/unrealize children in ClutterGroup,
ClutterActor already does it
* Do not realize impl by hand in clutter_stage_show(),
since showing impl already does that
* Do not unrealize in various dispose() methods, since
ClutterActor dispose implementation already does it
and chaining up is mandatory
* ClutterTexture uses COGL while unrealizable (before it's
added to a stage). Previously this breakage was affecting
ClutterActor because we had to allow realize outside
a stage. Move the breakage to ClutterTexture, by making
ClutterTexture just use COGL while not realized.
* Unrealize before we set parent to NULL in clutter_actor_unparent().
This means unrealize() implementations can get to the stage.
Because actors need the stage in order to detach from stage.
* Update clutter-actor-invariants.txt to reflect latest changes
* Remove explicit hide/unrealize from ClutterActor::dispose since
unparent already forces those
Instead just assert that unparent() occurred and did the right thing.
* Check whether parent implements unrealize before chaining up
Needed because ClutterGroup no longer has to implement unrealize.
* Perform unrealize in the default handler for the signal.
This allows non-containers that have children to work properly,
and allows containers to override how it's done.
* Add map/unmap virtual methods and set MAPPED flag on self and
children in there. This allows subclasses to hook map/unmap.
These are not signals, because notify::mapped is better for
anything it's legitimate for a non-subclass to do.
Signed-off-by: Emmanuele Bassi <ebassi@linux.intel.com>
2009-04-02 09:16:43 -04:00
|
|
|
/* FIXME this needs updating to use _clutter_actor_rerealize(),
|
|
|
|
* see the analogous code in x11 backend. Probably best if
|
|
|
|
* win32 maintainer does it so they can be sure it compiles
|
|
|
|
* and works.
|
|
|
|
*/
|
|
|
|
|
2008-04-15 12:12:37 -04:00
|
|
|
clutter_actor_unrealize (actor);
|
|
|
|
|
|
|
|
if (!GetClientRect (hwnd, &client_rect))
|
|
|
|
{
|
|
|
|
g_warning ("Unable to retrieve the new window geometry");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
window_pos.x = client_rect.left;
|
|
|
|
window_pos.y = client_rect.right;
|
|
|
|
ClientToScreen (hwnd, &window_pos);
|
|
|
|
|
|
|
|
CLUTTER_NOTE (BACKEND, "Setting foreign window (0x%x)", (int) hwnd);
|
|
|
|
|
|
|
|
stage_win32->hwnd = hwnd;
|
|
|
|
stage_win32->is_foreign_win = TRUE;
|
|
|
|
|
2008-06-12 08:12:25 -04:00
|
|
|
geom.x = 0;
|
|
|
|
geom.y = 0;
|
2008-04-15 12:12:37 -04:00
|
|
|
geom.width = client_rect.right - client_rect.left;
|
|
|
|
geom.height = client_rect.bottom - client_rect.top;
|
|
|
|
|
|
|
|
clutter_actor_set_geometry (actor, &geom);
|
|
|
|
clutter_actor_realize (actor);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2008-03-25 11:42:50 -04:00
|
|
|
void
|
|
|
|
clutter_stage_win32_map (ClutterStageWin32 *stage_win32)
|
|
|
|
{
|
2009-06-04 06:59:17 -04:00
|
|
|
clutter_actor_map (CLUTTER_ACTOR (stage_win32));
|
|
|
|
clutter_actor_map (CLUTTER_ACTOR (stage_win32->wrapper));
|
2008-03-25 11:42:50 -04:00
|
|
|
|
2008-06-12 08:12:25 -04:00
|
|
|
clutter_actor_queue_relayout (CLUTTER_ACTOR (stage_win32->wrapper));
|
2008-03-25 11:42:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
clutter_stage_win32_unmap (ClutterStageWin32 *stage_win32)
|
|
|
|
{
|
2009-06-04 06:59:17 -04:00
|
|
|
clutter_actor_unmap (CLUTTER_ACTOR (stage_win32));
|
|
|
|
clutter_actor_unmap (CLUTTER_ACTOR (stage_win32->wrapper));
|
2008-03-25 11:42:50 -04:00
|
|
|
}
|