1 /* Clutter - An OpenGL based 'interactive canvas' library.
2 * OSX backend - initial entry point
3 *
4 * Copyright (C) 2007-2008 Tommi Komulainen <tommi.komulainen@iki.fi>
5 * Copyright (C) 2007 OpenedHand Ltd.
6 * Copyright (C) 2011 Crystalnix <vgachkaylo@crystalnix.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
20 *
21 *
22 */
23 #include "config.h"
24
25 #import "clutter-osx.h"
26 #import "clutter-backend-osx.h"
27 #import "clutter-device-manager-osx.h"
28 #import "clutter-stage-osx.h"
29 #import "clutter-event-loop-osx.h"
30
31 #include "clutter-debug.h"
32 #include "clutter-private.h"
33 #include "clutter-stage-private.h"
34
35 #include "cogl/cogl.h"
36
37 #import <AppKit/AppKit.h>
38
39 #define DEFAULT_FONT_NAME "Lucida Grande 13"
40
41 #define clutter_backend_osx_get_type _clutter_backend_osx_get_type
42
43 G_DEFINE_TYPE (ClutterBackendOSX, clutter_backend_osx, CLUTTER_TYPE_BACKEND)
44
45 /* various flags corresponding to pre init setup calls */
46 static gboolean _no_event_retrieval = FALSE;
47
48 /*************************************************************************/
49 static gboolean
clutter_backend_osx_post_parse(ClutterBackend * backend,GError ** error)50 clutter_backend_osx_post_parse (ClutterBackend *backend,
51 GError **error)
52 {
53 ClutterSettings *settings = clutter_settings_get_default ();
54
55 CLUTTER_OSX_POOL_ALLOC();
56 /* getting standart dpi for main screen */
57 NSDictionary* prop = [[NSScreen mainScreen] deviceDescription];
58 NSSize size;
59 [[prop valueForKey:@"NSDeviceResolution"] getValue:&size];
60 CLUTTER_OSX_POOL_RELEASE();
61
62 /* setting dpi for backend, it needs by font rendering library */
63 if (size.height > 0)
64 {
65 int font_dpi = size.height * 1024;
66
67 g_object_set (settings, "font-dpi", font_dpi, NULL);
68 }
69
70 /* set the default font name */
71 g_object_set (settings, "font-name", DEFAULT_FONT_NAME, NULL);
72
73 /* finish launching the application */
74 [NSApp finishLaunching];
75
76 return TRUE;
77 }
78
79 void
clutter_osx_disable_event_retrieval(void)80 clutter_osx_disable_event_retrieval (void)
81 {
82 if (_clutter_context_is_initialized ())
83 {
84 g_warning ("clutter_osx_disable_event_retrieval() can only be "
85 "called before clutter_init()");
86 return;
87 }
88
89 _no_event_retrieval = TRUE;
90 }
91
92 static ClutterFeatureFlags
clutter_backend_osx_get_features(ClutterBackend * backend)93 clutter_backend_osx_get_features (ClutterBackend *backend)
94 {
95 return CLUTTER_FEATURE_STAGE_MULTIPLE
96 | CLUTTER_FEATURE_STAGE_USER_RESIZE;
97 }
98
99 void
_clutter_backend_osx_events_init(ClutterBackend * backend)100 _clutter_backend_osx_events_init (ClutterBackend *backend)
101 {
102 ClutterBackendOSX *backend_osx = CLUTTER_BACKEND_OSX (backend);
103
104 if (backend_osx->device_manager != NULL)
105 return;
106
107 CLUTTER_NOTE (BACKEND, "init_events");
108
109 backend->device_manager = backend_osx->device_manager =
110 g_object_new (CLUTTER_TYPE_DEVICE_MANAGER_OSX,
111 "backend", CLUTTER_BACKEND(backend_osx),
112 NULL);
113
114 if (!_no_event_retrieval)
115 _clutter_osx_event_loop_init ();
116 }
117
118 static gboolean
clutter_backend_osx_create_context(ClutterBackend * backend,GError ** error)119 clutter_backend_osx_create_context (ClutterBackend *backend,
120 GError **error)
121 {
122 ClutterBackendOSX *backend_osx = CLUTTER_BACKEND_OSX (backend);
123
124 CLUTTER_OSX_POOL_ALLOC();
125
126 if (backend_osx->context == nil)
127 {
128 /* Allocate ourselves a GL context. Since we're supposed to have
129 * only one per backend we can just as well create it now.
130 */
131 NSOpenGLPixelFormatAttribute attrs[] = {
132 NSOpenGLPFADoubleBuffer,
133 NSOpenGLPFADepthSize, 32,
134 NSOpenGLPFAStencilSize, 8,
135 0
136 };
137
138 #ifdef MAC_OS_X_VERSION_10_5
139 const int sw = 1;
140 #else
141 const long sw = 1;
142 #endif
143
144 backend_osx->pixel_format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
145
146 backend_osx->context = [[NSOpenGLContext alloc] initWithFormat: backend_osx->pixel_format
147 shareContext: nil];
148
149 /* Enable vblank sync - http://developer.apple.com/qa/qa2007/qa1521.html */
150 [backend_osx->context setValues:&sw forParameter: NSOpenGLCPSwapInterval];
151
152 CLUTTER_NOTE (BACKEND, "Context was created");
153 }
154
155 [backend_osx->context makeCurrentContext];
156
157 CLUTTER_BACKEND_CLASS (clutter_backend_osx_parent_class)->create_context (backend,
158 error);
159
160 CLUTTER_OSX_POOL_RELEASE();
161
162 return TRUE;
163 }
164
165 static void
clutter_backend_osx_ensure_context(ClutterBackend * backend,ClutterStage * wrapper)166 clutter_backend_osx_ensure_context (ClutterBackend *backend,
167 ClutterStage *wrapper)
168 {
169 ClutterBackendOSX *backend_osx = CLUTTER_BACKEND_OSX (backend);
170
171 CLUTTER_OSX_POOL_ALLOC();
172
173 CLUTTER_NOTE (BACKEND, "ensure_context: wrapper=%p", wrapper);
174
175 if (wrapper)
176 {
177 ClutterStageWindow *impl = _clutter_stage_get_window (wrapper);
178 ClutterStageOSX *stage_osx;
179
180 g_assert (CLUTTER_IS_STAGE_OSX (impl));
181 stage_osx = CLUTTER_STAGE_OSX (impl);
182
183 [backend_osx->context clearDrawable];
184 [backend_osx->context setView:stage_osx->view];
185 [backend_osx->context makeCurrentContext];
186 }
187 else
188 {
189 [backend_osx->context clearDrawable];
190 [NSOpenGLContext clearCurrentContext];
191 }
192
193 CLUTTER_OSX_POOL_RELEASE();
194 }
195
196 /*************************************************************************/
197
198 static void
clutter_backend_osx_init(ClutterBackendOSX * backend_osx)199 clutter_backend_osx_init (ClutterBackendOSX *backend_osx)
200 {
201 const ProcessSerialNumber psn = { 0, kCurrentProcess };
202
203 backend_osx->context = nil;
204 backend_osx->pixel_format = nil;
205
206 /* Bring our app to foreground, background apps don't appear in dock or
207 * accept keyboard focus.
208 */
209 TransformProcessType (&psn, kProcessTransformToForegroundApplication);
210
211 /* Also raise our app to front, otherwise our window will remain under the
212 * terminal.
213 */
214 SetFrontProcess (&psn);
215
216 [NSApplication sharedApplication];
217 }
218
219 static void
clutter_backend_osx_dispose(GObject * object)220 clutter_backend_osx_dispose (GObject *object)
221 {
222 ClutterBackendOSX *self = CLUTTER_BACKEND_OSX (object);
223
224 [self->context release];
225 self->context = NULL;
226
227 [self->pixel_format release];
228 self->pixel_format = NULL;
229
230 G_OBJECT_CLASS (clutter_backend_osx_parent_class)->dispose (object);
231 }
232
233 static void
clutter_backend_osx_class_init(ClutterBackendOSXClass * klass)234 clutter_backend_osx_class_init (ClutterBackendOSXClass *klass)
235 {
236 GObjectClass *object_class = G_OBJECT_CLASS (klass);
237 ClutterBackendClass *backend_class = CLUTTER_BACKEND_CLASS (klass);
238
239 object_class->dispose = clutter_backend_osx_dispose;
240
241 backend_class->stage_window_type = CLUTTER_TYPE_STAGE_OSX;
242
243 backend_class->post_parse = clutter_backend_osx_post_parse;
244 backend_class->get_features = clutter_backend_osx_get_features;
245 backend_class->create_context = clutter_backend_osx_create_context;
246 backend_class->ensure_context = clutter_backend_osx_ensure_context;
247 }
248
249 ClutterBackend *
clutter_backend_osx_new(void)250 clutter_backend_osx_new (void)
251 {
252 return g_object_new (CLUTTER_TYPE_BACKEND_OSX, NULL);
253 }
254