Proceedings of the August Be Developer Conference



August 1997 BeDC

Approaching the BeOS




WILLIAM ADAMS: Hello, my name is William Adams. I'm the manager of our Be developer services, Be tech support basically.

Before we get started, I was asked to ask a question. How many of you are interested in an introductory 3D session? (Large show of hands) So this session is Approaching Be, and specifically Approaching Be programming, not just walking up to it. What we're going to try to go through in this session is some of the highlights that we have from the general session, just to reiterate them, and tell you what exactly do these things mean. And we're going to go through a couple of code samples and then questions from you guys, basically, "Well, how do you do this? How do you do that?" So we'll go through a little bit of that.

Be reminded this is the Approaching session, so there are other advanced sessions of how do I do scripting exactly, you know, how do I do device drivers. That's what all the rest of the sessions are about. This session is very basic, very straightforward. If you're already way into Be programming, you probably don't really want to be in here, because you aren't going to learn anything new.

Can I have a show of hands of who is doing Be programming right now. (Show of hands) For how long? Less than a month? (Show of hands) Less than six months? (Show of hands) More than six months? (Show of hands) Okay. It's a pretty advanced group for an Approaching session.

So we'll just go as quickly as we can, and if I start to drone on, say, "Hey, hey, come on, move on," because, you know, we don't want to waste your time.



Why Be? Why should you deal with this whole BeOS thing in the first place? As you saw in the general session, we have buzzwords, that's why. Symmetrical multiprocessing, preemptive scheduling, protected memory multithreaded from the bottom up. What does all of that mean?

Symmetrical multiprocessing is that fact that all the CPUs in the system pretty much look exactly the same. That means any one of the CPUs can do any one of the tasks at any given time. That means also there's nothing special you do as a programmer to take advantage of it. You have one CPUs, two CPUs or four CPUs. The operating system will spread the load evenly; you don't have to worry about it.

Preemptive scheduling, that's a particular way of utilizing multithreaded programming where your threads are going along, and every once in a while the kernel comes along and says your time is up, someone else is going to get some work done. This is different from cooperative multitasking, which you might see in other OSes, where your code is littered with things such as "Yield, yield, yield." So it's just a different way of doing multithreaded programming.

Again, the advantage is that as long as you can isolate your code into little discrete things that can happen at the same time, you just do that. You write a function, and you say, "Okay, that's a thread, that's a thread." The system takes care of what thread runs at what time and how much time they're allocated and all the rest.

Protected memory is simply, if your app crashes, you don't necessarily take down the rest of the system with you. You may take down some critical service, but that's okay. The rest of the system will continue, your window will go away, and you go on with life. You probably just restart the program. That's another thing that modern OSes do.

Multithreaded from the bottom to the top. If you're familiar with, I don't know, the MacOS, multithreaded is something that is kind of an attachment. It's not something that's integral to the system. There is a thread kit, and it's kind of this extra thing. What threading from the bottom up means is that everything from our lowest device drivers to the file systems to the UI elements, everything has threading in mind.

This is also very critical when you look at something like, oh, the Mac or the mock kernel, which is said to be a multithreading kernel, yes, true, display postscript is not. The NeXT file system is not multithreaded. Ours is, which means that we get performance on performance, where the other ones just don't. It's just plain and simple.

And you don't really -- it's not something you can really appreciate until you are using the BeOS system for a long time, and you switch to something else, and you go, "Seems kind of sluggish." That's really the only reaction you are going to get out of it, which is the same reaction users get out of it.



Paradigms. We're not into shifting paradigms. BeOS is not nirvana or anything else. It's a logical evolution of the process of -- it's just an evolving OS over time.

Familiar frameworks. App kits are familiar to most programmers at this point. If you've grown up on the MacOS using MacApp or PowerPlant or anything else, or if you've done Windows programming with MFC, you know, a window is a window, it's an object. A view is view, it's an object. You get events, all these sort of things, so we use a familiar model that most people accept.

We didn't try to come out and see say, "Oh, here is a new language, Objective C or Small Talk," or whatever. We just said, "C, C++, yes, everybody knows it. You can go to the bookstore and buy 50 books on it, whereas you can't with some other obscure languages."

So C++ is our standard language, and it has its pluses and minuses. Some people say, "Well, you can't do open frameworks with C++, it's too closed," blah, blah, blah. For better, for worse, that's what we chose, and it's quite effective, and I think we're getting quite a few apps developed, regardless of what people think of its merits or detriments.

Familiar development tools, done with a twist. The familiar development tool in our case is the Metrowerks development environment, which, if you are a Mac developer, you're probably very familiar with. If you are a Windows developer, maybe not so familiar, but it's a very good environment, which we'll go and look at in a little bit.

