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: wwdc2001-112
$eventId
ID of event: wwdc2001
$eventContentId
ID of session without event part: 112
$eventShortId
Shortened ID of event: wwdc01
$year
Year of session: 2001
$extension
Extension of original filename: mov
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: ...

WWDC01 • Session 112

Carbon: Windows & Menus

Mac OS • 38:19

Learn about features in the Carbon Window and Menu Managers such as window grouping, sheets, asynchronous window dragging, new alert types, the standard Font, Help, Window menus, changes required for custom MDEFs, and more.

Speakers: Ed Voas, Guy Fullerton

Unlisted on Apple Developer site

Transcript

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

We've all had a good nap, and you're ready to learn about the great new features we've added to the Window Manager and the Menu Manager to make your applications look great on Mac OS X. And to introduce you to all that groovy new stuff, let me bring out the manager of the High Level Toolbox team, Ed Voas.

Alright, so the Window and Menu Managers are actually pretty important to every Carbon application. You need windows, you need menus. So, what we're planning to do in this session is kind of lead you through an overview of all the different things that we've added to the Carbon Window and Menu Managers. Here's a list on this slide, but we're going to hit each one of the points individually. First, sheets. Sheets are one of the most visible features of Aqua, and one of those features which you actually need to adopt. It doesn't come for free.

The whole point of a sheet is to provide a document model experience. This means that the sheet makes the document that the sheet is bound to go modal. The user can't interact with the document any longer, they must interact with the sheet instead, but the user can still deal with other documents, other windows, and the rest of your application in general.

To get sheets the easy way, we have a few APIs. The first is called Create Standard Sheet. And if you're familiar with Standard Alert or Create Standard Alert, this is the equivalent in the world of sheets. You can also get sheets for free through Navigation Services and Print Panels by passing the appropriate parameters to the calls in those two components. Or you can create sheets yourself. To do that, you have to create a window of KSheetWindowClass. And this is actually enforced by the Window Manager.

Once you have this sheet, you should install the Carbon Event Handler to handle the K event window draw content event. This is important because we actually need to render the content before we put the sheet on screen because we need to do the animation. So all the bits need to be in place before we can run that animation. So it's important to install that handler.

Once you have your sheet and you've installed your handler, you probably want to see it on screen. And the easy way to do that is just call Show Sheet Window. And that API basically takes the parent window that you want to bind the sheet to, and when you call this function, we do the animation, we make the sheet appear, and the Carbon Event Model then knows, oh, we're in a document modal situation, and it knows how to deal with clicks appropriately.

Once you're done with the sheet, the user has interacted with it, we call it Hide Sheet Window. We will do the inverse animation, make the sheet kind of get sucked back up into the title bar, and then you have to remember that once you've hidden it, it's just hidden, it still exists, you still need to dispose that window.

Transparent sheets are actually part of the Human Interface Guidelines. You're actually supposed to be able to see through sheets. Now that's supported in Cocoa in the first release of Mac OS X, but not in Carbon, but it is something we're working on. And I'm just making you aware of this because there's a few rules that you should follow in order for us to try to turn this feature on for free in most situations. In general, you will probably need to switch this on manually. However, for APIs like Create Standard Sheet, we want to be able to turn this on and just have it work for free, so you don't have to do anything. You get all the benefits of transparent sheets.

In order to do that, we actually have to make changes to the Control Manager. As you know, the Control Manager likes to erase behind controls. And this presents problems because when we erase, we use Quick Draw, and Quick Draw does not deal with alpha, and transparency means alpha. So we did have to make some changes there. So the goal is that Create Standard Sheet will just work. However, Create Standard Sheet actually returns the dialog ref to you. And at that point, you can actually take that dialog ref and start inserting dialog items.

So, that may actually work against the goal of us being able to turn it on automatically. So what we ask is that if you are going to do that, make sure you add standard controls, because all of the standard controls that are supplied by the toolbox will automatically work in this new transparent sheet mode. And if you're running custom controls, be aware that because sheets are transparent, alpha, that whole thing, you will have to actually render your controls with core graphics, Quartz, and not Quick Draw.

So, historically, we've supported three types of an alert: the Note, the Caution, and the Stop Alert. You'll notice on Mac OS X that when you call these APIs or specify these types of alerts, you actually don't see the correct icon. At the very least, you should see the caution icon, because that's part of our human interface guidelines. We are working on fixing that and doing the right thing. So it's important for your applications to not try to replace the icon yourselves. Just keep using the constants as you always have and we'll do the right thing in a future release.

