| < Previous PageNext Page > |
An application uses windows to claim an area of the screen in which to display content and respond to user actions. Windows are essential to both drawing and event handling.
Further Reading: Window Programming Guide for Cocoa discusses many of the topics covered in this section in greater detail.
The Windows of an Application
NSWindow and the Window Server
Window Buffering
Window Z-Order and Levels
Parts of a Window
Window Coordinates
Windows and Drawing
Window Status
Windows and Event Handling
Panels
Although it's possible to have an application with no visible windows (for example, a background application) such applications are rare. Generally, there are two types of applications based on the number of windows they can potentially display:
Document-based—An application capable of creating multiple documents, each in its own window. Examples are word-processing and drawing applications. In a document-based application, users choose a menu option (typically File > New) to create a new document. Most document-based applications in Cocoa are based on its document architecture. (You can find an overview of this architecture in “Other Cocoa Architectures”.)
Single-window—An application that displays no more than one window at any time. Examples in Mac OS X are iSync and Font Book. When a single-window application launches, it displays its window. Often closing the window causes the application to terminate.
Any application can also have secondary windows, also known as dialogs and panels. These windows are subordinate to the current document window or, in the case of single-window applications, to the main window. They support the document or main window in various ways—for example, allowing selection of fonts and color, allowing the selection of tools from a palette, or displaying a warning‚ A secondary window is often modal. See “Panels” for more information
In Cocoa an NSWindow object represents a physical window. The window server creates physical windows and ultimately manages them on the screen. It assigns each window a unique number as an identifier. The connection between an NSWindow object and its physical window is established through this window number.
When the window server creates a window, it obtains a window graphics context and initializes the graphics-state stack. It also creates the window's backing store, a memory region holding the pixel values of the window to be placed into the display device's frame buffer.
Note: It's possible to create a window without a backing store. This is called a deferred window. The backing store of a deferred window is created when the window is ordered on-screen.
Windows often overlap when there's more than one on the screen. When a group of windows are stacked one over another, a mouse click on a partially obscured window usually brings it to the front. In the process, its obscured contents become visible. If the window has a display buffer, the window server can automatically make those contents visible. Otherwise, the application has to redraw them.
There are two types of window buffering. A window's display buffer stores pixel values either for the entire window or for those portions of the window that are currently obscured. When an obscured window with a display buffer is made frontmost, the window server copies the exposed area from the display buffer to the screen. When you create an NSWindow object you can specify one of three buffering schemes, which are depicted in Figure 6-5.
Nonretained. No display buffer is provided. All drawing occurs directly onscreen—that is, the pixel values are written directly to the frame buffer. If part of the window is covered by another window, the bits for that part of the window's content area are lost. When the obscured window is exposed, the application must redraw the obscured portion; if it doesn't draw, that portion is displayed in the window's background color.
Retained. Although a retained window has a display buffer, drawing is done directly onscreen when possible). The display buffer isn't affected until the window is obscured; then the pixel values in the obscured areas are written to the display buffer. When the obscured areas are later revealed, the contents of the display buffer are copied to the screen.
Buffered. The buffer contains an exact duplicate of what's in backing store. In fact, drawing is done to the display buffer, and then its contents are flushed to the screen, composited with overlapping windows if there are shadows or transparency involved. If a window is obscured and then later brought frontmost, the entire display buffer is copied to the screen.
Because buffered windows are required for transparency or non-rectangular shapes, almost all Cocoa windows are buffered. Nonretained windows are appropriate for transitory images or simple connection lines, such as are used in Interface Builder for target-action connections.
The window server maintains the windows it displays on a screen in a front-to-back order known as the screen list or the Z-order. Each window has a unique position in the list. A window can be at the top of the list—that is, the frontmost window. Or it can be at the bottom of the list—that is, the window potentially overlapped by every other window. Or it can be in any other position where it is above and below other windows. The Z-order is changed every time a user clicks a window, which makes that window frontmost and puts the previously frontmost window behind it.
The concept of window layering is complicated by window levels. A level is a layering subset of windows of a particular functional type. Window levels are in a hierarchical order, with those windows in higher levels displayed above windows in lower levels. This scheme guarantees that a window of one particular type always appears above or below a window in another level. For example, a modal system dialog always appears above all application windows. Thus Z-order is really maintained within windows levels (see Figure 6-6).
The window server supports several levels of windows, in the following order:
Screen savers. (Screen savers use a window the size of the screen but without a title bar to display their content.) Screen-saver windows are displayed above all other windows.
The menu bar (which includes application menus).
The Dock.
Modal windows and panels (see “Modal Windows”.
Contextual menus.
Floating windows (for example, palette windows for a drawing application).
Any other types of windows, including application windows.
A window can be explicitly taken off the screen list, in which case it's known as an offscreen window. A window disappears when it's removed from the list, and it's restored to the screen when it's put back on the list. Events are not dispatched to offscreen windows. Moving windows off the screen list is the basis for an application's window-hiding capability. An offscreen window must be buffered or retained in order for it to be drawn into.
Note: You can also remove a borderless window from the screen by setting its frame coordinates outside of the visible coordinates of the screen. You cannot do this with other windows, however; the Application Kit constrains these windows to remain at least partially visible within the screen bounds.
NSWindow defines methods for manipulating the Z-order of application windows, for taking windows off and on the screen list, and for setting the level of windows. See the NSWindow class reference for details.
A window has two major parts: a frame area and a content area, as shown in Figure 6-7. These areas are views—specifically, instances of a subclass of NSView (see “Views”. The frame view surrounds the entire window area, and draws the window's border and title bar. The frame view is a private object created by NSWindow; it is not open to alteration through subclassing. However, when you create a window, you can specify which controls and other features—close button, miniaturize button, resizing triangle, title—you want the frame view to have.
The content view is inset into the frame view, usually occupying the entire area except for the title bar and the window border. Figure 6-7 shows the content view relative to the frame view. (One can create windows that don't have a title bar or visible border, but they still have a frame view.) The content view is the sole public subview of the frame view. It is not a private view so you can replace it with your own custom view, if you wish. Although the content view has a superview (that is, a view that owns and encloses it in the hierarchy of views), that superview is a private object. The content view is thus the root of the hierarchy of views for the window. For more on the view hierarchy, see “Views”.
As do all view objects, the content view keeps a reference to its window, accessible through the window method. Figure 6-8 depicts NSApp and its window list, the content view of each of the windows in the list, and the relationships between those objects.
The coordinates of a window are related to the coordinates of the screen. The entire screen can be thought of as the upper-right quadrant of a two-dimensional coordinate grid, with the origin in the lower-left corner and the positive x-axis extending horizontally to the right and the positive y-axis extending vertically upward (see Figure 6-9). You can locate a point in the screen by reference to this grid.
The primary function of the screen coordinate system is to position windows on the screen. When your application creates a new window and puts it on the screen, it must specify the window's initial size and location in screen coordinates. However, for drawing in a window, it uses a different coordinate system, one that's specific to the window: its base coordinate system (see Figure 6-10). This coordinate system differs from the screen coordinate system in two respects:
It applies only to a particular window; each window has its own base coordinate system.
The origin is at the lower-left corner of the window rather than at the lower-left corner of the screen. If the window moves, the origin and the entire coordinate system move with it. An image retains its position within a base coordinate system no matter where the window is located.
The base coordinate system is the reference point for defining the individual coordinate systems of the window's views. The frame view draws the window's border and title bar directly in the base coordinate system. The content view and its subviews draw in coordinate systems that are transformations of the base coordinate system.
Windows do not draw themselves. That job is left to the views they contain. However, an NSWindow object plays an important role in coordinating the drawing of its views.
Normally, during a pass of the event loop objects in an application may mark views (or regions of views) as needing to be redrawn. An NSWindow object collects references to these "dirty" views in a list, the order of which is determined by position in the view hierarchy. Shortly afterward—which is usually at the end of an event cycle—the Application Kit iterates through this list starting with the topmost view (that is, the view closest to the content view) and requests each view to draw itself. In this manner, views that are a background to other views are drawn first.
This automatic drawing of a window's views takes place only if the window's auto-display feature is turned on, which it is by default (see the setAutodisplay: method). If you turn off this feature, the application is responsible for updating window content when necessary. In addition, you can bypass the auto-display mechanism by sending an display, displayRect:, or displayRectIgnoringOpacity: message to any NSView object; as a result that view and its subviews are immediately redrawn. See “Displaying a View” for further information.
You can redraw an entire window with the NSWindow display and displayIfNeeded methods. These methods force an immediate display of the window's views, although the latter method iterates only through the list of invalidated views. The display method causes each view in the window's view hierarchy to redraw itself, starting with the content view. This method is invoked on a one-shot window (that is, a window whose backing store is released when the window is offscreen) before the window is shown onscreen. In addition, you can call setFrame:display: with a second argument of YES to cause the window to resize and to redraw all of its views.
A mechanism related to window display is window updating. At every pass through the event loop, NSApp sends an update message to each window in its window list. The default implementation of update does nothing, but subclasses of NSWindow can override this method to examine the state of the application and modify the behavior or appearance of the window as needed.
Each window of an application has a status related to the user's interaction with it. The appearance of a window is an indication of this status. Inactive windows are open and may be visible, but they are not in the foreground. The controls and title in the title bars of inactive windows are grayed out. Users cannot interact with these windows unless they click on them to bring them forward.
Active windows are windows that are currently the focus of user input or attention. They are in the foreground, their controls have color, and their titles are in a black font. Active windows can have two statuses: main and key. The active window that is currently the focus of user attention is the main window. It is also the key window much of the time; a window is key if it currently accepts keyboard events.
However, sometimes the main window and the key window are separate windows. While the main window is still the focus of user attention, another window is the input focus for key events. The key window must have an object such as a text field in which the user can enter characters by typing at the keyboard. In this case, the key window is typically a dialog or panel (for example, the Find dialog) in which the user specifies data relevant to the main window.
The application object (NSApp) maintains the main and key status of the application's windows. A window's status often determines the events it receives and dispatches (see “More About Event Dispatch”.
Further Reading: For more on main and key windows, see the section on window behavior in Apple Human Interface Guidelines.
NSWindow is involved with events and event handling in two principal ways. In one activity— event dispatch—it is actively involved. In the other, it is the passive recipient of a constrained stream of events.
As described in “More About Event Dispatch”, the application dispatches most events it receives by sending sendEvent: to the NSWindow objects to which the event "belongs." The window object, in turn, locates the NSView object that should receive the event and sends the appropriate NSResponder message to that view, passing in the NSEvent object. For example, if the event is a key-down event, it sends keyDown: to the view; if it's a mouse-dragged event (left button), it sends mouseDragged:. How the window object locates the target view generally differs between key and mouse events:
The window sends key events to the first responder of the view hierarchy.
The window sends mouse events to the view in which the mouse event occurred.
The key-down (NSKeyDown) and left-mouse-down (NSLeftMouseDown) events require the most handling. Before NSWindow attempts to send the keyDown: message to the first-responder view, it feeds the key character (or characters) to the system input manager, which interprets the input as text to insert or commands to perform. Before it sends a mouseDown: message, NSWindow attempts to make the target view the first responder. If the appropriate modifier keys are pressed, it doesn't send the message at all, instead handling it by displaying contextual help or a contextual menu.
Normally an application distributes events to all of its windows, guided primarily by where user actions occur. But sometimes an application may run a window modally, thus requiring users to complete a task—for example, selecting a file, entering a name, or even clicking an OK button—before they can dismiss the window. Modal windows are common in Mac OS X; they include error-message dialogs and panels for opening and printing documents.
NSWindow objects are passive participants in the modal-window mechanism; it's the application that programmatically initiates and manages modal behavior. To run a window modally, NSApp uses its normal event loop machinery but restricts input to a specific window or panel. In the loop, it fetches events but if the events do not meet certain criteria—most importantly their association with the modal window—it tosses them.
NSApplication offers a couple of ways to run a window modally:
Blocking—The application blocks until the user dismisses the modal window.
Nonblocking (modal session)—An application initiates the modal session and runs the window modally for one pass through the event loop. The modal-session code can continue to run the window modally in a loop until some condition is satisfied.
Other Application Kit classes also provide methods to run windows and panels modally.
Panels are secondary windows that act in a supporting role to an application or document window. They are frequently referred to as dialogs. In Cocoa, panels are instances of NSPanel or of a subclass of NSPanel. Panels have some special behaviors suitable to their auxiliary function. They can become the key window, but never the main window. By default, they are removed from the screen when the application becomes inactive, and are redisplayed when the application becomes active again. (Alert dialogs are an exception to this behavior.) And, because a panel is intended for repeated use, it isn't released when it's closed. You can also configure panels to become floating windows—such as utility windows—which are in a level above the other windows of an application.
| < Previous PageNext Page > |
© 2006 Apple Computer, Inc. All Rights Reserved. (Last updated: 2006-12-20)
|