/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;
::
|