remove 16-tab limit. add overflow menu (chevron). bug 261134

This commit is contained in:
pinkerton%aol.net 2004-10-03 21:33:08 +00:00
Родитель 58e0659db2
Коммит ee2dfe111b
12 изменённых файлов: 244 добавлений и 45 удалений

Просмотреть файл

@ -1692,6 +1692,7 @@
E010866D06BCA2E500BD5DE0, E010866D06BCA2E500BD5DE0,
E010866E06BCA2E500BD5DE0, E010866E06BCA2E500BD5DE0,
E010866F06BCA2E500BD5DE0, E010866F06BCA2E500BD5DE0,
3FF71AE00710A6800081B5D7,
); );
isa = PBXResourcesBuildPhase; isa = PBXResourcesBuildPhase;
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@ -5625,6 +5626,7 @@
E010867406BCA2E500BD5DE0, E010867406BCA2E500BD5DE0,
E010867506BCA2E500BD5DE0, E010867506BCA2E500BD5DE0,
E010867606BCA2E500BD5DE0, E010867606BCA2E500BD5DE0,
3FF71AE10710A6800081B5D7,
); );
isa = PBXResourcesBuildPhase; isa = PBXResourcesBuildPhase;
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@ -9216,6 +9218,26 @@
settings = { settings = {
}; };
}; };
3FF71ADF0710A67F0081B5D7 = {
isa = PBXFileReference;
lastKnownFileType = image.tiff;
name = tab_overflow.tif;
path = resources/images/chrome/tab_overflow.tif;
refType = 2;
sourceTree = SOURCE_ROOT;
};
3FF71AE00710A6800081B5D7 = {
fileRef = 3FF71ADF0710A67F0081B5D7;
isa = PBXBuildFile;
settings = {
};
};
3FF71AE10710A6800081B5D7 = {
fileRef = 3FF71ADF0710A67F0081B5D7;
isa = PBXBuildFile;
settings = {
};
};
//3F0 //3F0
//3F1 //3F1
//3F2 //3F2
@ -10002,6 +10024,7 @@
3FF08F1206E7D3C2001C9B19, 3FF08F1206E7D3C2001C9B19,
3FF08F1306E7D3C2001C9B19, 3FF08F1306E7D3C2001C9B19,
3FF08F1406E7D3C2001C9B19, 3FF08F1406E7D3C2001C9B19,
3FF71ADF0710A67F0081B5D7,
E091C0D006225EA3007D9E8F, E091C0D006225EA3007D9E8F,
F540BD1A029ED15301026D5D, F540BD1A029ED15301026D5D,
F540BD1C029ED17901026D5D, F540BD1C029ED17901026D5D,

Двоичные данные
camino/resources/images/chrome/tab_overflow.tif Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -47,19 +47,25 @@
IBOutlet BrowserTabView *mTabView; IBOutlet BrowserTabView *mTabView;
TabButtonCell *mActiveTabButton; // active tab button, mainly useful for handling drags (STRONG) TabButtonCell *mActiveTabButton; // active tab button, mainly useful for handling drags (STRONG)
NSButton *mOverflowButton; // button for overflow menu if we've got more tabs than space (STRONG)
NSMenu *mOverflowMenu; // menu for tab overflow (STRONG);
// drag tracking // drag tracking
NSPoint mLastClickPoint; NSPoint mLastClickPoint;
BOOL mDragStarted; BOOL mDragStarted;
NSView *mDragDest; NSView *mDragDest;
TabButtonCell *mDragDestButton; TabButtonCell *mDragDestButton;
BOOL mOverflowTabs;
NSMutableArray *mTrackingCells; // cells which currently have tracking rects in this view
} }
// destroy the tab bar and recreate it from the tabview // destroy the tab bar and recreate it from the tabview
-(void)rebuildTabBar; -(void)rebuildTabBar;
// return the height the tab bar should be // return the height the tab bar should be
-(float)tabBarHeight; -(float)tabBarHeight;
-(BrowserTabViewItem*)tabViewItemAtPoint:(NSPoint)location; -(BrowserTabViewItem*)tabViewItemAtPoint:(NSPoint)location;
- (void)windowClosed;
- (IBAction)overflowMenu:(id)sender;
@end @end

Просмотреть файл

