The Quartz Window Server

The Quartz Window Server is the part of the Mac OS X operating system that manages the location of windows on the computer’s screen and organizes the flow of events from the mouse and the keyboard. While the Window Server is mostly transparent to you as a programmer, you will occasionally see behavior in Mac OS X that is very different from what you might experience in Mac OS 9 or in Windows, and it’s important to understand why. For example, you can still move the windows of a Mac OS X application that is trapped inside an infinite loop (i.e., “hung”), because the moving of the windows is done by the Window Server itself, not by the application. Another result of the Window Server is that if you wish to draw on the screen, you must draw on a window — you cannot draw on the screen’s background itself.[36]

Quartz uses a mechanism called graphics context to present each Quartz client program with its own independent copy of the Quartz environment. NSViews can also have their own graphics contexts. A graphics context can be thought of as a “virtual printer.” Each has its own independent set of resources for drawing. You may have noticed on some Macs running Mac OS 9 that when you switch from one application to another, the colors of the application windows change. That sort of change never happens on Mac OS X, because the colors of each window are completely independent of one another.

Buffered, Retained, and Nonretained Windows

The underlying communication channel between an application and Quartz is buffered and bidirectional. Buffered means that the Quartz commands are drawn to an off-screen window that is periodically flushed to the computer’s display, so that the user sees only the final result. Bidirectional means that you can ask questions of the Quartz environment and get back sensible answers.

Normally, buffered drawing is precisely what you want, because it makes your program run with fewer distractions to the user. Instead of having every one of your program’s drawing commands made visible directly on the screen, the program draws into the buffer. When the drawing is finished, the buffer is flushed to the screen. The user sees only the final state, rather than how the window was created. Buffering has a second advantage as well: when a window is covered over and then exposed, the window’s contents are redrawn directly from the off-screen buffer, so the application does not need to reissue the drawing commands. This results in smooth, fast redisplay.

In some cases, however, you may want to partially or fully disable window buffering. You may have already noticed that in Interface Builder you can change the drawing type of a window from the default Buffered type to Retained or Nonretained. Windows that are Retained are drawn directly to the screen but are copied to an off-screen buffer when they are moved off the screen or obscured. Drawing to a Retained window can be somewhat faster than drawing to a Buffered window when you are working with very large images with lots of colors, because the image needs to be copied only once. Nonretained windows are just that: nonretained. You see all of the drawing as it takes place, and the window contents are lost when the window is covered up or moved off the screen. Nonretained windows can be useful if you are trying to optimize the speed of your drawing routines and want to see precisely what they are doing — that is, when you are developing and debugging your application — but it is unlikely that you will want to use Nonretained windows.

If you optimize your drawing commands properly, you may find that drawing in a Retained window can be marginally faster than drawing in a Buffered window. To create a Retained window, simply select the window’s icon in IB’s Nib File window, type Command-1 to bring up the Window Info panel, and change the Backing radio-button selection from Buffered to Retained.

Warning

The Window Info panel is associated with an instance of the NSWindow class, whereas the NSWindow Info panel is associated with the NSWindow class itself. They are different!

You may find that there are times that you need to flush the current graphics context in order to force a screen update. You can use the following Objective-C statement to do this:

[ [NSGraphicsContext currentContext] flush];

There is a lot more to the NSView and NSGraphicsContext classes than we can possibly cover here. We recommend that you spend some time looking over the documentation for these two classes before going on to the next section. While you’re at it, you might also spend some time with the documentation for NSView, NSGraphicsContext, and Quartz.

Drawing in an NSView with Quartz

There are two techniques you can use to draw in an NSView:

  • Place Quartz function calls in the NSView’s drawRect: method. When the window is displayed or redisplayed, this drawRect: method will automatically be invoked, and your specified drawing will take place.

  • Bracket your Quartz calls within a call to the NSView’s lockFocus and unlockFocus methods (e.g., [myView lockFocus], followed by your Quartz calls, followed by [myView unlockFocus]). The lockFocus method tells the Quartz system that all subsequent drawing should take place in the view that you specify.

You should use the drawRect: method for any code that you write from scratch. With this technique, you partition your program into two parts: the first part changes instance variables of your NSView subclass, and the second part draws in the NSView’s rectangle based on the current values of these state variables. When your view needs to be redrawn, it is sent the message setNeedsDisplay:YES. The AppKit then automatically invokes lockFocus and unlockFocus and calls drawRect: as needed. This is the most efficient way to draw with Cocoa and also the easiest to implement: all you need to concentrate on is how to draw the object; Cocoa handles the when.

The lockFocus/unlockFocus approach is often used by programmers who are coming to the Cocoa environment from other application frameworks and who are comfortable with the idea of drawing directly to the window in response to some sort of event. This technique is also useful when porting code from other operating systems.

We will use the drawRect: method for animating our About panel. This will allow us to divide the animation logic into two separate parts — one section that controls the movement of the animated figures and another that does the actual drawing. Dividing up the code in this manner makes it easier to debug.



[36] In practice, this isn’t much of a restriction, because you can always create a transparent, borderless window without a title bar that covers the entire screen, and draw on that.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.12.50