Break cycle with throbber so that we no longer crash when animating the

throbber and closing a window, or continue loading the page after the
window has gone away. (bug 153421)
This commit is contained in:
pinkerton%netscape.com 2002-06-24 19:33:45 +00:00
parent 4692c8d212
commit 5c5a4caa89
8 changed files with 708 additions and 444 deletions

View File

@ -43,6 +43,38 @@
class nsIDOMEvent;
class nsIDOMNode;
//
// ThrobberHandler
//
// A helper class that handles animating the throbber when it's alive. It starts
// automatically when you init it. To get it to stop, call |stopThrobber|. Calling
// |release| is not enough because the timer used to animate the images holds a strong
// ref back to the handler so it won't go away unless you break that cycle manually with
// |stopThrobber|.
//
// This class must be separate from BrowserWindowController else the
// same thing will happen there and the timer will cause it to stay alive and continue
// loading the webpage even though the window has gone away.
//
@interface ThrobberHandler : NSObject
{
NSTimer* mTimer;
NSArray* mImages;
int mFrame;
}
// public
- (id)initWithToolbarItem:(NSToolbarItem*)inButton images:(NSArray*)inImages;
- (void)stopThrobber;
// internal
- (void)startThrobber;
- (void)pulseThrobber:(id)aSender;
@end
@interface BrowserWindowController : NSWindowController<CHFind>
{
IBOutlet id mTabBrowser;
@ -105,9 +137,8 @@ class nsIDOMNode;
id mCachedBMDS;
// Throbber state variables.
NSTimer* mThrobberTimer;
ThrobberHandler* mThrobberHandler;
NSArray* mThrobberImages;
int mThrobberFrame;
}
- (void)dealloc;

View File

