This file is indexed.

/usr/share/SuperCollider/HelpSource/Classes/SCNSObject.schelp is in supercollider-common 1:3.6.3~repack-5.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
class:: SCNSObject
summary:: Cocoa / Objective-C bridge
categories:: Platform>OSX

description::

note::
This is experimental (03/2006), things might change and be careful wrong or unsupported Cocoa-calls can crash this Application !
::

subsection::Object Creation - LifeCycle

On creation only the init message is passed, alloc is called internally. Instance methods and Class methods are supported by the bridge, but if an object (id or SCNSObject) is returned by the method you owns it (even for autoreleased object - because they are retained internally by SuperCollider), so you must call strong::release:: when you're done with it (SCNSObject(s) are not automatically garbage collected).

subsection::Invocation

Once your Objective-C object is allocated / retained you can call it using strong::invoke::.

Example:
The Objective-C synthax:
code::
NSNumber *n = [[NSNumber alloc] initWithFloat: 1.1];
[n floatValue];
::
turns into:
code::
n = SCNSObject("NSNumber", "initWithFloat:", [1.1]);
n.invoke("floatValue");
::
Multiple messages are put together in one String and their arguments in one Array.

Example:
Cocoa:
code::
NSWindow *c = [[NSWindow alloc] initWithContentRect: rect styleMask: 10 backing: 2 defer:YES];
::
SC:
code::
c = SCNSObject("NSWindow", "initWithContentRect:styleMask:backing:defer:",[Rect(0,0,400,100), 10, 2, 1]);
::

subsection::Deferring your calls

Some methods need to be defered. If you want to defer ust call invoke with defer:true. Watch out there is no smart protection for methods that need defer until now! In general you should defer graphic operations.
So calling this might crash sc-lang:
code::
c.invoke("makeKeyAndOrderFront:", [nil]);
::
but this line is fine:
code::
c.invoke("makeKeyAndOrderFront:", [nil], true);
::

subsection::Common Conversion Table

SuperCollider will try to convert types when possible, here are the most common types and their translation betweem the two languages.

table::
## strong::SuperCollider Types ->:: || strong::Objective-C Types (when using invoke / SCNSObject.new)::
## SCNSObject || id (NSObject)
## Nil || nil, NULL pointer
## Number (Float, Integer) || float, int, long, short, char, NSNumber
## Boolean || YES, NO, bool, NSNumber
## String || NSString, SEL, char*, void*
## Rect || NSRect
## Color || NSColor
## Point || NSPoint, NSRange, NSSize
## Int8Array || void*, char*
## Int16Array || void*, short*
## Int32Array || void*, int*
## DoubleArray || void*, double*
## FloatArray || void*, float*
## Signal || float*
## Array || QTTime, NSRange, NSSize, SCNSObject*
::

table::
## strong::Objective-C Types ->:: || strong::SuperCollider Types (on method return)::
## NSString, char* || String
## NSColor || Color
## NSSize, NSRange, QTTime || Array
## NSRect || Rect
## NSPoint || Point
## BOOL, long, char, int, short || Integer
## float, double || Float
## c99 _bool || Boolean
## *(pointer type) || RawPointer
## id, (any other NSObject) || SCNSObject
::

ClassMethods::

method::new
Creates a new SCNSObject instance. SCNSObject creates a bridge between SuperCollider and Objective-C / Cocoa. It holds an NSObject and sends messages to it. The class and messages are passed as Strings. Arguments must be in an Array.

code::
a = SCNSObject("NSHost", "currentHost");
[\name, a.invoke("name"), \address, a.invoke("address")].postln;
a.release;
::

argument::classname
The Objective-C name of the class you want to invoke / instantiate.

argument::initname
can be either a class method or an instance initX method, depending on the possible initialization call. You do not need to specify alloc if you instantiate an object, it is automatically done for you.

argument::args
the Array of arguments for the initname method.

argument::defer
defer the call. Default is false.

