Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2002-301
$eventId
ID of event: wwdc2002
$eventContentId
ID of session without event part: 301
$eventShortId
Shortened ID of event: wwdc02
$year
Year of session: 2002
$extension
Extension of original filename: mov
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: ...

WWDC02 • Session 301

Cocoa: What's New

Cocoa • 1:00:06

This session provides an overview of new features and changes introduced in the Cocoa frameworks. Topics include enhancements to archiving, accessibility, text, localization, scripting, user interface, and Carbon/Cocoa interaction.

Speakers: Ali Ozer, Chris Parker, Chris Kane

Unlisted on Apple Developer site

Transcript

This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.

Good morning. Welcome to Cocoa: What's New. Today we're going to tell you what we did to Cocoa since the last time we were together, about a year ago. The talk is divided into two parts. First, we're going to talk about changes in the Foundation kit, followed by changes in the Application kit.

Note that in Foundation, we did not have too many public API changes in 10.1, so most of the changes here are actually new to Jaguar. To highlight here, NSNet services are the new APIs to support Rendezvous, and we have a new keyed archiving mechanism that I want to tell you about.

Then we're going to talk about the AppKit changes, first quickly covering the changes we introduced in 10.1, followed by the changes we've introduced in Jaguar. Now note that there's a lot of topics here, and we're going to be jumping from topic to topic, so hopefully it's not too disorienting for you. So at this point, I'd like to invite Chris Parker on stage to talk about some of the Foundation changes.

My name is Chris Parker. I'm a foundation engineer. I've been working a little bit on some of these things. First off, managed preferences. We've made some changes to NS File Manager since 10.1 and brought some new stuff in for Jaguar. There have been some updates to NSURL Handle and the new Rendezvous APIs in Foundation.

So starting off, it's over here. Managed preferences. Your applications may be operating in an environment where the user doesn't have the ability to change certain preferences. A lab administrator in a school or a parent in a single machine may set some preferences for a user to use, and they shouldn't be able to change those.

So what we do is we put a forced preferences domain at the beginning of the search path, and keys that appear in that domain always win out. So users shouldn't be able to set these things. Applications should disable their controls where the user can't change a preference key to give them a better user experience. You don't want them hammering on that button if they can't change the value. So what we've done is forced preferences.

Managed preferences. Your applications may be operating in an environment where the user doesn't have the ability to change certain preferences. They should be able to change those. So what we've done is forced preferences. Your applications may be operating in an environment where the user doesn't have the ability to change certain preferences. You don't want them hammering on that button if they can't change the value.

What we've done is forced values will always be returned when you use object for key. So if the administrator has placed a value in that forced preferences domain, you'll always get it when you ask for it with object for key. We've also provided a couple of routines for you to be able to pick out whether or not those objects are forced. That's object is forced for key and object is forced for key and domain. And these will return true if there's been a value forced for that key.

Some changes for NS File Manager. As of 10/1, we started doing some resource fork and catalog info preservation when you do moves and copies. We're trying to expand on that a little bit. We're also putting in support for the BSD file flags for the file immutable and file append only bits.

We've got some information there for file creation date, the HFS creator and type codes, as well as the account information for the owner and owner group IDs. We're also supplying an API to do some intermediate directory creation. You'll be able to create a whole series of directories at once rather than having to iterate through a path.

There have been some updates to NSURL handle. We've added some FTP support. A lot of bugs got shaken out over the course of the last several months. We now have asynchronous hostname lookup, so you're not going to block when you try and open up this thing to look for a hostname. There's going to be some tighter integration with system configuration planned out, and although it's not here, by the time Jaguar ships, I've been told this is going to also support FTP proxy support.

This NSNet Services stuff is our implementation in the foundation level of the Rendezvous API. This exposes some of the lower level features that have been put into Core Foundation and into the OS. If you do a top on a Jaguar machine, you'll probably see a little thing called MDNS responder, and that's part of what's doing the work for Rendezvous there. This exposes all of that stuff at the foundation level.

This allows us to do dynamic discovery of TCP/IP services. You don't need any prior knowledge of the address of the thing you're looking for, the host name, anything like that. You're just going to be able to find it right on the network. You advertise services, and then once you want to look for those services, you're going to discover them, and then discovered services, once you find them, you resolve them to be able to actually make the connection.

So when you start publishing a service, you're going to have to pick a domain. Right now that's local.arpa, and that's basically your local subnet. Okay, services that you offer are also going to have a name, a type, and a port. And you'll also create a delegate object which is going to listen for events that the NSNet services objects will tell you about. Okay, so when you first create this, you're going to alloc one up and then init it with a domain, a type, the name, and the port. The type string is a little bit of magic, but that's based on the services that are in Etsy services.

You'll set the delegate to some other object and then just tell it to publish. And that'll start advertising itself on the network with that information. What the user will wind up seeing is something like Nifty Demo Server. And that's about the only thing they need to worry about. The delegate implements methods like NetServiceWillPublish that's going to say, "Yes, I'm about to go out and make this service available on the network." And NetServiceDidNotPublish will be where you catch an error. The network wasn't ready, there's been a name collision, that kind of thing.

