1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
// 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 <objc/runtime.h>
#import <Carbon/Carbon.h>
#include "base/logging.h"
#include "base/mac/mac_util.h"
#include "base/mac/scoped_nsautorelease_pool.h"
namespace {
BOOL gCanDrawTitle = NO;
BOOL gCanGetCornerRadius = NO;
} // namespace
@interface NSView (Swizzles)
- (void)drawRectOriginal:(NSRect)rect;
- (NSPoint)_fullScreenButtonOriginOriginal;
@end
@interface NSWindow (FramedBrowserWindow)
- (NSPoint)fullScreenButtonOriginAdjustment;
@end
@implementation NSWindow (CustomFrameView)
- (void)drawCustomFrameRect:(NSRect)rect forView:(NSView*)view {
[view drawRectOriginal:rect];
}
@end
@interface CustomFrameView : NSView
@end
@implementation CustomFrameView
// This is where we swizzle drawRect, and add in two methods that we
// need. If any of these fail it shouldn't affect the functionality of the
// others. If they all fail, we will lose window frame theming and
// roll overs for our close widgets, but things should still function
// correctly.
+ (void)load {
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;
// Exchange draw rect.
Method m0 = class_getInstanceMethod([self class], @selector(drawRect:));
DCHECK(m0);
if (m0) {
BOOL didAdd = class_addMethod(borderViewClass,
@selector(drawRectOriginal:),
method_getImplementation(m0),
method_getTypeEncoding(m0));
DCHECK(didAdd);
if (didAdd) {
Method m1 = class_getInstanceMethod(borderViewClass,
@selector(drawRect:));
Method m2 = class_getInstanceMethod(borderViewClass,
@selector(drawRectOriginal:));
DCHECK(m1 && m2);
if (m1 && m2) {
method_exchangeImplementations(m1, m2);
}
}
}
// Swizzle the method that sets the origin for the Lion fullscreen button. Do
// nothing if it cannot be found.
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);
}
}
}
}
+ (BOOL)canDrawTitle {
return gCanDrawTitle;
}
+ (BOOL)canGetCornerRadius {
return gCanGetCornerRadius;
}
- (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;
}
// Here is our custom drawing for our frame.
- (void)drawRect:(NSRect)rect {
// Delegate drawing to the window, whose default implementation (above) is to
// call into the original implementation.
[[self window] drawCustomFrameRect:rect forView:self];
}
// 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
|