| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #import "chrome/browser/ui/cocoa/custom_frame_view.h" |
| |
| #import <Carbon/Carbon.h> |
| #include <crt_externs.h> |
| #import <objc/runtime.h> |
| #include <string.h> |
| |
| #include "base/logging.h" |
| #include "base/mac/mac_util.h" |
| #include "base/mac/scoped_nsautorelease_pool.h" |
| |
| @interface NSView (Swizzles) |
| - (NSPoint)_fullScreenButtonOriginOriginal; |
| @end |
| |
| @interface NSWindow (FramedBrowserWindow) |
| - (NSPoint)fullScreenButtonOriginAdjustment; |
| @end |
| |
| @interface CustomFrameView : NSView |
| |
| // Clang emits a warning if designated initializers don't call the super |
| // initializer, even if the method raises an exception. |
| // http://www.crbug.com/479019. |
| - (id)initWithFrame:(NSRect)frame UNAVAILABLE_ATTRIBUTE; |
| - (id)initWithCoder:(NSCoder*)coder UNAVAILABLE_ATTRIBUTE; |
| |
| @end |
| |
| @implementation CustomFrameView |
| |
| + (void)load { |
| // Swizzling should only happen in the browser process. Interacting with |
| // AppKit will run +[borderViewClass initialize] in the renderer, which |
| // may establish Mach IPC with com.apple.windowserver. |
| // Note that CommandLine has not been initialized yet, since this is running |
| // as a module initializer. |
| const char* const* const argv = *_NSGetArgv(); |
| const int argc = *_NSGetArgc(); |
| const char kType[] = "--type="; |
| for (int i = 1; i < argc; ++i) { |
| const char* arg = argv[i]; |
| if (strncmp(arg, kType, strlen(kType)) == 0) |
| return; |
| } |
| |
| // In Yosemite, the fullscreen button replaces the zoom button. We no longer |
| // need to swizzle out this AppKit private method. |
| if (!base::mac::IsOSMavericksOrEarlier()) |
| return; |
| |
| base::mac::ScopedNSAutoreleasePool pool; |
| |
| // On 10.8+ the background for textured windows are no longer drawn by |
| // NSGrayFrame, and NSThemeFrame is used instead <http://crbug.com/114745>. |
| Class borderViewClass = NSClassFromString( |
| base::mac::IsOSMountainLionOrLater() ? @"NSThemeFrame" : @"NSGrayFrame"); |
| DCHECK(borderViewClass); |
| if (!borderViewClass) return; |
| |
| // Swizzle the method that sets the origin for the Lion fullscreen button. |
| // Do nothing if it cannot be found. |
| Method m0 = class_getInstanceMethod([self class], |
| @selector(_fullScreenButtonOrigin)); |
| if (m0) { |
| BOOL didAdd = class_addMethod(borderViewClass, |
| @selector(_fullScreenButtonOriginOriginal), |
| method_getImplementation(m0), |
| method_getTypeEncoding(m0)); |
| if (didAdd) { |
| Method m1 = class_getInstanceMethod(borderViewClass, |
| @selector(_fullScreenButtonOrigin)); |
| Method m2 = class_getInstanceMethod( |
| borderViewClass, @selector(_fullScreenButtonOriginOriginal)); |
| if (m1 && m2) { |
| method_exchangeImplementations(m1, m2); |
| } |
| } |
| } |
| } |
| |
| - (id)initWithFrame:(NSRect)frame { |
| // This class is not for instantiating. |
| [self doesNotRecognizeSelector:_cmd]; |
| return nil; |
| } |
| |
| - (id)initWithCoder:(NSCoder*)coder { |
| // This class is not for instantiating. |
| [self doesNotRecognizeSelector:_cmd]; |
| return nil; |
| } |
| |
| // Override to move the fullscreen button to the left of the profile avatar. |
| - (NSPoint)_fullScreenButtonOrigin { |
| NSWindow* window = [self window]; |
| NSPoint offset = NSZeroPoint; |
| |
| if ([window respondsToSelector:@selector(fullScreenButtonOriginAdjustment)]) |
| offset = [window fullScreenButtonOriginAdjustment]; |
| |
| NSPoint origin = [self _fullScreenButtonOriginOriginal]; |
| origin.x += offset.x; |
| origin.y += offset.y; |
| return origin; |
| } |
| |
| @end |