When you want to go out and look for these things, you need an NSNetServiceBrowser object. Since domains and services are dynamic, each of these things can come and go off the network. So this is going to tell you about all the different events that happen when this domain disappears or when a service shuts down. And again, you're going to use a delegate to get these events.

So when you want to discover domains, I need to find what domains are available to browse. You just do a standard alloc init sequence and then again, set a delegate and then just tell it to search for all the domains that are available. Tell me everything that's out there.

You'll get "Did find domain" messages on your delegate. That's NetService Browser. "Did find domain more coming." The "more coming" part is to let you know that if there is something else coming up, you're going to want to hold off on any expensive UI updates. "Did remove domain" says, "Oh, it went away. I should remove it from my list." Once you've found domains, you're going to want to find services within that domain.

So you may want to use another object, set it up, set the delegate, and then just tell it to search for services of type in a given domain. Just like there's did find domain and did remove domain, there's did find service and did remove service. And these will tell you what happened.

Once you get it, for instance, in your did find service more coming method, you'll want to hang on to it. You're going to get one of these NSNet services when the event comes in. You're going to want to hang on to it, and then you're going to want to resolve it. And this will allow you to get all the information you need to be able to hand it off to something that will allow you to make the connection to that other machine.

This API is asynchronous, so you do have to have a run loop running when you're going to use it. The NetService objects that you create to resolve, okay, you can't use to publish. So anything you get from a NetService browser, you can't publish it immediately with that. Those are things that are happening on other machines. The only things you can publish are the things that you're going to make available on your own computer.

And NSNet Service browser objects can only go after one thing at a time. So you can't tell a browser object to say, "Go search for domains," and then immediately tell it to go search for services within that domain. You can either create another one or you can tell the first one to stop and then start a new kind of search. There have been a bunch of other foundation changes, but Chris Kane is going to tell you about those.

So I'm going to wrap up the Foundation changes here before we bring Ali back to talk about AppKit. I'm going to talk a little bit about the new archiving mechanism that we've added to Jaguar. Some of the new property list format and new APIs to deal with property lists in Foundation. How you do some version checking so that you can safely use these new APIs. And a few other miscellaneous topics.

So first, let's talk about NSArchiver. NSArchiver has always had a number of issues or limitations. To unarchive an object, you have to know what order and what state was archived in the archive for that object at some point in the past. And all the values must be unarchived in the same order that they were archived. You also cannot skip values. For example, you cannot choose to not unarchive some state that was previously unarchived if you don't want it anymore, for example.

You also cannot probe the archive to see, well, was this piece of state saved in the past? And if so, unarchive it. You would want to do that, for example, if you had many different versions of a class. You would want to do that, for example, if you had many different versions of a class. In the past, we wanted to see what version or what state had been saved. And for some reason, you didn't know.

All of this, these three limitations where you must unarchive values in the same order that you archive them, you must unarchive all the values, and you cannot ask to unarchive values which weren't actually saved, make both forwards and backwards compatibility, dealing with archives that are old or archives that are new on older systems, make both of those very cumbersome.

So we've introduced keyed archiving. This isn't a new idea with us by any means. We've introduced keyed archiving mechanism into Cocoa for Jaguar. This allows you to unarchive values in any order. You can choose to unarchive only the values that you want in that particular version of the class and ignore values which were previously saved, if you wish. And you can test the archive. You can ask for values which may not be in the archive.

You ask by name. And if the value that you're asking for, for example, you want to get some flags or some other state out of the archive, is not there, the new mechanism will return you some default value appropriate to the type. For example, if you try to unarchive an object and it's not there, we will return nil.

So, eliminating those three main limitations, and I'm just talking about those three, there are other... and Chris Kuhn. The key to archiving is simplifying backwards and forwards compatibility. We still do type checking, however, which is that if you encode an object, you must, say, decode an object. Or if you encode an int, you must decode an int. You cannot decode it later as a float, for example. We still enforce type checking, and that's primarily to help you help us.

Because we're also customers of this API. Find errors in the encoding and decoding code in classes. We do allow some simple conversions. For example, you can encode a float and decode it as a double, or vice versa. You can encode a 64-bit int and decode it as a 32-bit int, and as long as it fits in 32 bits, you're okay. Otherwise, we will raise an exception. So what does the new API look like? Well, very straightforward.

NSKeyedArchiver and NSKeyedUnarchiver are two new classes. These behave very much like the NSArchiver and NSUnarchiver classes that you are probably already familiar with. The NSCoding protocol has not changed. It remains the same. You still use encodeWithCoder and the initWithCoder methods. The new coder methods which take string keys to identify the values, some of them are given here as examples, like decode bool for key.

Not all the Coder subclasses are going to do keyed archiving. For example, we don't own, Apple doesn't provide all the subclasses of NSCoder that are out there. Obviously you guys have written some NSCoder subclasses and we can't obviously force your classes now to do keyed archiving. So, there's a way now in NSCoder to test to see if a Coder does the new keyed coding mechanism and that's the allowed keys coding method.

Currently in Foundation, in the Jaguar drop seed that you have gotten, only keyed archiver and NSKeed unarchiver do keyed coding. In the future, we'll be able to do keyed archiving. So, there's a way now in NSCoder to test to see if a Coder does the new keyed coding mechanism and that's the allowed keys coding method.