method::newFromRawPointer
Creates a new SCNSObject from a link::Classes/RawPointer::. Might be handy for very special occasion.

code::
i = SCImage.new("/Library/Desktop Pictures/Ripples Blue.jpg");
a = SCNSObject.newFromRawPointer(i.slotAt(0)).invoke("nsimage");
a.className.postln; // verify :)
// now do what you want with the NSImage of the SCImage
i.free; // release it when done
// you do not have here to release the SCNSObject - it is dangerous to do so in this case
::

method::dumpPool
Dump the current NSObjects in the pool, so retained by SuperCollider.

method::freePool
Release all the current NSObjects in the pool and clear it. Call this method only if you really know what you are doing : all the SCNSObjects will be unvalidated !

InstanceMethods::

method::invoke
Invoke an SCNSObject.

argument::method
The method to call the receiver with.

argument::args
The arguments link::Classes/Array::.

argument::defer
defer the call. Default is false. (might be needed for GUI otherwise you may experience a crash).

method::release
Release the internal NSObject retained by the application pool. You must call this method when you're done with your object.

note::
It is not fully equivalent to a [myObject release], the NSObject is removed from the pool so if the application is the only one who retained it and owns it, it will properly dealloc it. But if the object is not IN the pool, it won't do anything.
::

code::
SCNSObject.freePool; // free all object first to see
i = SCImage.new("/Library/Desktop Pictures/Ripples Blue.jpg"); // create a simple SCImage
a = SCNSObject.newFromRawPointer(i.slotAt(0)); // get the SCImage object
a.className; // SCImage
a.invoke("size");
SCNSObject.dumpPool; // look, we do not have any NSObject in our pool
// a.release; // so this won't do anything - just clear our NSObject ref - note that the SCImage is not IN the pool
a.invoke("retain"); // now we can retain the SCImage - but since the method returns the object it is also added - retained also in the pool !
i.free; // release the SCImage
SCNSObject.dumpPool; // look the SCImage is here
a.invoke("release"); // now we have to release it twice
SCNSObject.dumpPool; //
a.release; // should be fine
::

method::initAction
Creates a CocoaAction object, a special delegate to handle Target / Action mechanism (See explainations above). strong::initAction:: is a convenience method to add an action to a gui element, mostly for strong::NSControl:: subclasses. Once an action is setted, a special delegate is created on your behalf to wich you can attach a action. You can access this delegate using the strong::nsAction:: accessor method.

code::
(
var win, topview, slider;

win = SCNSObject("NSWindow", "initWithContentRect:styleMask:backing:defer:", [Rect(100,140,400,30), 10, 2, 1]);
win.registerNotification("NSWindowWillCloseNotification", {|name, nsnotification, object|
	[win, topview, slider].do { |obj| obj.release };
	[name, nsnotification, object].postln}
);

slider = SCNSObject("NSSlider", "initWithFrame:", [Rect(0,0,390,20)]);
slider.invoke("setFloatValue:", [0.5]);
slider.initAction.action_({|v,val| val.postln});

topview = win.invoke("contentView");
topview.invoke("addSubview:", [slider]);

win.invoke("makeKeyAndOrderFront:", [win], true);
win.invoke("setTitle:", ["cocoa test"]);
)
::

argument::actionName
may be "doFloatAction:" (default), "doIntAction:", "doStateAction:" or "doAction:".

method::setDelegate
Creates a special CocoaAction object delegate object to handle delegate methods and notifications. Should not be confused with the nsAction one. This delegate can be retrieved with the strong::nsDelegate:: accessor.

method::registerNotification
Register a special notification (see NSNotification) with a link::Classes/Function:: that will be triggered each time it is sent. This method will create a defaut strong::nsDelegate:: if it does exist already.