Done with a twist is that of course using all of our low level threading and whatnot, you will see some things out of our development environment that you don't see necessarily in other environments.



It's not UNIX. It is not PowerPlant. UNIX has been around for years and years. It's not UNIX, but we have POSIX support. What that means is if you typically want to port something like AWK, SED, PERL, you know, any one of a billion different little UNIX things, it's pretty straightforward. We're POSIX compliant to the point where you can pretty much take a Mg file, even run make, config and make, and it will probably just work.

When you start work talking about X-based application, there is a lot more work to do, and it's typically ripping code out, don't need that, don't need that. It's not PowerPlant. Like I said on the last slide, we are a familiar framework in that we've got objects and classes and all that sort of stuff, but we're not PowerPlant. We go beyond PowerPlant. We have multithread support in the UI widgets, which PowerPlant doesn't give you. So there are some things where, yes, it's familiar, but we do things differently, and differently enough that there's actually benefits out of that difference and not just different for the sake of difference.

So let's go look at HelloWorld, just get right to the jugular.

So here's the familiar desktop. We've got a few folders open here. I'll bring up the HelloWorld project. So if you're familiar with the Mac at all, this is the same as the IDE on the Mac. I've got the list of all the files here. I've got libraries that I'm linking with. I've got some extra things like a resource file that contains any icons or strings and things like that, and then my actual source files.

The structure of a Be application is that we have several -- we have kits, we have servers, and then there is your source code. The general structure is we have the app server which is a server that runs on the machine, and it deals with putting things on the screen, and dealing with UI, as in mouse and keyboard. So anything that is going to head to the screen, or if you are trying to get user input, it is going through the app server.

In order to talk to the app server in the first place, you typically have an application object (indicating), and you typically create windows and views and various other UI widgets. The application object is basically your connection to the app server. I'll move that up so you can see it.

In most cases, the only thing you will implement in your specific application object is a signature, which is this thing right here. This is just a way of specifying your application. This is one way of doing it. Where you see those -- that's basically an integer value. This can also be done with a MIME-type string, which is probably the more typical way of doing it, and as you go through this system, you will see more and more support for MIME type, so really this is the correct way of doing this particular application.

You see here that I also have -- to start this application up, I create a new instance of this application object, and I say run. That's is pretty much it. There is -- if this ever returns, it means the user said quit, you delete the application object, and you're done, okay, pretty straightforward.

Within the constructor of my application object, I've got a few things in here. I am going to have a window, I'm going to put a view in that window. My window is going to be a certain size.

So I create a rectangle, and I say it is going to be located at 100, 80, and it's going to be 260 pixels wide, and I say, okay, create that window, given that rectangle. And then I say, here is a view that I want to go within that window. I add the view to the window, and I tell the window to show itself.

So, at this point, the application then goes into a spinning loop of waiting for messages to come in from the outside world or whatever it's doing, but it's pretty much done at this point. It doesn't do much more for you.

Now we'll go take a look at this window object. The window is pretty straightforward as well. It basically instantiates itself, calls this constructor on its parent class, which is Be Window, says here's the frame, here's the title. I want it to be a titled window, and I don't want it to be resizeable.

That's all I do for the constructor. And the only other method that I implement here is QuitRequested. Windows by default, you can open them, you can close them, you can zoom them and shrink them. If you want a window to actually quit in your application before it goes -- or as it's going away, you have to do something about that, because otherwise you don't want every window in your app to make the whole application go away once they close.

So for those windows where it is important for it to have that behavior, you have to explicitly say quit, and what you are seeing here is this b_app PostMessage is the second critical feature of the system. b_app, b underscore app, is a global variable that specifies the application object. There is one of them for your running app and there's only one.

PostMessage is part of our messaging system. When we were talking earlier about the system is threaded, threaded, threaded from the bottom up, that's great, but for anyone who has ever done multithreaded programming, it can become unwieldy at times to have to deal with thread synchronization and getting data to the threads in the right orders and all of that. We wrap threads in a thing called a BLooper object, and a looper is basically a thread, and what it does in its loop is it waits for messages to come to it.

We have a BMessage object, which is basically just a bag of obscure data, named data. You can stick anything in the bag, and you can send it to a looper and say, here's a message, and the looper receives the bag and says, I'm looking for what type of message it was, and maybe there's a rectangle in here or whatever, but the receiver knows what the message means and decodes it and gets stuff out of the bag.

So what I'm doing here is I'm saying, this window, when it's closed, this QuitRequested method there will be called. It will go to the application object and say, here's the message, I want you to quit. And then it just returns and says, yeah, I'm done.

