This post originated from an RSS feed registered with Agile Buzz
by James Robertson.
Original Post: Display, VisualWorks and Flicker - Part 1
Feed Title: Pollock
Feed URL: http://www.cincomsmalltalk.com/rssBlog/pollock-rss.xml
Feed Description: Pollock - the next VW GUI
I've been thinking a lot about VisualWorks, it's display mechanisms and the totally unpleasant flicker that VisualWorks often exhibits. And, I've been thinking about what I can do about it in Pollock.
First though, we need to talk about the GraphicsContext, or more precisely, the VisualWorks GraphicsContext. The equivocation is due to the difference between the general notion of a graphics context in an OS, and the GraphicsContext in VisualWorks. In general, an OS graphics context is a resource, allocated from the OS, which allows you call drawing and graphics context manipulation functions with the graphics context as a parameter. (They are very UN-OO). There is one thing that is basically the same about an OS graphics context and the VisualWorks GraphicsContext. When you do a display function on an OS graphics context, or with a VisualWorks graphics context, the result of that display happens immediately.
Now, there are ways in both an OS graphics context, and in VisualWorks, to NOT have every write happen immediately. This is by creating a non displayed graphics medium (typically called something like a Pixmap), doing your drawing on that, and THEN, in one fell swoop, asking a window's OS graphics context to slap that pixmap on the screen/window in one fell swoop.
This last bit of magic was first invented for Smalltalk, and already has a name: BitBlt. BitBlt also has a bunch of cool capabilities to do things like combine areas of display in terms of OR and AND and XOR bits, and doing it very fast. This functionality has been in GUI OSs for just about as long as we can trace. It isn't typically used very much though. When people started doing simple animation, they "rediscovered" that if they used this facility, they could get high quality low flicker results. Of course, they didn't know they were using BitBlt, they just knew they created a Pixmap, drew stuff on it, and then called an OS function to slap that sucker to the screen. They got real smart about it too! They realized that video displays have a moment in time when they weren't actually displaying anything. This time is when a CRT gun is turned off between the time if finishes the last trace line at the bottom right of the screen, and the time it starts to display the top left trace. So, they discovered if they could get information about when that was happening, and slap that Pixmap to the screen during that moment when no display was happening, they could get no visible flicker.
So, that is the two ways that something is generally written to the display. One, directly and immediately, lines, characters and primitive graphic objects (circles and rectangles). The other, doing that all first to a Pixmap, and then slapping the pixmap on the screen.
Now we need to fill in some details about common features of a GraphicsContext. You can give a GraphicsContext a color. Once it has that color, it then proceeds to do all display in that color. Note, it does not have both a foreground and background color... a GraphicsContext has no notion of these concepts. In fact, when you first get a GraphicsContext you can think of it as getting a clear and transparent area of the screen. If you tell the GraphicsContext to write a character, it simply displays just that character, without affecting anything that may already be under that character at that point. In effect, but not in fact, it BitBlts that character on top of whatever is already there. Just the character, just the pixels that make up the character, nothing else.
Thus if you wanted to take a rectangle (imaging an InputField) and draw the white background area and then the text on it, you have to do it in four steps:
Tell the GraphicsContext to use color white
Tell the GraphicsContext to draw a filled rectangle of some size at some place.
Tell the GraphicsContext to use color black
Tell the GraphicsContext to display some text starting at some specific place (if you're paying attention, you'll tell it to be in a place that will be within the previous rectangle).
Remember, this all happens right now, immediately for each step.
The next thing we need to know about is something called Clipping. In VisualWorks, a GraphicsContext is given to you based on a specific window you want to draw on. When you ask to draw on that GraphicsContext, the origin for that is the upper left hand corner of the "Non Window" area of the target window. This area in OS speak is often called the Client area. The border, window label, edges and buttons in the window label area are often called the Non Client area. So, given that, let's say you have a window which has a client area of 200 x 200. The interesting thing about the GraphicsContext is that you can be real stupid and it will still "do the right thing." You can, for instance, tell the GraphicsContext to display a rectangle starting at position 400 @ 400. The GraphicsContext will see that it is totally outside of it's area of influence, and basically, ignore you. However, let's say you asked it to display a rectangle, starting at position 100 @ 100, which has a size of 200 x 200. Well, if you follow the math, you'll see that the area of that lays outside the area the GraphicsContext is supposed to manage for you. Therefore, it just draws the area that intersects where it is allowed to display and the area you asked for. Thus, the GraphicsContext clips displaying anything outside of it's designated display area.
One of the extra cool things you can tell a GraphicsContext to do is to limit any display to a subset region of it's whole display area. You do this by telling the GraphicsContext to use a specific Clipping Rectangle. It is easier to explain this by example than other means. So, a GraphicsContext which we got from a window exactly like the one above, which has a client area of 200 x 200. Now, let's tell that GraphicsContext to have a clipping rectangle starting at 100 @ 100, and having a size of 10 x 10. Again, like above, let's ask the GraphicsContext to display a rectangle, starting at 100 @ 100 and having a size of 200 x 200. This time, the GraphicsContext will only display that part of the rectangle that falls inside it's clipping rectangle. So it will only display in that area starting at 100 @ 100 and covering 10 x 10. If we were to ask it to now draw a rectangle at position 10 @ 10, and having a size of 10 x 10, we won't see anything. This is because that area of the GraphicsContext lays outside of the clipping rectangle.
That's how the guts work. Next time, I'll describe how VisualWorks and the Wrapper framework uses this mechanism