code::
(
var win, delegate;
win = SCNSObject("NSWindow", "initWithContentRect:styleMask:backing:defer:", [Rect(100,400,400,400), 10, 2, 1]);
win.registerNotification("NSWindowWillCloseNotification", {|name, nsnotification, object, delegate|
	[delegate /* the window.nsDelegate */, delegate.object /* the win SCNSObject */, name, nsnotification, object].postln;
	win.release;
});
win.invoke("setMinSize:", [[100,100]]);
win.invoke("makeKeyAndOrderFront:", [win], true);
win.invoke("setTitle:", ["notification test - Close Me"]);
)
::

argument::aNotificationName
The name of the notification.

argument::aFunc
The responder function.

argument::obj
The object of the notification, default is this.

method::asArray
SCNSObject holding an NSData object can be converted to array types using the strong::asArray:: method.

code::
d = SCNSObject.new("NSData", "dataWithBytes:length:", ["hellomydear", 11]); // 11 bytes passed
e = d.asArray(\string); // get it back as a String
d.release;

d = SCNSObject.new("NSData", "dataWithBytes:length:", [Int32Array[98,99,100,101], 4*4]); // 4x32bit integers = 16 bytes
e = d.asArray(\int32); // get it back as an Int32Array
d.release;

d = SCNSObject.new("NSData", "dataWithBytes:length:", [Int16Array[98,99,100,101], 4*2]); // 4x16bit integers = 8 bytes
e = d.asArray(\int16); // get it back an Int16Array
d.release;
::

argument::arrayType
\string \int8 \int16 \int32 \float \double are the possible argument for an explicit conversion.

Examples::

code::
//create a window and add a Slider that posts its value.
(
var win, slider;

win = SCNSObject("NSWindow", "initWithContentRect:styleMask:backing:defer:",
	[Rect(100,140,400,30), 10, 2, 1]);
win.setDelegate.action_({ // for NSWindow objects using setDelegate.action will trigger the nsAction.action function when it is closed
	"closing window, releasing objects".postln;
	[slider,e].do{|it| it.release};
});
slider = SCNSObject("NSSlider", "initWithFrame:", [Rect(0,0,390,20)]);
e = SCNSObject("SCGraphView", "initWithFrame:", [Rect(0,0,400,30)]);
win.invoke("setContentView:", [e], true);
e.invoke("addSubview:", [slider], true);
slider.invoke("setFloatValue:", [0.5]);
win.invoke("makeKeyAndOrderFront:", [nil], true);
win.invoke("setTitle:", ["cocoa test"]);

{
a = slider.initAction;
a.action_({|v,val| val.postln});}.defer(0.1);
~win = win;
)

~win.className
~win.invoke("close", defer:true);


(
c = SCNSObject("NSWindow", "initWithContentRect:styleMask:backing:defer:",[Rect(0,0,400,100), 10, 2, 1]);
c.setDelegate.action_({ // for NSWindow objects using setDelegate.action will trigger the nsAction.action function when it is closed
	"closing window, releasing objects".postln;
	[c,d,e].do{|it| it.release};
});
d = SCNSObject("NSTextField", "initWithFrame:", [Rect(0,0,100,20)]);
e = SCNSObject("NSView", "initWithFrame:", [Rect(0,0,400,100)]);
c.invoke("setContentView:", [e], true);
e.invoke("addSubview:", [d], true);
c.invoke("makeKeyAndOrderFront:", [nil], true);
)



(
c = SCNSObject("NSWindow", "initWithContentRect:styleMask:backing:defer:",[Rect(100,100,100,20), 10, 2, 1]);
c.setDelegate.action_({ // for NSWindow objects using setDelegate.action will trigger the nsAction.action function when it is closed
	"closing window, releasing objects".postln;
	[c,d,e].do{|it| it.release};
});
d = SCNSObject("NSButton", "initWithFrame:", [Rect(0,0,100,20)]);
e = SCNSObject("NSView", "initWithFrame:", [Rect(0,0,400,100)]);
c.invoke("setContentView:", [e], true);
e.invoke("addSubview:", [d], true);
c.invoke("makeKeyAndOrderFront:", [nil], true);
d.invoke("setButtonType:", [3]);
{
d.initAction("doStateAction:");
d.nsAction.action_({|it,val| val.postln;});
}.defer(0.1);
)
::