@ -47,25 +47,34 @@
-(TabButtonCell*)buttonAtPoint:(NSPoint)clickPoint; -(TabButtonCell*)buttonAtPoint:(NSPoint)clickPoint;
-(void)registerTabButtonsForTracking; -(void)registerTabButtonsForTracking;
-(void)unregisterTabButtonsForTracking; -(void)unregisterTabButtonsForTracking;
-(void)initOverflowMenu;
-(NSRect)tabsRect;
@end @end
static NSImage *gBackgroundImage = nil; static NSImage *gBackgroundImage = nil;
static NSImage *gTabButtonDividerImage = nil; static NSImage *gTabButtonDividerImage = nil;
static NSImage *gTabOverflowImage = nil;
static const float kTabBarDefaultHeight = 22.0; static const float kTabBarDefaultHeight = 22.0;
@implementation BrowserTabBarView @implementation BrowserTabBarView
static const int kTabBarMargin = 5; // left/right margin for tab bar static const int kTabBarMargin = 5; // left/right margin for tab bar
static const float kMinTabWidth = 42.0; // tabs smaller than this are useless... tabs this small may be useless static const float kMinTabWidth = 100.0; // the smallest tabs that will be drawn
static const float kMaxTabWidth = 175.0; // the widest tabs that will be drawn static const float kMaxTabWidth = 175.0; // the widest tabs that will be drawn
static const int kTabDragThreshold = 3; // distance a drag must go before we start dnd static const int kTabDragThreshold = 3; // distance a drag must go before we start dnd
static const float kOverflowButtonWidth = 16;
static const float kOverflowButtonHeight = 16;
static const int kOverflowButtonMargin = 1;
-(id)initWithFrame:(NSRect)frame -(id)initWithFrame:(NSRect)frame
{ {
self = [super initWithFrame:frame]; self = [super initWithFrame:frame];
if (self) { if (self) {
mActiveTabButton = nil; mActiveTabButton = nil;
mOverflowButton = nil;
mOverflowTabs = NO;
// this will not likely have any result here // this will not likely have any result here
[self rebuildTabBar]; [self rebuildTabBar];
[self registerForDraggedTypes:[NSArray arrayWithObjects: @"MozURLType", @"MozBookmarkType", NSStringPboardType, [self registerForDraggedTypes:[NSArray arrayWithObjects: @"MozURLType", @"MozBookmarkType", NSStringPboardType,
@ -82,7 +91,10 @@ static const int kTabDragThreshold = 3; // distance a drag must go before we s
-(void)dealloc -(void)dealloc
{ {
[mTrackingCells release];
[mActiveTabButton release]; [mActiveTabButton release];
[mOverflowButton release];
[mOverflowMenu release];
[super dealloc]; [super dealloc];
} }
@ -93,7 +105,10 @@ static const int kTabDragThreshold = 3; // distance a drag must go before we s
[self loadImages]; [self loadImages];
// determine the frame of the active tab button and fill the rest of the bar in with the background // determine the frame of the active tab button and fill the rest of the bar in with the background
NSRect activeTabButtonFrame = [mActiveTabButton frame]; NSRect activeTabButtonFrame = [mActiveTabButton frame];
NSRect tabsRect = [self tabsRect];
// if any of the active tab would be outside the drawable area, fill it in
if (NSMaxX(activeTabButtonFrame) > NSMaxX(tabsRect)) activeTabButtonFrame.size.width = 0.0;
[self drawTabBarBackgroundInRect:rect withActiveTabRect:activeTabButtonFrame]; [self drawTabBarBackgroundInRect:rect withActiveTabRect:activeTabButtonFrame];
NSArray *tabItems = [mTabView tabViewItems]; NSArray *tabItems = [mTabView tabViewItems];
NSEnumerator *tabEnumerator = [tabItems objectEnumerator]; NSEnumerator *tabEnumerator = [tabItems objectEnumerator];
@ -104,7 +119,7 @@ static const int kTabDragThreshold = 3; // distance a drag must go before we s
BrowserTabViewItem *nextTab = [tabEnumerator nextObject]; BrowserTabViewItem *nextTab = [tabEnumerator nextObject];
NSRect tabButtonFrame = [tabButton frame]; NSRect tabButtonFrame = [tabButton frame];
if (NSIntersectsRect(tabButtonFrame,rect)) if (NSIntersectsRect(tabButtonFrame,rect) && NSMaxX(tabButtonFrame) <= NSMaxX(tabsRect))
[tabButton drawWithFrame:tabButtonFrame inView:self]; [tabButton drawWithFrame:tabButtonFrame inView:self];
// draw the first divider. // draw the first divider.
if ((prevButton == nil) && ([tab tabState] != NSSelectedTab)) if ((prevButton == nil) && ([tab tabState] != NSSelectedTab))
@ -119,7 +134,9 @@ static const int kTabDragThreshold = 3; // distance a drag must go before we s
{ {
[super setFrame:frameRect]; [super setFrame:frameRect];
// tab buttons probably need to be resized if the frame changes // tab buttons probably need to be resized if the frame changes
[self unregisterTabButtonsForTracking];
[self layoutButtons]; [self layoutButtons];
[self registerTabButtonsForTracking];
} }
-(NSMenu*)menuForEvent:(NSEvent*)theEvent -(NSMenu*)menuForEvent:(NSEvent*)theEvent
@ -134,7 +151,7 @@ static const int kTabDragThreshold = 3; // distance a drag must go before we s
{ {
NSPoint clickPoint = [self convertPoint:[theEvent locationInWindow] fromView:nil]; NSPoint clickPoint = [self convertPoint:[theEvent locationInWindow] fromView:nil];
TabButtonCell *clickedTabButton = [self buttonAtPoint:clickPoint]; TabButtonCell *clickedTabButton = [self buttonAtPoint:clickPoint];
mLastClickPoint = clickPoint; mLastClickPoint = clickPoint;
if (clickedTabButton && ![clickedTabButton willTrackMouse:theEvent inRect:[clickedTabButton frame] ofView:self]) if (clickedTabButton && ![clickedTabButton willTrackMouse:theEvent inRect:[clickedTabButton frame] ofView:self])
@ -220,6 +237,8 @@ static const int kTabDragThreshold = 3; // distance a drag must go before we s
gBackgroundImage = [[NSImage imageNamed:@"tab_bar_bg"] retain]; gBackgroundImage = [[NSImage imageNamed:@"tab_bar_bg"] retain];
if (!gTabButtonDividerImage) if (!gTabButtonDividerImage)
gTabButtonDividerImage = [[NSImage imageNamed:@"tab_button_divider"] retain]; gTabButtonDividerImage = [[NSImage imageNamed:@"tab_button_divider"] retain];
if (!gTabOverflowImage)
gTabOverflowImage = [[NSImage imageNamed:@"tab_overflow"] retain];
} }
// construct the tab bar based on the current state of mTabView; // construct the tab bar based on the current state of mTabView;
@ -233,11 +252,20 @@ static const int kTabDragThreshold = 3; // distance a drag must go before we s
[self registerTabButtonsForTracking]; [self registerTabButtonsForTracking];
} }
- (void)windowClosed
{
// remove all tracking rects because this view is implicitly retained when they're registered
[self unregisterTabButtonsForTracking];
}
// allows tab button cells to react to mouse events // allows tab button cells to react to mouse events
-(void)registerTabButtonsForTracking -(void)registerTabButtonsForTracking
{ {
if ([self window]) { if ([self window]) {
NSArray * tabItems = [mTabView tabViewItems]; NSArray * tabItems = [mTabView tabViewItems];
if(mTrackingCells) [self unregisterTabButtonsForTracking];
mTrackingCells = [NSMutableArray arrayWithCapacity:[tabItems count]];
[mTrackingCells retain];
NSEnumerator *tabEnumerator = [tabItems objectEnumerator]; NSEnumerator *tabEnumerator = [tabItems objectEnumerator];
NSPoint local = [[self window] convertScreenToBase:[NSEvent mouseLocation]]; NSPoint local = [[self window] convertScreenToBase:[NSEvent mouseLocation]];
@ -246,8 +274,13 @@ static const int kTabDragThreshold = 3; // distance a drag must go before we s
BrowserTabViewItem *tab = nil; BrowserTabViewItem *tab = nil;
while (tab = [tabEnumerator nextObject]) { while (tab = [tabEnumerator nextObject]) {
TabButtonCell * tabButton = [tab tabButtonCell]; TabButtonCell * tabButton = [tab tabButtonCell];
NSRect trackingRect = [tabButton frame]; if (tabButton) {
[tabButton addTrackingRectInView: self withFrame:trackingRect cursorLocation:local]; [mTrackingCells addObject:tabButton];
NSRect trackingRect = [tabButton frame];
// only track tabs that are onscreen
if (NSMaxX(trackingRect) <= NSMaxX([self tabsRect]))
[tabButton addTrackingRectInView: self withFrame:trackingRect cursorLocation:local];
}
} }
} }
} }
@ -255,11 +288,14 @@ static const int kTabDragThreshold = 3; // distance a drag must go before we s
// causes tab buttons to stop reacting to mouse events // causes tab buttons to stop reacting to mouse events
-(void)unregisterTabButtonsForTracking -(void)unregisterTabButtonsForTracking
{ {
NSArray * tabItems = [mTabView tabViewItems]; if (mTrackingCells) {
NSEnumerator *tabEnumerator = [tabItems objectEnumerator]; NSEnumerator *tabEnumerator = [mTrackingCells objectEnumerator];
BrowserTabViewItem *tab = nil; TabButtonCell *tab = nil;
while (tab = [tabEnumerator nextObject]) while (tab = (TabButtonCell *)[tabEnumerator nextObject])
[[tab tabButtonCell] removeTrackingRectFromView: self]; [tab removeTrackingRectFromView: self];
[mTrackingCells release];
mTrackingCells = nil;
}
} }
// returns the height the tab bar should be if drawn // returns the height the tab bar should be if drawn
@ -282,8 +318,21 @@ static const int kTabDragThreshold = 3; // distance a drag must go before we s
const int numTabs = [mTabView numberOfTabViewItems]; const int numTabs = [mTabView numberOfTabViewItems];
float tabWidth = kMaxTabWidth; float tabWidth = kMaxTabWidth;
// calculate the largest tabs that would fit // calculate the largest tabs that would fit... [self tabsRect] may not be correct until mOverflowTabs is set here.
float maxWidth = floor((NSWidth([self bounds]) - (2*kTabBarMargin))/numTabs); float maxWidth = floor((NSWidth([self bounds]) - (2*kTabBarMargin))/numTabs);
// if tabs will overflow, leave space for the button
if (maxWidth < kMinTabWidth) {
mOverflowTabs = YES;
NSRect tabsRect = [self tabsRect];
for (int i = 1; i < numTabs; i++) {
maxWidth = floor(NSWidth(tabsRect)/(numTabs - i));
if (maxWidth >= kMinTabWidth) break;
}
// because the specific tabs which overflow may change, empty the menu and rebuild it as tabs are laid out
[self initOverflowMenu];
} else {
mOverflowTabs = NO;
}
// if our tabs are currently larger than that, shrink them to the larger of kMinTabWidth or maxWidth // if our tabs are currently larger than that, shrink them to the larger of kMinTabWidth or maxWidth
if (tabWidth > maxWidth) if (tabWidth > maxWidth)
tabWidth = (maxWidth > kMinTabWidth ? maxWidth : kMinTabWidth); tabWidth = (maxWidth > kMinTabWidth ? maxWidth : kMinTabWidth);
@ -299,25 +348,80 @@ static const int kTabDragThreshold = 3; // distance a drag must go before we s
buttonSize.width = tabWidth; buttonSize.width = tabWidth;
buttonSize.height = kTabBarDefaultHeight; buttonSize.height = kTabBarDefaultHeight;
NSPoint buttonOrigin = NSMakePoint(xCoord,0); NSPoint buttonOrigin = NSMakePoint(xCoord,0);
// TODO: take care of tabs that run off the end... right now we're the same as Firebird, except I think we
// hit our tab limit before we'll run off the end of the average user's windows given the current kMinTabWidth
[tabButtonCell setFrame:NSMakeRect(buttonOrigin.x,buttonOrigin.y,buttonSize.width,buttonSize.height)]; [tabButtonCell setFrame:NSMakeRect(buttonOrigin.x,buttonOrigin.y,buttonSize.width,buttonSize.height)];
// If the tab ran off the edge, suppress its close button
if (buttonOrigin.x + buttonSize.width > NSMaxX([self bounds]))
[tabButtonCell hideCloseButton];
// tell the button whether it needs to draw the right side dividing line // tell the button whether it needs to draw the right side dividing line
if (NSSelectedTab == [tab tabState]) { if ([tab tabState] == NSSelectedTab) {
[tabButtonCell setDrawDivider:NO]; [tabButtonCell setDrawDivider:NO];
[prevTabButton setDrawDivider:NO]; [prevTabButton setDrawDivider:NO];
} else { } else {
[tabButtonCell setDrawDivider:YES]; [tabButtonCell setDrawDivider:YES];
} }
// If the tab ran off the edge, suppress its close button, make sure the divider is drawn, and add it to the menu
if (buttonOrigin.x + buttonSize.width > NSMaxX([self tabsRect])) {
[tabButtonCell hideCloseButton];
// push the tab off the edge of the view to keep it from grabbing clicks if there is an area
// between the overflow menu and the last tab which is within tabsRect due to rounding
[tabButtonCell setFrame:NSMakeRect(NSMaxX([self bounds]),buttonOrigin.y,buttonSize.width,buttonSize.height)];
// if the tab prior to the overflow is not selected, it must draw a divider
if([[prevTabButton tabViewItem] tabState] != NSSelectedTab) [prevTabButton setDrawDivider:YES];
[mOverflowMenu addItem:[tab menuItem]];
}
prevTabButton = tabButtonCell; prevTabButton = tabButtonCell;
xCoord += (int)tabWidth; xCoord += (int)tabWidth;
} }
// if tabs overflowed, position and display the overflow button
if (mOverflowTabs) {
[mOverflowButton setFrame:NSMakeRect(NSMaxX([self tabsRect]) + kOverflowButtonMargin,
([self tabBarHeight] - kOverflowButtonHeight)/2,kOverflowButtonWidth,kOverflowButtonHeight)];
[self addSubview:mOverflowButton];
} else {
[mOverflowButton removeFromSuperview];
}
[self setNeedsDisplay:YES]; [self setNeedsDisplay:YES];
} }
-(void)initOverflowMenu
{
if (!mOverflowButton) {
// if it hasn't been created yet, create an NSPopUpButton and retain a strong reference
mOverflowButton = [[NSButton alloc] initWithFrame:NSMakeRect(0,0,kOverflowButtonWidth,kOverflowButtonHeight)];
if (!gTabOverflowImage) [self loadImages];
[mOverflowButton setImage:gTabOverflowImage];
[mOverflowButton setImagePosition:NSImageOnly];
[mOverflowButton setBezelStyle:NSShadowlessSquareBezelStyle];
[mOverflowButton setBordered:NO];
[[mOverflowButton cell] setHighlightsBy:NSNoCellMask];
[mOverflowButton setTarget:self];
[mOverflowButton setAction:@selector(overflowMenu:)];
[(NSButtonCell *)[mOverflowButton cell]sendActionOn:NSLeftMouseDownMask];
}
if (!mOverflowMenu) {
// create an empty NSMenu for later use and retain a strong reference
mOverflowMenu = [[NSMenu alloc] init];
[mOverflowMenu addItemWithTitle:@"" action:NULL keyEquivalent:@""];
}
// remove any items on the menu other than the dummy item
for (int i = [mOverflowMenu numberOfItems]; i > 1; i--)
[mOverflowMenu removeItemAtIndex:i-1];
}
- (IBAction)overflowMenu:(id)sender
{
NSPopUpButtonCell *popupCell = [[[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:YES] autorelease];
[popupCell setMenu:mOverflowMenu];
[popupCell trackMouse:[NSApp currentEvent] inRect:[sender bounds] ofView:sender untilMouseUp:YES];
}
// returns an NSRect of the area where tab widgets may be drawn
-(NSRect)tabsRect
{
NSRect rect = [self bounds];
rect.origin.x += kTabBarMargin;
rect.size.width -= 2 * kTabBarMargin + (mOverflowTabs ? kOverflowButtonWidth : 0.0);
return rect;
}
#pragma mark - #pragma mark -
// NSDraggingDestination destination methods // NSDraggingDestination destination methods

Просмотреть файл

@ -49,4 +49,6 @@
- (BrowserTabViewItem*)itemWithTag:(int)tag; - (BrowserTabViewItem*)itemWithTag:(int)tag;
- (void)refreshTabBar:(BOOL)rebuild; - (void)refreshTabBar:(BOOL)rebuild;
- (void)windowClosed;
@end @end

Просмотреть файл

@ -248,6 +248,20 @@
} }
} }
- (void)windowClosed
{
// Loop over all tabs, and tell them that the window is closed. This
// stops gecko from going any further on any of its open connections
// and breaks all the necessary cycles between Gecko and the BrowserWrapper.
int numTabs = [self numberOfTabViewItems];
for (int i = 0; i < numTabs; i++) {
NSTabViewItem* item = [self tabViewItemAtIndex: i];
[[item view] windowClosed];
}
// Tell the tab bar the window is closed so it will perform any needed cleanup
[mTabBar windowClosed];
}
- (BOOL)tabsVisible - (BOOL)tabsVisible
{ {

Просмотреть файл

@ -51,6 +51,7 @@
BrowserTabItemContainerView* mTabContentsView; BrowserTabItemContainerView* mTabContentsView;
NSProgressIndicator* mProgressWheel; // STRONG ref NSProgressIndicator* mProgressWheel; // STRONG ref
NSButton* mCloseButton; // STRING ref NSButton* mCloseButton; // STRING ref
NSMenuItem* mMenuItem; // STRONG ref
BOOL mDraggable; BOOL mDraggable;
int mTag; int mTag;
} }
@ -70,6 +71,10 @@
- (void)willBeRemoved:(BOOL)remove; - (void)willBeRemoved:(BOOL)remove;
- (NSButton *)closeButton; - (NSButton *)closeButton;
- (NSMenuItem *)menuItem;
- (void) willDeselect;
- (void) willSelect;
- (void) selectTab:(id)sender;
+ (NSImage*)closeIcon; + (NSImage*)closeIcon;
+ (NSImage*)closeIconPressed; + (NSImage*)closeIconPressed;

