Home | History | Annotate | Download | only in cocoa
      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