Bug 865374 - Position tabs in the OSX titlebar. Cocoa Widget work by Steven Michaud. r=dao,bgirard.

This commit is contained in:
Mike Conley 2013-05-02 14:15:29 -04:00
Родитель 094a6c7847
Коммит 40ddc57727
12 изменённых файлов: 277 добавлений и 16 удалений

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

@ -412,10 +412,10 @@ pref("browser.tabs.loadBookmarksInBackground", false);
pref("browser.tabs.tabClipWidth", 140);
pref("browser.tabs.animate", true);
pref("browser.tabs.onTop", true);
#ifdef XP_WIN
pref("browser.tabs.drawInTitlebar", true);
#else
#ifdef UNIX_BUT_NOT_MAC
pref("browser.tabs.drawInTitlebar", false);
#else
pref("browser.tabs.drawInTitlebar", true);
#endif
// Where to show tab close buttons:

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

@ -125,6 +125,23 @@ toolbar[printpreview="true"] {
#main-window[tabsintitlebar] #titlebar-buttonbox {
position: relative;
}
#titlebar-buttonbox {
-moz-appearance: -moz-window-button-box;
}
%ifdef XP_MACOSX
#titlebar-fullscreen-button {
-moz-appearance: -moz-mac-fullscreen-button;
}
%endif
%ifdef XP_WIN
#main-window[sizemode="maximized"] #titlebar-buttonbox {
-moz-appearance: -moz-window-button-box-maximized;
}
%endif
%endif
.bookmarks-toolbar-customize,

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

@ -4598,7 +4598,10 @@ var TabsInTitlebar = {
#endif
let captionButtonsBox = $("titlebar-buttonbox");
this._sizePlaceholder("caption-buttons", rect(captionButtonsBox).width);
#ifdef XP_MACOSX
let fullscreenButton = $("titlebar-fullscreen-button");
this._sizePlaceholder("fullscreen-button", rect(fullscreenButton).width);
#endif
let titlebarContentHeight = rect(titlebarContent).height;
let menuHeight = this._outerHeight(menubar);

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

@ -485,13 +485,20 @@
</hbox>
#endif
<spacer id="titlebar-spacer" flex="1"/>
<hbox id="titlebar-buttonbox-container" align="start">
<hbox id="titlebar-buttonbox-container" align="start"
#ifdef XP_MACOSX
ordinal="0"
#endif
>
<hbox id="titlebar-buttonbox">
<toolbarbutton class="titlebar-button" id="titlebar-min" oncommand="window.minimize();"/>
<toolbarbutton class="titlebar-button" id="titlebar-max" oncommand="onTitlebarMaxClick();"/>
<toolbarbutton class="titlebar-button" id="titlebar-close" command="cmd_closeWindow"/>
</hbox>
</hbox>
#ifdef XP_MACOSX
<hbox id="titlebar-fullscreen-button" ordinal="1000"/>
#endif
</hbox>
</vbox>
#endif
@ -519,8 +526,21 @@
</toolbaritem>
#ifdef CAN_DRAW_IN_TITLEBAR
#ifdef MENUBAR_CAN_AUTOHIDE
<hbox class="titlebar-placeholder" type="appmenu-button" ordinal="0"/>
<hbox class="titlebar-placeholder" type="caption-buttons" ordinal="1000"/>
#endif
<hbox class="titlebar-placeholder" type="caption-buttons"
#ifdef XP_MACOSX
ordinal="0"
#else
ordinal="1000"
#endif
/>
#ifdef XP_MACOSX
<hbox class="titlebar-placeholder" type="fullscreen-button" ordinal="1000"/>
#endif
#endif
</toolbar>
@ -827,8 +847,20 @@
tooltiptext="&closeTab.label;"/>
#ifdef CAN_DRAW_IN_TITLEBAR
#ifdef MENUBAR_CAN_AUTOHIDE
<hbox class="titlebar-placeholder" type="appmenu-button" ordinal="0"/>
<hbox class="titlebar-placeholder" type="caption-buttons" ordinal="1000"/>
#endif
<hbox class="titlebar-placeholder" type="caption-buttons"
#ifdef XP_MACOSX
ordinal="0"
#else
ordinal="1000"
#endif
/>
#ifdef XP_MACOSX
<hbox class="titlebar-placeholder" type="fullscreen-button"
ordinal="1000"/>
#endif
</toolbar>

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

@ -40,12 +40,12 @@
background-color: #eeeeee;
}
#titlebar-buttonbox-container {
#titlebar-buttonbox > .titlebar-button {
display: none;
}
#titlebar {
height: 22px;
padding-top: 9px;
}
#main-window:not(:-moz-lwtheme):not([privatebrowsingmode=temporary]) > #titlebar {

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

