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