Now, why would you need to post a message in the first place? Why don't you just say quit or exit or something like that? The reason is, every window in the Be operating system is running in its own thread, which means, when I have this window on the screen, and I'm moving it around like this, and then I go and grab this other window, each one of them is running in its own thread, so that if this window dies or crashes, it goes away, that's fine, but this window will still be active and running around. And if this window has a movie running in it, it's running in this window's thread, so that this window can still be clicked on while the movie is playing.

So you get a responsiveness to the system like when you saw this morning where we had, I don't know, eight or ten quick-time movies playing at the same time. We don't get behavior where you click on the window and everything stops. I mean, that's just kind of silly behavior. So, in our system, you click on a window, it's always going to be responsive, it will just keep going, and it's because each window is in its own thread.

In order to get the application to quit, you've got to tell the application through a message, because it's running in a separate thread, and this is how you talk to the thread. You're basically sending it a message saying, hey, I want you to quit, and then you kind of step back and wait for it to come and kill you. So that's the way messaging works. And then the application in its own time will get this message and say, okay, it said quit, I'm going to knock myself out, and that's the end of it.

So that's the window. It doesn't do much more than put itself on the screen and allow you to quit the application.

The last part of this is a view.

Similarly, the view -- of course, in this case, all we're doing is playing HelloWorld, but all views are pretty much constructed the same way. You give a rectangle, you gave it a name, you give it some flags, resize flags and when it should draw. When it's attached to the window, I set the font and the font size. This could happen anywhere. It doesn't really matter.

And then the critical thing about views is they have this draw method. Here I simply move to a location on the screen and I draw this string. That's the end. So if you wanted to do a POSIX-like program to do HelloWorld, it would be, you know, five lines of code, including the include files, and here it's a little bit more than that, but you get so much more.

So that's the basic application. Here's you create an application object, you create a window, you put a view in the window, you do something until the user says stop, which is typically by closing the window.

So, to review this complicated application, there is our window. It doesn't resize. I click on the close box. It goes away.

Questions so far?

FROM THE AUDIENCE: Can you open up that first source window that you opened up again? I guess it was the application.

ADAMS: The application.

FROM THE AUDIENCE: Why the double include of Hello Window dot H?

ADAMS: Because it's a mistake.

FROM THE AUDIENCE: I was wondering if there was something magic going on there.

ADAMS: Nothing special there. Even you can get rid of these things. This is a coding style, if you prefer doing this stuff or not. Having those in there makes it so that headers won't get included if they've already been included, but really all it does is change your compile time. So nothing special there.

FROM THE AUDIENCE: What linking format does BeOS use?

ADAMS: Linking format?

FROM THE AUDIENCE: Is it L --

ADAMS: Well, the NDX executable is a PEF file. So the linker can take -- what were those files -- X cof files and link them, so you could actually be on an AIX machine generating dot O files, bring them over and link them and it will know what to do with them, but in general when you're here, it's all PEF.

FROM THE AUDIENCE: Is there a visualization tool for creating widgets for the user interface?

ADAMS: Yes. Make sure you go to the App Sketcher session. That is one of the UI tool type things. Be does not supply a UI constructor, but two of our third parties do. App sketcher is one that is demonstrated here today, and there is another one called interface elements, which is similar but different, and it's not based on... So there are a couple of third parties that do supply that.

FROM THE AUDIENCE: In your project file, you have a resource in there. What actually does that do in the file, and how do you make those?

ADAMS: What good is a resource file? If you are a Mac type programmer, resources are where you store things like icons and screens and anything that you typically want to be external to the executable, so that you can easily change it. It's the same thing for us. The applications icon, if you have any strings that you want to store externally, and this is primarily for internationalization support, I suppose would be the best thing.

And if we look at an application -- the other interesting thing we store or can store in resources are MIME type information. In this case, this is a pretty boring application, it doesn't really do much of anything, and you see that it's created this file type signature, so the MIME type signature is one thing that you would store in the resource. Also, you can associate files with particular MIME types with this particular application.

So I can say, this application opens up jiff or tiff images, and actually, if we go and look at -- let's go right here. If we look at any one of our applications, like this guy, this application says, I know how to support jiff, jpeg, targa, PBM. So this is an image viewing application, and through the resource file you can say these are all the different types of applications I support, or these different MIME types that I support.

And the way you do that is you come in here and you just say, add another MIME type, I support this type, and you can save this into a resource file, and now you can include that resource in your project. And now when you compile the project and you install it, the system will go and look at your resource chunk and get out all the MIME types that you support, so that when someone does drop a file on you, it is going to say, oh, I know that MIME type and I'm going to open it.

