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