Window groups are a brand new feature to the Window Manager. Historically, people have done many evil things with the Window Manager by manipulating the window list themselves, doing things that would probably scare your grandmother. The problem with that isn't that they were really doing anything evil. The problem was that the toolbox couldn't actually rely on what it thought the correct state was.

In Carbon, we actually want to be able to have both the toolbox and your application play in the same sandbox and always know the correct state. So it allows you to actually change window layering. It also allows you to change the way you do window activation. But... The most important thing is that the toolbox is still in the loop, and we can continue to do the right thing.

For example, if you click on an application's icon in the dock, up comes a pop-up menu, and in that pop-up menu is a list of all the document windows. Well, we need to be able to just call Select Window on that window, or Activate Window. and have it actually do something correct that your application can deal with, and we don't trip up your application.

So one of the most common uses for window groups is to actually move windows between groups. And in some sense, you can actually think of groups as layers. So we have a document layer, we have a floating window layer, and we have like a modal layer. There are times when applications want to take a document window and make it float, or make a floating window not float. And you can do that through the Window Group API.

Actually, if you were here yesterday for the Carbon Event talk, we showed an application called Magnify. And part of the preferences there was a checkbox to allow the window to actually float above all windows or just be a floating window in that application. And the way that we actually make that switch is through window groups. So that's one aspect of it. The other aspect is the activation aspect. There are actually times in certain applications where they want to make a window active, and that window is not the frontmost window.

To accommodate this, we've implemented a new API called ActivateWindow. This basically does the mechanics of SelectWindow, and that it actually posts an Activate event to the window, but it doesn't actually change its Z order. So it'll deactivate whatever the currently active window is and make the window that you specify active. To go along with that, we have ActiveNonFloatingWindow. This is what you should probably use in place of FrontNonFloatingWindow or FrontWindow.

In fact, it's actually a bad thing to just use Front Window at all, unless you really, really know what you're doing and you know how to walk through the window list. There may be times when the system has windows in your window list, like for example, an input method has a window up. And if you call Front Window, you're not going to get your document window, you're going to end up getting the input method window. So you need to be able to code in such a way that you can deal with these situations.

One of the best parts about window groups is that you can create your own. You can create your own group, put your windows in it, and then you can actually do interesting things like make them move together or Z-order together. So treat them almost as one window. Sheets actually use this.

So when the sheet is bound to its document window, it creates a window group, and then that pairing of windows acts as one. When you move the parent, the sheet moves with it. When you click on one or the other window, they both come forward or they both go backward.

Overlay windows are our solution to allow you to actually draw on the screen. But you're really not drawing on the screen. What you're drawing into is a transparent window at a very high window level, meaning that it is above the menu bar and above the dock. Now, this is really cool. I could draw all over the screen.

That's great. But it does have its implications. For one, A window that is the size of the screen at 32-bit on a 10x7 display is going to take 3 meg. Just because you can't see it doesn't mean it doesn't exist. We actually have a back buffer for it.

So it's important to actually size your windows appropriately for whatever you're doing. It also requires core graphics to do your drawing. Again, Quick Draw doesn't deal well with an alpha channel, so you have to use CG. And the last thing is it can have nasty effects on classic windows. Classic windows are what we term non-retained. There is no back buffer for them. If something obscures it, it's

[Transcript missing]

One thing that we've added is the concept of automatic window positioning.

Whenever the monitor size changes, or a monitor size changes, or maybe the dock appears because you have it on, you know, you turn it on so you want it to show up, or you've resized the dock, we will actually go and move windows around if their title bars have become obscured.

Now, sometimes you don't want that to happen, and you can actually override that. We send out a K event window constraint event to all windows when we're about to do this. And you can intercept that event by installing a Carbon Event Handler on the window and just return no error saying, "Oh no, don't do anything. I handled this, even though you really didn't do anything." And with the advent of the Dock, it's a little tougher to actually find out where you can put your windows.

It used to be, if you were on the main monitor, you'd say, "Alright, I'll subtract out the menu bar height from the top." But now we have this Dock. How big is that? How do I, uh, you know, how do I subtract its height? Where do I get the Dock rectangle? Well, you can't. But what you can do is called Get Available Window Positioning Bounds. This is a new API that we've added.