So also the icon associated with a particular application is stored in the resource. If you go and drop your file onto IconWorld -- (pause) let's do it the other way -- then you will see that you can now come in here and, you know, edit your icon away and save that. So that's how you get your icons associated with your application: You drop it into IconWorld, mess with it, save it, and now it's in your resource file.

FROM THE AUDIENCE: Then you include it in your project?

ADAMS: Right.

Okay. Let me go through another sample that is just a little bit more complicated. I'm going to have to resize this before I show it to you, so just one second. Can you guys all see this? You can see it now, right? This one is a little bit more complicated, and -- well, let me show you what it does first so you can see where we're going.

This is a screen magnifier, so you can drag the cursor around the screen, and it shows you pieces of the screen. So not too spectacular, but it has some sort of functionality. This particular application was just done as one big giant file, and that's okay, if that's the way you like to do things.

This right here is the little piece of magic that is an undocumented feature, which will get you the screen bitmap. Specifically, you give it a bitmap, and you give it a rectangle, and it will give you back the bitmap filled with whatever was at that piece of the screen. So that's the little piece of magic you need to make this application work.

There's all sorts of stuff in here about just things, the magnification size, and ya-da-ya-da-ya-da. Here we've got a view, which is the more interesting thing we're after. This view is constructed with a color space, 8-bit, 32-bit, that sort of thing, and then really not much else.

So there is our view. Here is our window, which doesn't do much more than do the QuitRequested, do the minimize, and a constructor. Here's an application object. It has few more interesting things, ReadyToRun and MessageReceived. ReadyToRun is a method that's called after your application is constructed, and it's ready to run, the windows are all there and all that sort of stuff, and now you are ready to proceed. So if there is any last-minute thing that you want to do once you are in that state, like make that network connection or something like that, this is typically where you do it.

And MessageReceived. Now, an application object, just like a window object, is also a looper, meaning it's its own thread, and threads, you need to talk to them, and that's where the PostMessage command comes in. The receiving side of that is MessageReceived. When you receive a message, this MessageReceived method is called -- and you do some action based on that.

Similarly, some of the things like key downs and mouse downs, they are also messages posted to a thread. They get parsed a little bit, and it says, oh, this message is a key down, I'm going to call the KeyDown method, or it's a mouse down, so I'm going to call the MouseDown method. So you are not stuck in the message received loop trying to decode all of the messages. The system messages are already decoded for you, and an Appropriate method is called on your subclass object. So that makes it a little bit easier to do certain things.

So here -- let me get to something real quick. In this application, the only message we're waiting to receive is this toggle grid. Right now we have it commented out, because we're just not doing that. We always have the grid on. But if we wanted to turn it off, the application would send a message here, and we would say, okay, turn those grid marks on or off. That's about it. Otherwise, just pass the messages on to our parent class, things like QuitRequested, so that the application will automatically quit.

Here again, we have, in the window, the QuitRequested method. It does a little bit more, because it actually tries to find a directory and write some stuff into a file so it can say, well, this is where the magnify window was located when they quit, so the next time you launch, bring it up in the same location. So this is just an example of QuitRequested. It can do a little bit more than just tell the application to quit. It can actually save state of the application so that you can resurrect it in the same state that it was in before.

Here are some other, minimized method. Screen changes, if you move from one work space to the other, as in you change the bit depth of the screen you're looking at, this method will be called, and you can do Appropriate things.

In this case, I recreate a bitmap at a new screen depth and go on with that. So, right now, if I'm on a 32-bit screen -- which you will see where we're at; right now I'm on a 32-bit screen -- if I move the magnify window over to an 8-bit screen, then it will do the right thing and get me a new bitmap based on that new screen.

And in our view, the most interesting part is the draw method. It draws a bitmap. All that's doing is saying, well, I captured this bitmap, and I'm going to draw it. So that's all the draw method does. It's very simple and straightforward.

And the rest is just other stuff, like this is the task that actually magnifies the image that you capture and puts it into the bitmap in the first place.

So that's an application where there's a little bit more going on, but it's the same model. You post messages, you receive messages, and you draw. There is not much to it. If you're trying to get an app up for the first time, you can pretty much take the HelloWorld app, modify either the view or the window class, add a few methods, and you're off and running. It's just not that complicated. So questions on this one?

FROM THE AUDIENCE: How does the messaging system work with exceptions?

ADAMS: An exception as far the messaging system is concerned is, I don't understand that message, right? I mean, that's pretty much the only exception. Or if there is -- someone tries to get data out of a message that isn't actually there, I guess you could consider that an exception.