Currently in Foundation, in the Jaguar drop seed that you have gotten, only keyed archiver and NSKeed unarchiver do keyed coding. In the future, we're going to have, say for example, the NSPortCoder set of classes do keyed coding, but they don't in that CD you have. for Jaguar right now. Let's run through a quick example. In this code, I'm gonna archive an object.

Archive an integer, some flags, and archive another object. That's pretty straightforward. The class, in its initWithCoder, in this case, is going to choose to unarchive the second object first, and I don't know why I would do this. Obviously you can unarchive things in the same order that you archive them, just as you always have.

But if you want to, you can, for example, if you're going to make a decision based on one piece or two pieces of the state in an archive, you could request those first and then decide what different code path you're going to follow. Here in the fifth line of code, Code is trying to unarchive a value for the key shape, which wasn't previously archived. And what's going to happen is that decode_int for key is going to return zero, and the shape instance variable is going to have the value zero.

Finally, I'm going to show an error. Here, we're going to decode float for key, the flags. Obviously, as I said before, we still do type checking. So, the float value for flags doesn't exist, and we're going to throw an exception. That's because we encoded the flags as an int previously.

So, some other notes on the keyed archiving mechanism, just in passing. Now you can store as many values as you like, with string names, obviously, at the top level of the archive as you wish. Generally in the past, with an archive, you did encode root object and encoded one object, typically encoded one object at the top level.

Now I think it will become much more common for you to save potentially many different objects, all named, at the top level. And of course you can unarchive them in any order that you wish, or you can choose not to unarchive all of them if you're later reading an archive.

You should use a unique prefix on the key names for encoded state. And Cocoa is going to use the prefix NS, obviously. And this is to avoid colliding with any keys that your superclasses may have already chosen or may choose in the future, which they may not be using right now.

You can also use the non-keyed coding mechanisms. Obviously the NSCoder still implements methods like encode value of obc type at, and those are inherited by the new NSKeyedArchiver and NSKeyedUnarchiver classes. We don't recommend this, and what will happen is that the information will be stored in the archive, but for those cases where you still use the old methods, you are still subject to the old restrictions. That is, for those old bits of state, you still have to unarchive them in the same order, you still have to read all of them, and you still have to not try to read values which you didn't previously save.

So what is the output of a keyed archive? What does a keyed archive look like? Well, today, keyed archives come in two flavors. Both of them property lists. Either an XML property list of the type found in, say, 10.1, or a new binary format property list that I'll be talking about in a little while. Now, the output of an archiver, a keyed archiver, won't always be a property list. These are just the two formats that we've introduced so far, and we may introduce more formats in the future.

IB allows you to save a Nib document in the Jaguar snapshot that you've gotten. If you look in the preferences panel, it talks about, with a radio button, a pre-10.2 format, a 10.2 and later format, and both formats. What this allows you to do is save a Nib file with either NSArchiver output, NSKeedArchiver output, or both.

If you save a Nib file, for example, in both, you can take that Nib and then read it back on 10.1, as long as you haven't used any of the new features in 10.2, new widgets or what have you. Of course, this is true into the future. This is true into the future.

It's not just true of the 10.1 to 10.2 transients, but it will always be true that as long as you don't use any new features and you're using old archiving, you have to make sure you don't take that back to an older system if you use new features.

So there's a lot more information in the foundation release notes. I wrote like 13 pages of release notes on how to do the conversion of existing classes. They're init with coders and encode with coders, have to be modified to take advantage of keyed coding. And how to plan for and do compatibility within the classes.

Planning, with keyed archiving, planning becomes almost as important and potentially even more important than with the old NS archiver where really you had to deal with everything in the init with coder on the reading side. Now with keyed archiving you can do more on the encoding side to plan for the future.

I mentioned this new binary property list format. We've introduced this because it's more compact representation of a property list and it's faster. Especially for big property lists, it can be quite a bit faster to read the binary format. There's a lot less information, for example, that has to come off the disk. The binary format also opens up the possibility for us to add some additional efficiency capabilities and these will probably come after Jaguar. They will probably not come in Jaguar at this point.

Another note, just in passing, we've bumped the version string that you find in an XML property list to 1.0. It used to be 0.9. There have been no changes in the property list format. We've simply incremented the version to get it at 1.0. And we're also calling this new binary format 1.0. This becomes interesting because we now have APIs where you can choose which format you save right out to the disk. You can choose 1.0, 2.0, whatever there will be in the future.

As I was saying, we've added a new class and it's property list serialization and it has these methods to allow you to choose to write an archive, a property list in whichever format you choose. Also read, and on the read side it will tell you what format the file was so that you can preserve whichever format the file started in.

If you're going to read in a file, make some changes, write it back out. We've deprecated an serializer and a deserializer. and these have also never supported the new property list types that we added in Mac OS X, new relative to OpenSTEPP. The NSBoolean, or the Boolean number and date objects, as far as allowing them to be property lists.

So let me take a break here at this point and talk about how do you use these new APIs and features that we've been talking about. Such that your new binary in 10.2 could also run on 10.1. Well, the first thing to do is always use Objective-C runtime checks if you can.

