scide: implement selectionLength for openDocument
[supercollider.git] / HelpSource / Classes / SCNSObject.schelp
blobcace723d386bd399ddd0f5e80b13dd51ff8360fa
1 class:: SCNSObject
2 summary:: Cocoa / Objective-C bridge
3 categories:: Platform>OSX
5 description::
7 note::
8 This is experimental (03/2006), things might change and be careful wrong or unsupported Cocoa-calls can crash this Application !
9 ::
11 subsection::Object Creation - LifeCycle
13 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).
15 subsection::Invocation
17 Once your Objective-C object is allocated / retained you can call it using strong::invoke::.
19 Example:
20 The Objective-C synthax:
21 code::
22 NSNumber *n = [[NSNumber alloc] initWithFloat: 1.1];
23 [n floatValue];
25 turns into:
26 code::
27 n = SCNSObject("NSNumber", "initWithFloat:", [1.1]);
28 n.invoke("floatValue");
30 Multiple messages are put together in one String and their arguments in one Array.
32 Example:
33 Cocoa:
34 code::
35 NSWindow *c = [[NSWindow alloc] initWithContentRect: rect styleMask: 10 backing: 2 defer:YES];
37 SC:
38 code::
39 c = SCNSObject("NSWindow", "initWithContentRect:styleMask:backing:defer:",[Rect(0,0,400,100), 10, 2, 1]);
42 subsection::Deferring your calls
44 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.
45 So calling this might crash sc-lang:
46 code::
47 c.invoke("makeKeyAndOrderFront:", [nil]);
49 but this line is fine:
50 code::
51 c.invoke("makeKeyAndOrderFront:", [nil], true);
54 subsection::Common Conversion Table
56 SuperCollider will try to convert types when possible, here are the most common types and their translation betweem the two languages.
58 table::
59 ## strong::SuperCollider Types ->:: || strong::Objective-C Types (when using invoke / SCNSObject.new)::
60 ## SCNSObject || id (NSObject)
61 ## Nil || nil, NULL pointer
62 ## Number (Float, Integer) || float, int, long, short, char, NSNumber
63 ## Boolean || YES, NO, bool, NSNumber
64 ## String || NSString, SEL, char*, void*
65 ## Rect || NSRect
66 ## Color || NSColor
67 ## Point || NSPoint, NSRange, NSSize
68 ## Int8Array || void*, char*
69 ## Int16Array || void*, short*
70 ## Int32Array || void*, int*
71 ## DoubleArray || void*, double*
72 ## FloatArray || void*, float*
73 ## Signal || float*
74 ## Array || QTTime, NSRange, NSSize, SCNSObject*
77 table::
78 ## strong::Objective-C Types ->:: || strong::SuperCollider Types (on method return)::
79 ## NSString, char* || String
80 ## NSColor || Color
81 ## NSSize, NSRange, QTTime || Array
82 ## NSRect || Rect
83 ## NSPoint || Point
84 ## BOOL, long, char, int, short || Integer
85 ## float, double || Float
86 ## c99 _bool || Boolean
87 ## *(pointer type) || RawPointer
88 ## id, (any other NSObject) || SCNSObject
91 ClassMethods::
93 method::new
94 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.
96 code::
97 a = SCNSObject("NSHost", "currentHost");
98 [\name, a.invoke("name"), \address, a.invoke("address")].postln;
99 a.release;
102 argument::classname
103 The Objective-C name of the class you want to invoke / instantiate.
105 argument::initname
106 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.
108 argument::args
109 the Array of arguments for the initname method.
111 argument::defer
112 defer the call. Default is false.
114 method::newFromRawPointer
115 Creates a new SCNSObject from a link::Classes/RawPointer::. Might be handy for very special occasion.
117 code::
118 i = SCImage.new("/Library/Desktop Pictures/Ripples Blue.jpg");
119 a = SCNSObject.newFromRawPointer(i.slotAt(0)).invoke("nsimage");
120 a.className.postln; // verify :)
121 // now do what you want with the NSImage of the SCImage
122 i.free; // release it when done
123 // you do not have here to release the SCNSObject - it is dangerous to do so in this case
126 method::dumpPool
127 Dump the current NSObjects in the pool, so retained by SuperCollider.
129 method::freePool
130 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 !
132 InstanceMethods::
134 method::invoke
135 Invoke an SCNSObject.
137 argument::method
138 The method to call the receiver with.
140 argument::args
141 The arguments link::Classes/Array::.
143 argument::defer
144 defer the call. Default is false. (might be needed for GUI otherwise you may experience a crash).
146 method::release
147 Release the internal NSObject retained by the application pool. You must call this method when you're done with your object.
149 note::
150 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.
153 code::
154 SCNSObject.freePool; // free all object first to see
155 i = SCImage.new("/Library/Desktop Pictures/Ripples Blue.jpg"); // create a simple SCImage
156 a = SCNSObject.newFromRawPointer(i.slotAt(0)); // get the SCImage object
157 a.className; // SCImage
158 a.invoke("size");
159 SCNSObject.dumpPool; // look, we do not have any NSObject in our pool
160 // a.release; // so this won't do anything - just clear our NSObject ref - note that the SCImage is not IN the pool
161 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 !
162 i.free; // release the SCImage
163 SCNSObject.dumpPool; // look the SCImage is here
164 a.invoke("release"); // now we have to release it twice
165 SCNSObject.dumpPool; //
166 a.release; // should be fine
169 method::initAction
170 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.
172 code::
174 var win, topview, slider;
176 win = SCNSObject("NSWindow", "initWithContentRect:styleMask:backing:defer:", [Rect(100,140,400,30), 10, 2, 1]);
177 win.registerNotification("NSWindowWillCloseNotification", {|name, nsnotification, object|
178         [win, topview, slider].do { |obj| obj.release };
179         [name, nsnotification, object].postln}
182 slider = SCNSObject("NSSlider", "initWithFrame:", [Rect(0,0,390,20)]);
183 slider.invoke("setFloatValue:", [0.5]);
184 slider.initAction.action_({|v,val| val.postln});
186 topview = win.invoke("contentView");
187 topview.invoke("addSubview:", [slider]);
189 win.invoke("makeKeyAndOrderFront:", [win], true);
190 win.invoke("setTitle:", ["cocoa test"]);
194 argument::actionName
195 may be "doFloatAction:" (default), "doIntAction:", "doStateAction:" or "doAction:".
197 method::setDelegate
198 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.
200 method::registerNotification
201 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.
203 code::
205 var win, delegate;
206 win = SCNSObject("NSWindow", "initWithContentRect:styleMask:backing:defer:", [Rect(100,400,400,400), 10, 2, 1]);
207 win.registerNotification("NSWindowWillCloseNotification", {|name, nsnotification, object, delegate|
208         [delegate /* the window.nsDelegate */, delegate.object /* the win SCNSObject */, name, nsnotification, object].postln;
209         win.release;
211 win.invoke("setMinSize:", [[100,100]]);
212 win.invoke("makeKeyAndOrderFront:", [win], true);
213 win.invoke("setTitle:", ["notification test - Close Me"]);
217 argument::aNotificationName
218 The name of the notification.
220 argument::aFunc
221 The responder function.
223 argument::obj
224 The object of the notification, default is this.
226 method::asArray
227 SCNSObject holding an NSData object can be converted to array types using the strong::asArray:: method.
229 code::
230 d = SCNSObject.new("NSData", "dataWithBytes:length:", ["hellomydear", 11]); // 11 bytes passed
231 e = d.asArray(\string); // get it back as a String
232 d.release;
234 d = SCNSObject.new("NSData", "dataWithBytes:length:", [Int32Array[98,99,100,101], 4*4]); // 4x32bit integers = 16 bytes
235 e = d.asArray(\int32); // get it back as an Int32Array
236 d.release;
238 d = SCNSObject.new("NSData", "dataWithBytes:length:", [Int16Array[98,99,100,101], 4*2]); // 4x16bit integers = 8 bytes
239 e = d.asArray(\int16); // get it back an Int16Array
240 d.release;
243 argument::arrayType
244 \string \int8 \int16 \int32 \float \double are the possible argument for an explicit conversion.
246 Examples::
248 code::
249 //create a window and add a Slider that posts its value.
251 var win, slider;
253 win = SCNSObject("NSWindow", "initWithContentRect:styleMask:backing:defer:",
254         [Rect(100,140,400,30), 10, 2, 1]);
255 win.setDelegate.action_({ // for NSWindow objects using setDelegate.action will trigger the nsAction.action function when it is closed
256         "closing window, releasing objects".postln;
257         [slider,e].do{|it| it.release};
259 slider = SCNSObject("NSSlider", "initWithFrame:", [Rect(0,0,390,20)]);
260 e = SCNSObject("SCGraphView", "initWithFrame:", [Rect(0,0,400,30)]);
261 win.invoke("setContentView:", [e], true);
262 e.invoke("addSubview:", [slider], true);
263 slider.invoke("setFloatValue:", [0.5]);
264 win.invoke("makeKeyAndOrderFront:", [nil], true);
265 win.invoke("setTitle:", ["cocoa test"]);
268 a = slider.initAction;
269 a.action_({|v,val| val.postln});}.defer(0.1);
270 ~win = win;
273 ~win.className
274 ~win.invoke("close", defer:true);
278 c = SCNSObject("NSWindow", "initWithContentRect:styleMask:backing:defer:",[Rect(0,0,400,100), 10, 2, 1]);
279 c.setDelegate.action_({ // for NSWindow objects using setDelegate.action will trigger the nsAction.action function when it is closed
280         "closing window, releasing objects".postln;
281         [c,d,e].do{|it| it.release};
283 d = SCNSObject("NSTextField", "initWithFrame:", [Rect(0,0,100,20)]);
284 e = SCNSObject("NSView", "initWithFrame:", [Rect(0,0,400,100)]);
285 c.invoke("setContentView:", [e], true);
286 e.invoke("addSubview:", [d], true);
287 c.invoke("makeKeyAndOrderFront:", [nil], true);
293 c = SCNSObject("NSWindow", "initWithContentRect:styleMask:backing:defer:",[Rect(100,100,100,20), 10, 2, 1]);
294 c.setDelegate.action_({ // for NSWindow objects using setDelegate.action will trigger the nsAction.action function when it is closed
295         "closing window, releasing objects".postln;
296         [c,d,e].do{|it| it.release};
298 d = SCNSObject("NSButton", "initWithFrame:", [Rect(0,0,100,20)]);
299 e = SCNSObject("NSView", "initWithFrame:", [Rect(0,0,400,100)]);
300 c.invoke("setContentView:", [e], true);
301 e.invoke("addSubview:", [d], true);
302 c.invoke("makeKeyAndOrderFront:", [nil], true);
303 d.invoke("setButtonType:", [3]);
305 d.initAction("doStateAction:");
306 d.nsAction.action_({|it,val| val.postln;});
307 }.defer(0.1);
311 code::
313 simple QTMovie example
314 creates a movie in the SuperCollider folder + adds an image to it
318 d = SCNSObject("NSMutableDictionary", "dictionary");
319 d.invoke("setObject:forKey:", ["jpeg", "QTAddImageCodecType"]);
321 e = SCNSObject("NSMutableDictionary", "dictionary");
322 e.invoke("setObject:forKey:", [true, "QTMovieFlatten"]);
324 m = SCNSObject("QTMovie", "initToWritableFile:error:", [Platform.classLibraryDir ++ "/../test.mov", nil]); // creates an empty movie
325 i = SCImage("/Library/Desktop Pictures/Ripples Blue.jpg");
327 // newFromRawPointer does not need any release so fine to get the invocation result directly
328 a = SCNSObject.newFromRawPointer(i.slotAt(0)).invoke("nsimage"); // this is how you can create a NSImage from
329 m.invoke("addImage:forDuration:withAttributes:", [a, [3, 1], d]); // 3 seconds
330 m.invoke("updateMovieFile");
332 [m, d, e].do ({ |object| object.release; });
333 i.free;
336 // HUD Panels - 10.5 only
338 w = SCNSObject("NSPanel", "initWithContentRect:styleMask:backing:defer:", [Rect(250, 250, 300, 200), (1<<13) + (1<<4) + 4 + 2 + 8, 2, true]);
339 w.registerNotification("NSWindowWillCloseNotification", {|notificationName,nsNotification|
340         w.release;
342 w.invoke("makeKeyAndOrderFront:", [nil], true);
346 code::
347 /*----------------------
348 Notification Examples
349 using Webview
350 ________________________*/
353 var win, root, cocoaUI, cell, webview, levelIndicator;
354 win = SCNSObject("NSWindow", "initWithContentRect:styleMask:backing:defer:", [Rect(250, 250, 800, 600), 15, 2, 1]);
356 root = SCNSObject("NSView", "initWithFrame:", [Rect(0, 0, 800, 600)]);
357 root.invoke("setAutoresizingMask:", [1 + 2 + 8 + 16]);
359 webview = SCNSObject("WebView", "initWithFrame:frameName:groupName:", [Rect(10, 30, 800-20, 600-40), "mywebview", "mywebviewgroup"]);
360 webview.invoke("setAutoresizingMask:", [1 + 2 + 8 + 16]);
362 ~webview = webview; // just to retrieve the source after
364 cell = SCNSObject("NSLevelIndicatorCell", "initWithLevelIndicatorStyle:", [1]);
365 levelIndicator = SCNSObject("NSLevelIndicator", "initWithFrame:", [Rect(10, 5, 800-20, 10)]);
366 levelIndicator.invoke("setCell:", [cell]);
367 levelIndicator.invoke("setMinValue:", [0]);
368 levelIndicator.invoke("setMaxValue:", [100]);
369 levelIndicator.invoke("setFloatValue:", [0]);
370 levelIndicator.invoke("setContinuous:", [true]);
371 cell.release;
373 cocoaUI.add(root);
374 cocoaUI.add(webview);
375 cocoaUI.add(levelIndicator);
377 win.invoke("setContentView:", [root]);
378 root.invoke("addSubview:", [webview]);
379 root.invoke("addSubview:", [levelIndicator]);
381 ///// Notifications
382 // Window
383 win.registerNotification("NSWindowWillCloseNotification", {
384         |notificationName, nsNotificationObjectAsRawPointer|
385         "closing window".postln;
386         cocoaUI.do {|ui| ui.invoke("removeFromSuperviewWithoutNeedingDisplay")};
387         win.release;
388         root.release;
389         webview.release;
390         levelIndicator.release;
391         ~webview = nil;
394 win.registerNotification("NSWindowDidMoveNotification", {
395         |notificationName, nsNotificationObjectAsRawPointer|
396         notificationName.postln;
399 win.registerNotification("NSWindowDidMiniaturizeNotification", {
400         |notificationName, nsNotificationObjectAsRawPointer|
401         notificationName.postln;
403 // Webview Notifications
404 webview.registerNotification("WebProgressEstimateChangedNotification", {
405         |notificationName, nsNotificationObjectAsRawPointer|
406         var value;
407         value = webview.invoke("estimatedProgress");
408         levelIndicator.invoke("setFloatValue:", [value*100]);
409         ("loading progress: "+ (value*100) + "%").postln;
412 webview.registerNotification("WebProgressFinishedNotification", {
413         |notificationName, nsNotificationObjectAsRawPointer|
414         var t0, t1;
415         levelIndicator.invoke("setFloatValue:", [0]);
416         t0 = webview.invoke("mainFrame");
417         t1 = t0.invoke("dataSource"); t0.release;
418         t0 = t1.invoke("initialRequest"); t1.release;
419         t1 = t0.invoke("URL"); t0.release;
420         t0 = t1.invoke("absoluteString"); t1.release;
421         (t0 ++ " finished Loading").postln;
422         win.invoke("setTitle:", [t0]);
424 ///// Show Window
425 win.invoke("makeKeyAndOrderFront:", [win], true);
427 ///// URL Loading
429         var url;
430         url = "http://swiki.hfbk-hamburg.de:8888/MusicTechnology/6";
431         webview.invoke("setMainFrameURL:", [url]);
432         SCNSObject.dumpPool;
433 }.defer(0.2);
437 code::
438 /*----------------------
439 NSData conversion
440 using Webview html source
441 Do not close the window before you exec this code or reload previous example !
442 ________________________*/
444 /// interpret it AFTER previous example for getting source html file
445 var mainframe, datasource, nsdata;
446 mainframe = ~webview.invoke("mainFrame");
447 datasource = mainframe.invoke("dataSource"); mainframe.release;
448 nsdata = datasource.invoke("data"); datasource.release;
449 nsdata.isSubclassOf("NSData").postln; //
450 "---- HTML Source ----".postln;
451 nsdata.asArray(\string).postln;
452 "---- End of HTML Source ----".postln;
453 nsdata.release;
457 code::
458 /*----------------------
459 special Delegates actions with return values
460 using NSURLConnection as an example
461 ________________________*/
465 var url;
467 // first URL Request
468 url = SCNSObject("NSURL", "initWithString:", ["http://www.audiosynth.com"]);
469 ~urlRequest = SCNSObject("NSURLRequest", "requestWithURL:cachePolicy:timeoutInterval:", [url, 0, 60]); url.release;
471 // redirection to set after delegate call
472 url = SCNSObject("NSURL", "initWithString:", ["http://www.apple.com"]);
473 ~redirection = SCNSObject("NSURLRequest", "requestWithURL:cachePolicy:timeoutInterval:", [url, 0, 60]); url.release;
475 // we need here to set a void object to set its delegate before it is allocated really
476 // because urlConnection does not have a setDelegate: method
477 ~urlConnection = SCNSObject.newClear;
478 ~urlConnection.setDelegate; // create and attach a special delegate
479 ~urlConnection.nsDelegate.addMethod("connectionDidFinishLoading:", nil, "@", {
480 |method, args| [method, args].postln;
483 //// Custom Delegate Method with return values allowed (automatic conversion for most)
484 //// Here we have to provide the (name, return type of the delegate method, and the type encoding for the arguments)
485 //// see http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/Articles/chapter_13_section_9.html#//apple_ref/doc/uid/TP30001163-CH9-TPXREF165 for explanations
486 ~urlConnection.nsDelegate.addMethod("connection:didReceiveResponse:", nil, "@@", {
487         |method, args| [method, args].postln;
490 ~urlConnection.nsDelegate.addMethod("connection:willSendRequest:redirectResponse:", "@", "@@@", {
491         |method, arguments|
492         [method, arguments].postln;
493         url = ~redirection.invoke("URL");
494         ("redirecting to "++url.invoke("absoluteString")).postln; url.release;
495         ^~redirection; // redirect !
498 // we can init the object now
499 ~urlConnection.init("NSURLConnection", "initWithRequest:delegate:", [~urlRequest, ~urlConnection.nsDelegate]); // now we can alloc the object and attach its delegate
503 ~urlConnection.release;
504 ~urlRequest.release;
505 ~redirection.release;
509 SCNSObject.dumpPool;
510 SCNSObject.freePool;