When you send a message to someone, it knows the return path, so you can send a message, and if the receiver doesn't understand the message, it basically sends it back to you saying, I didn't understand that message, and you can do whatever you're going to do about that.

One example of that demo that we're not doing these days, but where you can have a paint program, and you drag out a selection from the program and drop it into the workspace. The way that one works is, you package up the message and say, the message type is, this is image data, and you drop it on the workspace, and it says, image data, what's that, and says, I don't know what that is.

And then the application that sent the message in the first place says, okay, how about this is a file, and it sends it back and says, this is a file, and then it says, oh, okay, I know what files are, and it will create a file based on the data. So in that way you can say that's an exception. The receiver says, I don't know what you're talking about, so you send a message back, the exact same message back, saying, I don't know what this is, and then the original sender can do something about that.

So, I guess that's -- does that answer it or not?

FROM THE AUDIENCE: Sort of, but let's say you have some mechanism where you would capture that exception being thrown back to you. Is there an intelligent way that the APL or the framework would --

ADAMS: Well, the intelligent thing is it will do nothing. I mean, there is really not much else you could do. You could make the framework automatically pop up a window saying, didn't understand this message, but that gets kind of ugly, and that's -- you, the developer, are pretty much in control of that. If that's what you want to do, go ahead. It's not too hard to implement.

But otherwise, we don't want to impose something on you where you start saying, "Why does it pop up this stupid window every time? Just ignore it." So it's pretty easy in the MessageReceived, you just check the message, "What field," and it will say, "Unknown message," and based on that, you can, you know, pop open a window or exit the application or whatever it is you want to do. So it's pretty easy for you to implement.

FROM THE AUDIENCE: (Inaudible)

ADAMS: You will crash. You're going to -- let's try to do something like that. Let's see. What can we do? How about we go in here. Good enough? In this case, we're getting lucky and it's not really caring.

FROM THE AUDIENCE: Try 20 million.

ADAMS: I know. Here. Let's do it this way. This is a guaranteed winner.

FROM THE AUDIENCE: It is really robust.

ADAMS: This proves the robustness of the BeOS operating system. (Applause) Nothing will crash it. Basically what is going to happen is, you are going to be dropped from the debugger, and it's going to say, you know, data access exception or some such nonsense. In this case, what's going on is the memory layout is something such that we're okay.

FROM THE AUDIENCE: (Inaudible)

ADAMS: You may or may not crash, depending on what was in that pointer and on and on.

FROM THE FLOOR: (Inaudible).

ADAMS: You really want to see it crawl. There we go. So, in this case, it pops up a first line message that says, the application, blah, blah, blah, has encountered an error. Captain, what should I do? So, if you really want to go further, you can go like this, and here's a little bit more information, data access exception, here's the thread ID, which is kind of useful to know, here is the programmer counter and blah, blah, blah. Let's go into the debugger. There is a little bit more information. It's too far gone.

Typically, what will happen is, wherever you have the crash, you can do a stack crawl and you can see, oh, it's this function. If you're using the Metrowerks source level debugger, you might even be in the right place, and you can see exactly where the reference is happening. But this is what is going to happen when you crash now through a data access exception, at least.

Exceptions in general, we don't really -- there's a few things in -- if you have been doing C++ programming for any more than a couple of years, you probably have gone through the heart of darkness and read quite a few books and said, "Oh, templates, I'll use those," and exceptions and blah, blah, blah. Don't. You know, these are -- STL is great if you want to sell a book on STL. It's all very useful stuff. You have to use it with caution.

Exceptions, I did a couple years at Taligent as a consultant, and they used exceptions, they used templates, they used absolutely every last feature of that language. Their virtual tables were this long, and the system was very unusable.

In the BeOS right now, at least, we don't use a heck of a lot of features that are not necessarily supported by a lot of C++ compilers. Everyone supports templates differently, everyone does exceptions differently, and Metrowerks is no different. So we have minimal use of exceptions and templates.

The downside of that is your programming looks a lot worse in some situations, because you're checking return values of functions a lot. I think it's an okay evil myself. Exceptions are great, but there is a whole lot of support you have to do to do it right, so we're not there yet.

FROM THE AUDIENCE: We're basically stuck with the lowest common denominator, C++, then?

ADAMS: Well, I wouldn't call it lowest common denominator. It's all there. You can use it all. You know, there is nothing in there that says you can't use whatever you want. We include the STL library, we include templates, we include RTTI, and we actually use RTTI, because that's absolutely rock solid. But as far as us being the system vendor who is saying, "Here's the framework we're foisting on our community," we try to keep our frameworks very simple, because we want you to get into it.

