1 /* Clutter.
2 * An OpenGL based 'interactive canvas' library.
3 * Authored By Matthew Allum <mallum@openedhand.com>
4 * Copyright (C) 2006-2007 OpenedHand
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
18 *
19 *
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <windows.h>
27
28 #include "clutter-backend-win32.h"
29 #include "clutter-stage-win32.h"
30 #include "clutter-win32.h"
31 #include "clutter-device-manager-win32.h"
32
33 #include "clutter-event.h"
34 #include "clutter-main.h"
35 #include "clutter-device-manager-private.h"
36 #include "clutter-debug.h"
37 #include "clutter-private.h"
38 #include "clutter-stage-private.h"
39
40 #include "cogl/cogl.h"
41
42 /* prototype decleration for DllMain to satisfy compiler checking in
43 * maintainer mode build.
44 */
45 BOOL WINAPI DllMain (HINSTANCE hinst, DWORD reason, LPVOID reserved);
46
47 G_DEFINE_TYPE (ClutterBackendWin32, clutter_backend_win32,
48 CLUTTER_TYPE_BACKEND);
49
50 typedef int (WINAPI * SwapIntervalProc) (int interval);
51
52 /* singleton object */
53 static ClutterBackendWin32 *backend_singleton = NULL;
54
55 static HINSTANCE clutter_hinst = NULL;
56
57 /* various flags corresponding to pre init setup calls */
58 static gboolean _no_event_retrieval = FALSE;
59
60 static void
clutter_backend_win32_init_events(ClutterBackend * backend)61 clutter_backend_win32_init_events (ClutterBackend *backend)
62 {
63 ClutterBackendWin32 *backend_win32 = CLUTTER_BACKEND_WIN32 (backend);
64
65 CLUTTER_NOTE (EVENT, "initialising the event loop");
66
67 backend->device_manager =
68 g_object_new (CLUTTER_TYPE_DEVICE_MANAGER_WIN32,
69 "backend", backend_win32,
70 NULL);
71
72 if (!_no_event_retrieval)
73 _clutter_backend_win32_events_init (backend);
74 }
75
76 HCURSOR
_clutter_backend_win32_get_invisible_cursor(ClutterBackend * backend)77 _clutter_backend_win32_get_invisible_cursor (ClutterBackend *backend)
78 {
79 ClutterBackendWin32 *backend_win32 = CLUTTER_BACKEND_WIN32 (backend);
80
81 if (backend_win32->invisible_cursor == NULL)
82 backend_win32->invisible_cursor =
83 LoadCursor (clutter_hinst, MAKEINTRESOURCE (42));
84
85 return backend_win32->invisible_cursor;
86 }
87
88 static void
clutter_backend_win32_finalize(GObject * gobject)89 clutter_backend_win32_finalize (GObject *gobject)
90 {
91 backend_singleton = NULL;
92
93 timeEndPeriod (1);
94
95 G_OBJECT_CLASS (clutter_backend_win32_parent_class)->finalize (gobject);
96 }
97
98 static void
clutter_backend_win32_dispose(GObject * gobject)99 clutter_backend_win32_dispose (GObject *gobject)
100 {
101 ClutterBackend *backend = CLUTTER_BACKEND (gobject);
102 ClutterBackendWin32 *backend_win32 = CLUTTER_BACKEND_WIN32 (gobject);
103 ClutterStageManager *stage_manager;
104
105 CLUTTER_NOTE (BACKEND, "Disposing the of stages");
106 stage_manager = clutter_stage_manager_get_default ();
107
108 g_object_unref (stage_manager);
109
110 CLUTTER_NOTE (BACKEND, "Removing the event source");
111 _clutter_backend_win32_events_uninit (CLUTTER_BACKEND (backend_win32));
112
113 G_OBJECT_CLASS (clutter_backend_win32_parent_class)->dispose (gobject);
114
115 if (backend->cogl_context)
116 {
117 cogl_object_unref (backend->cogl_context);
118 backend->cogl_context = NULL;
119 }
120 }
121
122 static GObject *
clutter_backend_win32_constructor(GType gtype,guint n_params,GObjectConstructParam * params)123 clutter_backend_win32_constructor (GType gtype,
124 guint n_params,
125 GObjectConstructParam *params)
126 {
127 GObjectClass *parent_class;
128 GObject *retval;
129
130 if (!backend_singleton)
131 {
132 parent_class = G_OBJECT_CLASS (clutter_backend_win32_parent_class);
133 retval = parent_class->constructor (gtype, n_params, params);
134
135 backend_singleton = CLUTTER_BACKEND_WIN32 (retval);
136
137 return retval;
138 }
139
140 g_warning ("Attempting to create a new backend object. This should "
141 "never happen, so we return the singleton instance.");
142
143 return g_object_ref (backend_singleton);
144 }
145
146 ClutterFeatureFlags
clutter_backend_win32_get_features(ClutterBackend * backend)147 clutter_backend_win32_get_features (ClutterBackend *backend)
148 {
149 ClutterBackendClass *parent_class;
150
151 parent_class = CLUTTER_BACKEND_CLASS (clutter_backend_win32_parent_class);
152
153 return parent_class->get_features (backend)
154 | CLUTTER_FEATURE_STAGE_USER_RESIZE
155 | CLUTTER_FEATURE_STAGE_CURSOR;
156 }
157
158 /**
159 * clutter_win32_disable_event_retrieval
160 *
161 * Disables retrieval of Windows messages in the main loop. Use to
162 * create event-less canvas.
163 *
164 * This function can only be called before calling clutter_init().
165 *
166 * Since: 0.8
167 */
168 void
clutter_win32_disable_event_retrieval(void)169 clutter_win32_disable_event_retrieval (void)
170 {
171 if (_clutter_context_is_initialized ())
172 {
173 g_warning ("clutter_win32_disable_event_retrieval() can only be "
174 "called before clutter_init()");
175 return;
176 }
177
178 _no_event_retrieval = TRUE;
179 }
180
181 static CoglRenderer *
clutter_backend_win32_get_renderer(ClutterBackend * backend,GError ** error)182 clutter_backend_win32_get_renderer (ClutterBackend *backend,
183 GError **error)
184 {
185 CoglRenderer *renderer;
186
187 CLUTTER_NOTE (BACKEND, "Creating a new WGL renderer");
188
189 renderer = cogl_renderer_new ();
190 cogl_renderer_set_winsys_id (renderer, COGL_WINSYS_ID_WGL);
191
192 /* We don't want Cogl to install its default event handler because
193 * we'll handle them manually */
194 cogl_win32_renderer_set_event_retrieval_enabled (renderer, FALSE);
195
196 return renderer;
197 }
198
199 static void
clutter_backend_win32_class_init(ClutterBackendWin32Class * klass)200 clutter_backend_win32_class_init (ClutterBackendWin32Class *klass)
201 {
202 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
203 ClutterBackendClass *backend_class = CLUTTER_BACKEND_CLASS (klass);
204
205 gobject_class->constructor = clutter_backend_win32_constructor;
206 gobject_class->dispose = clutter_backend_win32_dispose;
207 gobject_class->finalize = clutter_backend_win32_finalize;
208
209 backend_class->stage_window_type = CLUTTER_TYPE_STAGE_WIN32;
210
211 backend_class->init_events = clutter_backend_win32_init_events;
212 backend_class->get_features = clutter_backend_win32_get_features;
213 backend_class->get_renderer = clutter_backend_win32_get_renderer;
214 }
215
216 static void
clutter_backend_win32_init(ClutterBackendWin32 * backend_win32)217 clutter_backend_win32_init (ClutterBackendWin32 *backend_win32)
218 {
219 backend_win32->invisible_cursor = NULL;
220
221 /* FIXME: get from GetSystemMetric?
222 clutter_backend_set_double_click_time (backend, 250);
223 clutter_backend_set_double_click_distance (backend, 5);
224 clutter_backend_set_resolution (backend, 96.0);
225 */
226
227 /* Set the maximum precision for Windows time functions. Without
228 this glib will not be able to sleep accurately enough to give a
229 reasonable frame rate */
230 timeBeginPeriod (1);
231 }
232
233 BOOL WINAPI
DllMain(HINSTANCE hinst,DWORD reason,LPVOID reserved)234 DllMain (HINSTANCE hinst, DWORD reason, LPVOID reserved)
235 {
236 if (reason == DLL_PROCESS_ATTACH)
237 /* Store the module handle so that we can use it to load resources */
238 clutter_hinst = hinst;
239
240 return TRUE;
241 }
242
243 ClutterBackend *
clutter_backend_win32_new(void)244 clutter_backend_win32_new (void)
245 {
246 return g_object_new (CLUTTER_TYPE_BACKEND_WIN32, NULL);
247 }
248