OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #import "chrome/browser/ui/cocoa/hover_button.h" | 5 #import "chrome/browser/ui/cocoa/hover_button.h" |
| 6 #import "chrome/browser/ui/cocoa/tracking_area.h" |
6 | 7 |
7 @implementation HoverButton | 8 @implementation HoverButton |
8 | 9 |
| 10 @synthesize hoverState = hoverState_; |
| 11 |
9 - (id)initWithFrame:(NSRect)frameRect { | 12 - (id)initWithFrame:(NSRect)frameRect { |
10 if ((self = [super initWithFrame:frameRect])) { | 13 if ((self = [super initWithFrame:frameRect])) { |
11 [self setTrackingEnabled:YES]; | 14 [self setTrackingEnabled:YES]; |
12 hoverState_ = kHoverStateNone; | 15 hoverState_ = kHoverStateNone; |
13 [self updateTrackingAreas]; | 16 [self updateTrackingAreas]; |
14 } | 17 } |
15 return self; | 18 return self; |
16 } | 19 } |
17 | 20 |
18 - (void)awakeFromNib { | 21 - (void)awakeFromNib { |
19 [self setTrackingEnabled:YES]; | 22 [self setTrackingEnabled:YES]; |
20 hoverState_ = kHoverStateNone; | 23 self.hoverState = kHoverStateNone; |
21 [self updateTrackingAreas]; | 24 [self updateTrackingAreas]; |
22 } | 25 } |
23 | 26 |
24 - (void)dealloc { | 27 - (void)dealloc { |
25 [self setTrackingEnabled:NO]; | 28 [self setTrackingEnabled:NO]; |
26 [super dealloc]; | 29 [super dealloc]; |
27 } | 30 } |
28 | 31 |
29 - (void)mouseEntered:(NSEvent*)theEvent { | 32 - (void)mouseEntered:(NSEvent*)theEvent { |
30 hoverState_ = kHoverStateMouseOver; | 33 self.hoverState = kHoverStateMouseOver; |
31 [self setNeedsDisplay:YES]; | |
32 } | 34 } |
33 | 35 |
34 - (void)mouseExited:(NSEvent*)theEvent { | 36 - (void)mouseExited:(NSEvent*)theEvent { |
35 hoverState_ = kHoverStateNone; | 37 self.hoverState = kHoverStateNone; |
36 [self setNeedsDisplay:YES]; | |
37 } | 38 } |
38 | 39 |
39 - (void)mouseDown:(NSEvent*)theEvent { | 40 - (void)mouseDown:(NSEvent*)theEvent { |
40 hoverState_ = kHoverStateMouseDown; | 41 self.hoverState = kHoverStateMouseDown; |
41 [self setNeedsDisplay:YES]; | |
42 // The hover button needs to hold onto itself here for a bit. Otherwise, | 42 // The hover button needs to hold onto itself here for a bit. Otherwise, |
43 // it can be freed while |super mouseDown:| is in it's loop, and the | 43 // it can be freed while |super mouseDown:| is in it's loop, and the |
44 // |checkImageState| call will crash. | 44 // |checkImageState| call will crash. |
45 // http://crbug.com/28220 | 45 // http://crbug.com/28220 |
46 scoped_nsobject<HoverButton> myself([self retain]); | 46 scoped_nsobject<HoverButton> myself([self retain]); |
47 | 47 |
48 [super mouseDown:theEvent]; | 48 [super mouseDown:theEvent]; |
49 // We need to check the image state after the mouseDown event loop finishes. | 49 // We need to check the image state after the mouseDown event loop finishes. |
50 // It's possible that we won't get a mouseExited event if the button was | 50 // It's possible that we won't get a mouseExited event if the button was |
51 // moved under the mouse during tab resize, instead of the mouse moving over | 51 // moved under the mouse during tab resize, instead of the mouse moving over |
52 // the button. | 52 // the button. |
53 // http://crbug.com/31279 | 53 // http://crbug.com/31279 |
54 [self checkImageState]; | 54 [self checkImageState]; |
55 } | 55 } |
56 | 56 |
57 - (void)setTrackingEnabled:(BOOL)enabled { | 57 - (void)setTrackingEnabled:(BOOL)enabled { |
58 if (enabled) { | 58 if (enabled) { |
59 trackingArea_.reset( | 59 trackingArea_.reset( |
60 [[NSTrackingArea alloc] initWithRect:[self bounds] | 60 [[CrTrackingArea alloc] initWithRect:[self bounds] |
61 options:NSTrackingMouseEnteredAndExited | | 61 options:NSTrackingMouseEnteredAndExited | |
62 NSTrackingActiveAlways | 62 NSTrackingActiveAlways |
63 owner:self | 63 proxiedOwner:self |
64 userInfo:nil]); | 64 userInfo:nil]); |
65 [self addTrackingArea:trackingArea_.get()]; | 65 [self addTrackingArea:trackingArea_.get()]; |
66 | 66 |
67 // If you have a separate window that overlaps the close button, and you | 67 // If you have a separate window that overlaps the close button, and you |
68 // move the mouse directly over the close button without entering another | 68 // move the mouse directly over the close button without entering another |
69 // part of the tab strip, we don't get any mouseEntered event since the | 69 // part of the tab strip, we don't get any mouseEntered event since the |
70 // tracking area was disabled when we entered. | 70 // tracking area was disabled when we entered. |
71 [self checkImageState]; | 71 // Done with a delay of 0 because sometimes an event appears to be missed |
| 72 // between the activation of the tracking area and the call to |
| 73 // checkImageState resulting in the button state being incorrect. |
| 74 [self performSelector:@selector(checkImageState) |
| 75 withObject:nil |
| 76 afterDelay:0]; |
72 } else { | 77 } else { |
73 if (trackingArea_.get()) { | 78 if (trackingArea_.get()) { |
74 [self removeTrackingArea:trackingArea_.get()]; | 79 [self removeTrackingArea:trackingArea_.get()]; |
75 trackingArea_.reset(nil); | 80 trackingArea_.reset(nil); |
76 } | 81 } |
77 } | 82 } |
78 } | 83 } |
79 | 84 |
80 - (void)updateTrackingAreas { | 85 - (void)updateTrackingAreas { |
81 [super updateTrackingAreas]; | 86 [super updateTrackingAreas]; |
82 [self checkImageState]; | 87 [self checkImageState]; |
83 } | 88 } |
84 | 89 |
85 - (void)checkImageState { | 90 - (void)checkImageState { |
86 if (!trackingArea_.get()) | 91 if (!trackingArea_.get()) |
87 return; | 92 return; |
88 | 93 |
89 // Update the button's state if the button has moved. | 94 // Update the button's state if the button has moved. |
90 NSPoint mouseLoc = [[self window] mouseLocationOutsideOfEventStream]; | 95 NSPoint mouseLoc = [[self window] mouseLocationOutsideOfEventStream]; |
91 mouseLoc = [self convertPoint:mouseLoc fromView:nil]; | 96 mouseLoc = [self convertPoint:mouseLoc fromView:nil]; |
92 hoverState_ = NSPointInRect(mouseLoc, [self bounds]) ? | 97 self.hoverState = NSPointInRect(mouseLoc, [self bounds]) ? |
93 kHoverStateMouseOver : kHoverStateNone; | 98 kHoverStateMouseOver : kHoverStateNone; |
| 99 } |
| 100 |
| 101 - (void)setHoverState:(HoverState)state { |
| 102 hoverState_ = state; |
94 [self setNeedsDisplay:YES]; | 103 [self setNeedsDisplay:YES]; |
95 } | 104 } |
96 | 105 |
97 @end | 106 @end |
OLD | NEW |