For any monitor, for any G device that you hand it, it will hand you back a rectangle, which is the legal space that a window can live in. So it's important to start using that. Some of the APIs that we have actually already take the dock into consideration. So for example, resize window or zoom window. So you don't need to deal with it in that situation. We'll automatically handle it for you.

The Window Menu is something new, and it's completely supported by the Toolbox. It automatically tracks Document Class windows. And you add it to your menu bar by calling Create Standard Window Menu. It hands you back a menu. You then take the menu and insert it into the menu bar yourself. The reason that we don't insert it for you is you might have different requirements for where it lives with your particular menu bar.

All the menu items in the standard menu are handled automatically by the toolbox, but you can actually add items to this menu and not affect the menu adversely. We drive it completely by menu commands, so as long as you don't steal our commands, we'll just handle it for you.

You can add your own commands, maybe you want to add a menu item to do tiling or stacking or whatever you want. Another thing that we've added though is this concept of alternate titles. We have API to set a Windows alternate title. And what we use this for, we use it for like three things.

The first is we will show it in the Window menu. The second thing we'll use it for is when you minimize a window, its alternate title will show up when you roll over it with the mouse in the dock. And the third place you'll see it is actually in the doc pop-up when it shows the window list.

The reason for this particular alternate title concept is that you may have windows in your application that all have the actual same title, but maybe they're showing different parts of the file system or whatever it is. You can actually leave the window titles alone, but specify an alternate title, and that's what will show up in the window menu.

Certainly when you're looking at a window, you can pretty much tell, oh, this is for that, you know, I'm looking at, you know, whatever part of the file system or that part of the file system or whatever the case might be. But if you're looking in the window menu, there's no way to discriminate between the two or between all of your windows. So alternate titles allow you to specify different titles.

So we have a lot of default behavior in the toolbox, and we don't allow you to patch these days. But we do have Carbon events. So you can actually customize the Window Manager to your own desire by installing Carbon Event Handlers. And if you look at carbonevents.h, there are a lot of events that we send out for windows. I want to just point out some of the more common ones that you would tend to override. The first is KEventWindowBoundsChange. Whenever you are dragging a window or resizing a window, we will send out KEventWindowBoundsChange. It could actually be changing, but it's a little typo there.

And you can actually use this to do window gridding, snap to behavior. We can have pallets snap together or to the edges of the screen. That would be the most common use for that. The next one is K-Event Window Get Click Activation. This allows you to do click-through. Whenever the toolbox detects a click on a window that is not the front window, not the active window in your application, we will send this event to it, asking it, "What should we do? How do you want to handle this? We just got a click.

Should we bring you forward or not?" There are a couple of results that you can return. To do click-through, you would basically say, "Don't activate me, but I do want to handle the click." This is how you can accomplish background dragging. Dragging from a window that's in the background onto some window that's in the foreground without that window coming forward first.

The next event is Kevent Window Handle Content Click. If you're using the standard window handler, this is the way you would intercept clicks on your own custom content. This is essentially, what it does is it represents a click that is not in any toolbox entity that we know of.

It's in effectively some other region of the window. So if you have like custom views, but you have standard controls, the standard controls would actually be handled by the toolbox, but you can handle your custom views just by intercepting this event. And it's effectively a mouse down event. It has all the same parameters.

Now the toolbox, as I said, has a lot of default behaviors. And for example, we will actually zoom windows for you. When we do that, we need to know information. Like, what is the ideal size of the window? So when a zoom is detected, and we're about to do a zoom, we will actually send the window a K event window get ideal size event.

In response to that, your application should say, "Oh, I should be so big." Store that back into the event, and then the toolbox can do the right thing. Likewise, for a resize window, when we are about to resize, we will send out a KEventWindow.getMinimum and getMaximum size. You just tell us what those constraints are, and we'll do the right thing with it.

This next slide is about a feature that we're going to attempt to turn on in the next major release of Mac OS X. The reason that I'm bringing it up though is because I want to kind of get you ready for it. Server-side window dragging. What that means is that the window server is in control of dragging the windows around. Cocoa already does this. We're going to turn this on in Carbon.

The advantages are first that we don't actually have to keep talking to the Windows Server. So right now what happens is we get a mouse move while we're tracking a window, and we say, "Okay, move the window." We tell the Windows Server, "Move the window." It sends us another mouse move event, and we keep this back and forth traffic as you're dragging a window around. It's kind of a lot of crosstalk.