@ -588,14 +588,9 @@
* themes with Aero Glass.
*/
#titlebar-buttonbox {
-moz-appearance: -moz-window-button-box;
z-index: 1;
}
#main-window[sizemode="maximized"] #titlebar-buttonbox {
-moz-appearance: -moz-window-button-box-maximized;
}
.titlebar-placeholder[type="appmenu-button"] {
margin-left: 4px;
}

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

@ -246,8 +246,9 @@
#define NS_THEME_WIN_MEDIA_TOOLBOX 222
#define NS_THEME_WIN_BROWSER_TAB_BAR_TOOLBOX 223
// Unified toolbar on the Mac
// Unified toolbar and titlebar elements on the Mac
#define NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR 224
#define NS_THEME_MOZ_MAC_FULLSCREEN_BUTTON 226
// Vista glass
#define NS_THEME_WIN_BORDERLESS_GLASS 229

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

@ -107,6 +107,7 @@ CSS_KEY(-moz-mac-alternateprimaryhighlight, _moz_mac_alternateprimaryhighlight)
CSS_KEY(-moz-mac-chrome-active, _moz_mac_chrome_active)
CSS_KEY(-moz-mac-chrome-inactive, _moz_mac_chrome_inactive)
CSS_KEY(-moz-mac-focusring, _moz_mac_focusring)
CSS_KEY(-moz-mac-fullscreen-button, _moz_mac_fullscreen_button)
CSS_KEY(-moz-mac-menuselect, _moz_mac_menuselect)
CSS_KEY(-moz-mac-menushadow, _moz_mac_menushadow)
CSS_KEY(-moz-mac-menutextdisable, _moz_mac_menutextdisable)

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