If it's possible with whatever the particular API is, use runtime checks when they're available. So check for classes with NSClass from string, Check for methods with response to selector. If you must, you can go to the globals that AppKit and Foundation export and its Foundation version number and its AppKit version number.

What you do with those is that we have recorded the historical values like the 10.1 version of Foundation in Foundation API in one of the headers such as NS Foundation version number 10.1. You can compare against that. You can compare using the global to see if the current version is larger than the historical version to find out if you're running on a version which is newer than 10.1.

Sometimes the release notes also mention a particular version number and provide a constant for which you can test to see, okay, am I running, for example, on an app kit which has, for example, I don't want to give away any of Ali's features like directional tabs. I will.

So if you want to avoid using new API, if you don't want to risk it, because you want your app definitely to be able to run in 10.1, there's this new header called availabilitymacros.h. It's part of the system, not part of Cocoa, per se. And it simply defines some constants that can be used to protect, you know, if-def API and headers, protect them against accidental damage. So you can use this as a declaration if you're compiling your project, for example, so that you're only getting 10.1 declarations.

A couple of tips for OBC programmers are that you should not subclass new classes if you want them to run on an older system. That's just not going to work because the new class obviously won't be on the older system. And you should not reference new global variables.

Those are the two most common problems we see. Obviously, people do fail to check for responding to a selector, for example, before messaging an object. But those are problems that can easily be solved by calling something like response to selector. These other problems, like subclassing a new class, are much harder to discover.

So Foundation now supports Unicode 3.2. This includes a much larger range of Unicode characters. What is it? 17 times larger range than the old 0 to 65,536 range. 535, I should say. The string model is based on 16-bit characters, and so what an NSString will do to represent these higher Unicode characters is use Unicode 3.2 surrogate pairs.

Now, code which is examining a string should always have been using the range of composed character sequence at index method to iterate over the string or examine individual radians that you've got. So, this is a very important thing to remember. And this is still true. Now, in Jaguar, this method is going to return ranges for surrogate pairs that it finds.

So there's some new NSString API as well. Some methods to trim and pad the characters off the ends of strings, and these are commonly used. There's some new methods to pre-compose and decompose strings per algorithms defined in the Unicode 3.2 spec. And there's a new method I'm going to mention in passing on NSMutableString to efficiently replace all the occurrences of a string inside of another string, and that's the method that I've listed here at the bottom. I'm not going to read it.

Now, in 10.2, during the development of 10.2, we found that a number of places in NSString were not checking as strictly as they might for various out-of-bounds values and null values. And so the type checking in 10.2 is made much more strict on parameter errors like that. And these are programming errors. You need to fix them.

For 10.1 apps, apps compiled and linked on 10.1, we maintain compatibility. However, compatibility was often a crash. And so, compatibility is not necessarily always a good thing. Now you'll get an exception for these types of errors. UTF-8 conversions also, for example, are now less forgiving than they were about invalid UTF-8 sequences in 10.1.

So finally I'm going to wrap up by mentioning an often used, often needed rather, method, which is we've added a new method on NSObject called performSelectorOnMainThread with argument waitUntilDoneModes. That's the full one. There's another convenience. Often with the app kit, you have to get some work done. There's a thread in the background, and it wants to do some work. And it needs to get that work done by the main thread due to, well, whatever reason.

Now, to do this in the past, we've often recommended DIO. You set up a DIO connection on the main thread, and your background thread looks it up, sends messages via DIO between one thread and another. Well, this has never been a really appealing workaround solution for us, but it's the best we could recommend.

The new method, performSelectorOnMainThread, is much cheaper than setting up a big DO subsystem. You don't have to marshal arguments back and forth. And I had one person who had just gone in, ripped out, said, "Oh, I wish I'd had this when I first wrote the code." They ripped out 100 lines of their code and called this one function.

And they said, "This is the best method ever." We do maintain ordering for a particular background thread, you know, sending to the main thread, or the main thread can execute this method as well. We do maintain the order of those invocations, but obviously, there's no ordering guaranteed amongst threads, or amongst a background thread and the main thread performing this method.

Now let me bring Ali Ozer back out to talk about the APCIT changes that occurred in 10.1 and 10.2. Ali? Just to highlight this method again, if you are doing AppKit programming and you're using multiple threads, this method is your friend. It's as useful as the performAfterDelay method that some of you might be using.

That one lets you perform tomorrow what you can do today. The other one allows you to have somebody else perform what you can perform instead. So these are both very useful methods. Okay, so we're going to first talk a little bit about 10.1 AppKit changes. Just the highlights because many of you are already probably familiar with these.

And then we're going to dive into Jaguar changes. One of the biggest areas of change in 10.1 was NSDocument. We added the ability to track documents on file systems that support it, meaning if your document is open in an NSDocument-based app and the user renames the volume or renames the folder that encloses the document, moves the document, and so on, your app will notice this immediately and take action. And that is good Macintosh user experience. It also preserves attributes and aliases to documents. You move the document to a new location on your desktop, you re-save it again, the new location is maintained.

And also aliases to that document will also be maintained. These are all natural things that should work, and with NSDocument-based apps it does work. NSDocument in 10.1 also supports hidden extensions, which I will actually talk in a little detail about because this is an important feature we introduced. Okay, so we're going to talk about 10.1.