So we want to eliminate that. The next thing is that if your application is just stopped dead, something's happened, you're in a tight loop or you just went away for a while, the user can still move the windows of your application. You don't have to be actually handling that. And this is kind of useful at times. This also has an effect that it actually makes your application seem much more responsive.

The reason is, let's say your application was swapped out. He's got a lot of applications open and we had to swap your app out. So then we click on it, he needs to swap it back in. And normally we'd have to swap back in all the code that had to deal with dragging and all of that fun stuff.

Because the Windows server is in control, we can actually start to drag the window immediately. So rather than seeing a big delay before the window started to follow the mouse, the window would actually start moving immediately. And this has a profound impact on the user because they feel like they're in control, you know, the system's keeping up with them, and it's rather important.

Now the reason that I'm talking about this at all is because it's going to require changes to WDEFs. What we want to do is give a window definition The coordinate system that starts at 0, 0, not at the global coordinates that the window is. So if you are writing WDEFs, you will need to be aware of this when this happens.

Now, we're not going to break any existing WDEFs, but it will mean that if the WDEF does not support this server-side dragging, we can't turn it on for your application. Now, you're going to have to turn this on manually if you're doing the window dragging yourself. If you are using the standard window handler, this will be turned on for free. Again, provided that the WF supports it.

Custom WDEFs are still supported. For any WDEF that we need to reference in a resource, like a wind resource, you can register the resource ID. with the toolbox along with the PROC pointer, which implements the def.proc with register window definition. If you happen to have, or you happen to start writing a Carbon Event based DefProc, you would use Registered Toolbox Object. And then you just use Create Custom Window, and your custom window runs, and it's all good.

Now, what I'd like to do is show you a little bit about the stuff that we just talked about, and to do that, I'd like to bring up Guy Fullerton. But I do have to remind Ed that I won the last game last night, so... That was luck. not always a target.

First demo I want to show you guys has to do with window groups. One possible use you might have for window groups is if you have just a window that happens to display little subwindows for editing purposes. Like let's say this is a very, very primitive mail application that needs a way to add a name to an address book.

And it happens to pop up a little subwindow here, which is implemented as another window manager window. Now you can type in there and all, but with window groups, we actually allow you to tie those two windows together so that you can drag them around together and have them z-order together properly.

And another cool thing about window groups is they're totally arbitrary. You can set up whatever groups you like and you can include or remove windows from them as you wish. So I've got these four windows that as you saw just then as I was clicking on each of them, they activated separately. Now that I have them all grouped together, they activate together just as you would expect. And you can drag them together just as you would expect. And they minimize together just as you would expect.

So the next thing I want to show you is some of the overlay window support. One thing you might want to do with overlay windows is give the user a way to sort of draw on arbitrary parts of the screen. So this Event Horizon application has overlay support built into it, and I just turned on the overlay window for this app, so I can start to scribble wherever I want over the screen. I can scribble over the dock. I can scribble over finder icons, do whatever I want. You could even use it as sort of a primitive coach marking mechanism if you wanted to.

Oh, oh, oh. We might have just gotten ourselves in trouble. Well, I guess that would be me that got in trouble. Oh, no, okay. It worked out. Let's close that window. Now, another use for overlay windows might be if you're an alien race that wants to invade the planet and you need to throw a message up on somebody's screen. You could also do that just in one shot.

So one of the other things Ed mentioned is we've been working on transparent sheet support for Carbon. And what I'm running here isn't exactly Mac OS X GM. We've got some bleeding-age pieces in there, and I want to show you the progress we've been making. This application is simpler text. I showed this off yesterday. It's just a replacement for simple text.

And it uses the standard Nav Services Save/Don't Save dialog. But on the system, we've enabled transparent sheets. So if I try to close the window, you can see that the sheet really is transparent. It uses all the standard control manager controls, and it just works when we turn that on.

Now, I showed this app yesterday. This is Live Buttons. The cool thing about this actually has to do with the fact that we install Carbon event handlers to allow you to manipulate an otherwise static user interface. And while we were writing this application, it brought to the forefront one of the really major problems with the control manager.

And that is that if you have peer controls that happen to overlap, you get--let's do this too-- You get some really strange behaviors with the interface where whatever control you happen to click on last is what sort of owns the draw area, and you get really ugly looking graphics. And in fact, let's say you try to throw a picture into the background of that window.