code::
/*
simple QTMovie example
creates a movie in the SuperCollider folder + adds an image to it
*/

(
d = SCNSObject("NSMutableDictionary", "dictionary");
d.invoke("setObject:forKey:", ["jpeg", "QTAddImageCodecType"]);

e = SCNSObject("NSMutableDictionary", "dictionary");
e.invoke("setObject:forKey:", [true, "QTMovieFlatten"]);

m = SCNSObject("QTMovie", "initToWritableFile:error:", [Platform.classLibraryDir ++ "/../test.mov", nil]); // creates an empty movie
i = SCImage("/Library/Desktop Pictures/Ripples Blue.jpg");

// newFromRawPointer does not need any release so fine to get the invocation result directly
a = SCNSObject.newFromRawPointer(i.slotAt(0)).invoke("nsimage"); // this is how you can create a NSImage from
m.invoke("addImage:forDuration:withAttributes:", [a, [3, 1], d]); // 3 seconds
m.invoke("updateMovieFile");

[m, d, e].do ({ |object| object.release; });
i.free;
)

// HUD Panels - 10.5 only
(
w = SCNSObject("NSPanel", "initWithContentRect:styleMask:backing:defer:", [Rect(250, 250, 300, 200), (1<<13) + (1<<4) + 4 + 2 + 8, 2, true]);
w.registerNotification("NSWindowWillCloseNotification", {|notificationName,nsNotification|
	w.release;
});
w.invoke("makeKeyAndOrderFront:", [nil], true);
)
::

code::
/*----------------------
Notification Examples
using Webview
________________________*/

(
var win, root, cocoaUI, cell, webview, levelIndicator;
win = SCNSObject("NSWindow", "initWithContentRect:styleMask:backing:defer:", [Rect(250, 250, 800, 600), 15, 2, 1]);

root = SCNSObject("NSView", "initWithFrame:", [Rect(0, 0, 800, 600)]);
root.invoke("setAutoresizingMask:", [1 + 2 + 8 + 16]);

webview = SCNSObject("WebView", "initWithFrame:frameName:groupName:", [Rect(10, 30, 800-20, 600-40), "mywebview", "mywebviewgroup"]);
webview.invoke("setAutoresizingMask:", [1 + 2 + 8 + 16]);

~webview = webview; // just to retrieve the source after

cell = SCNSObject("NSLevelIndicatorCell", "initWithLevelIndicatorStyle:", [1]);
levelIndicator = SCNSObject("NSLevelIndicator", "initWithFrame:", [Rect(10, 5, 800-20, 10)]);
levelIndicator.invoke("setCell:", [cell]);
levelIndicator.invoke("setMinValue:", [0]);
levelIndicator.invoke("setMaxValue:", [100]);
levelIndicator.invoke("setFloatValue:", [0]);
levelIndicator.invoke("setContinuous:", [true]);
cell.release;

cocoaUI.add(root);
cocoaUI.add(webview);
cocoaUI.add(levelIndicator);

win.invoke("setContentView:", [root]);
root.invoke("addSubview:", [webview]);
root.invoke("addSubview:", [levelIndicator]);

///// Notifications
// Window
win.registerNotification("NSWindowWillCloseNotification", {
	|notificationName, nsNotificationObjectAsRawPointer|
	"closing window".postln;
	cocoaUI.do {|ui| ui.invoke("removeFromSuperviewWithoutNeedingDisplay")};
	win.release;
	root.release;
	webview.release;
	levelIndicator.release;
	~webview = nil;
});

win.registerNotification("NSWindowDidMoveNotification", {
	|notificationName, nsNotificationObjectAsRawPointer|
	notificationName.postln;
});

win.registerNotification("NSWindowDidMiniaturizeNotification", {
	|notificationName, nsNotificationObjectAsRawPointer|
	notificationName.postln;
});
// Webview Notifications
webview.registerNotification("WebProgressEstimateChangedNotification", {
	|notificationName, nsNotificationObjectAsRawPointer|
	var value;
	value = webview.invoke("estimatedProgress");
	levelIndicator.invoke("setFloatValue:", [value*100]);
	("loading progress: "+ (value*100) + "%").postln;
});

webview.registerNotification("WebProgressFinishedNotification", {
	|notificationName, nsNotificationObjectAsRawPointer|
	var t0, t1;
	levelIndicator.invoke("setFloatValue:", [0]);
	t0 = webview.invoke("mainFrame");
	t1 = t0.invoke("dataSource"); t0.release;
	t0 = t1.invoke("initialRequest"); t1.release;
	t1 = t0.invoke("URL"); t0.release;
	t0 = t1.invoke("absoluteString"); t1.release;
	(t0 ++ " finished Loading").postln;
	win.invoke("setTitle:", [t0]);
});
///// Show Window
win.invoke("makeKeyAndOrderFront:", [win], true);

///// URL Loading
{
	var url;
	url = "http://swiki.hfbk-hamburg.de:8888/MusicTechnology/6";
	webview.invoke("setMainFrameURL:", [url]);
	SCNSObject.dumpPool;
}.defer(0.2);
)
::

