• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
3// found in the LICENSE file.
4
5#import "chrome/browser/ui/cocoa/hover_button.h"
6
7@implementation HoverButton
8
9- (id)initWithFrame:(NSRect)frameRect {
10  if ((self = [super initWithFrame:frameRect])) {
11    [self setTrackingEnabled:YES];
12    hoverState_ = kHoverStateNone;
13    [self updateTrackingAreas];
14  }
15  return self;
16}
17
18- (void)awakeFromNib {
19  [self setTrackingEnabled:YES];
20  hoverState_ = kHoverStateNone;
21  [self updateTrackingAreas];
22}
23
24- (void)dealloc {
25  [self setTrackingEnabled:NO];
26  [super dealloc];
27}
28
29- (void)mouseEntered:(NSEvent*)theEvent {
30  hoverState_ = kHoverStateMouseOver;
31  [self setNeedsDisplay:YES];
32}
33
34- (void)mouseExited:(NSEvent*)theEvent {
35  hoverState_ = kHoverStateNone;
36  [self setNeedsDisplay:YES];
37}
38
39- (void)mouseDown:(NSEvent*)theEvent {
40  hoverState_ = kHoverStateMouseDown;
41  [self setNeedsDisplay:YES];
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
44  // |checkImageState| call will crash.
45  // http://crbug.com/28220
46  scoped_nsobject<HoverButton> myself([self retain]);
47
48  [super mouseDown:theEvent];
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
51  // moved under the mouse during tab resize, instead of the mouse moving over
52  // the button.
53  // http://crbug.com/31279
54  [self checkImageState];
55}
56
57- (void)setTrackingEnabled:(BOOL)enabled {
58  if (enabled) {
59    trackingArea_.reset(
60        [[NSTrackingArea alloc] initWithRect:[self bounds]
61                                     options:NSTrackingMouseEnteredAndExited |
62                                             NSTrackingActiveAlways
63                                       owner:self
64                                    userInfo:nil]);
65    [self addTrackingArea:trackingArea_.get()];
66
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
69    // part of the tab strip, we don't get any mouseEntered event since the
70    // tracking area was disabled when we entered.
71    [self checkImageState];
72  } else {
73    if (trackingArea_.get()) {
74      [self removeTrackingArea:trackingArea_.get()];
75      trackingArea_.reset(nil);
76    }
77  }
78}
79
80- (void)updateTrackingAreas {
81  [super updateTrackingAreas];
82  [self checkImageState];
83}
84
85- (void)checkImageState {
86  if (!trackingArea_.get())
87    return;
88
89  // Update the button's state if the button has moved.
90  NSPoint mouseLoc = [[self window] mouseLocationOutsideOfEventStream];
91  mouseLoc = [self convertPoint:mouseLoc fromView:nil];
92  hoverState_ = NSPointInRect(mouseLoc, [self bounds]) ?
93      kHoverStateMouseOver : kHoverStateNone;
94  [self setNeedsDisplay:YES];
95}
96
97@end
98