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 <objc/runtime.h>
8 #import <Carbon/Carbon.h>
10 #include "base/logging.h"
11 #include "base/mac/mac_util.h"
12 #include "base/mac/scoped_nsautorelease_pool.h"
15 BOOL gCanDrawTitle = NO;
16 BOOL gCanGetCornerRadius = NO;
19 @interface NSView (Swizzles)
20 - (void)drawRectOriginal:(NSRect)rect;
21 - (NSPoint)_fullScreenButtonOriginOriginal;
24 @interface NSWindow (FramedBrowserWindow)
25 - (NSPoint)fullScreenButtonOriginAdjustment;
28 @implementation NSWindow (CustomFrameView)
29 - (void)drawCustomFrameRect:(NSRect)rect forView:(NSView*)view {
30 [view drawRectOriginal:rect];
34 @interface CustomFrameView : NSView
38 @implementation CustomFrameView
40 // This is where we swizzle drawRect, and add in two methods that we
41 // need. If any of these fail it shouldn't affect the functionality of the
42 // others. If they all fail, we will lose window frame theming and
43 // roll overs for our close widgets, but things should still function
46 base::mac::ScopedNSAutoreleasePool pool;
48 // On 10.8+ the background for textured windows are no longer drawn by
49 // NSGrayFrame, and NSThemeFrame is used instead <http://crbug.com/114745>.
50 Class borderViewClass = NSClassFromString(
51 base::mac::IsOSMountainLionOrLater() ? @"NSThemeFrame" : @"NSGrayFrame");
52 DCHECK(borderViewClass);
53 if (!borderViewClass) return;
55 // Exchange draw rect.
56 Method m0 = class_getInstanceMethod([self class], @selector(drawRect:));
59 BOOL didAdd = class_addMethod(borderViewClass,
60 @selector(drawRectOriginal:),
61 method_getImplementation(m0),
62 method_getTypeEncoding(m0));
65 Method m1 = class_getInstanceMethod(borderViewClass,
66 @selector(drawRect:));
67 Method m2 = class_getInstanceMethod(borderViewClass,
68 @selector(drawRectOriginal:));
71 method_exchangeImplementations(m1, m2);
76 // Swizzle the method that sets the origin for the Lion fullscreen button. Do
77 // nothing if it cannot be found.
78 m0 = class_getInstanceMethod([self class],
79 @selector(_fullScreenButtonOrigin));
81 BOOL didAdd = class_addMethod(borderViewClass,
82 @selector(_fullScreenButtonOriginOriginal),
83 method_getImplementation(m0),
84 method_getTypeEncoding(m0));
86 Method m1 = class_getInstanceMethod(borderViewClass,
87 @selector(_fullScreenButtonOrigin));
88 Method m2 = class_getInstanceMethod(borderViewClass,
89 @selector(_fullScreenButtonOriginOriginal));
91 method_exchangeImplementations(m1, m2);
97 + (BOOL)canDrawTitle {
101 + (BOOL)canGetCornerRadius {
102 return gCanGetCornerRadius;
105 - (id)initWithFrame:(NSRect)frame {
106 // This class is not for instantiating.
107 [self doesNotRecognizeSelector:_cmd];
111 - (id)initWithCoder:(NSCoder*)coder {
112 // This class is not for instantiating.
113 [self doesNotRecognizeSelector:_cmd];
117 // Here is our custom drawing for our frame.
118 - (void)drawRect:(NSRect)rect {
119 // Delegate drawing to the window, whose default implementation (above) is to
120 // call into the original implementation.
121 [[self window] drawCustomFrameRect:rect forView:self];
124 // Override to move the fullscreen button to the left of the profile avatar.
125 - (NSPoint)_fullScreenButtonOrigin {
126 NSWindow* window = [self window];
127 NSPoint offset = NSZeroPoint;
129 if ([window respondsToSelector:@selector(fullScreenButtonOriginAdjustment)])
130 offset = [window fullScreenButtonOriginAdjustment];
132 NSPoint origin = [self _fullScreenButtonOriginOriginal];
133 origin.x += offset.x;
134 origin.y += offset.y;