rev |
line source |
nuclear@19
|
1 /* SimplyGL window system module for Cocoa */
|
nuclear@13
|
2 /* mac-framework: -framework Cocoa */
|
nuclear@13
|
3
|
nuclear@13
|
4 #include "config.h"
|
nuclear@13
|
5
|
nuclear@13
|
6 #ifdef USE_WSYS_MODULE_COCOA
|
nuclear@13
|
7
|
nuclear@15
|
8 #import <Cocoa/Cocoa.h>
|
nuclear@13
|
9 #include "sgl.h"
|
nuclear@15
|
10 #include "wsys.h"
|
nuclear@13
|
11
|
nuclear@15
|
12 @interface OpenGLView : NSOpenGLView
|
nuclear@13
|
13 {
|
nuclear@15
|
14 int foo;
|
nuclear@13
|
15 }
|
nuclear@13
|
16
|
nuclear@17
|
17 -(id) initWithFrame: (NSRect) frame pixelFormat: (NSOpenGLPixelFormat*) pf;
|
nuclear@13
|
18
|
nuclear@13
|
19 -(void) drawRect: (NSRect) rect;
|
nuclear@13
|
20 -(void) reshape;
|
nuclear@15
|
21 /*-(void) keyDown: (NSEvent*) ev;
|
nuclear@13
|
22 -(void) keyUp: (NSEvent*) ev;
|
nuclear@13
|
23 -(void) mouseDown: (NSEvent*) ev;
|
nuclear@13
|
24 -(void) mouseUp: (NSEvent*) ev;
|
nuclear@13
|
25 -(void) rightMouseDown: (NSEvent*) ev;
|
nuclear@13
|
26 -(void) rightMouseUp: (NSEvent*) ev;
|
nuclear@13
|
27 -(void) otherMouseDown: (NSEvent*) ev;
|
nuclear@13
|
28 -(void) otherMouseUp: (NSEvent*) ev;
|
nuclear@13
|
29 -(void) mouseDragged: (NSEvent*) ev;
|
nuclear@13
|
30 -(void) rightMouseDragged: (NSEvent*) ev;
|
nuclear@15
|
31 -(void) otherMouseDragged: (NSEvent*) ev;*/
|
nuclear@13
|
32
|
nuclear@13
|
33 -(BOOL) acceptsFirstResponder;
|
nuclear@13
|
34 @end
|
nuclear@13
|
35
|
nuclear@17
|
36
|
nuclear@17
|
37 @interface AppDelegate : NSObject
|
nuclear@16
|
38 {
|
nuclear@17
|
39 int foo;
|
nuclear@16
|
40 }
|
nuclear@17
|
41 -(BOOL) applicationShouldTerminate: (NSApplication*) app;
|
nuclear@16
|
42 -(BOOL) applicationShouldTerminateAfterLastWindowClosed: (NSApplication*)app;
|
nuclear@16
|
43 @end
|
nuclear@16
|
44
|
nuclear@17
|
45
|
nuclear@13
|
46 struct window {
|
nuclear@13
|
47 int wid;
|
nuclear@15
|
48 int width, height;
|
nuclear@13
|
49 NSWindow *win;
|
nuclear@15
|
50 OpenGLView *view;
|
nuclear@15
|
51 NSOpenGLContext *ctx;
|
nuclear@15
|
52 int needs_redisplay;
|
nuclear@13
|
53 struct window *next;
|
nuclear@13
|
54 };
|
nuclear@13
|
55
|
nuclear@13
|
56
|
nuclear@13
|
57 static int init(void);
|
nuclear@13
|
58 static void shutdown(void);
|
nuclear@13
|
59
|
nuclear@13
|
60 /* video mode switching */
|
nuclear@13
|
61 static int set_vidmode(int xsz, int ysz);
|
nuclear@13
|
62 static int get_vidmode(int *xsz, int *ysz);
|
nuclear@13
|
63
|
nuclear@13
|
64 /* create/destroy windows */
|
nuclear@13
|
65 static int create_window(int xsz, int ysz, unsigned int flags);
|
nuclear@13
|
66 static void close_window(int wid);
|
nuclear@13
|
67
|
nuclear@13
|
68 /* window management */
|
nuclear@13
|
69 static int set_active(int wid);
|
nuclear@13
|
70 static struct window *find_window(int wid);
|
nuclear@13
|
71 static int activate_window(struct window *win);
|
nuclear@13
|
72 static int set_title(const char *str);
|
nuclear@13
|
73 static void redisplay(void);
|
nuclear@13
|
74 static void swap_buffers(void);
|
nuclear@13
|
75
|
nuclear@13
|
76 static int get_modifiers(void);
|
nuclear@13
|
77
|
nuclear@13
|
78 /* event handling and friends */
|
nuclear@13
|
79 static void set_event(int idx, int enable);
|
nuclear@13
|
80 static int process_events(void);
|
nuclear@17
|
81
|
nuclear@17
|
82 static void fill_attr(NSOpenGLPixelFormatAttribute *attr, unsigned int flags);
|
nuclear@13
|
83
|
nuclear@13
|
84
|
nuclear@13
|
85 static struct wsys_module ws = {
|
nuclear@13
|
86 "cocoa", 0,
|
nuclear@13
|
87 init,
|
nuclear@13
|
88 shutdown,
|
nuclear@13
|
89 set_vidmode,
|
nuclear@13
|
90 get_vidmode,
|
nuclear@13
|
91 create_window,
|
nuclear@13
|
92 close_window,
|
nuclear@13
|
93 set_active,
|
nuclear@13
|
94 set_title,
|
nuclear@13
|
95 redisplay,
|
nuclear@13
|
96 swap_buffers,
|
nuclear@13
|
97 get_modifiers,
|
nuclear@13
|
98 set_event,
|
nuclear@13
|
99 process_events,
|
nuclear@13
|
100 0
|
nuclear@13
|
101 };
|
nuclear@13
|
102
|
nuclear@13
|
103 static struct window *winlist, *active_win;
|
nuclear@17
|
104 static int quit_main_loop;
|
nuclear@13
|
105
|
nuclear@13
|
106
|
nuclear@13
|
107 void sgl_register_cocoa(void)
|
nuclear@13
|
108 {
|
nuclear@15
|
109 sgl_register_module(&ws);
|
nuclear@13
|
110 }
|
nuclear@13
|
111
|
nuclear@13
|
112
|
nuclear@15
|
113 @implementation OpenGLView
|
nuclear@16
|
114
|
nuclear@17
|
115 -(id) initWithFrame: (NSRect) frame pixelFormat: (NSOpenGLPixelFormat*) pf
|
nuclear@16
|
116 {
|
nuclear@17
|
117 self = [super initWithFrame: frame pixelFormat: pf];
|
nuclear@17
|
118 return self;
|
nuclear@16
|
119 }
|
nuclear@13
|
120
|
nuclear@13
|
121 -(void) drawRect: (NSRect) rect
|
nuclear@13
|
122 {
|
nuclear@13
|
123 sgl_display_callback_t func = sgl_get_callback(SGL_DISPLAY);
|
nuclear@13
|
124 if(func) {
|
nuclear@13
|
125 func();
|
nuclear@13
|
126 }
|
nuclear@13
|
127 }
|
nuclear@13
|
128
|
nuclear@13
|
129 -(void) reshape
|
nuclear@13
|
130 {
|
nuclear@15
|
131 NSSize sz;
|
nuclear@15
|
132 sgl_reshape_callback_t func;
|
nuclear@15
|
133
|
nuclear@15
|
134 sz = [self bounds].size;
|
nuclear@15
|
135
|
nuclear@15
|
136 if((func = sgl_get_callback(SGL_RESHAPE)) && (sz.width != active_win->width ||
|
nuclear@15
|
137 sz.height != active_win->height)) {
|
nuclear@15
|
138 active_win->width = sz.width;
|
nuclear@15
|
139 active_win->height = sz.height;
|
nuclear@15
|
140 func(sz.width, sz.height);
|
nuclear@13
|
141 }
|
nuclear@13
|
142 }
|
nuclear@13
|
143
|
nuclear@13
|
144 -(BOOL) acceptsFirstResponder
|
nuclear@13
|
145 {
|
nuclear@13
|
146 return YES;
|
nuclear@13
|
147 }
|
nuclear@13
|
148 @end
|
nuclear@13
|
149
|
nuclear@17
|
150 @implementation AppDelegate
|
nuclear@17
|
151 -(BOOL) applicationShouldTerminate: (NSApplication*) app
|
nuclear@17
|
152 {
|
nuclear@17
|
153 return NSTerminateNow;
|
nuclear@17
|
154 }
|
nuclear@17
|
155
|
nuclear@17
|
156 -(BOOL) applicationShouldTerminateAfterLastWindowClosed: (NSApplication*) app
|
nuclear@16
|
157 {
|
nuclear@16
|
158 return YES;
|
nuclear@16
|
159 }
|
nuclear@17
|
160
|
nuclear@17
|
161 -(void) applicationWillTerminate: (NSNotification*) notification
|
nuclear@17
|
162 {
|
nuclear@17
|
163 printf("applicationWillTerminate\n");
|
nuclear@17
|
164 }
|
nuclear@17
|
165
|
nuclear@17
|
166 -(BOOL) windowShouldClose: (id) win
|
nuclear@17
|
167 {
|
nuclear@17
|
168 return YES;
|
nuclear@17
|
169 }
|
nuclear@17
|
170
|
nuclear@17
|
171 -(void) windowWillClose: (NSNotification*) notification
|
nuclear@17
|
172 {
|
nuclear@17
|
173 [NSApp terminate: nil];
|
nuclear@17
|
174 }
|
nuclear@16
|
175 @end
|
nuclear@16
|
176
|
nuclear@13
|
177 static int init(void)
|
nuclear@13
|
178 {
|
nuclear@17
|
179 AppDelegate *delegate;
|
nuclear@16
|
180
|
nuclear@16
|
181 [NSApplication sharedApplication];
|
nuclear@17
|
182
|
nuclear@17
|
183 delegate = [[AppDelegate alloc] init];
|
nuclear@16
|
184 [NSApp setDelegate: delegate];
|
nuclear@15
|
185 return 0;
|
nuclear@13
|
186 }
|
nuclear@13
|
187
|
nuclear@13
|
188 static void shutdown(void)
|
nuclear@13
|
189 {
|
nuclear@13
|
190 while(winlist) {
|
nuclear@13
|
191 struct window *win = winlist;
|
nuclear@13
|
192 winlist = winlist->next;
|
nuclear@13
|
193
|
nuclear@15
|
194 /* TODO destroy window */
|
nuclear@13
|
195 free(win);
|
nuclear@13
|
196 }
|
nuclear@16
|
197
|
nuclear@17
|
198 quit_main_loop = 1;
|
nuclear@13
|
199 }
|
nuclear@13
|
200
|
nuclear@13
|
201
|
nuclear@13
|
202 /* video mode switching */
|
nuclear@13
|
203 static int set_vidmode(int xsz, int ysz)
|
nuclear@13
|
204 {
|
nuclear@13
|
205 return 0; /* TODO */
|
nuclear@13
|
206 }
|
nuclear@13
|
207
|
nuclear@13
|
208 static int get_vidmode(int *xsz, int *ysz)
|
nuclear@13
|
209 {
|
nuclear@13
|
210 return 0; /* TODO */
|
nuclear@13
|
211 }
|
nuclear@13
|
212
|
nuclear@13
|
213
|
nuclear@13
|
214 /* create/destroy windows */
|
nuclear@13
|
215 static int create_window(int xsz, int ysz, unsigned int flags)
|
nuclear@13
|
216 {
|
nuclear@17
|
217 NSAutoreleasePool *pool;
|
nuclear@13
|
218 NSWindow *nswin;
|
nuclear@13
|
219 NSRect rect;
|
nuclear@15
|
220 OpenGLView *view;
|
nuclear@17
|
221 NSOpenGLPixelFormat *pf;
|
nuclear@17
|
222 NSOpenGLPixelFormatAttribute attr[32];
|
nuclear@13
|
223 unsigned int style;
|
nuclear@15
|
224 struct window *win;
|
nuclear@13
|
225 static int next_id = 1;
|
nuclear@13
|
226
|
nuclear@13
|
227 if(!(win = malloc(sizeof *win))) {
|
nuclear@13
|
228 return -1;
|
nuclear@13
|
229 }
|
nuclear@13
|
230
|
nuclear@17
|
231 pool = [[NSAutoreleasePool alloc] init];
|
nuclear@17
|
232
|
nuclear@17
|
233 /* create the view */
|
nuclear@17
|
234 fill_attr(attr, flags);
|
nuclear@17
|
235 pf = [[[NSOpenGLPixelFormat alloc] initWithAttributes: attr] autorelease];
|
nuclear@17
|
236 view = [[OpenGLView alloc] initWithFrame: rect pixelFormat: pf];
|
nuclear@17
|
237
|
nuclear@13
|
238 /* create the window and attach the OpenGL view */
|
nuclear@15
|
239 rect.origin.x = rect.origin.y = 0;
|
nuclear@15
|
240 rect.size.width = xsz;
|
nuclear@15
|
241 rect.size.height = ysz;
|
nuclear@13
|
242
|
nuclear@15
|
243 style = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask |
|
nuclear@15
|
244 NSResizableWindowMask;
|
nuclear@13
|
245
|
nuclear@13
|
246 nswin = [[NSWindow alloc] initWithContentRect: rect styleMask: style
|
nuclear@13
|
247 backing: NSBackingStoreBuffered defer: YES];
|
nuclear@17
|
248
|
nuclear@16
|
249 [nswin setTitle: @"OpenGL/Cocoa"];
|
nuclear@17
|
250 [nswin setReleasedWhenClosed: YES];
|
nuclear@13
|
251 [nswin setContentView: view];
|
nuclear@16
|
252 [nswin makeFirstResponder: view];
|
nuclear@16
|
253 [nswin makeKeyAndOrderFront: nil];
|
nuclear@15
|
254 [view release];
|
nuclear@13
|
255
|
nuclear@13
|
256 win->win = nswin;
|
nuclear@13
|
257 win->view = view;
|
nuclear@15
|
258 win->ctx = [view openGLContext];
|
nuclear@13
|
259 win->wid = next_id++;
|
nuclear@15
|
260 win->needs_redisplay = 1;
|
nuclear@13
|
261 win->next = winlist;
|
nuclear@13
|
262 winlist = win;
|
nuclear@13
|
263
|
nuclear@15
|
264 if(!active_win) {
|
nuclear@15
|
265 activate_window(win);
|
nuclear@15
|
266 }
|
nuclear@17
|
267
|
nuclear@17
|
268 [pool drain];
|
nuclear@13
|
269 return win->wid;
|
nuclear@13
|
270 }
|
nuclear@13
|
271
|
nuclear@13
|
272 static void close_window(int wid)
|
nuclear@13
|
273 {
|
nuclear@13
|
274 struct window *win, *prev, dummy;
|
nuclear@13
|
275 sgl_close_callback_t close_func;
|
nuclear@13
|
276
|
nuclear@13
|
277 dummy.next = win = winlist;
|
nuclear@13
|
278 prev = &dummy;
|
nuclear@13
|
279
|
nuclear@13
|
280 while(win) {
|
nuclear@13
|
281 if(win->wid == wid) {
|
nuclear@13
|
282 if(!(close_func = sgl_get_callback(SGL_CLOSE))) {
|
nuclear@13
|
283 close_func(wid);
|
nuclear@13
|
284 }
|
nuclear@13
|
285 [win->win close];
|
nuclear@13
|
286
|
nuclear@13
|
287 if(active_win == win) {
|
nuclear@13
|
288 activate_window(winlist);
|
nuclear@13
|
289 }
|
nuclear@13
|
290
|
nuclear@13
|
291 prev->next = win->next;
|
nuclear@13
|
292 free(win);
|
nuclear@13
|
293 return;
|
nuclear@13
|
294 }
|
nuclear@13
|
295 prev = win;
|
nuclear@13
|
296 win = win->next;
|
nuclear@13
|
297 }
|
nuclear@13
|
298 }
|
nuclear@13
|
299
|
nuclear@13
|
300
|
nuclear@13
|
301 /* window management */
|
nuclear@13
|
302 static int set_active(int wid)
|
nuclear@13
|
303 {
|
nuclear@15
|
304 struct window *win = find_window(wid);
|
nuclear@15
|
305 return activate_window(win);
|
nuclear@13
|
306 }
|
nuclear@13
|
307
|
nuclear@13
|
308 static struct window *find_window(int wid)
|
nuclear@13
|
309 {
|
nuclear@13
|
310 struct window *win = winlist;
|
nuclear@13
|
311
|
nuclear@13
|
312 while(win) {
|
nuclear@15
|
313 if(win->wid == wid) {
|
nuclear@13
|
314 return win;
|
nuclear@13
|
315 }
|
nuclear@13
|
316 win = win->next;
|
nuclear@13
|
317 }
|
nuclear@13
|
318 return 0;
|
nuclear@13
|
319 }
|
nuclear@13
|
320
|
nuclear@13
|
321 static int activate_window(struct window *win)
|
nuclear@13
|
322 {
|
nuclear@13
|
323 if(!win) {
|
nuclear@13
|
324 return -1;
|
nuclear@13
|
325 }
|
nuclear@13
|
326 [win->ctx makeCurrentContext];
|
nuclear@13
|
327 active_win = win;
|
nuclear@13
|
328 return 0;
|
nuclear@13
|
329 }
|
nuclear@13
|
330
|
nuclear@13
|
331 static int set_title(const char *str)
|
nuclear@13
|
332 {
|
nuclear@13
|
333 NSString *nsstr;
|
nuclear@13
|
334
|
nuclear@13
|
335 nsstr = [[NSString alloc] initWithCString: str encoding: NSASCIIStringEncoding];
|
nuclear@13
|
336 [active_win->win setTitle: nsstr];
|
nuclear@13
|
337 [nsstr release];
|
nuclear@15
|
338 return 0;
|
nuclear@13
|
339 }
|
nuclear@13
|
340
|
nuclear@13
|
341 static void redisplay(void)
|
nuclear@13
|
342 {
|
nuclear@15
|
343 active_win->needs_redisplay = 1;
|
nuclear@13
|
344 }
|
nuclear@13
|
345
|
nuclear@13
|
346 static void swap_buffers(void)
|
nuclear@13
|
347 {
|
nuclear@15
|
348 [active_win->ctx flushBuffer];
|
nuclear@13
|
349 }
|
nuclear@13
|
350
|
nuclear@13
|
351
|
nuclear@13
|
352 static int get_modifiers(void)
|
nuclear@13
|
353 {
|
nuclear@13
|
354 return 0; /* TODO */
|
nuclear@13
|
355 }
|
nuclear@13
|
356
|
nuclear@13
|
357
|
nuclear@13
|
358 /* event handling and friends */
|
nuclear@13
|
359 static void set_event(int idx, int enable)
|
nuclear@13
|
360 {
|
nuclear@13
|
361 }
|
nuclear@13
|
362
|
nuclear@13
|
363 static int process_events(void)
|
nuclear@13
|
364 {
|
nuclear@13
|
365 NSAutoreleasePool *pool;
|
nuclear@17
|
366 NSRunLoop *runloop;
|
nuclear@17
|
367 NSDate *block, *nonblock, *limdate;
|
nuclear@17
|
368
|
nuclear@14
|
369 sgl_idle_callback_t idle;
|
nuclear@15
|
370 sgl_display_callback_t disp;
|
nuclear@15
|
371 struct window *win;
|
nuclear@15
|
372 int res = 0;
|
nuclear@15
|
373
|
nuclear@15
|
374 pool = [[NSAutoreleasePool alloc] init];
|
nuclear@16
|
375
|
nuclear@16
|
376 idle = sgl_get_callback(SGL_IDLE);
|
nuclear@15
|
377 disp = sgl_get_callback(SGL_DISPLAY);
|
nuclear@13
|
378
|
nuclear@15
|
379 win = winlist;
|
nuclear@15
|
380 while(win) {
|
nuclear@15
|
381 if(win->needs_redisplay && disp) {
|
nuclear@15
|
382 activate_window(win);
|
nuclear@15
|
383 disp();
|
nuclear@15
|
384 win->needs_redisplay = 0;
|
nuclear@15
|
385 }
|
nuclear@15
|
386 win = win->next;
|
nuclear@15
|
387 }
|
nuclear@15
|
388
|
nuclear@17
|
389 runloop = [[NSRunLoop currentRunLoop] retain];
|
nuclear@17
|
390 block = [runloop limitDateForMode: NSDefaultRunLoopMode];
|
nuclear@17
|
391 nonblock = [[NSDate distantPast] retain];
|
nuclear@16
|
392 limdate = idle ? nonblock : block;
|
nuclear@15
|
393
|
nuclear@17
|
394 while(!quit_main_loop) {
|
nuclear@16
|
395 NSEvent *ev = [NSApp nextEventMatchingMask: NSAnyEventMask untilDate: limdate
|
nuclear@16
|
396 inMode: NSDefaultRunLoopMode dequeue: YES];
|
nuclear@16
|
397 if(!ev) break;
|
nuclear@16
|
398
|
nuclear@16
|
399 [NSApp sendEvent: ev];
|
nuclear@16
|
400 if(limdate == block) {
|
nuclear@16
|
401 limdate = nonblock;
|
nuclear@13
|
402 }
|
nuclear@15
|
403 }
|
nuclear@15
|
404
|
nuclear@15
|
405 if(idle) {
|
nuclear@15
|
406 idle();
|
nuclear@15
|
407 }
|
nuclear@15
|
408
|
nuclear@17
|
409 [runloop release];
|
nuclear@15
|
410 [pool drain];
|
nuclear@17
|
411 return quit_main_loop ? -1 : 0;
|
nuclear@13
|
412 }
|
nuclear@13
|
413
|
nuclear@17
|
414 static void fill_attr(NSOpenGLPixelFormatAttribute *attr, unsigned int flags)
|
nuclear@13
|
415 {
|
nuclear@17
|
416 int i = 0;
|
nuclear@14
|
417
|
nuclear@17
|
418 /* this is very important. makes pixelformat selection behave like GLX
|
nuclear@17
|
419 * where any non-zero value will denote "choose highest possible". This
|
nuclear@17
|
420 * is pretty much what we intend, as the user doesn't actually pass any
|
nuclear@17
|
421 * of these numbers.
|
nuclear@17
|
422 */
|
nuclear@17
|
423 attr[i++] = NSOpenGLPFAMaximumPolicy;
|
nuclear@17
|
424
|
nuclear@17
|
425 attr[i++] = NSOpenGLPFAColorSize;
|
nuclear@17
|
426 attr[i++] = 1;
|
nuclear@17
|
427
|
nuclear@17
|
428 if(flags & SGL_DOUBLE) {
|
nuclear@17
|
429 attr[i++] = NSOpenGLPFADoubleBuffer;
|
nuclear@15
|
430 }
|
nuclear@17
|
431 if(flags & SGL_DEPTH) {
|
nuclear@17
|
432 attr[i++] = NSOpenGLPFADepthSize;
|
nuclear@17
|
433 attr[i++] = 1;
|
nuclear@17
|
434 }
|
nuclear@17
|
435 if(flags & SGL_STENCIL) {
|
nuclear@17
|
436 attr[i++] = NSOpenGLPFAStencilSize;
|
nuclear@17
|
437 attr[i++] = 8; /* max-policy has no effect on stencil selection */
|
nuclear@17
|
438 }
|
nuclear@17
|
439 if(flags & SGL_STEREO) {
|
nuclear@17
|
440 attr[i++] = NSOpenGLPFAStereo;
|
nuclear@17
|
441 }
|
nuclear@17
|
442 if(flags & SGL_MULTISAMPLE) {
|
nuclear@17
|
443 attr[i++] = NSOpenGLPFASampleBuffers;
|
nuclear@17
|
444 attr[i++] = 1;
|
nuclear@17
|
445 attr[i++] = NSOpenGLPFASamples;
|
nuclear@17
|
446 attr[i++] = 4; /* TODO don't hardcode, query */
|
nuclear@17
|
447 }
|
nuclear@17
|
448 attr[i++] = 0;
|
nuclear@13
|
449 }
|
nuclear@13
|
450
|
nuclear@20
|
451 #else
|
nuclear@20
|
452 int sgl_wsys_cocoa_silence_the_fucking_empty_file_warnings;
|
nuclear@13
|
453 #endif /* USE_WSYS_MODULE_COCOA */
|