As most of you know, file extensions are a good idea for compatibility with other systems and the web. I think most of you agree with that. Well, we also know that they confuse some users, scare others, and some users are just plain disgusted by file extensions. And that's true too, because they get in the way of naming their files the way they want. So, what we did in 10.1 is to introduce this concept of hidden file extensions. And this isn't just hiding the file extension across all files. This is hide the file extension on a per-file basis. So, it's a pretty powerful feature.

The extension is still in the name. It's not displayed. If the user wants to save their image as WWDCphoto and hits return, that is the name that they see in Finder, in the Save panel, in their window title bar. However, in the file system, the file is called WWDCphoto.jpg.

So let me just talk a little bit about what it takes to take advantage of this feature in your application. When you put up a save panel, you need to call this method saying that you are willing to deal with hidden extensions. And this caused the save panel to get a little more UI and look for this case.

And then when the save panel is dismissed, you ask, is the extension hidden? This basically indicates whether the user wanted the extension hidden or not. And based on this, you will hide the extension. Now note that the file name the save panel returns will still have the extension. It will always be called WWDCphoto.jpg, and this will tell you whether you should hide the extension.

If the extension should be hidden, you would use NSFileManager and this new attribute, NSFileExtensionHidden, on the second line there, to set its value to yes. And you might already have code like this in your app to set attributes on your files. Here is yet one more attribute you would use this for.

And finally, when dealing with hidden extensions, if you do want to show the name of a file, you should be using this file manager method, displayNameAtPath, which returns to you the user-visible, the human-readable name of the file. So in this case, it will not have the .jpg if the file extension was hidden.

And the savePanel, finder, windowTitleBars, etc., those already call this method, obviously, so you don't have to worry about those cases. The good thing is NSDocument does all this for you. So if you're not an NSDocument-based app, for instance, TextEdit, it does this by hand, but if you're NSDocument-based, all of this happens for you. There are a few override points or methods you can call to customize this behavior, like find out if the user did want the hidden extension and so on, but in general, you don't have to worry about it. So NSDocument is your friend.

In TextSystem in 10.1, we added support for filter services and we taught it how to speak. Filter services, if you're familiar with NSImages' support of filter services, work the same way. Methods in the TextSystem that open files generically, meaning just by file path or by URL, now know how to open files that can be opened via a filter service. What I mean by here is if the user has a filter service that converts Word documents or RightNow documents, say, to RTF, the TextSystem can now open them after running them through the filter service.

And just like in S-Image, there are methods to tell you what the native types supported by the text system are, so RTF, etc., and what the filter service converted types are, so you can make decisions based on the return values here. And also note that if you open a file and it was converted, you get this key converted in the document's attributes dictionary with a value of true, indicating that the file was converted. So you can indicate to the user that this file was loaded as a result of conversion.

The text system now knows how to speak. This one is fairly straightforward. It's a very high-level API that is connected to responder methods. The startSpeaking, stopSpeaking menu items will drive these, and if you actually implement these on your responder classes, the menu items will also apply to your classes as well.

In between 10.0 and 10.1, one of the things we did to the system was a lot of performance improvements. And one area where performance was improved was live resizing of windows. And one way to achieve this is via these APIs that we publicized in 10.1. You can find out when a view starts a live resize or when the window starts a live resize or when the window ends live resizing.

You'll get these method calls once, at the beginning and at the end. And even if your view is inserted and removed from the view hierarchy repeatedly, like the columns of a browser, you'll still only get these methods once. These methods allow you to set up some state and tear down that state at the end.

For example, if your view does some very complicated drawing that takes some time, during live resize, you might want to take a shortcut. You might want to cache parts of the view. If you're a map program, you might want to not display every little village in the map and just draw less things. If you use these methods at the end, you do want your view to be redrawn. You just say set needs display, yes, and the view will be redrawn once the view is redrawn.

Once the live resize is over. There's also additional convenience method in live resize, which is fairly easy. You can just call it from your draw rect to see if you're in live resize. If you are, do less work, and the live resize will be smoother for the user. This also applies to split view resizing and any other live resizing situations.

This application in 10.1 has the ability to set the contents of a doc menu. This is fairly straightforward. You can provide a menu in a Nib and provide the name of that Nib file. That's fairly static. Or you can provide the menu via a delegate method, which is of course more dynamic. Many of you have reported this bug where the sender in these cases was the application object and not the menu item. This has been fixed in Jaguar.

We also have doc notifications. Some of you might have noticed those bouncing doc icons and wondered where they're coming from. There are two APIs that let you start a notification and end a notification. These are automatic for modal panels in an active app. What happens is if your app is in the background, not active, and it puts up a modal panel, instead of that modal panel coming right to the front, right in your face, interrupting your typing, the doc icon automatically starts bouncing.

You don't have to do anything for modal panels in this case. Note that you can set the settings for the doc menu. The only thing I'll add in Jaguar is in case this bouncing wasn't enough for you, this will also cause some speaking and other things to happen. You'll see it.

[Transcript missing]