Not only do you get the...

[Transcript missing]

Oh, you know what? I'm clicking on text at that point. If I click on it over here, you can see that just the picture highlights, none of the other controls highlight. All the animation just works. You still have a spinning progress arrows drawing on top of the OK button. So this is something that you can look forward to in a future release of Mac OS X. And now I'm going to send it back to Ed to talk a little bit about the Menu Manager.

So obviously the first bit of that that you'll see would be the transparent sheets and later on we'll actually make that a general purpose thing that anybody can use. So the Menu Manager. We made quite a few changes to the Menu Manager as well. First, you can have icons for menu titles.

Oh yes, believe it. Next thing is we support Indication and Menu Section support. A good example of this is the Recent Items menu, which is under the Apple menu in Mac OS X. You can actually do this. We support it fully in the Menu Manager. You don't have to write a custom MDEF.

We have much better command ID access. So command IDs are a way to identify a menu item, which is a position independent method of doing so. And that's great, but you actually want to manipulate those menu items using the command ID as well. And we have full support for doing so with Carbon. We support ref counting. Dynamic Items. This would be if you have a particular menu accelerator in your menu and you want it to actually change the text depending on what modifier keys are down, we support that.

We actually have, and we also have much better hierarchical support. Historically, what you've done is you insert your menu, your hierarchical menu, into the hierarchical menu list using, you know, insert menu negative one, and then you reference that by putting the ID of that menu into the actual parent item. Well, we've come up with a slightly better way, which is you just take the menu ref and you set it on the parent item, and you're done. You don't have to play those games anymore.

We also support certain Carbon Events. The first is Begin and End Tracking. Whenever the mouse goes down in the menu bar and we are about to call, or basically when Menu Select is called, is what it comes down to, when we start Menu Select, we send out Begin Tracking. When we end Menu Select, we call End Tracking, and we send that event out. And this might be useful if you have timers which are firing but you don't want them to fire while the menus are down. You can actually disable them by looking for this notification.

We also have a really cool event called K-Event Menu Opening. And you can do this for lazy construction of menus. Let's say you had a hierarchical menu and it showed part of a file system or something. You don't necessarily want to populate it all up at once. That might be kind of intensive.

So what you can do is wait for K-Event Menu Opening and then go out to the file system, fill in the menu, and then it will be displayed with those contents. And lastly, we have what is the direct replacement for the menu hook function: KEVENT_MENU_TARGET_ITEM. So whenever you are rolling over an item, we will send this event out, and you can use that notification to maybe put up some contextual help or whatever you need to do.

[Transcript missing]

And it supports commands. Like I said, we have much better command ID support. Part of that involves dealing with enabling and disabling menu items. Whenever a menu is about to be shown for every item in the menu, we send out kevent command update status events. That's your time to say update the text, add a check mark, whatever you want to do.

Now, like I said, we do that for every item in the menu. So that could potentially be a lot of different update status commands that we're sending around. Your application might want to do it all at once, and you can do that by intercepting the KEVENT_MENU_ENABLE_ITEMS event. In fact, the default toolbox response to an unhandled ENABLE_ITEMS event is to send out update status for every item in the menu. So maybe your application architecture only works based on a per-menu enabling strategy, so that's the event that you would tap in for that.

It's actually important that WaitNext event-based apps respond to these events as well as pure Carbon event-based apps. And the reason is that if you happen to have event handlers in your application, they will be called while you are inside WaitNext event. Typically what would happen in the past is you'd exit from Wait Next Event, find out you had a keyboard event or maybe a mouse event that happened to be in the menu bar, and then you would go and update the status of your menu items.

Well, because we're dispatching this inside of WaitNextEvent, you don't necessarily get that chance. So it might be that it usually hits a command key, That item is enabled currently in the menu bar. We will actually go and call a command handler for that. It might not even be the effect that you want because it might actually be the quit command. So your application may end up getting a quit Apple event and you didn't expect it to. So in those cases you need to make sure that you're dealing with enabling and disabling the items appropriately.

Back in traditional Mac OS, we dealt with the Edit menu in a very interesting manner. Basically, we had this thing which kind of looked for any window as they were coming up. It was like a JG&E filter, and we'd see a new window and go, "Oh, a new window. Is it a dialog?" And then we'd say, "Oh, yeah, it's a dialog. Is there a text field?" They'd go, "Yes, oh, good. Great. Then let's deal with the Edit Menu. Where is it?" "Oh, I don't know.

