Application • 35:02
The power of Dashboard comes from its widgets, which users see and use when Dashboard is invoked. Developing a widget requires working with bundles, property lists, and some combination of HTML, CSS, and JavaScript. We explain all of this and walk you through the creation of several sample widgets, discuss optional features that may be implemented in a widget, and touch on native code integration through a widget plug-in.
Speakers: Andy Grignon, John Louch, Richard Williamson
Unlisted on Apple Developer site
Transcript
This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.
Thank you all for coming today. I'm sure you're here to hear Andy and me speak, and there's nothing going on here about a PowerBook demo, a PowerBook giveaway or anything. OK, so this is Dashboard Development In-Deepth. What we're going to do today is show you a little bit about the architecture of the Dashboard, how it works, and then we're basically going to get right into creating a gadget.
We had a little mix up here, and we're not quick time in digital media, but they have a pretty slide. OK. So there we go. See, it's beautiful. Okay, so I'm John Louch, and this is Andy Grignon. Hello. And basically, Andy and I are the engineers responsible for the Dashboard project.
Okay, so what is the Dashboard for you? What is the Dashboard? It is expose for your information. So Andy, what does that mean? I have absolutely no idea. That's a marketing line. Yeah. Okay, so expose for your information. Basically, it's an accessory layer that comes and goes quickly, not interfering with your workflow. Very similar to what expose did. It's kind of a modal interface. You can interact with it. You can go back to whatever you were using before and nothing, you know, everything is exactly the same way.
Okay, let's talk about the pieces of the Dashboard. There's basically four things. There's a Dashboard server. There's clients. There's basically one client for every gadget. Okay, and in this client, there is a gadget, and the gadget can also contain a native code plug-in, and we'll get to that a little bit later.
Okay, so the Dashboard server. It's a very lightweight process that manages the Dashboard clients. Really, all it's doing is launching and relaunching the Dashboard clients. What that means is if the gadget, for some reason, crashes, we instantly relaunch it, and you almost won't be able to tell this, or the user almost won't be able to tell this. There might be some data loss if there's a crash, of course. We prevent crash loops and only do this three times in some period. I forget the exact amount of time.
It's also responsible for delivering or marshalling events from the system to the clients back and forth. This allows us to do a lot of powerful things, which you saw in the demo, server-side dragging and that type of thing. The other main thing it does is it does all the Dashboard-specific user interface. You guys have seen the closed boxes, you've seen the ripples, you've seen the configuration spins. Anything that's not in the gadget that is UI-related is in the Dashboard server. That's what's doing the work for you.
Okay, so the Dashboard Client. This is a very small AppKit process, and really, it's just a WebView. There'll be lots of sessions about WebView and WebKit technologies throughout today. The other things it does is it provides a bridge between the Dashboard Server and the Client. So, you know, this is how you get data back and forth between them. This is all hidden from you, but that's what one of its responsibilities are.
The other thing it does, and the main thing that's important for you writing a gadget, is it provides this Gadget Object. This is a JavaScript object, Eject to See object that is bridged into the JavaScript runtime that allows you to do the things like flips and other things we'll mention soon.
Okay, so a gadget. It's just a web page. It's that easy. It really is just an HTML web page. The few things it requires is a gadget extension. It's a bundle. Sorry, it's a bundle. You're all familiar with bundles on our system. Same structure that you're all familiar with.
We actually use a flat bundle, which you may or may not be familiar with. This is just everything kind of at the top level. It's a valid bundle format. Any bundle format will actually work. It requires a gadget extension. Something to note here, too, you're probably hearing the words widget and gadget interchangeably.
The name is in transition, I think, and basically everything on your DVD has a .gadget extension. So if you're developing these, you have to use the .gadget stuff. And that's also what you'll see in the interface on the DVDs. So inside of the bundle, you have an Info.plist. You have a default image. The default image has to be a PNG file. This is just a requirement for WWDC. And then you have an HTML file.
When we say HTML file, it doesn't necessarily mean one file. There just has to be a starting place. And an HTML file, of course, can reference all other kinds of web content. Other CSS style pages, JavaScript, what have you. Any even network resources. And then you can have a native code plug-in as well.
Okay, so writing a gadget. What Andy and I found was the best way to start is go find a gadget, copy it. That's just, you know, it's the easiest thing to do. We have, I think, seven gadgets on the disk for you, plus some in the SDK. You just copy those, you can go look in there, there's all the codes already there for you, and that's the best place to start.
So you copy the gadget, you go into the bundle, and you go to the Info.plist, and you start massaging the Info.plist to match what your gadget needs, you know, change the keys and whatnot. And then launch Safari. Safari is the debugger's choice for this environment, and you can use any text editor to do your editing. I think Andy and I use BBEdit, but you can use anything, TextEdit, BBEdit, you could use Microsoft Word, right? Okay. So let's get coding.
And Andy here. I appeared to-- Yes, all right. So we are on demo machine. All right. So I thought-- I have killed this slide. It's only one second, Andy. Oh, sorry. We're new at this. So we thought we'd start today by writing a sample gadget. Now, I already wrote this yesterday, but we're going to go through the exercise of putting one together. The thing we're going to write today is a validator. Now, there's a million things that you've probably found that can go wrong when you try to put together a gadget.
You know, some key is wrong. You're missing something. So we thought it'd be kind of cool to put together a gadget whose sole purpose is to validate a gadget that you've already written. So all it does is you bring up dashboard. Actually, what you do is you start a drag of your gadget.
You bring up dashboard, and you drop your gadget onto what we're going to write today. And what it's going to do is it's going to generate a report for you using HTML. And it's going to launch Safari, and it's going to tell you what's wrong. Hey, Andy, do we have a little omission to make here? We do have a little omission to make, since I'm such a-- Does it? --loser coder. Actually, the thing that you guys have available to you doesn't actually validate. Yeah.
Small. It's more of an info P-list walker. But I fixed it this morning very early. And so actually, this guy will validate. It's kind of interesting, because it's really-- it's really easy to make mistakes, but it's really easy to fix them in this environment because it's interpreted. In fact, we shipped some gadgets to you with a few minor issues with them on your developer DVD. And so maybe what we could do is just fix one of them for them. Let's start by fixing a bug, actually.
You guys can follow along if you want. I think the one we're going to attack is Calculator, aside from just being ridiculously wrong in some of its math. Andy and I, we don't do math. As I'm sure you found, yeah. I'm not really good like that. So all the gadgets are stored inside of /librarygadgets.
We'll go ahead and go there. You guys can do this, too. You'll see CalculatorGadgets.com. Calculator.gadget. Now, all of our code is plain as day inside of this stuff. Let me mention one thing here, too. What you notice is Andy's going to show package contents. That's because the gadget extensions claim that what's called a package. It means in the Finder and other Open Safe panels, you can't actually go inside of it without going through a custom interface.
It's a better experience for the end user, because they can drag these things around, and they don't actually go into them. But it makes it a little harder to develop. OK. So let's fix the bug. The bug that we're going to fix is-- we're going to go ahead and launch Safari.
If you drop Calculator-- onto Safari, you'll see that it has this font. It's actually Helvetica, but you'll notice on Steve's machine he had a segmented LCD display. And you guys have it, too. It's just-- I'm a moron. So what you have to do is open up your Calculator HTML file.
And the actual bug is this guy right here. You see where we set the font. This is CSS. So you see where we set the font. This is just dblcd temp. That's the name of our font. So we're just going to-- that's the bug. So-- This is real. I mean, it's on your machine. This is actually real, yeah. Now you'll see that-- There's your font.
There's your font. So you guys can actually fix our bugs. Yeah. Please. Please, right. OK. So that's the first thing. We just wanted to get that out of the way. So you guys can actually do this too. And if there's some technique that you saw on any of the gadgets that you've played with, feel free.
Copy the technique. We have some animation stuff in there. That's actually kind of interesting. We have some workarounds to some bugs that we've come across. And those are scattered throughout there. Obviously, we're engineers. We don't put comments in anything. So it's best if you just learn by seeing what we've done.
So let's go ahead and get something working. What we have here is-- Hello World. So this is the build gadget. It's on the SDK that you guys all have. So I'm going to start by copying that. Now you'll see validator gadget. Well, this is actually-- I'm going to call it validator gadget. So I'm going to call it validator temp. And then I'm going to call this guy.
There we go. The validator. It's really not that cool. Show package contents. Okay. Now, you'll see we have a few things in this folder. We've got a default ping, the hello world, and the Info.plist. If you haven't seen it already, all it does is just show hello world. Not that exciting. So what we're going to do is we're going to modify the Info.plist. Go ahead and double-click it.
A few things inside of here. Allow multiple instances. That's just if you want to have something like stickies, where you can keep dragging your gadget off. By default, if that's set to no, you're going to get a grayed out title in the configuration bar. The thing you absolutely have to change is the CFBundle identifier. These have to be unique across all the gadgets on the system. So we're going to call this just plain old validator.
The next thing is the CFBundle name. So this is the display name that's going to show up in the config bar. So you can make this pretty looking, so we'll just call it the validator. We call the config bar the plus at the top. We drag everything to and from. Okay. The next thing, you know, these versions don't really matter. The default image, what that should be is a ping file at the top level of your gadget. You don't put the .ping extension on. I think that's a bug. Yeah.
So that should just be, you know, your name. So if you have, you know, foobar.ping, just call it foobar. The next thing you're going to see is the height and width. These are the numbers that we use to specify the width and height of your image for the drag.
Now, if you put a big number in there, I think what we're going to do is stretch the image to fill that number. If the image does not match the size you put there, the default image will be stretched. It's going to look bad. So what we're going to do is, in my temp, we're going to go ahead and show package contents. Here's my... Amen.
What the hell did I just do? Oh, is this? Cut the mic. I'm sorry. He's out. Sorry. Yeah, okay. So what we're going to do is go ahead and move. I think there's a bug in Finder where that doesn't actually work. So if you go ahead and move default ping in there, that's our new picture. Can you show that to us, Andy? Yeah, we're going to see this in icon view. So Andy and I are actually artists on the side. You'll be picking this up. So this is our picture. It looks pretty lame.
And, God, give a guy a break. Okay, so you'll see in Safari that it tells us how big this picture is. So it's 150 by 150 pixels. So we're going to go ahead and go in here, change that to 150, 150. Now, the last thing we have is the main HTML file, and we're going to want that to be the validator HTML file. So there is our validator HTML. Here's our hello world. We're going to just toss that guy. We're going to go ahead and move the validator in.
bug. Nice. Okay, so we now have the basic structure. Now we're going to get into this in just a little bit, but this gadget requires a native code plug-in to do something we'll tell you in about a bit. So what I'm going to do is I'm going to go ahead and put my plug-in. And since we'll get to this again in a little bit, that these plug-ins need to be owned by root, and we'll tell you why in just a second. So we'll call this val.togadget. And now we're going to do a pseudo-traveling root validator.
Okay, so now we have a gadget. Let's go ahead and try it out. So, a couple ways you can get these into Dashboard, right? So if we go ahead and bring up Dashboard, we just have this. You can either double-click it, or you can start a drag, and I'm going to show you this because this is how we're going to use the mechanisms. Go ahead and start a drag. Go ahead and bring up Dashboard, and let go.
That looks bad, doesn't it? And actually, there's probably something wrong in our validator. So this is what the validator is supposed to fix. So OK, we have our Info.plist. We go through everything. Oh, you know what the big problem is? I didn't change this guy. So these are little dodges that can get you.
We know it's a pain. We're going to try and make this better. This is just like a bundle in the same bundle format. You set your resources. The names have to match. You have to point to the right resources. OK. We've done that. Let's go ahead and try it again.
There we go. It looks better. And it's going to actually stick around. That means it's there. Now, let's try it out. Let's bring up Hello World. This guy takes a drop target, and it's actually going to go ahead and do the Safari thing. Now, I think because I screwed that up, I'm going to, again, ignore all this stuff.
You can actually-- if Dashboard-- actually, don't ignore this. No, don't ignore this. Dashboard can sometimes get into kind of a funky state. This is a developer DVD. This is a developer DVD. OK. What you may have to do sometimes is kill the Dashboard. It's going to restart itself.
All you got to do is bring it up, just like that. It's also-- you should note that the Dashboard server is-- all these things are so lightweight that they do really start up almost instantly. Right, right. It might feel like it's not restarted, but it has. So the next thing is-- so now we have-- you'll notice it still didn't work. And that's because inside of this code, we have a plug-in.
And one more key that we're going to show you in just a bit, I promise, is that we need to specify that. So I'm going to go ahead and add a new child. I'm going to call it plug-in, P-L-U-G-I-N. OK. And we're going to call it the valid data-- you know, I spell things out as I type. I don't know why. Plug-in dot gadget plug-in.
Let's see if that works. And just to be paranoid, I'm going to go ahead and do that. Just sprinkle those around when things don't work. I mean, really. OK, now let's give it another whirl. Go ahead and drop this guy. Finally, it worked. OK, so what it did is generated this little bit of HTML, and it tells us that it succeeded. Now I've actually mocked up a bad demo-- or I'm sorry, a bad demo, yeah.
Telling. A bad gadget. Now this is going to tell us that this gadget failed because we're missing the width key. And so you guys can come get this from us, the fixed version of all this, in the lab. We'll go through that. So if we look in the p list, you'll see that, lo and behold, we have a height but no width. And if we add a width, and then one-- I don't even know what it was. And then it should--
[Transcript missing]
That was a very simple gadget. One of the things you saw Andy do was he caused a Dashboard layer to disappear and has Safari to launch. This is done through the gadget extension I was telling you about before, a JavaScript object that we push into the environment that lets you do a few things. There's a couple... There's a couple of methods that you should know about the gadget op.
This is all documented in the SDK, so you can read what all the methods do and whatnot. There's a couple we should call out. I'm going to start actually here at the bottom about resizing your gadget or widget. Your gadget exists inside of a window. The window has to be the exact size of your gadget, or a lot of the animations don't work. The ripple effects, the close box, whatnot. They all look at the window size to then try to determine what to do.
So what we have here is a gadget resize to method. There's actually two methods, resize to and resize by. They're pretty self-evident. It takes a width and a height or a delta width and a delta height. This is very close also if you're familiar with client-side JavaScript. It's very similar to the window. The window resize to, resize by methods. They're a little bit different in that these don't have limitations on size where the window one does. So that's resizing your widget. We also have the configuration flip.
I'm assuming all of you have seen the demo, but you can click. You need some place in the dashboard to store preferences. So what we came up with this idea is that you flip everything around and put that on the back. So it doesn't interfere with your work, but it's easy to get to. We have a real simple way to do this inside of this gadget object.
There's basically three methods, and that's it. There's a start edit, a finish edit, and a run edit transition. Let me tell you how this works. So all you do is you say start edit. It basically takes a screen capture of your gadget, whatever's on the screen at that time. Then it's freezing all updates to the screen. It's freezing all the updates to the monitor.
Then all you do is call run edit transition. Sorry. Then what you do is you change your HTML in a variety of different ways. You know, you can add elements, remove stuff, do whatever you need to do, and none of this will go to the screen because the screen is frozen. Then you say run edit transition. Then what we do behind your guys' back is we take those two sides and we do the OpenGL flip.
and then we also have the backwards version, which is finish edit. That's the same thing as start edit, but it flips in the opposite direction, going back from your edit side to your actual gadget. Really important thing to realize here is you must call run edit transition. If you do not call run edit transition, all screen updates, not just for this gadget, all screen updates are stopped.
This is a limitation of the DVD. Not necessarily a limitation of being in Tiger. If you don't do it, we actually do have a timer, because we don't want to stop the whole system, and we'll call it for you. I'm not actually familiar with the granularity of the timer. I think it's like three or five seconds, something like that.
Okay, so that's how we do the configuration flip. Another thing I was talking about is how we do the server-side dragging. You're familiar with this in AppKit and Carbon Apps, where if an application is hung, you can still move the window around. This is really nice. We wanted to take that same behavior into the gadget or the dashboard layer. So no matter what's wrong with the gadget, you can take it, you can move it around, you can even close it, get rid of it. So if you have a bad gadget, you can spank it.
Sorry. Excuse me. Where did we get you, man? I think we need more practicing here, Andy. Okay. So in any case, the server-side dragging is really great, but there's times when you don't want that. I mean, you have, say, a slider. You have any type of tracking control.
You want to resize something, whatever, right? When you have that, so we have some methods for you to help you out here. These are only just a few of them. Basically, we have what are called control regions or control areas, and what that comes down to is circles and racks.
What's important is there's always an open and a close. When you open some control racks, you set them, and then you close them. When you close them, they go to the server. If you don't close them, nothing's going to happen, all right? Hey, same thing is also you need to open and close when you clear your racks. Yeah, true. That's a common mistake we always make. Yeah, you can't just call clear all control racks or clear a control rack. Everything is between an open and a close closure.
Okay, let's move along. Okay, so you saw Andy having to do some nasty things in the terminal. We really want you guys to try to stay inside of HTML as much as possible, just HTML and JavaScript. And the reason why is because it's a cleaner environment for the end user. It's a sandbox environment where there's not much they can do and they can't hurt your machine.
But eventually, you're going to run against a wall for something you're going to create. And that's why we have the ability to write Objective-C code that then links into the gadget. We call these gadget plug-ins. All these are is a Cocoa bundle. To create a Cocoa bundle, you launch Xcode. I believe there's a template for that. It's called Cocoa bundle.
So you create one of these things. And they live either in system library gadget plug-ins or they can live also inside the bundle. The important thing is they have to be owned by root. And the reason why we did that is so that if a user gets one of these gadgets, they have to put in their administrative password to actually install it so they can't install malicious code on their system.
The important thing to note there is that just because it's owned by root doesn't mean you're actually running as root. Right. None of this is running by root. This is all running by the user. So this is just a file permission issue. Okay, so you use the gadget plug-in extension, and you have to have a principal class.
Creating plug-ins is simple. There's basically two APIs. You have this principal class, and there's two methods that you have to implement on that principal class. InitWithWebView is the first one. InitWithWebView, we find we almost never use it, right, Andy? No. What we do is, if you need, InitWithWebView allows you access to the web view as it's loading. It also allows you to set up any initialization you might want to do or whatnot. The major method is Windows Script Object Available. This method gets called before any JavaScript is executed in your web page.
This allows you to do what we did with the gadget extension. So you can stick any Objective-C object and push it through the binding system of WebKit, and it gives a JavaScript runtime allowing you to do anything, literally anything, right? So that's the Windows Script Object Available. OK, why don't we do a demo, just to explain a little more about how you write a code plug-in. Right. So back to demo two. Here we go. I've got the source code for the validator plug-in right here.
It's an Xcode project. I'm going to take you through just a couple things in the project. So when you create a new plug-in, a new Cocoa bundle, you're going to get an empty project. Inside of, what is it, targets, you're going to have a default target. If we get info on that target, you're going to see a properties panel. Now, you can set your identifier here. It doesn't really matter. The interesting thing to us is you have to set your principal class. So when you go ahead and create a new Objective-C object using Xcode, just set its principal class right here.
The other thing you're going to want to do is go to the Build tab, and there's a little thing down here called Wrapper Extension. By default, on a Cocoa bundle, it's going to say Bundle. You're going to want to change that to Gadget Plugin. Now, technically, this is not enforced, but it might be enforced in the future. So it would be good to use the extension now. Yeah. Okay, so let's take a quick look through the code. Here we see the init with VEBU. Can you guys see this, or is that too small? Too small? All right. I'm going to make it bigger.
Font, bigger. Rock solid. Oh, preferences. Any Xcode experts? We just do HTML now. Oh, syntax. This guy? Yeah, I use this a lot. We really are engineers, by the way. Okay, so, is that better? Okay, so, let's take a look. Here we have our knit with WebView. It does nothing. I was going to have some big grand plans, but it doesn't do anything in there right now. We have a dialic. Here's the interesting part, the Windows script object available. So, you're passed a WebScript object. This comes from WebKit.
And you're going to call a method, or you're actually just going to do a set value for key on that object that you're passed in. And what you set for that value, we're going to set ourself. And that means tell the JavaScript binding system to look at ourself for any methods that we want to export into the JS runtime. By the way, this is all documented in another session coming later today, I think. We have it on our slides. It explains this process more in detail. The whole binding mechanism will be touched on tomorrow. The key is, in this case, validated.
So, that's how you're going to access this object inside of the JS runtime. So, it's going to be a global object called validator dot whatever. Now, let's go to the rest of this. Do you want to show them that in the HTML? Yeah, I'll show them in a sec.
So, here we have WebScript name for selector. This is also called by the WebKit. And what this allows you to do is set a pretty name for the names of your methods. So, this maps an Objective-C selector to a JavaScript name. By default, these guys are called WebKit.
So, these guys come up with a pretty ugly name. I think it's underscore, underscore, you know, whatever your method name is. That can get kind of tedious, but that's done so that there aren't any collisions in the namespace. So, we just remap everything to check plugin permissions. And in this case, you know, save results to temp. The other thing we can do is you can exclude things from the JS binding system. So, by default, the bindings use object introspection.
[Transcript missing]
Now it turns out we actually don't have any other variables, but you guys can use that. We have two methods here, check plug-in permissions. All this guy does in this validator gadget is just check. It returns a bool, and it says if the plug-in, the path that you pass in, is owned by root.
So this is what we were talking about before. We were forcing this root thing. Now the validator will actually check that and make sure your plug-in is set correctly. And this is real. I mean, all we do, you know, you do whatever you want. But in this case, we just call lstat and we just do something. You'll notice what's interesting here is that we don't actually do any marshalling of arguments between the JS and the Objective-C world. That's all handled for us by the binding system.
So any object... I believe any scalar type. Any scalar type, correct. Any scalar type or any object can be passed back and forth. You don't deal with it. It just happens for free. Right. And same thing. So we just use NSStrings. Everything just works. And that's how you build a native code.
Oh, let's show you what it looks like inside of the code. So I'm going to go back to this guy, validator gadget. So you'll see in our HTML file, it's going to be real simple. There's just going to be a...
[Transcript missing]
Thank you, Andy. OK. So there's a couple tips we'd like to get across. This is the type of stuff-- well, first, let me tell you something.
Andy and I, when we came to this project, knew absolutely, what, less than zero HTML. We knew basically something with a .html extension went to a web browser. So we had no experience in HTML. I think we had both had maybe a little experience in JavaScript. So we're basically doing the same type of learning that you may or may not be doing.
So we came across a couple of tips that really helped us out. One way we debug mostly is with alerts and exceptions. Both alerts and exceptions in the dashboard layer go to the console. So you can always go and look at your console and find errors and whatnot.
The exceptions only go to your console for the WWDC build. In the future, they would not go there because that would flood the end user. But it's helpful if you have a runway, especially if you have something like an event handler that keeps throwing an exception that keeps happening. You can find it really quickly in something like this.
One of the other things we added, primarily for development, is the ability to reload your gadget inside of the dashboard layer. All you have to do is bring up the dashboard, select it, hit Command-R, and all the HTML will reload. This makes it really easy just to go into your HTML if you need to. Change some CSS, change some HTML, change some JavaScript, whatever, hit Reload, and bam, it's right there. It's instantaneous. It's great.
So it's a quick way to test changes. OK, so now we've shown writing a plug-in, Andy writing a plug-in over here. And so if you're like Andy, you might have some issues with your code. It might crash or something else, or you might need to debug something. Just relentless. All right. So unfortunately, it's a little hard to debug these things. It's unfortunate for you, unfortunate for the end user.
What happens is the server is launching the client process. You don't have access to the server or the client process. You're only writing these gadgets, which are in HTML, or these plug-ins being loaded in by the client process. So you need to find the PID to get to those processes to attach to them via GDB. I'm not going to go too deep into attachments with GDB, but we can show you that later.
So you need to find it. Unfortunately, that doesn't show up in Top or any of the normal Unix tools. It does show up in some higher level tools we have. We have a great utility in application utilities called Activity Monitor. If you double click on that, you'll find that the name of your gadget is something like dashboard-- it's something, name a gadget dashboard client. You will see that in this PID. So you can go there, look at it, get the PID, and then attach.
The other thing that you're going to maybe have trouble with in this environment is that the dashboard layer takes over your whole screen. So it's very hard to GDB it at the same time. In fact, almost impossible. So dual machine debugging is the best way to go at that point. Until one of you writes us a GDB gadget. .
and Andrew Kahn. Yeah, that would be really cool. Eric Schmidt: All right. I quote PowerBook, "We really want that gadget." Okay. Okay. So, another thing, this is just a shortcoming in the system we have right now. We load automatically things until the library gadgets and library gadgets/library gadgets, we do not do this once the Dashboard is loading.
So that's only when it starts up. So if you dump something there, it's not going to automatically load for you. What you can do is what Andy kind of showed before, you can either double-click on them, brings up the Dashboard layer, or you can drag them. Then they're added, then both the Config bar, the Dashboard server, everybody knows about them. Okay. Let's go to the next slide.
Oh, another thing. Part of this, you're all familiar with Crash Reporter, probably, or maybe not. Crash Reporter gives you this great way to get backtraces on code plug-ins or anything else that are crashing. Unfortunately, for a developer, no background applications, Crash Reporters are actually shown. They're all hidden. So what you need to do is go to another utility called Crash Reporter Press inside of developer application utilities. And there's, I think, a radio button that says developer. As soon as you hit that, any background application will then show Crash Reports, and that will help you debug.
There's a great thing that the AppDate team, I'm sorry, there's a great thing that the WebKit team added, too many kit teams at Apple. It's called a debug menu, and you see here the command to turn that on. It's, I think, defaults right, com.apple.safariinclude debug menu. This is a great tool. In fact, the Safari team added, I think, a new menu called JavaScript Console. The JavaScript Console will be really helpful for tracking down exceptions and whatnot inside of your JavaScript code. It also has snippet editors and whatnot. That will be talked about in other sessions.
The other thing they added, by the way, is the ability to make the Safari window. I know this is kind of flaky, but it allows you to make the Safari window look like the dashboard. So it turns off background drawing, makes the window transparent, so you can basically see a web page floating. So you can get an idea of what your gadget looks like. It's really great.
It just takes away, makes it look like a, it's really kind of funny. Actually, maybe we could show that. For those of you not familiar with Unix programming, and you need to make your plug-in root like we're talking about for security reasons, here's the command to do it if you need to do it from the command line.
Or you can build this root. There's a lot of alternatives there. All right. So there are tips. We have a lot of sessions coming up that will help you write gadgets. Most of them are the WebKit-related sessions. You kind of see them here. I'm not going to go into them. I think the Building Visually Complect Webpages especially will be interesting for you.
All right. We also have a reference library. I think we have lots of examples on disk in the SDK. We have documentation. There's tutorials. There's an interesting picture gadget in there. That's what's done. It's actually done by one of our documentation people who picked this up and did it in two days, to give you an idea. I think you guys can do the same thing for the contest.
And there's two books. There's two books that Andy and I think we sleep with these books at this point, right? I sleep with these books. These books are great. These books really help us out if you're starting out. The Definitive Guide by David Plannigan, JavaScript, and the Cascading Style Sheets. These will really help you out learning how to write HTML, learning how to use CSS, incorporating all that.
All right. We also have a lab. We kind of went through this really kind of quickly, and it's kind of hard to kind of take it in. So what we're going to have is a lab today from 12:00 to 5:00, where Andy and myself and the WebKit team, Richard Williamson, David Hyatt, and maybe a few others will be around to help you out, answer any questions, step you through stuff. We're your bitch for the day until 5 o'clock. 5:00? 5 o'clock. Right. So we're going to be there till 3:00. We'll be drinking heavily after 3:00. Yeah, yeah. Something like 4:00, right.