@ -127,6 +127,8 @@ static NSString *SearchToolbarItemIdentifier = @"Search Toolbar Item";
mContextMenuFlags = 0;
mContextMenuEvent = nsnull;
mContextMenuNode = nsnull;
mThrobberImages = nil;
mThrobberHandler = nil;
}
return self;
}
@ -165,11 +167,7 @@ static NSString *SearchToolbarItemIdentifier = @"Search Toolbar Item";
[mProgress release];
if (mThrobberTimer) {
[mThrobberTimer invalidate];
[mThrobberTimer release];
}
[self stopThrobber];
[mThrobberImages release];
[super dealloc];
@ -636,14 +634,20 @@ static NSString *SearchToolbarItemIdentifier = @"Search Toolbar Item";
[[mBrowserView getBrowserView] loadURI:[NSURL URLWithString: @"http://dmoz.org/"] flags:NSLoadFlagsNone];
}
static Boolean movieControllerFilter(MovieController mc, short action, void *params, long refCon)
- (NSToolbarItem*)throbberItem
{
if (action == mcActionMovieClick || action == mcActionMouseDown) {
EventRecord* event = (EventRecord*) params;
event->what = nullEvent;
return true;
// find our throbber toolbar item.
NSToolbar* toolbar = [[self window] toolbar];
NSArray* items = [toolbar visibleItems];
unsigned count = [items count];
for (unsigned i = 0; i < count; ++i) {
NSToolbarItem* item = [items objectAtIndex: i];
if ([item tag] == 'Thrb') {
return item;
}
}
return false;
return nil;
}
- (NSArray*)throbberImages
@ -666,119 +670,37 @@ static Boolean movieControllerFilter(MovieController mc, short action, void *par
return mThrobberImages;
}
- (NSToolbarItem*)throbberItem
{
// find our throbber toolbar item.
NSToolbar* toolbar = [[self window] toolbar];
NSArray* items = [toolbar visibleItems];
unsigned count = [items count];
for (unsigned i = 0; i < count; ++i) {
NSToolbarItem* item = [items objectAtIndex: i];
if ([item tag] == 'Thrb') {
return item;
}
}
return nil;
}
// XXX this is just temporary for testing the throbber.
- (void)testThrobber:(id)aSender
{
if (mThrobberTimer == nil)
[self startThrobber];
else
[self stopThrobber];
if (!mThrobberHandler)
[self startThrobber];
else
[self stopThrobber];
}
// Called by an NSTimer.
- (void)pulseThrobber:(id)aSender
{
// advance to next frame.
NSArray* throbberImages = [self throbberImages];
if (++mThrobberFrame >= [throbberImages count])
mThrobberFrame = 0;
NSToolbarItem* toolbarItem = (NSToolbarItem*) [aSender userInfo];
[toolbarItem setImage: [throbberImages objectAtIndex: mThrobberFrame]];
}
#define QUICKTIME_THROBBER 0
- (void)startThrobber
{
#if QUICKTIME_THROBBER
// Use Quicktime to draw the frames from a single Animated GIF. This works fine for the animation, but
// when the frames stop, the poster frame disappears.
NSToolbarItem* throbberItem = [self throbberItem];
if (throbberItem != nil && [throbberItem view] == nil) {
NSSize minSize = [throbberItem minSize];
NSLog(@"Origin minSize = %f X %f", minSize.width, minSize.height);
NSSize maxSize = [throbberItem maxSize];
NSLog(@"Origin maxSize = %f X %f", maxSize.width, maxSize.height);
NSURL* throbberURL = [NSURL fileURLWithPath: [[NSBundle mainBundle] pathForResource:@"throbber" ofType:@"gif"]];
NSLog(@"throbberURL = %@", throbberURL);
NSMovie* throbberMovie = [[[NSMovie alloc] initWithURL: throbberURL byReference: YES] autorelease];
NSLog(@"throbberMovie = %@", throbberMovie);
if ([throbberMovie QTMovie] != nil) {
NSMovieView* throbberView = [[[NSMovieView alloc] init] autorelease];
[throbberView setMovie: throbberMovie];
[throbberView showController: NO adjustingSize: NO];
[throbberView setLoopMode: NSQTMovieLoopingPlayback];
[throbberItem setView: throbberView];
NSSize size = NSMakeSize(32, 32);
[throbberItem setMinSize: size];
[throbberItem setMaxSize: size];
[throbberView gotoPosterFrame: self];
[throbberView start: self];
// experiment, veto mouse clicks in the movie controller by using an action filter.
MCSetActionFilterWithRefCon((MovieController) [throbberView movieController],
NewMCActionFilterWithRefConUPP(movieControllerFilter),
0);
}
}
#else
// optimization: only throb if the throbber toolbar item is visible.
if (mThrobberTimer == nil) {
NSToolbarItem* throbberItem = [self throbberItem];
if (throbberItem != nil) {
mThrobberTimer = [[NSTimer scheduledTimerWithTimeInterval: 0.2
target: self selector: @selector(pulseThrobber:)
userInfo: throbberItem repeats: YES] retain];
}
}
#endif
// optimization: only throb if the throbber toolbar item is visible.
NSToolbarItem* throbberItem = [self throbberItem];
if (throbberItem) {
[self stopThrobber];
mThrobberHandler = [[ThrobberHandler alloc] initWithToolbarItem:throbberItem
images:[self throbberImages]];
}
}
- (void)stopThrobber
{
#if QUICKTIME_THROBBER
// Stop the quicktime animation.
NSToolbarItem* throbberItem = [self throbberItem];
if (throbberItem != nil) {
NSMovieView* throbberView = [throbberItem view];
if ([throbberView isPlaying]) {
[throbberView stop: self];
[throbberView gotoPosterFrame: self];
} else {
[throbberView start: self];
}
}
#else
if (mThrobberTimer != nil) {
[mThrobberTimer invalidate];
[mThrobberTimer release];
mThrobberTimer = nil;
mThrobberFrame = 0;
[[self throbberItem] setImage: [[self throbberImages] objectAtIndex: 0]];
}
#endif
[mThrobberHandler stopThrobber];
[mThrobberHandler release];
mThrobberHandler = nil;
[[self throbberItem] setImage: [[self throbberImages] objectAtIndex: 0]];
}
- (BOOL)findInPage:(NSString*)text
{
return [[mBrowserView getBrowserView] findInPage:text];
@ -1335,3 +1257,116 @@ static Boolean movieControllerFilter(MovieController mc, short action, void *par
@end
@implementation ThrobberHandler
-(id)initWithToolbarItem:(NSToolbarItem*)inButton images:(NSArray*)inImages
{
if ( (self = [super init]) ) {
mImages = [inImages retain];
mTimer = [[NSTimer scheduledTimerWithTimeInterval: 0.2
target: self selector: @selector(pulseThrobber:)
userInfo: inButton repeats: YES] retain];
mFrame = 0;
[self startThrobber];
}
return self;
}
-(void)dealloc
{
[self stopThrobber];
[mImages release];
}
// Called by an NSTimer.
- (void)pulseThrobber:(id)aSender
{
// advance to next frame.
if (++mFrame >= [mImages count])
mFrame = 0;
NSToolbarItem* toolbarItem = (NSToolbarItem*) [aSender userInfo];
[toolbarItem setImage: [mImages objectAtIndex: mFrame]];
}
static Boolean movieControllerFilter(MovieController mc, short action, void *params, long refCon)
{
if (action == mcActionMovieClick || action == mcActionMouseDown) {
EventRecord* event = (EventRecord*) params;
event->what = nullEvent;
return true;
}
return false;
}
#define QUICKTIME_THROBBER 0
- (void)startThrobber
{
#if QUICKTIME_THROBBER
// Use Quicktime to draw the frames from a single Animated GIF. This works fine for the animation, but
// when the frames stop, the poster frame disappears.
NSToolbarItem* throbberItem = [self throbberItem];
if (throbberItem != nil && [throbberItem view] == nil) {
NSSize minSize = [throbberItem minSize];
NSLog(@"Origin minSize = %f X %f", minSize.width, minSize.height);
NSSize maxSize = [throbberItem maxSize];
NSLog(@"Origin maxSize = %f X %f", maxSize.width, maxSize.height);
NSURL* throbberURL = [NSURL fileURLWithPath: [[NSBundle mainBundle] pathForResource:@"throbber" ofType:@"gif"]];
NSLog(@"throbberURL = %@", throbberURL);
NSMovie* throbberMovie = [[[NSMovie alloc] initWithURL: throbberURL byReference: YES] autorelease];
NSLog(@"throbberMovie = %@", throbberMovie);
if ([throbberMovie QTMovie] != nil) {
NSMovieView* throbberView = [[[NSMovieView alloc] init] autorelease];
[throbberView setMovie: throbberMovie];
[throbberView showController: NO adjustingSize: NO];
[throbberView setLoopMode: NSQTMovieLoopingPlayback];
[throbberItem setView: throbberView];
NSSize size = NSMakeSize(32, 32);
[throbberItem setMinSize: size];
[throbberItem setMaxSize: size];
[throbberView gotoPosterFrame: self];
[throbberView start: self];
// experiment, veto mouse clicks in the movie controller by using an action filter.
MCSetActionFilterWithRefCon((MovieController) [throbberView movieController],
NewMCActionFilterWithRefConUPP(movieControllerFilter),
0);
}
}
#else
#endif
}
- (void)stopThrobber
{
#if QUICKTIME_THROBBER
// Stop the quicktime animation.
NSToolbarItem* throbberItem = [self throbberItem];
if (throbberItem != nil) {
NSMovieView* throbberView = [throbberItem view];
if ([throbberView isPlaying]) {
[throbberView stop: self];
[throbberView gotoPosterFrame: self];
} else {
[throbberView start: self];
}
}
#else
if (mTimer) {
[mTimer invalidate];
[mTimer release];
mTimer = nil;
mFrame = 0;
}
#endif
}
@end

View File

@ -43,6 +43,38 @@
class nsIDOMEvent;
class nsIDOMNode;
//
// ThrobberHandler
//
// A helper class that handles animating the throbber when it's alive. It starts
// automatically when you init it. To get it to stop, call |stopThrobber|. Calling
// |release| is not enough because the timer used to animate the images holds a strong
// ref back to the handler so it won't go away unless you break that cycle manually with
// |stopThrobber|.
//
// This class must be separate from BrowserWindowController else the
// same thing will happen there and the timer will cause it to stay alive and continue
// loading the webpage even though the window has gone away.
//
@interface ThrobberHandler : NSObject
{
NSTimer* mTimer;
NSArray* mImages;
int mFrame;
}
// public
- (id)initWithToolbarItem:(NSToolbarItem*)inButton images:(NSArray*)inImages;
- (void)stopThrobber;
// internal
- (void)startThrobber;
- (void)pulseThrobber:(id)aSender;
@end
@interface BrowserWindowController : NSWindowController<CHFind>
{
IBOutlet id mTabBrowser;
@ -105,9 +137,8 @@ class nsIDOMNode;
id mCachedBMDS;
// Throbber state variables.
NSTimer* mThrobberTimer;
ThrobberHandler* mThrobberHandler;
NSArray* mThrobberImages;
int mThrobberFrame;
}
- (void)dealloc;

View File

@ -127,6 +127,8 @@ static NSString *SearchToolbarItemIdentifier = @"Search Toolbar Item";
mContextMenuFlags = 0;
mContextMenuEvent = nsnull;
mContextMenuNode = nsnull;
mThrobberImages = nil;
mThrobberHandler = nil;
}
return self;
}
@ -165,11 +167,7 @@ static NSString *SearchToolbarItemIdentifier = @"Search Toolbar Item";
[mProgress release];
if (mThrobberTimer) {
[mThrobberTimer invalidate];
[mThrobberTimer release];
}
[self stopThrobber];
[mThrobberImages release];
[super dealloc];
@ -636,14 +634,20 @@ static NSString *SearchToolbarItemIdentifier = @"Search Toolbar Item";
[[mBrowserView getBrowserView] loadURI:[NSURL URLWithString: @"http://dmoz.org/"] flags:NSLoadFlagsNone];
}
static Boolean movieControllerFilter(MovieController mc, short action, void *params, long refCon)
- (NSToolbarItem*)throbberItem
{
if (action == mcActionMovieClick || action == mcActionMouseDown) {
EventRecord* event = (EventRecord*) params;
event->what = nullEvent;
return true;
// find our throbber toolbar item.
NSToolbar* toolbar = [[self window] toolbar];
NSArray* items = [toolbar visibleItems];
unsigned count = [items count];
for (unsigned i = 0; i < count; ++i) {
NSToolbarItem* item = [items objectAtIndex: i];
if ([item tag] == 'Thrb') {
return item;
}
}
return false;
return nil;
}
- (NSArray*)throbberImages
@ -666,119 +670,37 @@ static Boolean movieControllerFilter(MovieController mc, short action, void *par
return mThrobberImages;
}
- (NSToolbarItem*)throbberItem
{
// find our throbber toolbar item.
NSToolbar* toolbar = [[self window] toolbar];
NSArray* items = [toolbar visibleItems];
unsigned count = [items count];
for (unsigned i = 0; i < count; ++i) {
NSToolbarItem* item = [items objectAtIndex: i];
if ([item tag] == 'Thrb') {
return item;
}
}
return nil;
}
// XXX this is just temporary for testing the throbber.
- (void)testThrobber:(id)aSender
{
if (mThrobberTimer == nil)
[self startThrobber];
else
[self stopThrobber];
if (!mThrobberHandler)
[self startThrobber];
else
[self stopThrobber];
}
// Called by an NSTimer.
- (void)pulseThrobber:(id)aSender
{
// advance to next frame.
NSArray* throbberImages = [self throbberImages];
if (++mThrobberFrame >= [throbberImages count])
mThrobberFrame = 0;
NSToolbarItem* toolbarItem = (NSToolbarItem*) [aSender userInfo];
[toolbarItem setImage: [throbberImages objectAtIndex: mThrobberFrame]];
}
#define QUICKTIME_THROBBER 0
- (void)startThrobber
{
#if QUICKTIME_THROBBER
// Use Quicktime to draw the frames from a single Animated GIF. This works fine for the animation, but
// when the frames stop, the poster frame disappears.
NSToolbarItem* throbberItem = [self throbberItem];
if (throbberItem != nil && [throbberItem view] == nil) {
NSSize minSize = [throbberItem minSize];
NSLog(@"Origin minSize = %f X %f", minSize.width, minSize.height);
NSSize maxSize = [throbberItem maxSize];
NSLog(@"Origin maxSize = %f X %f", maxSize.width, maxSize.height);
NSURL* throbberURL = [NSURL fileURLWithPath: [[NSBundle mainBundle] pathForResource:@"throbber" ofType:@"gif"]];
NSLog(@"throbberURL = %@", throbberURL);
NSMovie* throbberMovie = [[[NSMovie alloc] initWithURL: throbberURL byReference: YES] autorelease];
NSLog(@"throbberMovie = %@", throbberMovie);
if ([throbberMovie QTMovie] != nil) {
NSMovieView* throbberView = [[[NSMovieView alloc] init] autorelease];
[throbberView setMovie: throbberMovie];
[throbberView showController: NO adjustingSize: NO];
[throbberView setLoopMode: NSQTMovieLoopingPlayback];
[throbberItem setView: throbberView];
NSSize size = NSMakeSize(32, 32);
[throbberItem setMinSize: size];
[throbberItem setMaxSize: size];
[throbberView gotoPosterFrame: self];
[throbberView start: self];
// experiment, veto mouse clicks in the movie controller by using an action filter.
MCSetActionFilterWithRefCon((MovieController) [throbberView movieController],
NewMCActionFilterWithRefConUPP(movieControllerFilter),
0);
}
}
#else
// optimization: only throb if the throbber toolbar item is visible.
if (mThrobberTimer == nil) {
NSToolbarItem* throbberItem = [self throbberItem];
if (throbberItem != nil) {
mThrobberTimer = [[NSTimer scheduledTimerWithTimeInterval: 0.2
target: self selector: @selector(pulseThrobber:)
userInfo: throbberItem repeats: YES] retain];
}
}
#endif
// optimization: only throb if the throbber toolbar item is visible.
NSToolbarItem* throbberItem = [self throbberItem];
if (throbberItem) {
[self stopThrobber];
mThrobberHandler = [[ThrobberHandler alloc] initWithToolbarItem:throbberItem
images:[self throbberImages]];
}
}
- (void)stopThrobber
{
#if QUICKTIME_THROBBER
// Stop the quicktime animation.
NSToolbarItem* throbberItem = [self throbberItem];
if (throbberItem != nil) {
NSMovieView* throbberView = [throbberItem view];
if ([throbberView isPlaying]) {
[throbberView stop: self];
[throbberView gotoPosterFrame: self];
} else {
[throbberView start: self];
}
}
#else
if (mThrobberTimer != nil) {
[mThrobberTimer invalidate];
[mThrobberTimer release];
mThrobberTimer = nil;
mThrobberFrame = 0;
[[self throbberItem] setImage: [[self throbberImages] objectAtIndex: 0]];
}
#endif
[mThrobberHandler stopThrobber];
[mThrobberHandler release];
mThrobberHandler = nil;
[[self throbberItem] setImage: [[self throbberImages] objectAtIndex: 0]];
}
- (BOOL)findInPage:(NSString*)text
{
return [[mBrowserView getBrowserView] findInPage:text];
@ -1335,3 +1257,116 @@ static Boolean movieControllerFilter(MovieController mc, short action, void *par
@end
@implementation ThrobberHandler
-(id)initWithToolbarItem:(NSToolbarItem*)inButton images:(NSArray*)inImages
{
if ( (self = [super init]) ) {
mImages = [inImages retain];
mTimer = [[NSTimer scheduledTimerWithTimeInterval: 0.2
target: self selector: @selector(pulseThrobber:)
userInfo: inButton repeats: YES] retain];
mFrame = 0;
[self startThrobber];
}
return self;
}
-(void)dealloc
{
[self stopThrobber];
[mImages release];
}
// Called by an NSTimer.
- (void)pulseThrobber:(id)aSender
{
// advance to next frame.
if (++mFrame >= [mImages count])
mFrame = 0;
NSToolbarItem* toolbarItem = (NSToolbarItem*) [aSender userInfo];
[toolbarItem setImage: [mImages objectAtIndex: mFrame]];
}
static Boolean movieControllerFilter(MovieController mc, short action, void *params, long refCon)
{
if (action == mcActionMovieClick || action == mcActionMouseDown) {
EventRecord* event = (EventRecord*) params;
event->what = nullEvent;
return true;
}
return false;
}
#define QUICKTIME_THROBBER 0
- (void)startThrobber
{
#if QUICKTIME_THROBBER
// Use Quicktime to draw the frames from a single Animated GIF. This works fine for the animation, but
// when the frames stop, the poster frame disappears.
NSToolbarItem* throbberItem = [self throbberItem];
if (throbberItem != nil && [throbberItem view] == nil) {
NSSize minSize = [throbberItem minSize];
NSLog(@"Origin minSize = %f X %f", minSize.width, minSize.height);
NSSize maxSize = [throbberItem maxSize];
NSLog(@"Origin maxSize = %f X %f", maxSize.width, maxSize.height);
NSURL* throbberURL = [NSURL fileURLWithPath: [[NSBundle mainBundle] pathForResource:@"throbber" ofType:@"gif"]];
NSLog(@"throbberURL = %@", throbberURL);
NSMovie* throbberMovie = [[[NSMovie alloc] initWithURL: throbberURL byReference: YES] autorelease];
NSLog(@"throbberMovie = %@", throbberMovie);
if ([throbberMovie QTMovie] != nil) {
NSMovieView* throbberView = [[[NSMovieView alloc] init] autorelease];
[throbberView setMovie: throbberMovie];
[throbberView showController: NO adjustingSize: NO];
[throbberView setLoopMode: NSQTMovieLoopingPlayback];
[throbberItem setView: throbberView];
NSSize size = NSMakeSize(32, 32);
[throbberItem setMinSize: size];
[throbberItem setMaxSize: size];
[throbberView gotoPosterFrame: self];
[throbberView start: self];
// experiment, veto mouse clicks in the movie controller by using an action filter.
MCSetActionFilterWithRefCon((MovieController) [throbberView movieController],
NewMCActionFilterWithRefConUPP(movieControllerFilter),
0);
}
}
#else
#endif
}
- (void)stopThrobber
{
#if QUICKTIME_THROBBER
// Stop the quicktime animation.
NSToolbarItem* throbberItem = [self throbberItem];
if (throbberItem != nil) {
NSMovieView* throbberView = [throbberItem view];
if ([throbberView isPlaying]) {
[throbberView stop: self];
[throbberView gotoPosterFrame: self];
} else {
[throbberView start: self];
}
}
#else
if (mTimer) {
[mTimer invalidate];
[mTimer release];
mTimer = nil;
mFrame = 0;
}
#endif
}
@end

View File

@ -43,6 +43,38 @@
class nsIDOMEvent;
class nsIDOMNode;
//
// ThrobberHandler
//
// A helper class that handles animating the throbber when it's alive. It starts
// automatically when you init it. To get it to stop, call |stopThrobber|. Calling
// |release| is not enough because the timer used to animate the images holds a strong
// ref back to the handler so it won't go away unless you break that cycle manually with
// |stopThrobber|.
//
// This class must be separate from BrowserWindowController else the
// same thing will happen there and the timer will cause it to stay alive and continue
// loading the webpage even though the window has gone away.
//
@interface ThrobberHandler : NSObject
{
NSTimer* mTimer;
NSArray* mImages;
int mFrame;
}
// public
- (id)initWithToolbarItem:(NSToolbarItem*)inButton images:(NSArray*)inImages;
- (void)stopThrobber;
// internal
- (void)startThrobber;
- (void)pulseThrobber:(id)aSender;
@end
@interface BrowserWindowController : NSWindowController<CHFind>
{
IBOutlet id mTabBrowser;
@ -105,9 +137,8 @@ class nsIDOMNode;
id mCachedBMDS;
// Throbber state variables.
NSTimer* mThrobberTimer;
ThrobberHandler* mThrobberHandler;
NSArray* mThrobberImages;
int mThrobberFrame;
}
- (void)dealloc;

View File

@ -127,6 +127,8 @@ static NSString *SearchToolbarItemIdentifier = @"Search Toolbar Item";
mContextMenuFlags = 0;
mContextMenuEvent = nsnull;
mContextMenuNode = nsnull;
mThrobberImages = nil;
mThrobberHandler = nil;
}
return self;
}
@ -165,11 +167,7 @@ static NSString *SearchToolbarItemIdentifier = @"Search Toolbar Item";
[mProgress release];
if (mThrobberTimer) {
[mThrobberTimer invalidate];
[mThrobberTimer release];
}
[self stopThrobber];
[mThrobberImages release];
[super dealloc];
@ -636,14 +634,20 @@ static NSString *SearchToolbarItemIdentifier = @"Search Toolbar Item";
[[mBrowserView getBrowserView] loadURI:[NSURL URLWithString: @"http://dmoz.org/"] flags:NSLoadFlagsNone];
}
static Boolean movieControllerFilter(MovieController mc, short action, void *params, long refCon)
- (NSToolbarItem*)throbberItem
{
if (action == mcActionMovieClick || action == mcActionMouseDown) {
EventRecord* event = (EventRecord*) params;
event->what = nullEvent;
return true;
// find our throbber toolbar item.
NSToolbar* toolbar = [[self window] toolbar];
NSArray* items = [toolbar visibleItems];
unsigned count = [items count];
for (unsigned i = 0; i < count; ++i) {
NSToolbarItem* item = [items objectAtIndex: i];
if ([item tag] == 'Thrb') {
return item;
}
}
return false;
return nil;
}
- (NSArray*)throbberImages
@ -666,119 +670,37 @@ static Boolean movieControllerFilter(MovieController mc, short action, void *par
return mThrobberImages;
}
- (NSToolbarItem*)throbberItem
{
// find our throbber toolbar item.
NSToolbar* toolbar = [[self window] toolbar];
NSArray* items = [toolbar visibleItems];
unsigned count = [items count];
for (unsigned i = 0; i < count; ++i) {
NSToolbarItem* item = [items objectAtIndex: i];
if ([item tag] == 'Thrb') {
return item;
}
}
return nil;
}
// XXX this is just temporary for testing the throbber.
- (void)testThrobber:(id)aSender
{
if (mThrobberTimer == nil)
[self startThrobber];
else
[self stopThrobber];
if (!mThrobberHandler)
[self startThrobber];
else
[self stopThrobber];
}
// Called by an NSTimer.
- (void)pulseThrobber:(id)aSender
{
// advance to next frame.
NSArray* throbberImages = [self throbberImages];
if (++mThrobberFrame >= [throbberImages count])
mThrobberFrame = 0;
NSToolbarItem* toolbarItem = (NSToolbarItem*) [aSender userInfo];
[toolbarItem setImage: [throbberImages objectAtIndex: mThrobberFrame]];
}
#define QUICKTIME_THROBBER 0
- (void)startThrobber
{
#if QUICKTIME_THROBBER
// Use Quicktime to draw the frames from a single Animated GIF. This works fine for the animation, but
// when the frames stop, the poster frame disappears.
NSToolbarItem* throbberItem = [self throbberItem];
if (throbberItem != nil && [throbberItem view] == nil) {
NSSize minSize = [throbberItem minSize];
NSLog(@"Origin minSize = %f X %f", minSize.width, minSize.height);
NSSize maxSize = [throbberItem maxSize];
NSLog(@"Origin maxSize = %f X %f", maxSize.width, maxSize.height);
NSURL* throbberURL = [NSURL fileURLWithPath: [[NSBundle mainBundle] pathForResource:@"throbber" ofType:@"gif"]];
NSLog(@"throbberURL = %@", throbberURL);
NSMovie* throbberMovie = [[[NSMovie alloc] initWithURL: throbberURL byReference: YES] autorelease];
NSLog(@"throbberMovie = %@", throbberMovie);
if ([throbberMovie QTMovie] != nil) {
NSMovieView* throbberView = [[[NSMovieView alloc] init] autorelease];
[throbberView setMovie: throbberMovie];
[throbberView showController: NO adjustingSize: NO];
[throbberView setLoopMode: NSQTMovieLoopingPlayback];
[throbberItem setView: throbberView];
NSSize size = NSMakeSize(32, 32);
[throbberItem setMinSize: size];
[throbberItem setMaxSize: size];
[throbberView gotoPosterFrame: self];
[throbberView start: self];
// experiment, veto mouse clicks in the movie controller by using an action filter.
MCSetActionFilterWithRefCon((MovieController) [throbberView movieController],
NewMCActionFilterWithRefConUPP(movieControllerFilter),
0);
}
}
#else
// optimization: only throb if the throbber toolbar item is visible.
if (mThrobberTimer == nil) {
NSToolbarItem* throbberItem = [self throbberItem];
if (throbberItem != nil) {
mThrobberTimer = [[NSTimer scheduledTimerWithTimeInterval: 0.2
target: self selector: @selector(pulseThrobber:)
userInfo: throbberItem repeats: YES] retain];
}
}
#endif
// optimization: only throb if the throbber toolbar item is visible.
NSToolbarItem* throbberItem = [self throbberItem];
if (throbberItem) {
[self stopThrobber];
mThrobberHandler = [[ThrobberHandler alloc] initWithToolbarItem:throbberItem
images:[self throbberImages]];
}
}
- (void)stopThrobber
{
#if QUICKTIME_THROBBER
// Stop the quicktime animation.
NSToolbarItem* throbberItem = [self throbberItem];
if (throbberItem != nil) {
NSMovieView* throbberView = [throbberItem view];
if ([throbberView isPlaying]) {
[throbberView stop: self];
[throbberView gotoPosterFrame: self];
} else {
[throbberView start: self];
}
}
#else
if (mThrobberTimer != nil) {
[mThrobberTimer invalidate];
[mThrobberTimer release];
mThrobberTimer = nil;
mThrobberFrame = 0;
[[self throbberItem] setImage: [[self throbberImages] objectAtIndex: 0]];
}
#endif
[mThrobberHandler stopThrobber];
[mThrobberHandler release];
mThrobberHandler = nil;
[[self throbberItem] setImage: [[self throbberImages] objectAtIndex: 0]];
}
- (BOOL)findInPage:(NSString*)text
{
return [[mBrowserView getBrowserView] findInPage:text];
@ -1335,3 +1257,116 @@ static Boolean movieControllerFilter(MovieController mc, short action, void *par
@end
@implementation ThrobberHandler
-(id)initWithToolbarItem:(NSToolbarItem*)inButton images:(NSArray*)inImages
{
if ( (self = [super init]) ) {
mImages = [inImages retain];
mTimer = [[NSTimer scheduledTimerWithTimeInterval: 0.2
target: self selector: @selector(pulseThrobber:)
userInfo: inButton repeats: YES] retain];
mFrame = 0;
[self startThrobber];
}
return self;
}
-(void)dealloc
{
[self stopThrobber];
[mImages release];
}
// Called by an NSTimer.
- (void)pulseThrobber:(id)aSender
{
// advance to next frame.
if (++mFrame >= [mImages count])
mFrame = 0;
NSToolbarItem* toolbarItem = (NSToolbarItem*) [aSender userInfo];
[toolbarItem setImage: [mImages objectAtIndex: mFrame]];
}
static Boolean movieControllerFilter(MovieController mc, short action, void *params, long refCon)
{
if (action == mcActionMovieClick || action == mcActionMouseDown) {
EventRecord* event = (EventRecord*) params;
event->what = nullEvent;
return true;
}
return false;
}
#define QUICKTIME_THROBBER 0
- (void)startThrobber
{
#if QUICKTIME_THROBBER
// Use Quicktime to draw the frames from a single Animated GIF. This works fine for the animation, but
// when the frames stop, the poster frame disappears.
NSToolbarItem* throbberItem = [self throbberItem];
if (throbberItem != nil && [throbberItem view] == nil) {
NSSize minSize = [throbberItem minSize];
NSLog(@"Origin minSize = %f X %f", minSize.width, minSize.height);
NSSize maxSize = [throbberItem maxSize];
NSLog(@"Origin maxSize = %f X %f", maxSize.width, maxSize.height);
NSURL* throbberURL = [NSURL fileURLWithPath: [[NSBundle mainBundle] pathForResource:@"throbber" ofType:@"gif"]];
NSLog(@"throbberURL = %@", throbberURL);
NSMovie* throbberMovie = [[[NSMovie alloc] initWithURL: throbberURL byReference: YES] autorelease];
NSLog(@"throbberMovie = %@", throbberMovie);
if ([throbberMovie QTMovie] != nil) {
NSMovieView* throbberView = [[[NSMovieView alloc] init] autorelease];
[throbberView setMovie: throbberMovie];
[throbberView showController: NO adjustingSize: NO];
[throbberView setLoopMode: NSQTMovieLoopingPlayback];
[throbberItem setView: throbberView];
NSSize size = NSMakeSize(32, 32);
[throbberItem setMinSize: size];
[throbberItem setMaxSize: size];
[throbberView gotoPosterFrame: self];
[throbberView start: self];
// experiment, veto mouse clicks in the movie controller by using an action filter.
MCSetActionFilterWithRefCon((MovieController) [throbberView movieController],
NewMCActionFilterWithRefConUPP(movieControllerFilter),
0);
}
}
#else
#endif
}
- (void)stopThrobber
{
#if QUICKTIME_THROBBER
// Stop the quicktime animation.
NSToolbarItem* throbberItem = [self throbberItem];
if (throbberItem != nil) {
NSMovieView* throbberView = [throbberItem view];
if ([throbberView isPlaying]) {
[throbberView stop: self];
[throbberView gotoPosterFrame: self];
} else {
[throbberView start: self];
}
}
#else
if (mTimer) {
[mTimer invalidate];
[mTimer release];
mTimer = nil;
mFrame = 0;
}
#endif
}
@end

View File

@ -43,6 +43,38 @@
class nsIDOMEvent;
class nsIDOMNode;
//
// ThrobberHandler
//
// A helper class that handles animating the throbber when it's alive. It starts
// automatically when you init it. To get it to stop, call |stopThrobber|. Calling
// |release| is not enough because the timer used to animate the images holds a strong
// ref back to the handler so it won't go away unless you break that cycle manually with
// |stopThrobber|.
//
// This class must be separate from BrowserWindowController else the
// same thing will happen there and the timer will cause it to stay alive and continue
// loading the webpage even though the window has gone away.
//
@interface ThrobberHandler : NSObject
{
NSTimer* mTimer;
NSArray* mImages;
int mFrame;
}
// public
- (id)initWithToolbarItem:(NSToolbarItem*)inButton images:(NSArray*)inImages;
- (void)stopThrobber;
// internal
- (void)startThrobber;
- (void)pulseThrobber:(id)aSender;
@end
@interface BrowserWindowController : NSWindowController<CHFind>
{
IBOutlet id mTabBrowser;
@ -105,9 +137,8 @@ class nsIDOMNode;
id mCachedBMDS;
// Throbber state variables.
NSTimer* mThrobberTimer;
ThrobberHandler* mThrobberHandler;
NSArray* mThrobberImages;
int mThrobberFrame;
}
- (void)dealloc;

View File

@ -127,6 +127,8 @@ static NSString *SearchToolbarItemIdentifier = @"Search Toolbar Item";
mContextMenuFlags = 0;
mContextMenuEvent = nsnull;
mContextMenuNode = nsnull;
mThrobberImages = nil;
mThrobberHandler = nil;
}
return self;
}
@ -165,11 +167,7 @@ static NSString *SearchToolbarItemIdentifier = @"Search Toolbar Item";
[mProgress release];
if (mThrobberTimer) {
[mThrobberTimer invalidate];
[mThrobberTimer release];
}
[self stopThrobber];
[mThrobberImages release];
[super dealloc];
@ -636,14 +634,20 @@ static NSString *SearchToolbarItemIdentifier = @"Search Toolbar Item";
[[mBrowserView getBrowserView] loadURI:[NSURL URLWithString: @"http://dmoz.org/"] flags:NSLoadFlagsNone];
}
static Boolean movieControllerFilter(MovieController mc, short action, void *params, long refCon)
- (NSToolbarItem*)throbberItem
{
if (action == mcActionMovieClick || action == mcActionMouseDown) {
EventRecord* event = (EventRecord*) params;
event->what = nullEvent;
return true;
// find our throbber toolbar item.
NSToolbar* toolbar = [[self window] toolbar];
NSArray* items = [toolbar visibleItems];
unsigned count = [items count];
for (unsigned i = 0; i < count; ++i) {
NSToolbarItem* item = [items objectAtIndex: i];
if ([item tag] == 'Thrb') {
return item;
}
}
return false;
return nil;
}
- (NSArray*)throbberImages
@ -666,119 +670,37 @@ static Boolean movieControllerFilter(MovieController mc, short action, void *par
return mThrobberImages;
}
- (NSToolbarItem*)throbberItem
{
// find our throbber toolbar item.
NSToolbar* toolbar = [[self window] toolbar];
NSArray* items = [toolbar visibleItems];
unsigned count = [items count];
for (unsigned i = 0; i < count; ++i) {
NSToolbarItem* item = [items objectAtIndex: i];
if ([item tag] == 'Thrb') {
return item;
}
}
return nil;
}
// XXX this is just temporary for testing the throbber.
- (void)testThrobber:(id)aSender
{
if (mThrobberTimer == nil)
[self startThrobber];
else
[self stopThrobber];
if (!mThrobberHandler)
[self startThrobber];
else
[self stopThrobber];
}
// Called by an NSTimer.
- (void)pulseThrobber:(id)aSender
{
// advance to next frame.
NSArray* throbberImages = [self throbberImages];
if (++mThrobberFrame >= [throbberImages count])
mThrobberFrame = 0;
NSToolbarItem* toolbarItem = (NSToolbarItem*) [aSender userInfo];
[toolbarItem setImage: [throbberImages objectAtIndex: mThrobberFrame]];
}
#define QUICKTIME_THROBBER 0
- (void)startThrobber
{
#if QUICKTIME_THROBBER
// Use Quicktime to draw the frames from a single Animated GIF. This works fine for the animation, but
// when the frames stop, the poster frame disappears.
NSToolbarItem* throbberItem = [self throbberItem];
if (throbberItem != nil && [throbberItem view] == nil) {
NSSize minSize = [throbberItem minSize];
NSLog(@"Origin minSize = %f X %f", minSize.width, minSize.height);
NSSize maxSize = [throbberItem maxSize];
NSLog(@"Origin maxSize = %f X %f", maxSize.width, maxSize.height);
NSURL* throbberURL = [NSURL fileURLWithPath: [[NSBundle mainBundle] pathForResource:@"throbber" ofType:@"gif"]];
NSLog(@"throbberURL = %@", throbberURL);
NSMovie* throbberMovie = [[[NSMovie alloc] initWithURL: throbberURL byReference: YES] autorelease];
NSLog(@"throbberMovie = %@", throbberMovie);
if ([throbberMovie QTMovie] != nil) {
NSMovieView* throbberView = [[[NSMovieView alloc] init] autorelease];
[throbberView setMovie: throbberMovie];
[throbberView showController: NO adjustingSize: NO];
[throbberView setLoopMode: NSQTMovieLoopingPlayback];
[throbberItem setView: throbberView];
NSSize size = NSMakeSize(32, 32);
[throbberItem setMinSize: size];
[throbberItem setMaxSize: size];
[throbberView gotoPosterFrame: self];
[throbberView start: self];
// experiment, veto mouse clicks in the movie controller by using an action filter.
MCSetActionFilterWithRefCon((MovieController) [throbberView movieController],
NewMCActionFilterWithRefConUPP(movieControllerFilter),
0);
}
}
#else
// optimization: only throb if the throbber toolbar item is visible.
if (mThrobberTimer == nil) {
NSToolbarItem* throbberItem = [self throbberItem];
if (throbberItem != nil) {
mThrobberTimer = [[NSTimer scheduledTimerWithTimeInterval: 0.2
target: self selector: @selector(pulseThrobber:)
userInfo: throbberItem repeats: YES] retain];
}
}
#endif
// optimization: only throb if the throbber toolbar item is visible.
NSToolbarItem* throbberItem = [self throbberItem];
if (throbberItem) {
[self stopThrobber];
mThrobberHandler = [[ThrobberHandler alloc] initWithToolbarItem:throbberItem
images:[self throbberImages]];
}
}
- (void)stopThrobber
{
#if QUICKTIME_THROBBER
// Stop the quicktime animation.
NSToolbarItem* throbberItem = [self throbberItem];
if (throbberItem != nil) {
NSMovieView* throbberView = [throbberItem view];
if ([throbberView isPlaying]) {
[throbberView stop: self];
[throbberView gotoPosterFrame: self];
} else {
[throbberView start: self];
}
}
#else
if (mThrobberTimer != nil) {
[mThrobberTimer invalidate];
[mThrobberTimer release];
mThrobberTimer = nil;
mThrobberFrame = 0;
[[self throbberItem] setImage: [[self throbberImages] objectAtIndex: 0]];
}
#endif
[mThrobberHandler stopThrobber];
[mThrobberHandler release];
mThrobberHandler = nil;
[[self throbberItem] setImage: [[self throbberImages] objectAtIndex: 0]];
}
- (BOOL)findInPage:(NSString*)text
{
return [[mBrowserView getBrowserView] findInPage:text];
@ -1335,3 +1257,116 @@ static Boolean movieControllerFilter(MovieController mc, short action, void *par
@end
@implementation ThrobberHandler
-(id)initWithToolbarItem:(NSToolbarItem*)inButton images:(NSArray*)inImages
{
if ( (self = [super init]) ) {
mImages = [inImages retain];
mTimer = [[NSTimer scheduledTimerWithTimeInterval: 0.2
target: self selector: @selector(pulseThrobber:)
userInfo: inButton repeats: YES] retain];
mFrame = 0;
[self startThrobber];
}
return self;
}
-(void)dealloc
{
[self stopThrobber];
[mImages release];
}
// Called by an NSTimer.
- (void)pulseThrobber:(id)aSender
{
// advance to next frame.
if (++mFrame >= [mImages count])
mFrame = 0;
NSToolbarItem* toolbarItem = (NSToolbarItem*) [aSender userInfo];
[toolbarItem setImage: [mImages objectAtIndex: mFrame]];
}
static Boolean movieControllerFilter(MovieController mc, short action, void *params, long refCon)
{
if (action == mcActionMovieClick || action == mcActionMouseDown) {
EventRecord* event = (EventRecord*) params;
event->what = nullEvent;
return true;
}
return false;
}
#define QUICKTIME_THROBBER 0
- (void)startThrobber
{
#if QUICKTIME_THROBBER
// Use Quicktime to draw the frames from a single Animated GIF. This works fine for the animation, but
// when the frames stop, the poster frame disappears.
NSToolbarItem* throbberItem = [self throbberItem];
if (throbberItem != nil && [throbberItem view] == nil) {
NSSize minSize = [throbberItem minSize];
NSLog(@"Origin minSize = %f X %f", minSize.width, minSize.height);
NSSize maxSize = [throbberItem maxSize];
NSLog(@"Origin maxSize = %f X %f", maxSize.width, maxSize.height);
NSURL* throbberURL = [NSURL fileURLWithPath: [[NSBundle mainBundle] pathForResource:@"throbber" ofType:@"gif"]];
NSLog(@"throbberURL = %@", throbberURL);
NSMovie* throbberMovie = [[[NSMovie alloc] initWithURL: throbberURL byReference: YES] autorelease];
NSLog(@"throbberMovie = %@", throbberMovie);
if ([throbberMovie QTMovie] != nil) {
NSMovieView* throbberView = [[[NSMovieView alloc] init] autorelease];
[throbberView setMovie: throbberMovie];
[throbberView showController: NO adjustingSize: NO];
[throbberView setLoopMode: NSQTMovieLoopingPlayback];
[throbberItem setView: throbberView];
NSSize size = NSMakeSize(32, 32);
[throbberItem setMinSize: size];
[throbberItem setMaxSize: size];
[throbberView gotoPosterFrame: self];
[throbberView start: self];
// experiment, veto mouse clicks in the movie controller by using an action filter.
MCSetActionFilterWithRefCon((MovieController) [throbberView movieController],
NewMCActionFilterWithRefConUPP(movieControllerFilter),
0);
}
}
#else
#endif
}
- (void)stopThrobber
{
#if QUICKTIME_THROBBER
// Stop the quicktime animation.
NSToolbarItem* throbberItem = [self throbberItem];
if (throbberItem != nil) {
NSMovieView* throbberView = [throbberItem view];
if ([throbberView isPlaying]) {
[throbberView stop: self];
[throbberView gotoPosterFrame: self];
} else {
[throbberView start: self];
}
}
#else
if (mTimer) {
[mTimer invalidate];
[mTimer release];
mTimer = nil;
mFrame = 0;
}
#endif
}
@end