class library: Spawner - don't access PriorityQueue-array
[supercollider.git] / editors / scapp / SCVirtualMachine.M
blob0fc33bd7f34758aafb176e4d8fea3fb7e0471e54
1 /*
2 SuperCollider real time audio synthesis system
3 Copyright (c) 2002 James McCartney. All rights reserved.
4 http://www.audiosynth.com
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program 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
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 #import <objc/objc-class.h>
22 #import "SCVirtualMachine.h"
23 #import "MyDocument.h"
24 #import "SCGraphView.h"
25 #import "SCNSWindow.h"
26 #include "ChangeCounter.h"
28 #import "RendezvousClient.h"
29 #import "SCService.h"
31 #include "SCBase.h"
32 #include "PyrSymbol.h"
33 #include "PyrObject.h"
34 #include "PyrKernel.h"
35 #include "GC.h"
36 #include "VMGlobals.h"
37 #include "UserPanel.h"
38 #include "SC_DirUtils.h" // for gIdeName
40 #include <pthread.h>
42 #if (MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4)
43 #define class_getName(a) ((a)->name)
44 #endif
46 ChangeCounter gUIChangeCounter;
48 extern bool compiledOK;
49 extern pthread_mutex_t gLangMutex;
50 extern PyrSymbol *s_tick;
52 PyrString* newPyrStringN(class PyrGC *gc, long length, long flags, bool collect);
53 void dumpByteCodes(PyrBlock *theBlock);
55 void initPostBuffer();
56 void flushPostBuf();
57 void SetupHomeDirectory();
58 double elapsedTime();
60 extern char *gHomePath;
62 @implementation SCVirtualMachine
64 static id sharedSCVM = nil;
66 + (id)sharedInstance {
67 if (!sharedSCVM) {
68 [[self allocWithZone:[NSApp zone]] init];
70 return sharedSCVM;
73 - (id)init
75 if (sharedSCVM) {
76 [super dealloc];
77 return sharedSCVM;
80 if (!(self = [super init])) return nil;
82 deferredOperations = [NSMutableArray arrayWithCapacity: 8];
83 [deferredOperations retain];
84 deferredTaskInterval = 1.f/60;
86 guiWindows = [NSMutableArray arrayWithCapacity: 8];
87 [guiWindows retain];
88 [NSApp setDelegate: self]; //just to get a notification when sc quits. jan.t
89 sharedSCVM = self;
90 return self;
93 - (void)start
95 gIdeName = "scapp"; // declare that code specific to SC.app IDE will be compiled in
96 deferredTaskTimer =
97 [NSTimer scheduledTimerWithTimeInterval: deferredTaskInterval target: self selector:
98 @selector(doPeriodicTask:) userInfo: nil repeats: YES];
100 appClockTimer =
101 [NSTimer scheduledTimerWithTimeInterval: 0.020 target: self selector:
102 @selector(doClockTask:) userInfo: nil repeats: YES];
104 [deferredTaskTimer retain];
105 [appClockTimer retain];
107 [[NSRunLoop currentRunLoop] addTimer: deferredTaskTimer
108 forMode: NSModalPanelRunLoopMode];
110 [[NSRunLoop currentRunLoop] addTimer: deferredTaskTimer
111 forMode: NSEventTrackingRunLoopMode];
113 [[NSRunLoop currentRunLoop] addTimer: appClockTimer
114 forMode: NSModalPanelRunLoopMode];
116 [[NSRunLoop currentRunLoop] addTimer: appClockTimer
117 forMode: NSEventTrackingRunLoopMode];
119 SetupHomeDirectory();
120 pyr_init_mem_pools( 2*1024*1024, 256*1024 );
121 initPostBuffer();
122 init_OSC(57120);
123 schedInit();
124 compileLibrary();
126 // CR ADDED
127 [[RendezvousClient sharedClient] findOSCServices];
129 [self sendMain: "applicationStart"];
131 // Sleep - Technical Q&A QA1340
132 //These notifications are filed on NSWorkspace's notification center, not the default notification center.
133 // You will not receive sleep/wake notifications if you file with the default notification center.
134 [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver: self
135 selector: @selector(receiveSleepNote:) name: NSWorkspaceWillSleepNotification object: NULL];
136 [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver: self
137 selector: @selector(receiveWakeNote:) name: NSWorkspaceDidWakeNotification object: NULL];
141 -(void)setDeferredTaskInterval: (float) interval
144 [deferredTaskTimer invalidate];
145 [deferredTaskTimer release];
146 deferredTaskInterval = sc_max(interval, 1.f/600);
147 deferredTaskTimer =
148 [NSTimer scheduledTimerWithTimeInterval: deferredTaskInterval target: self selector:
149 @selector(doPeriodicTask:) userInfo: nil repeats: YES];
151 [deferredTaskTimer retain];
153 [[NSRunLoop currentRunLoop] addTimer: deferredTaskTimer
154 forMode: NSModalPanelRunLoopMode];
156 [[NSRunLoop currentRunLoop] addTimer: deferredTaskTimer
157 forMode: NSEventTrackingRunLoopMode];
160 - (void)doPeriodicTask: (NSTimer*) timer
162 [self performDeferredOperations];
163 [self doAnimatedViews];
164 flushPostBuf();
167 // Sleep
168 // Technical Q&A QA1340
169 // Registering and unregistering for sleep and wake notifications
170 - (void) receiveSleepNote: (NSNotification*) note
172 // NSLog(@"receiveSleepNote: %@", [note name]);
173 [self sendMain: "sleep"];
176 - (void) receiveWakeNote: (NSNotification*) note
178 // NSLog(@"receiveSleepNote: %@", [note name]);
179 [self sendMain: "wake"];
182 - (void)doClockTask: (NSTimer*) timer
184 if (pthread_mutex_trylock(&gLangMutex) == 0) {
185 if (compiledOK) runLibrary(s_tick);
186 pthread_mutex_unlock(&gLangMutex);
188 flushPostBuf();
192 - (void)setCmdLine: (const char*) text length: (int)length
194 if (!compiledOK) {
195 postfl("The library has not been compiled successfully.\n");
196 return;
198 pthread_mutex_lock(&gLangMutex);
199 if (compiledOK) {
200 VMGlobals *g = gMainVMGlobals;
202 int textlen = length;
203 PyrString* strobj = newPyrStringN(g->gc, textlen, 0, true);
204 memcpy(strobj->s, (char*)text, textlen);
206 SetObject(&slotRawInterpreter(&g->process->interpreter)->cmdLine, strobj);
207 g->gc->GCWrite(slotRawObject(&g->process->interpreter), strobj);
209 pthread_mutex_unlock(&gLangMutex);
212 - (void)sendMain: (char*) methodName
214 pthread_mutex_lock(&gLangMutex);
215 runLibrary(getsym(methodName));
216 pthread_mutex_unlock(&gLangMutex);
219 - (void)compileLibrary:(id)sender
221 // if not and user pref, open first error file to that line
222 if(! compileLibrary() ) [self postWindowToFront: NULL];
225 - (void)runMain:(id)sender
227 [self sendMain: "run"];
230 - (void)stopMain:(id)sender
232 [self sendMain: "stop"];
235 - (void)hardStopMain:(id)sender
237 [self sendMain: "hardStop"];
240 - (IBAction) preferences: (id) sender
242 [self sendMain: "preferences"];
245 - (IBAction) newSCWindow: (id) sender
247 [self sendMain: "newSCWindow"];
249 /* i am the delegate for each SCGraphView window */
250 -(BOOL)windowShouldClose:(id)sender
252 return [(SCGraphView*)([(SCNSWindow*)sender getSCGraphView]) windowShouldClose];
255 extern NSTextView *gPostView;
257 - (void)postWindowToFront:(id)sender
259 if (gPostView) [[gPostView window] makeKeyAndOrderFront: sender];
261 - (void)clearPostWindow:(id)sender
263 if(gPostView) {
264 NSTextStorage *textStorage = [gPostView textStorage];
265 NSRange range = NSMakeRange(0, [textStorage length]);
266 if ([gPostView shouldChangeTextInRange: range replacementString: @""]) {
267 [gPostView replaceCharactersInRange: range withString: @""];
268 [gPostView didChangeText];
272 - (void)defer: (NSInvocation*) action
274 [deferredOperations addObject: action];
278 - (void)removeDeferredOperationsFor:(id) object
280 NSMutableArray *newArray = [NSMutableArray arrayWithCapacity: 8];
281 [newArray retain];
282 for (unsigned int i=0; i<[deferredOperations count]; ++i) {
283 NSInvocation* action = (NSInvocation*)[deferredOperations objectAtIndex: i];
284 if ([action target] != object) {
285 [newArray addObject: action];
288 [deferredOperations release];
289 deferredOperations = newArray;
292 - (void)performDeferredOperations
294 while ([deferredOperations count]) {
295 NSInvocation* action = (NSInvocation*)[deferredOperations objectAtIndex: 0];
296 [action retain];
297 [deferredOperations removeObjectAtIndex: 0];
298 ///NSLog(@"%d %@ %08X\n", [deferredOperations count], action, [action target]);
299 [action invoke];
300 [action release];
304 - (void)doAnimatedViews
306 SCView* view = gAnimatedViews;
307 while (view)
309 view->animate();
310 view = view->NextAnimatedView();
314 - (void)closeAllGUIWindows
316 [UserPanel closeAll];
318 if ([guiWindows count]) {
319 NSMutableArray *copy = [guiWindows copy];
320 [guiWindows removeAllObjects];
321 [copy makeObjectsPerformSelector: @selector(close)];
322 [copy release];
325 [deferredOperations removeAllObjects];
328 - (void)addWindow: (NSWindow*)window;
330 [guiWindows addObject: window];
333 void setupUserPaneViews(id target, id view, int tagsum)
336 int newTagSum = tagsum;
337 if ([view respondsToSelector: @selector(setTag:)]) {
338 int thisTag = [view tag];
339 if (thisTag > 0) newTagSum += thisTag;
341 post(" view '%s' %d %d\n", class_getName(view->isa), tagsum, newTagSum);
343 if ([view respondsToSelector: @selector(setTarget:)]) {
344 [view setTarget: target];
346 if ([view respondsToSelector: @selector(setAction:)]) {
347 [view setAction: @selector(panelAction:)];
349 if ([view respondsToSelector: @selector(setTag:)]) {
350 [view setTag: newTagSum];
353 if ([view respondsToSelector: @selector(subviews)]) {
354 NSArray *subviews = [view subviews];
355 int numSubviews = [subviews count];
356 for (int i=0; i<numSubviews; ++i) {
357 id subview = [subviews objectAtIndex: i];
358 setupUserPaneViews(target, subview, newTagSum);
361 if ([view respondsToSelector: @selector(cells)]) {
362 NSArray *cells = [view cells];
363 if (cells) {
364 int numCells = [cells count];
365 for (int i=0; i<numCells; ++i) {
366 id cell = [cells objectAtIndex: i];
367 setupUserPaneViews(target, cell, newTagSum);
373 - (void)loadUserPanel:(NSString*)filename SCObject: (void*)scobj
375 UserPanel* panel = [[UserPanel alloc] init];
376 [panel retain];
378 NSURL *url = [NSURL fileURLWithPath: filename];
379 [filename release];
380 NSString *nspath = [url path];
381 NSMutableDictionary *dict = [NSMutableDictionary dictionary];
382 [dict setObject: panel forKey: @"NSOwner"];
383 NSZone *zone = [NSApp zone];
384 post("path '%s'\n", [nspath cString]);
385 BOOL result = [NSBundle loadNibFile: nspath externalNameTable: dict withZone: zone];
386 if (!result) {
387 post("loadNibFile failed\n");
388 return;
391 NSWindow *window = [panel window];
392 if (!window) {
393 post("UserPanel window outlet was not bound.\n");
394 return;
397 NSView *view = [window contentView];
398 [panel setSCObject: (PyrObject*)scobj];
399 setupUserPaneViews(panel, view, 0);
401 [window makeKeyAndOrderFront: nil];
403 // set all targets
407 bool gIsFullScreen = false;
409 - (void)becomeFullScreen: (NSWindow*)window
411 int err = CGDisplayCapture(kCGDirectMainDisplay);
412 if (err != kCGErrorSuccess) {
413 post("Can't capture screen.\n");
414 return;
417 int windowLevel = CGShieldingWindowLevel();
418 [window setLevel: windowLevel];
419 gIsFullScreen = true;
421 NSRect bounds = [[NSScreen mainScreen] frame];
422 [window setFrame: bounds display: YES];
423 [window setShowsResizeIndicator: NO];
425 //can't set NSBorderlessWindowMask after created
426 // but if you create it with that,
427 // subclass NSWindow,override canBecomeKeyWindow { return YES; }
428 // or you can't get key events
430 // then you can't move it
433 - (void)endFullScreen: (NSWindow*)window
435 if (gIsFullScreen) {
436 CGDisplayRelease(kCGDirectMainDisplay);
437 [window setShowsResizeIndicator: YES];
438 //[window close];
439 gIsFullScreen = false;
443 - (void)windowWillClose:(NSNotification *)aNotification
445 SCNSWindow* window = [aNotification object];
446 [self endFullScreen: window];
447 [guiWindows removeObject: window];
449 [(SCGraphView*)[window getSCGraphView] willClose];
452 - (void)windowWillMiniaturize:(NSNotification *)notification
454 if(gIsFullScreen){
455 SCNSWindow* window = [notification object];
456 [self sendMain:"exitFullScreen"];
460 - (void) windowDidBecomeKey:(NSNotification *)aNotification
462 SCNSWindow* window = [aNotification object];
463 [(SCGraphView*)[window getSCGraphView] didBecomeKey];
466 - (void) windowDidResignKey:(NSNotification *)aNotification
468 SCNSWindow* window = [aNotification object];
469 [(SCGraphView*)[window getSCGraphView] didResignKey];
472 - (void) runAsModal:(NSWindow*)window {
473 [NSApp runModalForWindow: window];
475 // after abort:
476 [window close];
479 - (void) runAsModalSheet: (NSWindow*)sheet forWindow:(NSWindow*)window {
480 SEL sel = @selector(sheetDidEnd:returnCode:contextInfo:);
481 [NSApp beginSheet: sheet modalForWindow: window modalDelegate:self didEndSelector:sel contextInfo:NULL];
484 - (void)sheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo {
485 SEL sel = @selector(close);
486 NSMethodSignature *sig = [SCNSWindow instanceMethodSignatureForSelector: sel];
488 NSInvocation *anInvocation = [NSInvocation invocationWithMethodSignature: sig];
489 SCVirtualMachine* scvm = [SCVirtualMachine sharedInstance];
490 [anInvocation setTarget: sheet];
491 [anInvocation setSelector: sel];
492 [scvm defer: anInvocation];
495 - (IBAction)showHelpFor:(id)sender {
496 [self sendMain: "showHelp"];
498 - (IBAction)showHelpBrowser:(id)sender {
499 [self sendMain: "showHelpBrowser"];
501 - (IBAction)showHelpSearch:(id)sender {
502 [self sendMain: "showHelpSearch"];
504 - (IBAction)showClassBrowser:(id)sender {
505 [self sendMain: "showClassBrowser"];
508 - (IBAction) executeSelection: (id)sender
510 [self sendMain: "interpretPrintCmdLine" ];
512 - (IBAction) openCode: (id)sender
514 [self sendMain: "openCodeFile"];
516 - (IBAction) methodTemplates: (id)sender
518 [self sendMain: "methodTemplates"];
520 - (IBAction) methodReferences: (id)sender
522 [self sendMain: "methodReferences"];
526 - (void)applicationWillTerminate:(NSNotification *)notification
528 [self sendMain: "shutdown"];
531 - (void)applicationDidFinishLaunching:(NSNotification *)notification;
533 SCService* serviceObject = [[SCService alloc] init];
534 [NSApp setServicesProvider: serviceObject];
538 @end
540 void closeAllGUIScreens();
541 void closeAllGUIScreens()
543 [[SCVirtualMachine sharedInstance] closeAllGUIWindows];