Okay, I didn't skip anything. No. Okay, so now I'm going to go to the Jaguar AppKit changes, which is the bulk of the rest of the talk here. Text system. We have more changes in the text system. Now as you saw in Scott's talk yesterday, it comes with more built-in spelling checkers.

And there's an interesting little story here, spelling checking disasters. That colorful over there was supposed to be spelled the proper way for people coming from England. But PowerPoint spell checker at the last minute seems to have fixed it, so here I am up there with my point somewhat ruined.

Anyway, if you're using the British English spell checker, which is distinct from the American spell checker, you would get colorful to be recognized with a U. And there's also multilingual spell checker, which does recognize many languages at once if you're doing a lot of multilingual work. So that's fairly obvious. We finally added support for right centered and decimal tabs.

And we've also added support for bidirectional text. The tab stops is fairly straightforward. For many years now, you might have seen these little widgets in the ruler of TextCited and other Cocoa applications, and they were dimmed. Well, now they aren't, so that's that. And the enum values were there before, so there's no new API.

Bi-directional text, as some of you are probably aware, bi-directional text is needed for proper support of Hebrew, Arabic, and some other scripts. It's not just right-to-left text, it's actually the ability to put the English and Japanese normal left-to-right scripts with these other scripts going in the same line at the same time, which actually has a lot of complicated rules. Selections can now be disjoint. When you make a selection, you'll see two or three boxes and so on. So it's actually fairly complex functionality in there.

One thing we've said with regards to this feature before is that the tech system is ready for this feature API-wise, and we will not add any new APIs. It turns out that was true. We did not really add any new APIs. The only API we added is some highly obscure thing, which most of you won't need. It's basically a new glyph attribute indicating the bi-directional text levels.

We did also add a new typesetter subclass, because we want to keep the old typesetter there for those of you who might have subclassed it or who might have a need to use that exact typesetter with its typesetting rules. But the new typesetter subclass will be the default typesetter, so by default most apps will just get this functionality out of the box. Now note that in the Jaguar CD you got, the new typesetter subclass is not enabled by default.

Localized File System View, you probably saw this in Scott Forstall's talk yesterday. Here we show the file system to you in localized for the user's language. We're not localizing the file system. The file system names, the folders, etc. are not renamed. Instead, we just display localized names for different entities, which allows different users on the same machine to see the file system entities in their own language.

Now some of you might be saying, you're recycling slides, aren't you? Because this is the slide I just showed 15 slides ago where I said, use this if you want to get proper hidden extension behavior. Well, it turns out in Jaguar you can use this if you want to get proper localized file system view behavior. This method now not only does hidden extensions, it will also localize as well.

Now some of you might be wondering, oh great, now how do I localize my app name so it appears localized? The process is actually pretty straightforward. It's what you already do, really, for the most part. You add CFBundle.name to your Info.plist. PV already puts one there for you. It needs to be the same as bundle's actual name. So if your bundle is called textedit.app, your CFBundle.name is textedit. That's because if the username is textedit.old or some simple word processor, at that point it's no longer localized because the name has been changed.

Then you add this key ls.has.localized.displayname to your Info.plist. This is probably the only special thing you need to do. This is for performance reasons. We decided we needed to have a separate key. Then you would have a CFBundle.name in your Info.plist.strings, which you might already have added. So CFBundle.name in your Info.plist.strings provides localized names. This other key tells the system that there is a localized name. Note that in addition to localizing your app name, you can localize your bundles with the same process. You can localize arbitrary folders as well. This will be documented in the release notes in Jaguar.

So tab views. Chris already spilled the beans on this one. But anyway, so there's directional tabs. Before we only had the northward, the upward facing tabs. Actually that's not really true. We also had the rather shy and elusive tabless tab view, which actually is more useful than some people think.

But anyway, the one in the middle was also there, although most people probably didn't use it. Now we have the left, right, and the bottom tab views as well. The interesting thing here is that there's no new APIs. Again, all the API was there. But the methods that you might override or call to draw the labels do the right thing.

In that, they transform the coordinate system for you and then call you. So if you do drawing, if you write some text, they will appear in the orientation shown here. So you don't have to worry about it. If you want to do something special, then you might have to do other coordinate system transforms yourself.

NSImage now, there are a lot of bug fixes and performance enhancements in NSImage. These are the top three. It now supports animated images. This is a support at very low level where NSImage reps created from animated images, for instance animated GIF files, have these three properties which lets you find out what the frame count is, what the duration is, and also set what the current frame is. Now, it's possible, of course, using this API, it's possible to do all sorts of animated image stuff. We are looking at getting feature into NSImageView and NSText for Jaguar. Currently, the support is in NSImageRep.

Progressive image loading allows you to load an image in the background and display it to the user in pieces as the image becomes available. There are four delegate methods. All you have to do is implement the last one for the simplest approach here while you are here when the image is finally loaded. But, for instance, you can also override the second method to find out when the header of the image has been loaded so you know how big it is and you can start displaying a placeholder if you want.

You can also override the third one to find out as the image chunks are coming in. There is also a more sophisticated API down in ImageRep for if you are the one getting the data and you want to pass it to NSImage, you can also use that API.