Go scan the menu bar for anything with an X or a V next to it." That must be the Edit Menu. That has some negative connotations in that, first off, it pulls like crazy, and we don't want to do that in Mac OS X. Second off, it's just bad code, and we don't want that. So, we already had this mechanism, which was the command ID mechanism. It's the right mechanism.

So, it's actually important that for your edit menus in Carbon, you use the standard command IDs that we've put into carbon-events.h. It doesn't hurt anything if you're not using the command IDs for your application at all. It doesn't hurt you, but it allows us to at least find them in the menu bar.

And this is important, particularly when we put up dialogues, because the dialogue manager still wants to deal with the edit menu appropriately. And actually, it's not even the dialogue manager these days, it's the individual edit text controls. Because they are the focus, they get to control the edit menu appropriately.

And lastly, it's important to note that these update status commands can actually be sent out at any time. It's not just, "Oh, there was a key down," or "There was a mouse down" in the menu bar. It might have been some programmatic change of the window ordering or something. Maybe somebody called Select Window, like the Toolbox.

When that happens, if you had a focused edit text control, which was only in the Edit menu, and now you're in a window which has no focus, the Edit menu should actually be disabled. So the toolbox will actually in that case detect, "Oh, I need to, you know, the focus has changed. I need to go and dirty the menu bar." So when it sees that it's dirty, it will actually send out these update status commands. So be aware that they could be flying at you at any time.

The Apple and Application menus are one and the same on Mac OS 9, but they're different on Mac OS X. The Apple menu just exists on Mac OS X. It's always there, omnipresent, staring at you, watching you. But the Apple menu on Mac OS 9 is the Apple menu that you always knew, while on Mac OS X it becomes what we term the application menu. It's the menu with the name of your application.

You should continue to insert your Apple Menu into the Menu Bar just like you always have. Basically, it's the placeholder. It's the place that you put your About item and whatever other items that you've historically put there. So you want to keep doing that. And like I said, on 9, it just is the Apple Menu like you always knew it.

And on 10, it's the Application Menu. Most of the items in these menus are handled automatically. The exceptions are really quit and preferences. These are commands that you need to deal with. Obviously, if the user selects Command Q, they want to quit your app, you should probably respond and quit being so stubborn.

For preferences, the user wants to change some aspect of your application, the way it works or whatever. You need to respond to that. By default, the Preferences item is disabled. So it's actually up to your application to enable it. And you can do it by Command ID. We supply the Command ID in carbonevents.h. And you can also enable and disable the Quit menu item however you need to via Command ID as well.

Now don't let the first bullet scare you. I mean, we don't by default have a Help menu there. However, if you call hm get help menu, we will automatically insert one. If your application happens to specify a help book in your Info.plist, we will automatically create the help menu for you as well.

As in the past, you can just add menu items as you see fit to this menu. For any menu items that you add, you will get the commands for them. You can just install a command handler. For any items that the system has installed, we'll handle them automatically. Well, that was short. That was because they dropped a couple of my slides out.

Either that or I talk too fast. So the bottom line here is we've done a lot of work in the Menu Manager. We've done a lot of work in the Window Manager. The Window Manager, just think about it. I mean, we've taken it from a system where everything was non-retained, we had to deal with damage repair ourselves, all of these other things, to a system where we actually have window buffering, which was the slide that was missing, by the way.

And, I mean, we've just added window groups, we have overlay windows, and the Window Manager is actually in such a state these days that we can start adding new window classes at a very fast pace. The entire code base of the high-level toolbox is in great shape these days, and we're making constant improvements. And especially with the advent of Carbon events, you know, mixing in with that, we can actually just start going wild now. So now is the time that it's really getting exciting.

You should look at carbonevents.h as always if you're looking to override a lot of the window behaviors, menu behaviors. And it's important to go import your application. That's why you're here. You're trying to learn about Mac OS X. We're trying to tell you all we can. We're trying to help you along.

So with that, I'd like to bring Mark Turner back out, take you through roadmap, and then we'll do Q&A. Thanks. Thank you, Ed. So coming up tomorrow morning, we have Controls and Appearance 1 and 2 back-to-back.

[Transcript missing]

This is me. My job is to help you adopt Carbon and get your apps to Mac OS X. So if you have questions, either today or after WWDC, email me.