1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #import "chrome/browser/ui/cocoa/custom_frame_view.h"
7 #import <Carbon/Carbon.h>
8 #include <crt_externs.h>
9 #import <objc/runtime.h>
12 #include "base/logging.h"
13 #include "base/mac/mac_util.h"
14 #include "base/mac/scoped_nsautorelease_pool.h"
17 BOOL gCanDrawTitle = NO;
18 BOOL gCanGetCornerRadius = NO;
21 @interface NSView (Swizzles)
22 - (void)drawRectOriginal:(NSRect)rect;
23 - (NSPoint)_fullScreenButtonOriginOriginal;
26 @interface NSWindow (FramedBrowserWindow)
27 - (NSPoint)fullScreenButtonOriginAdjustment;
30 @implementation NSWindow (CustomFrameView)
31 - (void)drawCustomFrameRect:(NSRect)rect forView:(NSView*)view {
32 [view drawRectOriginal:rect];
36 @interface CustomFrameView : NSView
40 @implementation CustomFrameView
42 // This is where we swizzle drawRect, and add in two methods that we
43 // need. If any of these fail it shouldn't affect the functionality of the
44 // others. If they all fail, we will lose window frame theming and
45 // roll overs for our close widgets, but things should still function
48 // Swizzling should only happen in the browser process. Interacting with
49 // AppKit will run +[borderViewClass initialize] in the renderer, which
50 // may establish Mach IPC with com.apple.windowserver.
51 // Note that CommandLine has not been initialized yet, since this is running
52 // as a module initializer.
53 const char* const* const argv = *_NSGetArgv();
54 const int argc = *_NSGetArgc();
55 const char kType[] = "--type=";
56 for (int i = 1; i < argc; ++i) {
57 const char* arg = argv[i];
58 if (strncmp(arg, kType, strlen(kType)) == 0)
62 base::mac::ScopedNSAutoreleasePool pool;
64 // On 10.8+ the background for textured windows are no longer drawn by
65 // NSGrayFrame, and NSThemeFrame is used instead <http://crbug.com/114745>.
66 Class borderViewClass = NSClassFromString(
67 base::mac::IsOSMountainLionOrLater() ? @"NSThemeFrame" : @"NSGrayFrame");
68 DCHECK(borderViewClass);
69 if (!borderViewClass) return;
71 // Exchange draw rect.
72 Method m0 = class_getInstanceMethod([self class], @selector(drawRect:));
75 BOOL didAdd = class_addMethod(borderViewClass,
76 @selector(drawRectOriginal:),
77 method_getImplementation(m0),
78 method_getTypeEncoding(m0));
81 Method m1 = class_getInstanceMethod(borderViewClass,
82 @selector(drawRect:));
83 Method m2 = class_getInstanceMethod(borderViewClass,
84 @selector(drawRectOriginal:));
87 method_exchangeImplementations(m1, m2);
92 // Swizzle the method that sets the origin for the Lion fullscreen button. Do
93 // nothing if it cannot be found.
94 m0 = class_getInstanceMethod([self class],
95 @selector(_fullScreenButtonOrigin));
97 BOOL didAdd = class_addMethod(borderViewClass,
98 @selector(_fullScreenButtonOriginOriginal),
99 method_getImplementation(m0),
100 method_getTypeEncoding(m0));
102 Method m1 = class_getInstanceMethod(borderViewClass,
103 @selector(_fullScreenButtonOrigin));
104 Method m2 = class_getInstanceMethod(borderViewClass,
105 @selector(_fullScreenButtonOriginOriginal));
107 method_exchangeImplementations(m1, m2);
113 + (BOOL)canDrawTitle {
114 return gCanDrawTitle;
117 + (BOOL)canGetCornerRadius {
118 return gCanGetCornerRadius;
121 - (id)initWithFrame:(NSRect)frame {
122 // This class is not for instantiating.
123 [self doesNotRecognizeSelector:_cmd];
127 - (id)initWithCoder:(NSCoder*)coder {
128 // This class is not for instantiating.
129 [self doesNotRecognizeSelector:_cmd];
133 // Here is our custom drawing for our frame.
134 - (void)drawRect:(NSRect)rect {
135 // Delegate drawing to the window, whose default implementation (above) is to
136 // call into the original implementation.
137 [[self window] drawCustomFrameRect:rect forView:self];
140 // Override to move the fullscreen button to the left of the profile avatar.
141 - (NSPoint)_fullScreenButtonOrigin {
142 NSWindow* window = [self window];
143 NSPoint offset = NSZeroPoint;
145 if ([window respondsToSelector:@selector(fullScreenButtonOriginAdjustment)])
146 offset = [window fullScreenButtonOriginAdjustment];
148 NSPoint origin = [self _fullScreenButtonOriginOriginal];
149 origin.x += offset.x;
150 origin.y += offset.y;