So far the experience of developers who have Approached Be has been, "It was so easy, within the first night, I did" blah, blah, blah. I mean, half the postings you see on the FTP site are "Look what I did last night." You know, it's like, "Yeah, take it further." (Laughter) You know, it is very Approachable. I mean, within -- look at that HelloWorld. It is like, oh, yeah, application, object, window, view, done. You know, it's not very hard.

If you had to worry about exceptions and templates and all the rest, you'd be going, "Oh, man, I've got to wade through this and get through that," and it would take you a lot longer. So it's all there, you can use it all; it's just we don't necessarily take advantage of it ourselves.

FROM THE AUDIENCE: It is obvious that Be is a messaging system that is protected memory so it tries to hide itself from complications, but is there a way, for example, to set up yourself as the top level parser of keyboard data, more like macro processing?

ADAMS: Today, no. The way -- well, specifically, the keyboard input chain is very tied to the app server. The app server specifically opens a particular device and queries it at a particular interval or whatever it does and gets data, and there is really no way for you to jump in there.

Now, over time, over the past however months I've been at Be, maybe eight months, one of my first things was, "Yeah, boy, let's open that up." And what we've done is given various developers code that says, here's our keyboard driver, knock yourself out. One thing you can do, which is pretty simple and we'll finish this -- we're writing a Wacom tablet driver so that you can replace your mouse with a Wacom tablet, you know, and we're one step away from actually finishing that.

Basically what it does is we created a Wacom tablet thing, and all we had to do is tell the keyboard mouse driver, look for a /dev/mouse instead of doing it all yourself. If you don't find /dev/mouse, do what you ordinarily do, but look for /dev/mouse. If you find /dev/mouse, go query it for mouse information. So in that way you can replace the driver with a new driver and get the same results.

Another way of doing it is let's say you rewrote the keyboard mouse driver and you gave it a port that you can talk to, and ports are -- they come with the system. I mean, threads have ports, ports receive messages or data. You could have a driver with a receive port where any application could, you know, send data to that port and say, oh, these are mouse events, you know, or these are keyboard events, and they would instantly kind of get into the stream. So these are the things that could be done. They're not in the system as it stands today.

If you really want to do those things, you know, send it to dev support; that's the kind of stuff we like to enable.

FROM THE AUDIENCE: Is there a space for user-defined messages?

ADAMS: Everything is pretty much a user- defined message. There is a list of system-defined messages. Let me see if I can find the documentation on that stuff.

The system defines a number of messages, and there are things like QuitRequested, MouseDown, KeyDown, that sort of stuff, message protocols. So there are these system messages, which is about requested, app activated, arguments received, pulse, blah, blah, blah, blah, blah, and then there is KeyDown, Minimize, MouseUp, all these sorts of things.

Everything else, a message, the what field is a 32-bit integer, so there's the world out there for messages. You can create any message you want, and when you look at a message, which we still haven't had one handy here -- let's look at a mouse -- here's a MouseDown. It has got a when, which is what time did the message happen, where, which is the point, any modifiers on the keyboard that were pressed at the time, which buttons on the mouse were pressed and how many clicks is this.

So, you know, any application -- ah, I have a good example. Any application can generate these messages, and if you want to -- an application that I have been playing with is this infrared input for a television application, and what I have is this infrared detector thingie, I've got my remote, and I'm going like this (demonstrating).

Now, I have that tied in -- the remote I was actually using was a web TV keyboard just because it was cool. I have a little thread that sits there and goes, infrared, infrared, infrared, it gets an infrared key, and they come in as some encoded thing, and you have to turn that into a message that looks like a KeyDown.

So you basically create a BMessage object saying this is a KeyDown, you fill it with all the right stuff, and you post the message to the currently active window. It comes in like any other KeyDown. So that's impersonating a system message, but you can create any message you want and stuff anything you want into it, as long as the receiver knows that, oh, this is a foobar message, a foobar message has a image and a rectangle and a blah, blah, blah, so you create whatever you want.

FROM THE AUDIENCE: Can you do a cut and paste just by taking a whole bunch of KeyDown messages?

ADAMS: That's not how it works. You could do that if you wanted to. But that's a good thing, because cut and paste works exactly the same way. You stuff things into a message, you know, you hand it to the clipboard, and you're done from the sender side. Then the receiver side receives a message, which is the paste message, and you unpack it and see what is in there and do the paste.

You could do a -- what is that thing, Superkey or Softkey or whatever, one of those macro sort of things where you capture a whole bunch of keystrokes, and then you feed them to something, right? You could do an application like that by faking a bunch of KeyDown messages and feeding them to an app pretty easily.

FROM THE AUDIENCE: How can you get like the current active window?

