sgl
view src/wsys_cocoa.m @ 32:fc2dba4c5a5f
fuck yeah, I fixed the motherfucker, now let's roll
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sun, 03 Jul 2011 05:23:30 +0300 |
parents | 124195562f7e |
children | 46e90f9c1e0f |
line source
1 /* SimplyGL window system module for Cocoa */
2 /* mac-framework: -framework Cocoa */
4 #include "config.h"
6 #ifdef USE_WSYS_MODULE_COCOA
8 #import <Cocoa/Cocoa.h>
9 #include "sgl.h"
10 #include "wsys.h"
11 #include "log.h"
13 #define APPLE_SUCKS() sgl_log("%s called\n", __func__)
15 @interface OpenGLView : NSOpenGLView
16 {
17 int foo;
18 }
20 -(id) initWithFrame: (NSRect) frame pixelFormat: (NSOpenGLPixelFormat*) pf;
22 -(void) drawRect: (NSRect) rect;
23 -(void) reshape;
24 /*-(void) keyDown: (NSEvent*) ev;
25 -(void) keyUp: (NSEvent*) ev;
26 -(void) mouseDown: (NSEvent*) ev;
27 -(void) mouseUp: (NSEvent*) ev;
28 -(void) rightMouseDown: (NSEvent*) ev;
29 -(void) rightMouseUp: (NSEvent*) ev;
30 -(void) otherMouseDown: (NSEvent*) ev;
31 -(void) otherMouseUp: (NSEvent*) ev;
32 -(void) mouseDragged: (NSEvent*) ev;
33 -(void) rightMouseDragged: (NSEvent*) ev;
34 -(void) otherMouseDragged: (NSEvent*) ev;*/
36 -(BOOL) acceptsFirstResponder;
37 @end
40 @interface AppDelegate : NSObject
41 {
42 }
44 -(void) applicationWillFinishLaunching: (NSNotification*) notification;
45 -(void) applicationDidFinishLaunching: (NSNotification*) notification;
47 -(BOOL) applicationShouldTerminate: (NSApplication*) app;
48 -(BOOL) applicationShouldTerminateAfterLastWindowClosed: (NSApplication*) app;
49 -(void) applicationWillTerminate: (NSNotification*) notification;
50 @end
52 struct window;
54 @interface WinDelegate : NSObject <NSWindowDelegate>
55 {
56 struct window *win;
57 }
58 -(id) init;
59 -(void) dealloc;
61 -(void) windowDidExpose: (NSNotification*) notification;
62 -(void) windowDidResize: (NSNotification*) notification;
63 -(BOOL) windowShouldClose: (id) win;
64 -(void) windowWillClose: (NSNotification*) notification;
65 @end
68 struct window {
69 int wid;
70 int width, height;
71 NSWindow *win;
72 OpenGLView *view;
73 NSOpenGLContext *ctx;
74 int needs_redisplay;
75 struct window *next;
76 };
79 static int init(void);
80 static void shutdown(void);
82 /* video mode switching */
83 static int set_vidmode(int xsz, int ysz);
84 static int get_vidmode(int *xsz, int *ysz);
86 /* create/destroy windows */
87 static int create_window(int xsz, int ysz, unsigned int flags);
88 static void close_window(int wid);
90 /* window management */
91 static int set_active(int wid);
92 static struct window *find_window(int wid);
93 static int activate_window(struct window *win);
94 static int set_title(const char *str);
95 static void redisplay(void);
96 static void swap_buffers(void);
98 static int get_modifiers(void);
100 /* event handling and friends */
101 static void set_event(int idx, int enable);
102 static int process_events(void);
104 static void fill_attr(NSOpenGLPixelFormatAttribute *attr, unsigned int flags);
107 static struct wsys_module ws = {
108 "cocoa", 0,
109 init,
110 shutdown,
111 set_vidmode,
112 get_vidmode,
113 create_window,
114 close_window,
115 set_active,
116 set_title,
117 redisplay,
118 swap_buffers,
119 get_modifiers,
120 set_event,
121 process_events,
122 0
123 };
125 static struct window *winlist, *active_win;
126 static int quit_main_loop;
128 static NSAutoreleasePool *global_pool;
130 void sgl_register_cocoa(void)
131 {
132 sgl_register_module(&ws);
133 }
136 @implementation OpenGLView
138 -(id) initWithFrame: (NSRect) frame pixelFormat: (NSOpenGLPixelFormat*) pf
139 {
140 APPLE_SUCKS();
141 self = [super initWithFrame: frame pixelFormat: pf];
142 return self;
143 }
145 -(void) drawRect: (NSRect) rect
146 {
147 APPLE_SUCKS();
148 sgl_display_callback_t func = sgl_get_callback(SGL_DISPLAY);
149 if(func) {
150 func();
151 }
152 }
154 -(void) reshape
155 {
156 APPLE_SUCKS();
157 NSSize sz;
158 sgl_reshape_callback_t func;
160 sz = [self bounds].size;
162 if((func = sgl_get_callback(SGL_RESHAPE)) && (sz.width != active_win->width ||
163 sz.height != active_win->height)) {
164 active_win->width = sz.width;
165 active_win->height = sz.height;
166 func(sz.width, sz.height);
167 }
168 }
170 -(BOOL) acceptsFirstResponder
171 {
172 APPLE_SUCKS();
173 return YES;
174 }
175 @end
177 @implementation AppDelegate
178 -(void) applicationWillFinishLaunching: (NSNotification*) notification
179 {
180 APPLE_SUCKS();
181 }
183 -(void) applicationDidFinishLaunching: (NSNotification*) notification
184 {
185 APPLE_SUCKS();
186 }
188 -(BOOL) applicationShouldTerminate: (NSApplication*) app
189 {
190 APPLE_SUCKS();
191 return NSTerminateNow;
192 }
194 -(BOOL) applicationShouldTerminateAfterLastWindowClosed: (NSApplication*) app
195 {
196 APPLE_SUCKS();
197 return YES;
198 }
200 -(void) applicationWillTerminate: (NSNotification*) notification
201 {
202 APPLE_SUCKS();
203 /*[NSApp setDelegate: nil];
204 [global_pool drain];*/
205 }
206 @end
208 @implementation WinDelegate
209 -(id) init
210 {
211 APPLE_SUCKS();
212 self = [super init];
213 return self;
214 }
216 -(void) dealloc
217 {
218 APPLE_SUCKS();
219 [super dealloc];
220 }
222 -(void) windowDidExpose: (NSNotification*) notification
223 {
224 APPLE_SUCKS();
225 }
227 -(void) windowDidResize: (NSNotification*) notification
228 {
229 APPLE_SUCKS();
230 }
232 -(BOOL) windowShouldClose: (id) win
233 {
234 APPLE_SUCKS();
235 assert(self->win);
236 close_window(self->win->wid);
237 return YES;
238 }
240 -(void) windowWillClose: (NSNotification*) notification
241 {
242 APPLE_SUCKS();
243 /*[NSApp terminate: nil];*/
244 }
245 @end
247 static int init(void)
248 {
249 APPLE_SUCKS();
250 AppDelegate *delegate;
252 global_pool = [[NSAutoreleasePool alloc] init];
254 [NSApplication sharedApplication];
256 delegate = [[AppDelegate alloc] init];
257 [NSApp setDelegate: delegate];
258 return 0;
259 }
261 static void shutdown(void)
262 {
263 APPLE_SUCKS();
264 while(winlist) {
265 close_window(winlist->wid);
266 }
268 quit_main_loop = 1;
269 [NSApp terminate: nil];
270 }
273 /* video mode switching */
274 static int set_vidmode(int xsz, int ysz)
275 {
276 return 0; /* TODO */
277 }
279 static int get_vidmode(int *xsz, int *ysz)
280 {
281 return 0; /* TODO */
282 }
285 /* create/destroy windows */
286 static int create_window(int xsz, int ysz, unsigned int flags)
287 {
288 APPLE_SUCKS();
289 NSAutoreleasePool *pool;
290 WinDelegate *delegate;
291 NSWindow *nswin;
292 NSRect rect;
293 OpenGLView *view;
294 NSOpenGLPixelFormat *pf;
295 NSOpenGLPixelFormatAttribute attr[32];
296 unsigned int style;
297 struct window *win;
298 static int next_id = 1;
300 if(!(win = malloc(sizeof *win))) {
301 return -1;
302 }
304 pool = [[NSAutoreleasePool alloc] init];
306 /* create the view */
307 fill_attr(attr, flags);
308 pf = [[[NSOpenGLPixelFormat alloc] initWithAttributes: attr] autorelease];
309 view = [[OpenGLView alloc] initWithFrame: rect pixelFormat: pf];
311 /* create the window and attach the OpenGL view */
312 rect.origin.x = rect.origin.y = 0;
313 rect.size.width = xsz;
314 rect.size.height = ysz;
316 style = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask |
317 NSResizableWindowMask;
319 nswin = [[NSWindow alloc] initWithContentRect: rect styleMask: style
320 backing: NSBackingStoreBuffered defer: YES];
322 delegate = [[WinDelegate alloc] init];
324 [nswin setDelegate: delegate];
325 [nswin setTitle: @"OpenGL/Cocoa"];
326 [nswin setReleasedWhenClosed: YES];
327 [nswin setContentView: view];
328 [nswin makeFirstResponder: view];
329 [nswin makeKeyAndOrderFront: nil];
330 [view release];
332 win->win = nswin;
333 win->view = view;
334 win->ctx = [view openGLContext];
335 win->wid = next_id++;
336 win->needs_redisplay = 1;
337 win->next = winlist;
338 winlist = win;
340 delegate->win = win;
342 if(!active_win) {
343 activate_window(win);
344 }
346 [pool drain];
347 return win->wid;
348 }
350 static void close_window(int wid)
351 {
352 APPLE_SUCKS();
353 struct window *win, *prev, dummy;
354 sgl_close_callback_t close_func;
356 dummy.next = win = winlist;
357 prev = &dummy;
359 while(win) {
360 if(win->wid == wid) {
361 if((close_func = sgl_get_callback(SGL_CLOSE))) {
362 close_func(wid);
363 }
364 [win->win close];
366 prev->next = win->next;
368 if(!dummy.next) {
369 winlist = 0;
370 }
372 if(active_win == win) {
373 activate_window(winlist);
374 }
375 free(win);
376 break;
377 }
378 prev = win;
379 win = win->next;
380 }
382 if(!dummy.next) {
383 winlist = 0;
384 shutdown();
385 }
386 }
389 /* window management */
390 static int set_active(int wid)
391 {
392 struct window *win = find_window(wid);
393 return activate_window(win);
394 }
396 static struct window *find_window(int wid)
397 {
398 struct window *win = winlist;
400 while(win) {
401 if(win->wid == wid) {
402 return win;
403 }
404 win = win->next;
405 }
406 return 0;
407 }
409 static int activate_window(struct window *win)
410 {
411 if(!win) {
412 return -1;
413 }
414 [win->ctx makeCurrentContext];
415 active_win = win;
416 return 0;
417 }
419 static int set_title(const char *str)
420 {
421 NSString *nsstr;
423 nsstr = [[NSString alloc] initWithCString: str encoding: NSASCIIStringEncoding];
424 [active_win->win setTitle: nsstr];
425 [nsstr release];
426 return 0;
427 }
429 static void redisplay(void)
430 {
431 active_win->needs_redisplay = 1;
432 }
434 static void swap_buffers(void)
435 {
436 [active_win->ctx flushBuffer];
437 }
440 static int get_modifiers(void)
441 {
442 return 0; /* TODO */
443 }
446 /* event handling and friends */
447 static void set_event(int idx, int enable)
448 {
449 }
451 static int process_events(void)
452 {
453 NSAutoreleasePool *pool;
454 NSRunLoop *runloop;
455 NSDate *block, *nonblock, *limdate;
457 sgl_idle_callback_t idle;
458 sgl_display_callback_t disp;
459 struct window *win;
461 pool = [[NSAutoreleasePool alloc] init];
463 idle = sgl_get_callback(SGL_IDLE);
464 disp = sgl_get_callback(SGL_DISPLAY);
466 win = winlist;
467 while(win) {
468 if(win->needs_redisplay && disp) {
469 activate_window(win);
470 disp();
471 win->needs_redisplay = 0;
472 }
473 win = win->next;
474 }
476 runloop = [[NSRunLoop currentRunLoop] retain];
477 block = [runloop limitDateForMode: NSDefaultRunLoopMode];
478 nonblock = [[NSDate distantPast] retain];
479 limdate = idle ? nonblock : block;
481 while(!quit_main_loop) {
482 NSEvent *ev = [NSApp nextEventMatchingMask: NSAnyEventMask untilDate: limdate
483 inMode: NSDefaultRunLoopMode dequeue: YES];
484 if(!ev) break;
486 [NSApp sendEvent: ev];
487 if(limdate == block) {
488 limdate = nonblock;
489 }
490 }
492 if(idle) {
493 idle();
494 }
496 [runloop release];
497 [pool drain];
499 /*sgl_log("%s returning: %d\n", __func__, quit_main_loop ? -1 : 0);*/
500 return quit_main_loop ? -1 : 0;
501 }
503 static void fill_attr(NSOpenGLPixelFormatAttribute *attr, unsigned int flags)
504 {
505 int i = 0;
507 /* this is very important. makes pixelformat selection behave like GLX
508 * where any non-zero value will denote "choose highest possible". This
509 * is pretty much what we intend, as the user doesn't actually pass any
510 * of these numbers.
511 */
512 attr[i++] = NSOpenGLPFAMaximumPolicy;
514 attr[i++] = NSOpenGLPFAColorSize;
515 attr[i++] = 1;
517 if(flags & SGL_DOUBLE) {
518 attr[i++] = NSOpenGLPFADoubleBuffer;
519 }
520 if(flags & SGL_DEPTH) {
521 attr[i++] = NSOpenGLPFADepthSize;
522 attr[i++] = 1;
523 }
524 if(flags & SGL_STENCIL) {
525 attr[i++] = NSOpenGLPFAStencilSize;
526 attr[i++] = 8; /* max-policy has no effect on stencil selection */
527 }
528 if(flags & SGL_STEREO) {
529 attr[i++] = NSOpenGLPFAStereo;
530 }
531 if(flags & SGL_MULTISAMPLE) {
532 attr[i++] = NSOpenGLPFASampleBuffers;
533 attr[i++] = 1;
534 attr[i++] = NSOpenGLPFASamples;
535 attr[i++] = 4; /* TODO don't hardcode, query */
536 }
537 attr[i++] = 0;
538 }
540 #else
541 int sgl_wsys_cocoa_silence_the_fucking_empty_file_warnings;
542 #endif /* USE_WSYS_MODULE_COCOA */