@ -596,6 +596,7 @@ const int32_t nsCSSProps::kAppearanceKTable[] = {
eCSSKeyword__moz_win_glass, NS_THEME_WIN_GLASS,
eCSSKeyword__moz_win_borderless_glass, NS_THEME_WIN_BORDERLESS_GLASS,
eCSSKeyword__moz_mac_unified_toolbar, NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR,
eCSSKeyword__moz_mac_fullscreen_button, NS_THEME_MOZ_MAC_FULLSCREEN_BUTTON,
eCSSKeyword__moz_window_titlebar, NS_THEME_WINDOW_TITLEBAR,
eCSSKeyword__moz_window_titlebar_maximized, NS_THEME_WINDOW_TITLEBAR_MAXIMIZED,
eCSSKeyword__moz_window_frame_left, NS_THEME_WINDOW_FRAME_LEFT,

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

@ -115,6 +115,25 @@ typedef struct _nsCocoaWindowList {
- (void)setBottomCornerRounded:(BOOL)rounded;
- (BOOL)bottomCornerRounded;
// Present since at least OS X 10.5. The OS calls this method on NSWindow
// (and its subclasses) to find out which NSFrameView subclass to instantiate
// to create its "frame view".
+ (Class)frameViewClassForStyleMask:(NSUInteger)styleMask;
@end
// Present since at least OS X 10.5 in NSFrameView or one of its subclasses.
@interface NSObject (NSFrameViewMethods)
- (NSButton*)closeButton;
- (NSButton*)zoomButton;
- (NSButton*)minimizeButton;
- (NSButton*)fullScreenButton;
- (void)initTitleCell:(id)cell;
@end
@interface NSView (MozFrameViewMethods)
- (int32_t)buttonBoxDisplayPixelsWidth;
- (int32_t)fullScreenButtonDisplayPixelsWidth;
@end
@interface PopupWindow : BaseWindow

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

@ -2475,6 +2475,110 @@ GetDPI(NSWindow* aWindow)
return dpi * backingScale;
}
// Methods of our MozTitleCell and MozFrameView classes, created below as
// subclasses of the appropriate undocumented superclasses. Since we don't
// know beforehand exactly what the superclasses will be, each of these
// classes is created dynamically, using low-level Objective-C runtime
// methods. So their methods' declarations can't use Objective-C syntax.
static Class gMozTitleCellClass = nil;
typedef void (*NSCell_drawWithFrame)(struct objc_super *, SEL, NSRect, NSView *);
static void MozTitleCell_drawWithFrame(id self, SEL sel, NSRect cellFrame,
NSView *controlView)
{
BaseWindow *window = nil;
// The documentation for -[NSCell drawWithFrame:(NSRect)cellFrame
// inView:(NSView*)controlView] says "this method draws the cell in the
// currently focused view", which is what's returned by [NSView focusView].
// So in the very unlikely event that 'controlView' is nil, we fall back
// to using [NSView focusView].
if (controlView) {
window = (BaseWindow *) [controlView window];
} else {
window = (BaseWindow *) [[NSView focusView] window];
}
if ([window isKindOfClass:[BaseWindow class]]) {
if ([window drawsContentsIntoWindowFrame]) {
return;
}
}
struct objc_super target;
target.receiver = self;
target.super_class = [self superclass];
NSCell_drawWithFrame super = (NSCell_drawWithFrame) objc_msgSendSuper;
super(&target, sel, cellFrame, controlView);
}
static NSMutableDictionary *gFrameViewClassesByStyleMask = nil;
typedef void (*NSFrameView_initTitleCell)(struct objc_super *, SEL, id);
static void MozFrameView_initTitleCell(id self, SEL sel, id cell)
{
struct objc_super target;
target.receiver = self;
target.super_class = [self superclass];
NSFrameView_initTitleCell super = (NSFrameView_initTitleCell) objc_msgSendSuper;
super(&target, sel, cell);
Class oldCellClass = [cell class];
if (cell) {
if (!gMozTitleCellClass) {
Class superclass = [cell class];
Class newClass = objc_allocateClassPair(superclass,
"MozTitleCell", 0);
if (newClass) {
if ([superclass instancesRespondToSelector:@selector(drawWithFrame:inView:)]) {
class_addMethod(newClass, @selector(drawWithFrame:inView:),
(IMP)MozTitleCell_drawWithFrame,
"v@:{_NSRect={_NSPoint=ff}{_NSSize=ff}}@");
}
objc_registerClassPair(newClass);
gMozTitleCellClass = newClass;
}
}
if (gMozTitleCellClass) {
object_setClass(cell, gMozTitleCellClass);
}
}
}
static int32_t MozFrameView_buttonBoxDisplayPixelsWidth(id self, SEL sel)
{
NSRect buttonBox = NSZeroRect;
NSButton *closeButton = [self closeButton];
if (closeButton) {
NSRect closeButtonBox = [self convertRect:[closeButton bounds]
fromView:closeButton];
buttonBox = NSUnionRect(buttonBox, closeButtonBox);
}
NSButton *minimizeButton = [self minimizeButton];
if (minimizeButton) {
NSRect minimizeButtonBox = [self convertRect:[minimizeButton bounds]
fromView:minimizeButton];
buttonBox = NSUnionRect(buttonBox, minimizeButtonBox);
}
NSButton *zoomButton = [self zoomButton];
if (zoomButton) {
NSRect zoomButtonBox = [self convertRect:[zoomButton bounds]
fromView:zoomButton];
buttonBox = NSUnionRect(buttonBox, zoomButtonBox);
}
return rint(buttonBox.size.width);
}
static int32_t MozFrameView_fullScreenButtonDisplayPixelsWidth(id self, SEL sel)
{
CGFloat floatWidth = 0;
NSButton *fullScreenButton = [self fullScreenButton];
if (fullScreenButton) {
floatWidth += [self convertSize:[fullScreenButton bounds].size
fromView:fullScreenButton].width;
}
return rint(floatWidth);
}
@interface BaseWindow(Private)
- (void)removeTrackingArea;
- (void)cursorUpdated:(NSEvent*)aEvent;
@ -2482,6 +2586,50 @@ GetDPI(NSWindow* aWindow)
@implementation BaseWindow
+ (Class)frameViewClassForStyleMask:(NSUInteger)styleMask
{
Class retval = [super frameViewClassForStyleMask:styleMask];
if (!gFrameViewClassesByStyleMask) {
gFrameViewClassesByStyleMask =
[[NSMutableDictionary dictionaryWithCapacity:3] retain];
}
if (!gFrameViewClassesByStyleMask) {
return retval;
}
NSString *styleMaskString =
[NSString stringWithFormat:@"%p", (void *) styleMask];
Class existingClass = (Class)
[gFrameViewClassesByStyleMask valueForKey:styleMaskString];
if (existingClass) {
retval = existingClass;
} else if (retval) {
char newClassName[32];
snprintf(newClassName, sizeof(newClassName) - 1, "MozFrameView%s",
[styleMaskString UTF8String]);
Class newClass = objc_allocateClassPair(retval, newClassName, 0);
if (newClass) {
if ([retval instancesRespondToSelector:@selector(initTitleCell:)]) {
class_addMethod(newClass, @selector(initTitleCell:),
(IMP)MozFrameView_initTitleCell,
"v@:@");
}
class_addMethod(newClass, @selector(buttonBoxDisplayPixelsWidth),
(IMP)MozFrameView_buttonBoxDisplayPixelsWidth,
"l@:");
class_addMethod(newClass, @selector(fullScreenButtonDisplayPixelsWidth),
(IMP)MozFrameView_fullScreenButtonDisplayPixelsWidth,
"l@:");
objc_registerClassPair(newClass);
[gFrameViewClassesByStyleMask setValue:newClass forKey:styleMaskString];
retval = newClass;
}
}
return retval;
}
- (id)initWithContentRect:(NSRect)aContentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)aBufferingType defer:(BOOL)aFlag
{
[super initWithContentRect:aContentRect styleMask:aStyle backing:aBufferingType defer:aFlag];

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

@ -357,6 +357,38 @@ static NSWindow* NativeWindowForFrame(nsIFrame* aFrame,
return (NSWindow*)topLevelWidget->GetNativeData(NS_NATIVE_WINDOW);
}
static NSView* FrameViewForFrame(nsIFrame* aFrame)
{
NSWindow* window = NativeWindowForFrame(aFrame);
return [[window contentView] superview];
}
static int32_t ButtonBoxDisplayPixelsWidth(nsIFrame* aFrame)
{
int32_t retval = 60; // Default value;
NSView *frameView = FrameViewForFrame(aFrame);
if ([frameView respondsToSelector:@selector(buttonBoxDisplayPixelsWidth)]) {
int32_t measuredWidth = [frameView buttonBoxDisplayPixelsWidth];
if (measuredWidth) {
retval = measuredWidth;
}
}
return retval;
}
static int32_t FullScreenButtonDisplayPixelsWidth(nsIFrame* aFrame)
{
int32_t retval = 20; // Default value;
NSView *frameView = FrameViewForFrame(aFrame);
if ([frameView respondsToSelector:@selector(fullScreenButtonDisplayPixelsWidth)]) {
int32_t measuredWidth = [frameView fullScreenButtonDisplayPixelsWidth];
if (measuredWidth) {
retval = measuredWidth;
}
}
return retval;
}
static BOOL FrameIsInActiveWindow(nsIFrame* aFrame)
{
nsIWidget* topLevelWidget = NULL;
@ -2685,7 +2717,17 @@ nsNativeThemeCocoa::GetMinimumWidgetSize(nsRenderingContext* aContext,
aResult->SizeTo(0, (2 + 2) /* top */ + 9 + (1 + 1) /* bottom */);
break;
}
case NS_THEME_WINDOW_BUTTON_BOX: {
aResult->SizeTo(ButtonBoxDisplayPixelsWidth(aFrame), 0);
break;
}
case NS_THEME_MOZ_MAC_FULLSCREEN_BUTTON: {
aResult->SizeTo(FullScreenButtonDisplayPixelsWidth(aFrame), 0);
break;
}
case NS_THEME_PROGRESSBAR:
{
SInt32 barHeight = 0;
@ -2947,10 +2989,12 @@ nsNativeThemeCocoa::ThemeSupportsWidget(nsPresContext* aPresContext, nsIFrame* a
case NS_THEME_DIALOG:
case NS_THEME_WINDOW:
case NS_THEME_WINDOW_BUTTON_BOX:
case NS_THEME_WINDOW_TITLEBAR:
case NS_THEME_MENUPOPUP:
case NS_THEME_MENUITEM:
case NS_THEME_MENUSEPARATOR:
case NS_THEME_MOZ_MAC_FULLSCREEN_BUTTON:
case NS_THEME_TOOLTIP:
case NS_THEME_CHECKBOX: