14
14
* Lesser General Public License for more details.
16
16
* You should have received a copy of the GNU Lesser General Public
17
* License along with this library; if not, write to the
18
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19
* Boston, MA 02111-1307, USA.
17
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
22
22
#ifdef HAVE_CONFIG_H
45
45
#include <windows.h>
47
47
static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface);
49
49
G_DEFINE_TYPE_WITH_CODE (ClutterStageWin32,
50
50
clutter_stage_win32,
52
52
G_IMPLEMENT_INTERFACE
53
53
(CLUTTER_TYPE_STAGE_WINDOW,
54
54
clutter_stage_window_iface_init));
57
clutter_stage_win32_show (ClutterActor *actor)
59
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (actor);
61
if (stage_win32->hwnd)
62
ShowWindow (stage_win32->hwnd, SW_SHOW);
66
clutter_stage_win32_hide (ClutterActor *actor)
68
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (actor);
70
if (stage_win32->hwnd)
71
ShowWindow (stage_win32->hwnd, SW_HIDE);
75
clutter_stage_win32_get_preferred_width (ClutterActor *self,
78
gfloat *natural_width_p)
80
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (self);
83
/* If we're in fullscreen mode then return the size of the screen
85
if ((stage_win32->state & CLUTTER_STAGE_STATE_FULLSCREEN))
86
width = stage_win32->fullscreen_rect.right
87
- stage_win32->fullscreen_rect.left;
89
width = stage_win32->win_width;
95
*natural_width_p = width;
99
clutter_stage_win32_get_preferred_height (ClutterActor *self,
101
gfloat *min_height_p,
102
gfloat *natural_height_p)
104
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (self);
107
/* If we're in fullscreen mode then return the size of the screen
109
if ((stage_win32->state & CLUTTER_STAGE_STATE_FULLSCREEN))
110
height = stage_win32->fullscreen_rect.bottom
111
- stage_win32->fullscreen_rect.top;
113
height = stage_win32->win_height;
116
*min_height_p = height;
118
if (natural_height_p)
119
*natural_height_p = height;
57
clutter_stage_win32_show (ClutterStageWindow *stage_window,
60
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (stage_window);
62
if (stage_win32->hwnd)
64
ShowWindow (stage_win32->hwnd, do_raise ? SW_SHOW : SW_SHOWNA);
66
clutter_stage_ensure_viewport (CLUTTER_STAGE (stage_win32->wrapper));
67
clutter_actor_map (CLUTTER_ACTOR (stage_win32->wrapper));
72
clutter_stage_win32_hide (ClutterStageWindow *stage_window)
74
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (stage_window);
76
if (stage_win32->hwnd)
78
clutter_actor_unmap (CLUTTER_ACTOR (stage_win32->wrapper));
79
ShowWindow (stage_win32->hwnd, SW_HIDE);
84
clutter_stage_win32_get_geometry (ClutterStageWindow *stage_window,
85
ClutterGeometry *geometry)
87
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (stage_window);
89
if ((stage_win32->state & CLUTTER_STAGE_STATE_FULLSCREEN))
91
geometry->width = (stage_win32->fullscreen_rect.right
92
- stage_win32->fullscreen_rect.left);
93
geometry->height = (stage_win32->fullscreen_rect.bottom
94
- stage_win32->fullscreen_rect.top);
98
geometry->width = stage_win32->win_width;
99
geometry->height = stage_win32->win_height;
182
clutter_stage_win32_allocate (ClutterActor *self,
183
const ClutterActorBox *box,
184
ClutterAllocationFlags flags)
162
clutter_stage_win32_resize (ClutterStageWindow *stage_window,
186
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (self);
187
gint new_width, new_height;
189
new_width = ABS (box->x2 - box->x1);
190
new_height = ABS (box->y2 - box->y1);
192
if (new_width != stage_win32->win_width ||
193
new_height != stage_win32->win_height)
166
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (stage_window);
169
resize = clutter_stage_get_user_resizable (stage_win32->wrapper);
171
if (width != stage_win32->win_width || height != stage_win32->win_height)
195
173
/* Ignore size requests if we are in full screen mode */
196
174
if ((stage_win32->state & CLUTTER_STAGE_STATE_FULLSCREEN) == 0)
198
stage_win32->win_width = new_width;
199
stage_win32->win_height = new_height;
201
if (stage_win32->hwnd != NULL && !stage_win32->is_foreign_win)
203
int full_width, full_height;
205
get_full_window_size (stage_win32,
206
new_width, new_height,
207
&full_width, &full_height);
209
SetWindowPos (stage_win32->hwnd, NULL,
211
full_width, full_height,
212
SWP_NOZORDER | SWP_NOMOVE);
176
stage_win32->win_width = width;
177
stage_win32->win_height = height;
179
if (stage_win32->hwnd != NULL && !stage_win32->is_foreign_win)
181
int full_width, full_height;
183
get_full_window_size (stage_win32,
185
&full_width, &full_height);
187
SetWindowPos (stage_win32->hwnd, NULL,
189
full_width, full_height,
190
SWP_NOZORDER | SWP_NOMOVE);
216
194
CLUTTER_SET_PRIVATE_FLAGS (stage_win32->wrapper,
217
CLUTTER_ACTOR_SYNC_MATRICES);
195
CLUTTER_ACTOR_SYNC_MATRICES);
220
CLUTTER_ACTOR_CLASS (clutter_stage_win32_parent_class)
221
->allocate (self, box, flags);
226
201
const gchar *title)
228
203
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (stage_window);
231
205
/* Empty window titles not allowed, so set it to just a period. */
232
206
if (title == NULL || !title[0])
235
wtitle = g_utf8_to_utf16 (title, -1, NULL, NULL, NULL);
236
SetWindowTextW (stage_win32->hwnd, wtitle);
209
if (stage_win32->wtitle != NULL)
210
g_free (stage_win32->wtitle);
211
stage_win32->wtitle = g_utf8_to_utf16 (title, -1, NULL, NULL, NULL);
213
/* If the window is not yet created, the title will be set during the
215
if (stage_win32->hwnd != NULL)
216
SetWindowTextW (stage_win32->hwnd, stage_win32->wtitle);
220
_clutter_stage_win32_update_cursor (ClutterStageWin32 *stage_win32)
224
if (stage_win32->is_cursor_visible)
225
cursor = (HCURSOR) GetClassLongPtrW (stage_win32->hwnd, GCL_HCURSOR);
228
ClutterBackend *backend = clutter_get_default_backend ();
229
/* The documentation implies that we can just use
230
SetCursor(NULL) to get rid of the cursor but apparently this
231
doesn't work very well so instead we create an invisible
233
cursor = _clutter_backend_win32_get_invisible_cursor (backend);
240
clutter_stage_win32_set_cursor_visible (ClutterStageWindow *stage_window,
241
gboolean cursor_visible)
243
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (stage_window);
245
if (stage_win32->is_cursor_visible != cursor_visible)
250
stage_win32->is_cursor_visible = cursor_visible;
252
/* If the cursor is already over the client area of the window
253
then we need to update it immediately */
254
GetCursorPos (&cursor_pos);
255
if (WindowFromPoint (cursor_pos) == stage_win32->hwnd &&
256
ScreenToClient (stage_win32->hwnd, &cursor_pos) &&
257
GetClientRect (stage_win32->hwnd, &client_rect) &&
258
cursor_pos.x >= client_rect.left &&
259
cursor_pos.y >= client_rect.top &&
260
cursor_pos.x < client_rect.right &&
261
cursor_pos.y < client_rect.bottom)
262
_clutter_stage_win32_update_cursor (stage_win32);
296
322
| (old_style & WS_VISIBLE));
297
323
/* Update the window size */
300
get_fullscreen_rect (stage_win32);
301
SetWindowPos (hwnd, HWND_TOP,
302
stage_win32->fullscreen_rect.left,
303
stage_win32->fullscreen_rect.top,
304
stage_win32->fullscreen_rect.right
305
- stage_win32->fullscreen_rect.left,
306
stage_win32->fullscreen_rect.bottom
307
- stage_win32->fullscreen_rect.top,
326
get_fullscreen_rect (stage_win32);
327
SetWindowPos (hwnd, HWND_TOP,
328
stage_win32->fullscreen_rect.left,
329
stage_win32->fullscreen_rect.top,
330
stage_win32->fullscreen_rect.right
331
- stage_win32->fullscreen_rect.left,
332
stage_win32->fullscreen_rect.bottom
333
- stage_win32->fullscreen_rect.top,
312
int full_width, full_height;
314
get_full_window_size (stage_win32,
315
stage_win32->win_width,
316
stage_win32->win_height,
317
&full_width, &full_height);
319
SetWindowPos (stage_win32->hwnd, NULL,
321
full_width, full_height,
322
SWP_NOZORDER | SWP_NOMOVE);
338
int full_width, full_height;
340
get_full_window_size (stage_win32,
341
stage_win32->win_width,
342
stage_win32->win_height,
343
&full_width, &full_height);
345
SetWindowPos (stage_win32->hwnd, NULL,
347
full_width, full_height,
348
SWP_NOZORDER | SWP_NOMOVE);
325
351
CLUTTER_SET_PRIVATE_FLAGS (stage_win32->wrapper,
326
352
CLUTTER_ACTOR_SYNC_MATRICES);
363
clutter_stage_win32_check_gl_version ()
365
const char *version_string, *major_end, *minor_end;
366
int major = 0, minor = 0;
368
/* Get the OpenGL version number */
369
if ((version_string = (const char *) glGetString (GL_VERSION)) == NULL)
372
/* Extract the major number */
373
for (major_end = version_string; *major_end >= '0'
374
&& *major_end <= '9'; major_end++)
375
major = (major * 10) + *major_end - '0';
376
/* If there were no digits or the major number isn't followed by a
377
dot then it is invalid */
378
if (major_end == version_string || *major_end != '.')
381
/* Extract the minor number */
382
for (minor_end = major_end + 1; *minor_end >= '0'
383
&& *minor_end <= '9'; minor_end++)
384
minor = (minor * 10) + *minor_end - '0';
385
/* If there were no digits or there is an unexpected character then
387
if (minor_end == major_end + 1
388
|| (*minor_end && *minor_end != ' ' && *minor_end != '.'))
391
/* Accept OpenGL 1.2 or later */
392
return major > 1 || (major == 1 && minor >= 2);
396
clutter_stage_win32_pixel_format_is_better (const PIXELFORMATDESCRIPTOR *pfa,
397
const PIXELFORMATDESCRIPTOR *pfb)
399
/* Always prefer a format with a stencil buffer */
400
if (pfa->cStencilBits == 0)
402
if (pfb->cStencilBits > 0)
405
else if (pfb->cStencilBits == 0)
408
/* Prefer a bigger color buffer */
409
if (pfb->cColorBits > pfa->cColorBits)
411
else if (pfb->cColorBits < pfa->cColorBits)
414
/* Prefer a bigger depth buffer */
415
return pfb->cDepthBits > pfa->cDepthBits;
419
clutter_stage_win32_choose_pixel_format (HDC dc, PIXELFORMATDESCRIPTOR *pfd)
421
int i, num_formats, best_pf = 0;
422
PIXELFORMATDESCRIPTOR best_pfd;
424
num_formats = DescribePixelFormat (dc, 0, sizeof (best_pfd), NULL);
426
for (i = 1; i <= num_formats; i++)
428
memset (pfd, 0, sizeof (*pfd));
430
if (DescribePixelFormat (dc, i, sizeof (best_pfd), pfd)
431
/* Check whether this format is useable by Clutter */
432
&& ((pfd->dwFlags & (PFD_SUPPORT_OPENGL
435
| PFD_GENERIC_FORMAT))
436
== (PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW))
437
&& pfd->iPixelType == PFD_TYPE_RGBA
438
&& pfd->cColorBits >= 16 && pfd->cColorBits <= 32
439
&& pfd->cDepthBits >= 16 && pfd->cDepthBits <= 32
440
/* Check whether this is a better format than one we've
443
|| clutter_stage_win32_pixel_format_is_better (&best_pfd, pfd)))
456
clutter_stage_win32_realize (ClutterActor *actor)
458
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (actor);
389
clutter_stage_win32_realize (ClutterStageWindow *stage_window)
391
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (stage_window);
459
392
ClutterBackendWin32 *backend_win32;
460
393
PIXELFORMATDESCRIPTOR pfd;
395
GError *error = NULL;
463
397
CLUTTER_NOTE (MISC, "Realizing main stage");
470
404
int win_xpos, win_ypos, win_width, win_height;
472
406
if (window_class == 0)
474
408
g_critical ("Unable to register window class");
478
412
/* If we're in fullscreen mode then use the fullscreen rect
480
414
if ((stage_win32->state & CLUTTER_STAGE_STATE_FULLSCREEN))
482
get_fullscreen_rect (stage_win32);
483
win_xpos = stage_win32->fullscreen_rect.left;
484
win_ypos = stage_win32->fullscreen_rect.top;
485
win_width = stage_win32->fullscreen_rect.right - win_xpos;
486
win_height = stage_win32->fullscreen_rect.left - win_ypos;
416
get_fullscreen_rect (stage_win32);
417
win_xpos = stage_win32->fullscreen_rect.left;
418
win_ypos = stage_win32->fullscreen_rect.top;
419
win_width = stage_win32->fullscreen_rect.right - win_xpos;
420
win_height = stage_win32->fullscreen_rect.bottom - win_ypos;
490
win_xpos = win_ypos = CW_USEDEFAULT;
492
get_full_window_size (stage_win32,
493
stage_win32->win_width,
494
stage_win32->win_height,
495
&win_width, &win_height);
424
win_xpos = win_ypos = CW_USEDEFAULT;
426
get_full_window_size (stage_win32,
427
stage_win32->win_width,
428
stage_win32->win_height,
429
&win_width, &win_height);
432
if (stage_win32->wtitle == NULL)
433
stage_win32->wtitle = g_utf8_to_utf16 (".", -1, NULL, NULL, NULL);
498
435
stage_win32->hwnd = CreateWindowW ((LPWSTR) MAKEINTATOM (window_class),
500
437
get_window_style (stage_win32),
523
460
stage_win32->client_dc = GetDC (stage_win32->hwnd);
525
pf = clutter_stage_win32_choose_pixel_format (stage_win32->client_dc, &pfd);
527
if (pf == 0 || !SetPixelFormat (stage_win32->client_dc, pf, &pfd))
462
/* Create a context. This will be a no-op if we already have one */
463
if (!_clutter_backend_create_context (CLUTTER_BACKEND (backend_win32),
466
g_critical ("Unable to realize stage: %s", error->message);
467
g_error_free (error);
471
/* Use the same pixel format as the dummy DC */
472
pf = GetPixelFormat (backend_win32->dummy_dc);
473
DescribePixelFormat (backend_win32->dummy_dc, pf, sizeof (pfd), &pfd);
474
if (!SetPixelFormat (stage_win32->client_dc, pf, &pfd))
529
476
g_critical ("Unable to find suitable GL pixel format");
533
if (backend_win32->gl_context == NULL)
535
backend_win32->gl_context = wglCreateContext (stage_win32->client_dc);
537
if (backend_win32->gl_context == NULL)
539
g_critical ("Unable to create suitable GL context");
543
/* Make the context current so we can check the GL version */
544
wglMakeCurrent (stage_win32->client_dc, backend_win32->gl_context);
546
if (!clutter_stage_win32_check_gl_version ())
548
g_critical ("OpenGL version number is too low");
553
480
CLUTTER_NOTE (BACKEND, "Successfully realized stage");
558
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
562
clutter_stage_win32_unrealize (ClutterActor *actor)
489
clutter_stage_win32_unprepare_window (ClutterStageWin32 *stage_win32)
564
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (actor);
566
CLUTTER_NOTE (BACKEND, "Unrealizing stage");
568
if (CLUTTER_ACTOR_CLASS (clutter_stage_win32_parent_class)->unrealize != NULL)
569
CLUTTER_ACTOR_CLASS (clutter_stage_win32_parent_class)->unrealize (actor);
571
491
if (stage_win32->client_dc)
573
493
ReleaseDC (stage_win32->hwnd, stage_win32->client_dc);
577
497
if (!stage_win32->is_foreign_win && stage_win32->hwnd)
579
499
/* Drop the pointer to this stage in the window so that any
580
further messages won't be processed. The stage might be being
581
destroyed so otherwise the messages would be handled with an
582
invalid stage instance */
500
further messages won't be processed. The stage might be being
501
destroyed so otherwise the messages would be handled with an
502
invalid stage instance */
583
503
SetWindowLongPtrW (stage_win32->hwnd, 0, (LONG_PTR) 0);
584
504
DestroyWindow (stage_win32->hwnd);
585
stage_win32->hwnd = NULL;
509
clutter_stage_win32_unrealize (ClutterStageWindow *stage_window)
511
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (stage_window);
513
CLUTTER_NOTE (BACKEND, "Unrealizing stage");
515
clutter_stage_win32_unprepare_window (stage_win32);
590
519
clutter_stage_win32_dispose (GObject *gobject)
592
521
ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (gobject);
523
/* Make sure that context and window are destroyed in case unrealize
524
* hasn't been called yet.
526
if (stage_win32->hwnd)
527
clutter_stage_win32_unprepare_window (stage_win32);
529
if (stage_win32->wtitle)
530
g_free (stage_win32->wtitle);
594
532
G_OBJECT_CLASS (clutter_stage_win32_parent_class)->dispose (gobject);
598
536
clutter_stage_win32_class_init (ClutterStageWin32Class *klass)
600
538
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
601
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
603
540
gobject_class->dispose = clutter_stage_win32_dispose;
605
actor_class->get_preferred_width = clutter_stage_win32_get_preferred_width;
606
actor_class->get_preferred_height = clutter_stage_win32_get_preferred_height;
607
actor_class->allocate = clutter_stage_win32_allocate;
608
actor_class->realize = clutter_stage_win32_realize;
609
actor_class->unrealize = clutter_stage_win32_unrealize;
631
563
iface->get_wrapper = clutter_stage_win32_get_wrapper;
632
564
iface->set_title = clutter_stage_win32_set_title;
633
565
iface->set_fullscreen = clutter_stage_win32_set_fullscreen;
566
iface->set_cursor_visible = clutter_stage_win32_set_cursor_visible;
634
567
iface->set_user_resizable = clutter_stage_win32_set_user_resize;
635
568
iface->show = clutter_stage_win32_show;
636
569
iface->hide = clutter_stage_win32_hide;
570
iface->resize = clutter_stage_win32_resize;
571
iface->get_geometry = clutter_stage_win32_get_geometry;
572
iface->realize = clutter_stage_win32_realize;
573
iface->unrealize = clutter_stage_win32_unrealize;