Просмотреть файл

@ -52,6 +52,8 @@
// we cannot use the spinner before 10.2, so don't allow it. This is the // we cannot use the spinner before 10.2, so don't allow it. This is the
// version of appkit in 10.2 (taken from the 10.3 SDK headers which we cannot use). // version of appkit in 10.2 (taken from the 10.3 SDK headers which we cannot use).
const double kJaguarAppKitVersion = 663; const double kJaguarAppKitVersion = 663;
// truncate menuitem title to the same width as the bookmarks menu
const int kMenuTruncationChars = 60;
@interface BrowserTabViewItem(Private) @interface BrowserTabViewItem(Private)
- (void)setTag:(int)tag; - (void)setTag:(int)tag;
@ -107,6 +109,8 @@ const double kJaguarAppKitVersion = 663;
{ {
[mLabelCell release]; [mLabelCell release];
[mTabButtonCell release]; [mTabButtonCell release];
// needs to be nil so that [super dealloc]'s call to setMenu doesn't cause us to call setMenu on an invalid object
mTabButtonCell = nil;
[super dealloc]; [super dealloc];
} }
@ -340,7 +344,12 @@ const double kJaguarAppKitVersion = 663;
[mCloseButton setTarget:self]; [mCloseButton setTarget:self];
[mCloseButton setAction:@selector(closeTab)]; [mCloseButton setAction:@selector(closeTab)];
[mCloseButton setAutoresizingMask:NSViewMinXMargin]; [mCloseButton setAutoresizingMask:NSViewMinXMargin];
[mCloseButton retain];
// create a menu item, to be used when there are more tabs than screen real estate. keep a strong ref
// since it will be added to and removed from the menu repeatedly
mMenuItem = [[NSMenuItem alloc] initWithTitle:[self label] action:@selector(selectTab:) keyEquivalent:@""];
[mMenuItem setTarget:self];
[mMenuItem retain];
[[self tabView] setAutoresizesSubviews:YES]; [[self tabView] setAutoresizesSubviews:YES];
@ -363,6 +372,7 @@ const double kJaguarAppKitVersion = 663;
[mTabContentsView release]; // balance our init [mTabContentsView release]; // balance our init
[mProgressWheel release]; [mProgressWheel release];
[mCloseButton release]; [mCloseButton release];
[mMenuItem release];
[super dealloc]; [super dealloc];
} }
@ -423,6 +433,7 @@ const double kJaguarAppKitVersion = 663;
{ {
NSAttributedString* labelString = [[[NSAttributedString alloc] initWithString:label attributes:mLabelAttributes] autorelease]; NSAttributedString* labelString = [[[NSAttributedString alloc] initWithString:label attributes:mLabelAttributes] autorelease];
[[mTabContentsView labelCell] setAttributedStringValue:labelString]; [[mTabContentsView labelCell] setAttributedStringValue:labelString];
[mMenuItem setTitle:[label stringByTruncatingTo:kMenuTruncationChars at:kTruncateAtMiddle]];
[(BrowserTabView *)[self tabView] refreshTabBar:NO]; [(BrowserTabView *)[self tabView] refreshTabBar:NO];
[super setLabel:label]; [super setLabel:label];
@ -447,6 +458,7 @@ const double kJaguarAppKitVersion = 663;
{ {
[super setTabIcon:newIcon]; [super setTabIcon:newIcon];
[[mTabContentsView labelCell] setImage:mTabIcon]; [[mTabContentsView labelCell] setImage:mTabIcon];
[mMenuItem setImage:mTabIcon];
[(BrowserTabView *)[self tabView] refreshTabBar:NO]; [(BrowserTabView *)[self tabView] refreshTabBar:NO];
} }
@ -500,6 +512,27 @@ const double kJaguarAppKitVersion = 663;
return mCloseButton; return mCloseButton;
} }
- (NSMenuItem *) menuItem
{
return mMenuItem;
}
- (void) selectTab:(id)sender
{
[[self tabView] selectTabViewItem:self];
}
// called by delegate when a tab will be deselected
- (void) willDeselect
{
[mMenuItem setState:NSOffState];
}
// called by delegate when a tab will be selected
- (void) willSelect
{
[mMenuItem setState:NSOnState];
}
#pragma mark - #pragma mark -
+ (NSImage*)closeIcon + (NSImage*)closeIcon