And finally, we are making caching policy more explicit. Here, by caching, I mean NSImage's ability to put bitmaps, PDFs, etc. in off-screen windows. Clearly, if all the images are cached in off-screen windows, they're faster, but also there's more memory used. So, NSImage does make the decision by itself on a per-image basis, but if you're dealing with hundreds of images, you might find that it's better for your app's purposes to set the policy on a per-image basis one way or the other. This API will do that.

There's a little stylized spinning arrow on the side for you, but basically this is a control that was missing in Cocoa. We've added this as a variant of progress indicator class. It's because this is pretty much the same thing as an indeterminate progress indicator. You can set the style by default, you get the bar, but if you set the style you can get the spinning one.

There's also more API in progress indicator. You can now size to fit it. You can create a spinning arrow that's as big as your screen, but if you size to fit it will give you the natural recommended size. You can also set whether the spinning arrows or the bar is displayed when it's stopped. Typically the spinning arrows are not displayed when it's stopped, for instance, so this controls that.

NS Toolbar now has a small icon mode. We will automatically resize your images for you if you want, or you can provide small images if you really want to control every pixel in that toolbar. The API is fairly straightforward. It's much like the other toolbar APIs. One thing that people have been asking in NS Workspace is to get more information about launched applications and running applications. This is something that you guys had to go to the process manager in Carbon for on occasion.

Now what we've done is the notifications for launching apps now include in the user info dictionary these keys: the path of the application, the PID, and so on. So you can find out more about launched applications. In addition, you can ask what are the launched applications so far and what's the current active application. These return either an array of dictionaries or a dictionary which contain the keys I showed on the previous slide.

Yesterday you saw the textured, the metal background window. So that's shown here at the end there. Textured background window mask. We call it textured just in case it changes from metal. But anyway, so this This is now available to you either through IB or through API to use. Now one warning about this, every window and every app on the system is metal. The system is going to look rather heavy.

The idea here is you would want to use this either in one window apps like Calculator or apps where the window represents an interface to the device. iTunes, iPhoto, those are good examples. You should not use this style of window for your panels, your auxiliary windows, your sheets, and so on. Those still use the favorite corduroy pattern.

Now the one I didn't talk about, non-activating panel mask. If your app wants to put up a panel that gets user input, like keyboard entry, but you don't want your app to become active, this is the style of panel you want to use. It's useful on certain occasions. It's certainly used by the system.

In addition to the textured background stuff, we've also added slightly finer control. You can now make windows movable by window background. This is appropriate, clearly, for textured windows which have no title bar, but also for other windows where there's no obvious title bar, like a clock and so on.

This will make the window move from anywhere. In addition, you can set the background color of a window to an arbitrary color or, in fact, even a texture, as you know, because NS colors can represent textures, patterns. And again, don't use this everywhere, but there are cases where it's handy.

Yesterday in Scott's talk, you heard about Carbon/CoCoa integration. So the goal here is, for you Cocoa developers, the goal here is for you to allow writing plug-ins in Cocoa, say, for existing Carbon applications. And you saw that Photoshop demo where a Cocoa plug-in worked in Photoshop. A few weeks ago, we did not think that would be possible at all, but it turns out it was.

And also, you want your Cocoa app to be able to use existing Carbon plug-ins. Or maybe you're transitioning from one environment to the other and you want to use existing code fragments in your application. And that's what our goal here is to enable. It doesn't enable really fine control within a window.

You can't have a Carbon button, a Cocoa button, a Carbon toolbar, a Cocoa drawer all talking to each other. That's more fine control than we're providing at this point. But one thing that really surprised me. I was working on these systems. I was working on these slides, like 1:00 AM a few weeks ago.

And I brought up the color panel in PowerPoint on Jaguar, and it was a Cocoa color panel. And I just, I didn't even guess. I knew that we had hooked up the thing, but I didn't know that PowerPoint was using the standard Standard Color APIs in Carbon, which is GetColor. So what in fact has happened is Carbon currently, for its GetColor APIs, uses the Cocoa Color panel. And it uses it modally. So the color panel had to learn how to work modally.

In addition, the font panel, Carbon also uses the Cocoa font panel now. And that one there's new APIs for, because the existing Carbon font APIs are all in terms of the menus. So there's new APIs which, once Carbon developers adopt, they will be able to use the Cocoa font. the Cocoa FOD panel.

To do this integration, These two APIs, which actually I think were there before, but these two APIs now have a lot more smarts. You can create an NSWindow around a CarbonWindow with initWithWindowRef. WindowRef is the Carbon way to refer to a window. Once you do this, you can now start treating that CarbonWindow as if it was a CocoaWindow. In addition, you can return a CarbonWindow from an existing CocoaWindow. Obviously, in the first case, if you provide the WindowRef, that's what you'll get back.

But if you have some arbitrary CocoaWindow, you can call this, and it will create a WindowRef and return it to you. And then you can start making Carbon calls on that, or you can pass it to Carbon subsystems. And if you need to interact with Carbon subsystems, probably the thing you want to do is start handling events via CarbonEvents and learn about CarbonEvents.

To load Cocoa bundles in Carbon apps, you would load the bundle with CFBundle. One thing you need to assure is if the Carbon app has not linked against Cocoa at all, you need to call NSApplicationLoad to initialize the Cocoa application stack. This can be called either from the bundle or from the application.