code::
/*----------------------
NSData conversion
using Webview html source
Do not close the window before you exec this code or reload previous example !
________________________*/
(
/// interpret it AFTER previous example for getting source html file
var mainframe, datasource, nsdata;
mainframe = ~webview.invoke("mainFrame");
datasource = mainframe.invoke("dataSource"); mainframe.release;
nsdata = datasource.invoke("data"); datasource.release;
nsdata.isSubclassOf("NSData").postln; //
"---- HTML Source ----".postln;
nsdata.asArray(\string).postln;
"---- End of HTML Source ----".postln;
nsdata.release;
)
::

code::
/*----------------------
special Delegates actions with return values
using NSURLConnection as an example
________________________*/

/*
(
var url;

// first URL Request
url = SCNSObject("NSURL", "initWithString:", ["http://www.audiosynth.com"]);
~urlRequest = SCNSObject("NSURLRequest", "requestWithURL:cachePolicy:timeoutInterval:", [url, 0, 60]); url.release;

// redirection to set after delegate call
url = SCNSObject("NSURL", "initWithString:", ["http://www.apple.com"]);
~redirection = SCNSObject("NSURLRequest", "requestWithURL:cachePolicy:timeoutInterval:", [url, 0, 60]); url.release;

// we need here to set a void object to set its delegate before it is allocated really
// because urlConnection does not have a setDelegate: method
~urlConnection = SCNSObject.newClear;
~urlConnection.setDelegate; // create and attach a special delegate
~urlConnection.nsDelegate.addMethod("connectionDidFinishLoading:", nil, "@", {
|method, args| [method, args].postln;
});

//// Custom Delegate Method with return values allowed (automatic conversion for most)
//// Here we have to provide the (name, return type of the delegate method, and the type encoding for the arguments)
//// see http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/Articles/chapter_13_section_9.html#//apple_ref/doc/uid/TP30001163-CH9-TPXREF165 for explanations
~urlConnection.nsDelegate.addMethod("connection:didReceiveResponse:", nil, "@@", {
	|method, args| [method, args].postln;
});

~urlConnection.nsDelegate.addMethod("connection:willSendRequest:redirectResponse:", "@", "@@@", {
	|method, arguments|
	[method, arguments].postln;
	url = ~redirection.invoke("URL");
	("redirecting to "++url.invoke("absoluteString")).postln; url.release;
	^~redirection; // redirect !
});

// we can init the object now
~urlConnection.init("NSURLConnection", "initWithRequest:delegate:", [~urlRequest, ~urlConnection.nsDelegate]); // now we can alloc the object and attach its delegate
)

(
~urlConnection.release;
~urlRequest.release;
~redirection.release;
)
*/

SCNSObject.dumpPool;
SCNSObject.freePool;
::