Просмотреть файл

@ -126,7 +126,7 @@ static NSString *NavigatorWindowFrameSaveName = @"NavigatorWindow";
// hardcoded defaults. // hardcoded defaults.
static NSArray* sToolbarDefaults = nil; static NSArray* sToolbarDefaults = nil;
#define kMaxBrowserWindowTabs 16 #define kMaxBrowserWindowTabs 0
enum BWCOpenDest { enum BWCOpenDest {
kDestinationNewWindow = 0, kDestinationNewWindow = 0,
@ -504,14 +504,8 @@ enum BWCOpenDest {
NS_IF_RELEASE(mURIFixer); NS_IF_RELEASE(mURIFixer);
} // matters } // matters
// Loop over all tabs, and tell them that the window is closed. This // Tell the BrowserTabView the window is closed
// stops gecko from going any further on any of its open connections [mTabBrowser windowClosed];
// and breaks all the necessary cycles between Gecko and the BrowserWrapper.
int numTabs = [mTabBrowser numberOfTabViewItems];
for (int i = 0; i < numTabs; i++) {
NSTabViewItem* item = [mTabBrowser tabViewItemAtIndex: i];
[[item view] windowClosed];
}
// if the bookmark manager is visible when we close the window, all hell // if the bookmark manager is visible when we close the window, all hell
// breaks loose in the autorelease pool and when we try to show another // breaks loose in the autorelease pool and when we try to show another
@ -2406,6 +2400,18 @@ enum BWCOpenDest {
[mBrowserView makePrimaryBrowserView: mURLBar status: mStatus windowController: self]; [mBrowserView makePrimaryBrowserView: mURLBar status: mStatus windowController: self];
} }
- (void)tabView:(NSTabView *)aTabView willSelectTabViewItem:(NSTabViewItem *)aTabViewItem
{
// we'll get called for the sidebar tabs as well. ignore any calls coming from
// there, we're only interested in the browser tabs.
if (aTabView != mTabBrowser)
return;
if ([aTabView isKindOfClass:[BrowserTabView class]] && [aTabViewItem isKindOfClass:[BrowserTabViewItem class]]) {
[(BrowserTabViewItem *)[aTabView selectedTabViewItem] willDeselect];
[(BrowserTabViewItem *)aTabViewItem willSelect];
}
}
- (void)tabViewDidChangeNumberOfTabViewItems:(NSTabView *)aTabView - (void)tabViewDidChangeNumberOfTabViewItems:(NSTabView *)aTabView
{ {
[[NSApp delegate] fixCloseMenuItemKeyEquivalents]; [[NSApp delegate] fixCloseMenuItemKeyEquivalents];

Просмотреть файл

@ -89,8 +89,11 @@
NSView *view = [userData objectForKey:@"view"]; NSView *view = [userData objectForKey:@"view"];
mMouseWithin = YES; mMouseWithin = YES;
// only act on the mouseEntered if the view is active or accepts the first mouse click // only act on the mouseEntered if the view is active or accepts the first mouse click
if ([[view window] isKeyWindow] || [view acceptsFirstMouse:theEvent]) if ([[view window] isKeyWindow] || [view acceptsFirstMouse:theEvent]) {
[view setNeedsDisplayInRect:[self frame]]; [view setNeedsDisplayInRect:[self frame]];
// calling displayIfNeeded prevents the "lag" observed when displaying rollover events
[view displayIfNeeded];
}
} }
- (void)mouseExited:(NSEvent*)theEvent - (void)mouseExited:(NSEvent*)theEvent
@ -99,8 +102,11 @@
NSView *view = [userData objectForKey:@"view"]; NSView *view = [userData objectForKey:@"view"];
mMouseWithin = NO; mMouseWithin = NO;
// only act on the mouseExited if the view is active or accepts the first mouse click // only act on the mouseExited if the view is active or accepts the first mouse click
if ([[view window] isKeyWindow] || [view acceptsFirstMouse:theEvent]) if ([[view window] isKeyWindow] || [view acceptsFirstMouse:theEvent]) {
[view setNeedsDisplayInRect:[self frame]]; [view setNeedsDisplayInRect:[self frame]];
// calling displayIfNeeded prevents the "lag" observed when displaying rollover events
[view displayIfNeeded];
}
} }
- (void)setDragTarget:(BOOL)isDragTarget - (void)setDragTarget:(BOOL)isDragTarget

