Bug 868211 - Simplify Mac implementation of -moz-window-button-box. r=smichaud

This commit is contained in:
Markus Stange 2013-05-03 19:31:01 +02:00
Родитель 07f9252ffd
Коммит 3bbae4a42e
3 изменённых файлов: 59 добавлений и 193 удалений

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

@ -122,20 +122,6 @@ typedef struct _nsCocoaWindowList {
@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
{
@private

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

@ -2475,171 +2475,58 @@ 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);
if (cell) {
Class cellClass = [cell class];
if (!gMozTitleCellClass) {
Class newClass = objc_allocateClassPair(cellClass,
"MozTitleCell", 0);
if (newClass) {
if ([cellClass 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 &&
cellClass == class_getSuperclass(gMozTitleCellClass)) {
object_setClass(cell, gMozTitleCellClass);
}
}
}
static int32_t MozFrameView_buttonBoxDisplayPixelsWidth(id self, SEL sel)
{
NSRect buttonBox = NSZeroRect;
NSButton *closeButton = nil;
if ([self respondsToSelector:@selector(closeButton)]) {
closeButton = [self closeButton];
}
if (closeButton) {
NSRect closeButtonBox = [self convertRect:[closeButton bounds]
fromView:closeButton];
buttonBox = NSUnionRect(buttonBox, closeButtonBox);
}
NSButton *minimizeButton = nil;
if ([self respondsToSelector:@selector(minimizeButton)]) {
minimizeButton = [self minimizeButton];
}
if (minimizeButton) {
NSRect minimizeButtonBox = [self convertRect:[minimizeButton bounds]
fromView:minimizeButton];
buttonBox = NSUnionRect(buttonBox, minimizeButtonBox);
}
NSButton *zoomButton = nil;
if ([self respondsToSelector:@selector(zoomButton)]) {
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 = nil;
if ([self respondsToSelector:@selector(fullScreenButton)]) {
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;
@end
@interface NSView(FrameViewMethodSwizzling)
- (void)FrameViewClass__drawTitleBar:(NSRect)aRect;
@end
@implementation NSView(FrameViewMethodSwizzling)
- (void)FrameViewClass__drawTitleBar:(NSRect)aRect
{
NSWindow* window = [self window];
if ([window isKindOfClass:[BaseWindow class]] &&
[(BaseWindow*)window drawsContentsIntoWindowFrame]) {
// Do not draw the title.
return;
}
[self FrameViewClass__drawTitleBar:aRect];
}
@end
static NSMutableSet *gSwizzledFrameViewClasses = nil;
@implementation BaseWindow
// The frame of a window is implemented using undocumented NSView subclasses.
// We disable window title drawing by overriding the _drawTitleBar: method on
// these frame view classes. The class which is used for a window is
// determined in the window's frameViewClassForStyleMask: method, so this is
// where we make sure that we have swizzled the method on all encountered
// classes.
+ (Class)frameViewClassForStyleMask:(NSUInteger)styleMask
{
Class retval = [super frameViewClassForStyleMask:styleMask];
Class frameViewClass = [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;
if (!gSwizzledFrameViewClasses) {
gSwizzledFrameViewClasses = [[NSMutableSet setWithCapacity:3] retain];
if (!gSwizzledFrameViewClasses) {
return frameViewClass;
}
}
return retval;
if (![gSwizzledFrameViewClasses containsObject:frameViewClass]) {
nsToolkit::SwizzleMethods(frameViewClass, @selector(_drawTitleBar:),
@selector(FrameViewClass__drawTitleBar:));
[gSwizzledFrameViewClasses addObject:frameViewClass];
}
return frameViewClass;
}
- (id)initWithContentRect:(NSRect)aContentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)aBufferingType defer:(BOOL)aFlag

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

@ -358,36 +358,27 @@ static NSWindow* NativeWindowForFrame(nsIFrame* aFrame,
return (NSWindow*)topLevelWidget->GetNativeData(NS_NATIVE_WINDOW);
}
static NSView* FrameViewForFrame(nsIFrame* aFrame)
static int32_t WindowButtonsReservedWidth(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;
}
if (!window) {
return 61; // fallback value
}
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;
}
NSRect buttonBox = NSZeroRect;
NSButton* closeButton = [window standardWindowButton:NSWindowCloseButton];
if (closeButton) {
buttonBox = NSUnionRect(buttonBox, [closeButton frame]);
}
return retval;
NSButton* minimizeButton = [window standardWindowButton:NSWindowMiniaturizeButton];
if (minimizeButton) {
buttonBox = NSUnionRect(buttonBox, [minimizeButton frame]);
}
NSButton* zoomButton = [window standardWindowButton:NSWindowZoomButton];
if (zoomButton) {
buttonBox = NSUnionRect(buttonBox, [zoomButton frame]);
}
return int32_t(NSMaxX(buttonBox));
}
static BOOL FrameIsInActiveWindow(nsIFrame* aFrame)
@ -2768,12 +2759,14 @@ nsNativeThemeCocoa::GetMinimumWidgetSize(nsRenderingContext* aContext,
}
case NS_THEME_WINDOW_BUTTON_BOX: {
aResult->SizeTo(ButtonBoxDisplayPixelsWidth(aFrame), 0);
aResult->SizeTo(WindowButtonsReservedWidth(aFrame), 0);
break;
}
case NS_THEME_MOZ_MAC_FULLSCREEN_BUTTON: {
aResult->SizeTo(FullScreenButtonDisplayPixelsWidth(aFrame), 0);
// This value is hardcoded because it's needed before we can measure the
// position and size of the fullscreen button.
aResult->SizeTo(20, 0);
break;
}