ADAMS: Through the application, you can say, well, what's the current active window, or through the -- there's a higher level system thing, which is the roster, the application roster, and that thing, you can say, well, what's the currently active application? So if you are an outside application, you can find out who is the active app, and then actually, when you're looking at the menu up here on the right-hand side, our task bar, these are windows that each one of these applications has.

So you can enumerate all the applications and you can enumerate all the windows within the application. There is a bit of hidden voodoo about the API to do this, but it can be done, and if you really want to do this in your -- as a third-party application, we'll tell you, but it is just not a documented API at this point.

FROM THE AUDIENCE: One question about drawing a window. Is there a way you could draw a window, say, with like a different color or a different background, maybe add texture to it?

ADAMS: Yes.

FROM THE AUDIENCE: To the outline of it, you know what I mean.

ADAMS: Oh, yes, well, that. What you can do is -- well, let's bring this thing up. There are a number of thingies that you can fiddle with. You can change your menu styles. Here I can change the font that shows up in the menus, I can change the font size, I can change the way you activate them. You can change your -- well, keyboard repeat rate and delay and all that sort of stuff. You can change the keyboard layout, so if you want that kind of keyboard or this kind of keyboard or whatever, Dvorak keyboard, you can change all that stuff. You can change your scroll bars. You get the sense I'm leading up to, you can't change your windows?

You can change your screen, you can change your name, but you can't -- well, there is actually an API for changing the window colors, but that's all you can change. You can't say, "Oh, I want round windows," or "I want this kind of windows." The background of the window is governed by the application, so, you know, the tracker says, these windows are white, and it's really the view that says they are white. You can change the color, that's the border, and that's about it.

If you want to get anything more fancy than that, we're not there yet. I guess that's similar to the Apple -- I don't know what they call those things, WDevs or whatever. We have a similar kind of thing, but we're not ready to be hogwild with that yet.

FROM THE AUDIENCE: Can you change the plan area window color; does that work with windows?

ADAMS: Well, windows don't do any drawing; views do drawing.

FROM THE AUDIENCE: So you can't make that black instead of white?

ADAMS: This application could. There is no way of setting the color on a window per se, because a window always has a view on it, so there is -- the way it is actually constructed is every window has a default view, which is the bottom view, and whenever you say add child, you're actually adding to that view, but you don't have access to that view at all.

So, no, the only way can you ever set a color or an image on a window is by putting a view on it that's the size of the window and doing whatever you're going to do.

FROM THE AUDIENCE: A while back you mentioned that the base executable model was PEF. Is there any form of shared library support such as SOM or shared objects like they have at UNIX on top of that?

ADAMS: We have shared libraries ourselves, which is the same thing as -- well, it's not the same thing as SOM. Shared libraries are like DLLs in Windows.

Actually, let's look at that, because that's kind of an interesting point. Let's bring up something that looks like a somewhat substantial application, let's say CD player. So here's a CD player, and if I had a CD, you know, stop, rewind, play, blah, blah, blah, volume control, a bunch of neat little images and whatnot. So, a guess as to how big that app is?

FROM THE AUDIENCE: 16K?

ADAMS: Smart alec. Zero bytes. No, that's not true. (Laughter)

FROM THE AUDIENCE: Magic.

ADAMS: Magic. It works by inference. 129K for that one, which you can think is big or small. I think it's pretty dang small. If I had an equivalent Windows application, it would probably be bigger than that.

The reason it's so small is because all of this stuff having to do with UI -- actually, I'll say the reason it's so big is because all of these little gray buttons and whatnot are actually in that executable size as well, and that probably accounts for at least 30 or 40K of it. The rest is because you have the app server, and you have a shared library for all the UI widgets, so all of that isn't actually static in your code. It's in the shared library, and the shared library gets loaded once for the whole basically. That's the way it works.

So you have shared libraries. You also have dynamically loadable add-ons. I can show that most easily by showing this little application called Rraster. This application right here is called Rraster, and what it does is it just lets you view images and any kind of image that you have a codeck for. I just created a screen shot, hopefully, and there it is. I'll drag it on there. It should open up.

So this is a targa file. Rraster knows how to deal with targas, jiffs, jpegs and all that stuff. If you remember back when we did the file type on it, we saw all the extension of the different types of images that it knows how to deal with. The way it knows how to do that is because it has all these add-ons, these little things, 4K, 6K, jpeg is 59K, you know, these little tiny files. Tiff is 152K. The application itself is probably not very big. The application is 53K. Granted it doesn't do much more than view images, but images of any type.

These add-ons are basically -- the application defines an API that says if you want to be a little add-on that knows how to serve up images, you need to have this function that says create bitmap, I'll give you a file name, you hand me back Be bitmap, so that's what these things could for these different formats. At run time, Rraster looks through this directory and loads all these add-ons and says, okay, well, now I know how to view all of these different types of images.

You will see, again and again, where applications in the BeOS, everyone will say, blah blah, blah, add-on, blah, blah, blah, add-on, blah, blah, blah, add-on, just like this morning when we showed Adam, everything was an add-on. Why? Because your applications can be really small, and you can extend it by just throwing more add-ons out there.

So you probably won't see a lot of applications in the BeOS where revisions come really slowly. Someone is probably going to say, "Oh, yes, we have a new jpeg to work." Boing, there it goes, there is your add-on. So that, along with shared libraries, makes small applications that are extendable, you know, fairly quickly.

FROM THE AUDIENCE: What's the link between add-ons and the MIME types that seem to be sitting in resource fork in the application? Can you do that dynamically?

ADAMS: Yes. Well, it works both ways. The application, in this case, since we shipped with this set of add-ons, we wanted to make sure that by default any image of those types showed up in that MIME type thing.

The other thing is, whenever you create an add-on, this can also have a resource file associated with it, and for that file, you can say, I understand image/target or jpeg or whatever it is, so really the application doesn't have to do anything. It can just say, I view images in general, and then when you drag and drop a targa onto it, it will go, oh, what's this, and then it can know that this add-on belongs to it.

But if you don't list it with the original application in some way, at least by saying, I understand all images, you know, when you drop an image on it, it will say, I don't know what that is; do you really want to open it? So, by specifying some, you will at least get the list of the ones that we shipped with it.

FROM THE AUDIENCE: In that documentation, the win field for that event set, it specified that in microseconds. Is that accurate to the microsecond?

ADAMS: Well, it's accurate to the microsecond, as accurate as the system is. So, you know, when you call system time, which is the way you typically get this time, it takes some amount of time to actually call system time, and the event probably actually happened a couple of milliseconds before that and on and on. So, yes, it is. There is nothing in the system that would give you a 1 microsecond tick, you know, but as far as you're concerned, you know, everything is done in microseconds. So... Does that make sense?

FROM THE AUDIENCE: Yes.

ADAMS: Okay.

FROM THE AUDIENCE: Where can one find documentation on how to use Rraster add-ons?

ADAMS: You will not. There is this other thing called data types, which is really what -- as far as imaging, images, movies and sound add-ons, there is this other library by a guy named Jon Watte, who is from Metrowerks, and it's what everyone in the community supports. It's similar to this in that you create these add-ons and it dynamically loads them and all that sort of stuff.

This one was done because Datatypes was not ready to go into our system when we were actually shipping this, so there they are. But really, don't worry about this, but if you really care, and you want to use the ones that come with this system, I wrote a MacTech magazine article back in January that talked about this.

FROM THE AUDIENCE: What's the other library called?

ADAMS: Datatypes. Learn it, love it, embrace it. It will serve you well.

FROM THE AUDIENCE: Will Datatypes be included in future releases.

ADAMS: Yes, it's actually in this release, but it was kind of.... We'll get our act together. It's going to be there. We definitely want it to be there, and everyone is already supporting it.

FROM THE AUDIENCE: And also are the add-ons dynamically loaded and unloaded on an as-needed basis?

ADAMS: Depends on the application. So Rraster, for instance, does not load an add-on until it needs it, so, you know, other applications may or may not do that, so it just depends. Is there one over there?

FROM THE AUDIENCE: Do you support for daemons?

ADAMS: Daemons? Applications that don't necessarily have windows, stuff like that? Yes. It is just -- well, kind of like what you would do in UNIX, but not. You can launch an application, and if you don't have a window, it just won't show up anywhere. We have plenty of -- oh, yes, last demo. This shows it pretty plainly. Let's go to the evil shell. So this is a list of all the threads and teams, i.e., processes that are in the system. You don't see that many application windows on the screen, so all of these are daemons for the most part, servers as we would say, I guess. So, yes, we definitely have support for servers, demons, whatever.

That's all we have time for, I guess. If you want to accost me later, you can. Go to the other sessions, because they will tell you all the details on how to actually do more of this stuff. And that's it.

(Applause)

(End of session)


Home | About Be | Be Products | BeWare | Purchase | Events | Developers | Be User Groups | Support


Copyright ©1997 Be, Inc. Be is a registered trademark, and BeOS, BeBox, BeWare, GeekPort, the Be logo and the BeOS logo are trademarks of Be, Inc.
All other trademarks mentioned are the property of their respective owners.
Comments about this site? Please write us at webmaster@be.com.
Icons used herein are the property of Be Inc. All rights reserved.