Re: Refresh woes for custom OGL pane
Re: Refresh woes for custom OGL pane
- Subject: Re: Refresh woes for custom OGL pane
- From: "Erik M. Buck" <email@hidden>
- Date: Tue, 30 Apr 2002 09:29:54 -0500
- Organization: EMB & Assocites Inc.
----- Original Message -----
From: "Brent Gulanowski" <email@hidden>
>
>
On Tuesday, April 30, 2002, at 01:04 AM, Erik M. Buck wrote:
>
>
>> I'm basically calling [self drawRect] everytime the view changes via
>
>> user input, etc... This works WAY better. Two problems though (so
>
>> far :)
>
>
>
> NEVER CALL -drawRect:! Call -display or -displayRect: or
>
> -setNeedsDisplay:
>
> or -setNeedsDisplayInRect:. Your failure to call one of these methods
may
>
> explain all of your problems.
>
>
Erik, did you have a bad experience with a -drawRect: call or something?
>
Flashbacks? Insomnia? Memory loss? I'm sure we can find you some help for
>
that ;-)
>
[Deleted]
>
So what BAD THINGS HAPPEN when you call -drawRect: directly?
>
>
brent
Here is Apple's documentation:
drawRect:
- (void)drawRect:(NSRect)aRect
Overridden by subclasses to draw the receiver's image within aRect. The
receiver can assume the focus has been locked, drawing will be clipped to
its frame rectangle, and the coordinate transformations of its frame and
bounds rectangles have been applied; all it need do is invoke rendering
client functions. aRect is provided for optimization; it's perfectly
correct, though inefficient, to draw images that lie outside the requested
rectangle. See "How to Draw" in the class description for information and
references on drawing.
This method is intended to be completely overridden by each subclass that
performs drawing. Don't invoke super's implementation in your subclass.
See Also: - display, - shouldDrawColor, - isFlipped
If you call - drawRect: yourself, the contract that the receiver "can assume
the focus has been locked, drawing will be clipped to its frame rectangle,
and the coordinate transformations of its frame and bounds rectangles have
been applied" is invalid. Furthermore, -displayRect: does even more: it
causes views below transparent views to be redrawn, coordinates backing
store buffer flushes, and cleans up the graphics context after -drawRect:.
This is particularly important for subclasses of NSOpenGLView! -displayRect:
configures the GL context and manages buffer copies between main memory and
VRAM. If you bypass -displayRect: by calling -drawRect: directly, you are
abusing the frameworks and will almost certainly cause problems including
the reported problem of not having a valid GL context within -drawRect:.
With all of that said, an expert can safely call -drawRect: directly under
special circumstances. It is unwise in most cases and unnecessary for the
person I answered.
More Apple documentation:
- (void)display
Displays the receiver and all its subviews if possible, invoking each
NSView's lockFocus, drawRect:, and unlockFocus methods as necessary. If the
receiver isn't opaque, this method backs up the view hierarchy to the first
opaque ancestor, calculates the portion of the opaque ancestor covered by
the receiver, and begins displaying from there.
See Also: - canDraw, - opaqueAncestor, - visibleRect, -
displayIfNeededIgnoringOpacity
The Display Mechanism
Displaying an NSView centers around the drawRect: method, which transmits
drawing instructions to the Window Server. Before this can happen, however,
a number of other things must be established. First, of course, is the
rectangle in the view that needs to be drawn. Once this is known, the view
must be checked for opacity; if the view is partially transparent, its
nearest opaque ancestor must be found and drawing must commence from there.
Once all of this is determined and a particular view is to be drawn, the
Window Server must know which window device the view is in, how to clip
drawing to the appropriate region, and what coordinate system to use. This
is all handled outside drawRect:, by NSView's various display methods. The
following sections examine each of these points in turn.
Marking a View as Needing Display
The most common way of causing an NSView to redisplay is to tell it that its
image is invalid. On each pass through the event loop, all views that need
to redisplay do so. NSView defines two methods for marking a view's image as
invalid; setNeedsDisplay:, which invalidates the view's entire bounds
rectangle, and setNeedsDisplayInRect:, which invalidates a portion of the
view. The automatic display of views is controlled by their window; you can
turn this behavior off using NSWindow's setAutodisplay: method. You should
rarely need to do this however; the autodisplay mechanism is well-suited to
most kinds of update and redisplay.
The autodisplay mechanism invokes various methods that actually do the work
of displaying. You can also use these methods to force a view to redisplay
itself immediately when necessary. display and displayRect: are the
counterparts to the methods mentioned above; both cause the receiver to
redisplay itself regardless of whether it needs to or not. Two additional
methods, displayIfNeeded and displayIfNeededInRect:, redisplay invalidated
rectangles in the receiver if it's been marked invalid with the methods
above. The rectangles that actually get drawn are guaranteed to be at least
those marked as invalid, but the view may coalesce them into larger
rectangles to save multiple invocations of drawRect:.
Opacity
NSViews don't necessarily cover every bit of their frames with drawing.
Because of this, the display methods must be sure to find an opaque
background behind the view that's ostensibly being drawn, and begin
displaying from there forward. The display methods above all pull back up
the view hierarchy to the first view that responds YES to an isOpaque
message, bringing the invalidated rectangles along. NSView by default
responds NO to isOpaque, so it's important to remember to override this
method to return YES if appropriate when defining a subclass. Most
Application Kit subclasses of NSView actually do this.
If you want to exclude background views from drawing when forcing display to
occur unconditionally, you can use NSView methods that explicitly omit
backing up to an opaque ancestor. These methods, parallel to those mentioned
above, are displayRectIgnoringOpacity:, displayIfNeededIgnoringOpacity, and
displayIfNeededInRectIgnoringOpacity:.
Locking Focus
Before a display... method invokes drawRect:, it sets the Window Server up
with information about the view, including the window device it draws in,
the coordinate system and clipping path it uses, and other graphics state
information. The method used to do this is lockFocus, and it has a companion
method that undoes its effects, called unlockFocus.
All drawing code invoked by an NSView must be bracketed by invocations of
these methods to produce proper results. If you define some methods that
need to draw in a view without going through the display methods above, for
example, you must send lockFocus to the view that you're drawing in before
sending commands to the Window Server, and unlockFocus as soon as you are
done.
It's perfectly reasonable to lock the focus on one view when another already
has it. In fact, this is exactly what happens when subviews are drawn in
their superview. The focusing machinery keeps a stack of which views have
been focused, so that when one view is sent an unlockFocus message, the
focus is restored to the view that was focused immediately before.
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.