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"
32 #include "PyrSymbol.h"
33 #include "PyrObject.h"
34 #include "PyrKernel.h"
36 #include "VMGlobals.h"
37 #include "UserPanel.h"
38 #include "SC_DirUtils.h" // for gIdeName
42 #if (MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4)
43 #define class_getName(a) ((a)->name)
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();
57 void SetupHomeDirectory();
60 extern char *gHomePath
;
62 @implementation SCVirtualMachine
64 static id sharedSCVM
= nil;
66 + (id)sharedInstance
{
68 [[self allocWithZone
:[NSApp zone
]] init
];
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];
88 [NSApp setDelegate
: self]; //just to get a notification when sc quits. jan.t
95 gIdeName
= "scapp"; // declare that code specific to SC.app IDE will be compiled in
97 [NSTimer scheduledTimerWithTimeInterval
: deferredTaskInterval target
: self selector
:
98 @selector(doPeriodicTask
:) userInfo
: nil repeats
: YES
];
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 );
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);
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
];
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
);
192 - (void)setCmdLine
: (const char*) text length
: (int)length
195 postfl("The library has not been compiled successfully.\n");
198 pthread_mutex_lock(&gLangMutex
);
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
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];
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];
297 [deferredOperations removeObjectAtIndex
: 0];
298 ///NSLog(@"%d %@ %08X\n", [deferredOperations count], action, [action target]);
304 - (void)doAnimatedViews
306 SCView
* view
= gAnimatedViews
;
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
)];
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
];
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
];
378 NSURL
*url
= [NSURL fileURLWithPath
: filename
];
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
];
387 post("loadNibFile failed\n");
391 NSWindow
*window
= [panel window
];
393 post("UserPanel window outlet was not bound.\n");
397 NSView
*view
= [window contentView
];
398 [panel setSCObject
: (PyrObject
*)scobj
];
399 setupUserPaneViews(panel
, view
, 0);
401 [window makeKeyAndOrderFront
: nil];
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");
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
436 CGDisplayRelease(kCGDirectMainDisplay
);
437 [window setShowsResizeIndicator
: YES
];
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
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
];
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
];
540 void closeAllGUIScreens();
541 void closeAllGUIScreens()
543 [[SCVirtualMachine sharedInstance
] closeAllGUIWindows
];