Where it's called depends on which one is the one who knows. For instance, if you're writing a Cocoa bundle to work in a Carbon application, and the Carbon application is an unsuspecting application like Photoshop, you probably put this call in your bundle because you know you want to work in the context of Carbon app. Or vice versa, maybe there's a Carbon app that wants to use existing Cocoa bundles. For instance, a Carbon app wants to use Cocoa screensavers, and the Carbon app would be responsible for calling this function.

Quick note about NSPaceBoard. This was a frequently requested feature. There's now a new data type, the vCard/Pboard type. So if your app deals in vCards, deals in people trade or whatever, you can now use this as a standard way to trade vCard information with other apps. But more interestingly, we have AddressBook.framework, a brand new public framework which has Objective-C Cocoa APIs to get to that underlying people information that Scott and Steve were talking about yesterday. So this is, there are a bunch of AD classes and a bunch of good APIs and you can hear all about this in the AddressBook framework talk.

Accessibility. You saw demos of this yesterday. This is to allow writing assistive applications. Assistive applications are these Applications that run outside of other applications, but that either control those applications or get more information to them to communicate to the user. The screen reader you saw was an example of that. Or alternate input devices, devices that are way beyond the simple keyboard and mouse interface, ones that are really radically different. These use the accessibility features to provide users access to all the other applications.

There are two sets of APIs here. There are actually three. The one API is the C APIs, which the assistive application creator uses. The screen reader or the alternate input device would use these C APIs. Most of you probably won't be writing assistive applications, but it doesn't mark the opportunity there. These are the C APIs like this. These C APIs in turn know how to talk to Cocoa or Carbon. There are Cocoa APIs, which you are probably more interested in. for providing accessibility features to these apps.

The way this works is UI elements in Cocoa applications implement this informal protocol called NSAccessibility and they just have to implement a few methods on their UI elements. This API basically presents the hierarchy of objects: NSApplication, Windows, Views inside them, Controls, etc. as a hierarchy of these UI elements. Note that built-in controls in Cocoa implement this and in fact many subclasses you guys create will also just work.

But if you have some really wacky subclasses or you create some UI element totally from scratch, you might want to look at this accessibility protocol to see what it takes to implement that. Because just by implementing that your app will be speakable and drivable by these assistive applications. There's a lot more details of this in the Cocoa Controls and Cocoa Accessibility on Thursday.

Scripting. We've added a lot of nifty features to scripting as well and a lot of bug fixes. NSAppleScript is probably the most interesting thing there. It's a new class which allows you to load, compile, and execute Apple scripts of any format. It also even allows you to get back pretty printed scripts in RTF so you can display them in your application if need be and let the user deal with them. There's also automatic support for properties property, better conversions between various data types, and there's a whole talk for Cocoa scripting where Mark will talk about scripting in general and the changes we've introduced in Jaguar.

So that's really all I have to say. Now, one thing to note is that the Jaguar release notes on your CD are current. So they do include these changes we've talked about. They also include many more changes we haven't talked about here. Also note that not all the changes we've talked about are necessarily in the header files yet. I mean, many are, but some aren't. And also, some of the things we talked about might change further before Jaguar. Because after all, we still have a few months to ship Jaguar, and we're still doing engineering on this stuff.

So anyway, these two files, apt-get.html and foundation.html, have a lot of information. I also want to point out one more thing in regards to what's new in Cocoa. As you know, Apple is delivering Cocoa and here we are telling you about all the enhancements we're doing in Cocoa.

There's a lot of stuff. But one additional thing to note is that Apple is also delivering applications that use Cocoa. They're the old favorites: Project Builder, Interface Builder, you know and you love them, hopefully. They're the recent favorites: iDVD2, iPhoto, those are Cocoa applications. And one thing you might not realize is the apps Steve showed yesterday, Address Book, Sherlock 3, and iChat, those are all Cocoa applications as well. And for all new applications, Apple is always seriously considering Cocoa as the way to deliver those to you and to all the users.

Okay, whoop! Documentation. If you weren't at the Cocoa intro talk yesterday, one exciting documentation announcement from Matt Rolofson was that the AppKit and Foundation reference will be available in printed form in summer or late summer. Anyway, look for that in your ADC mailings. I think that's very exciting for those of us who still like to look through books and papers and so on and can't deal with too many windows on our screen at the same time.

There's more information there, the Learning Cocoa book and the new building applications and the website, clearly. Here's a roadmap of the various Cocoa talks. The API techniques will go into some of the not-so-subtle and subtle API issues, design techniques, etc. Scripting, controls, accessibility, I already talked about those. Drawing and text, these are all overviews of these Cocoa technologies, touching upon some of the new things that have also happened recently. In addition, earlier you heard about the new Cocoa tools.

Earlier you heard about the Rendezvous stuff. You can go to the CF Network talk or Zero Configuration Networking to hear more about how the Rendezvous stuff is implemented. Address Book Frameworks is on Friday. That's the new address book APIs. And there's the Cocoa feedback session for those of you who are here Friday at 5pm. Hope to see you there. And I'd like to invite Heather Hickman, the Cocoa Technology Manager, on stage to run the QA. on stage to run the Q&A.