Просмотреть файл

@ -43,6 +43,7 @@
@interface TabButtonCell : RolloverTrackingCell { @interface TabButtonCell : RolloverTrackingCell {
BrowserTabViewItem *mTabViewItem; BrowserTabViewItem *mTabViewItem;
BOOL mNeedsDivider; BOOL mNeedsDivider;
NSButton * mCloseButton;
} }
-(id)initFromTabViewItem:(BrowserTabViewItem*)tabViewItem; -(id)initFromTabViewItem:(BrowserTabViewItem*)tabViewItem;

Просмотреть файл

@ -64,16 +64,15 @@ static NSImage * tabButtonDividerImage = nil;
-(id)initFromTabViewItem:(BrowserTabViewItem *)tabViewItem -(id)initFromTabViewItem:(BrowserTabViewItem *)tabViewItem
{ {
[super init]; [super init];
mTabViewItem = [tabViewItem retain]; mTabViewItem = tabViewItem;
mNeedsDivider = YES; mNeedsDivider = YES;
return self; return self;
} }
// XXX does the menu need released here??
-(void)dealloc -(void)dealloc
{ {
[[mTabViewItem closeButton] removeFromSuperview]; [mCloseButton removeFromSuperview];
[mTabViewItem release]; [mCloseButton release];
[super dealloc]; [super dealloc];
} }
@ -102,7 +101,11 @@ static NSImage * tabButtonDividerImage = nil;
// we have bigger problems // we have bigger problems
NSSize textSize = [mTabViewItem sizeOfLabel:NO]; NSSize textSize = [mTabViewItem sizeOfLabel:NO];
NSSize buttonSize = [[mTabViewItem closeButton] frame].size;
// retain a reference to the close button; otherwise we can't be sure it's removed from the view hierarchy
// during our d'tor, when mTabViewItem will be invalid.
if (!mCloseButton) mCloseButton = [[mTabViewItem closeButton] retain];
NSSize buttonSize = [mCloseButton frame].size;
// center based on the larger of the two heights if there's a difference // center based on the larger of the two heights if there's a difference
float maxHeight = textSize.height > buttonSize.height ? textSize.height : buttonSize.height; float maxHeight = textSize.height > buttonSize.height ? textSize.height : buttonSize.height;
@ -148,13 +151,10 @@ static NSImage * tabButtonDividerImage = nil;
rect.origin.y += kTabBottomPad; rect.origin.y += kTabBottomPad;
NSRectFill(rect); NSRectFill(rect);
} }
NSButton *closeButton = [mTabViewItem closeButton]; if (controlView != [mCloseButton superview]) {
if (controlView != [closeButton superview]) { [controlView addSubview:mCloseButton];
[controlView addSubview:closeButton];
} }
[closeButton setFrame:buttonRect]; [mCloseButton setFrame:buttonRect];
// XXX is this necessary, or even good?
[closeButton setNeedsDisplay:YES];
[labelCell drawInteriorWithFrame:labelRect inView:controlView]; [labelCell drawInteriorWithFrame:labelRect inView:controlView];
} }
@ -170,9 +170,8 @@ static NSImage * tabButtonDividerImage = nil;
-(void)hideCloseButton -(void)hideCloseButton
{ {
NSButton * closeButton = [mTabViewItem closeButton]; if ([mCloseButton superview] != nil)
if ([closeButton superview] != nil) [mCloseButton removeFromSuperview];
[closeButton removeFromSuperview];
} }
-(void)setDrawDivider:(BOOL)willDraw -(void)setDrawDivider:(BOOL)willDraw