MainWindowTitle.m 22.6 KB
Newer Older
1 2 3
/*****************************************************************************
 * MainWindowTitle.m: MacOS X interface module
 *****************************************************************************
4
 * Copyright (C) 2011-2012 Felix Paul Kühne
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 * $Id$
 *
 * Authors: Felix Paul Kühne <fkuehne -at- videolan -dot- org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#import <vlc_common.h>
#import "intf.h"
#import "MainWindowTitle.h"
27
#import "VLCCoreInteraction.h"
28
#import "CompatibilityFixes.h"
29
#import <SystemConfiguration/SystemConfiguration.h> // for the revealInFinder clone
30 31 32

/*****************************************************************************
 * VLCMainWindowTitleView
33 34 35 36
 *
 * this is our title bar, which can do anything a title should do
 * it relies on the VLCWindowButtonCell to display the correct traffic light
 * states, since we can't capture the mouse-moved events here correctly
37 38
 *****************************************************************************/

39 40
@interface VLCMainWindowTitleView()
{
41 42 43 44 45 46 47 48 49
    NSImage *_redImage;
    NSImage *_redHoverImage;
    NSImage *_redOnClickImage;
    NSImage * _yellowImage;
    NSImage * _yellowHoverImage;
    NSImage * _yellowOnClickImage;
    NSImage * _greenImage;
    NSImage * _greenHoverImage;
    NSImage * _greenOnClickImage;
50
    // yosemite fullscreen images
51 52 53
    NSImage * _fullscreenImage;
    NSImage * _fullscreenHoverImage;
    NSImage * _fullscreenOnClickImage;
54
    // old native fullscreen images
55 56 57
    NSImage * _oldFullscreenImage;
    NSImage * _oldFullscreenHoverImage;
    NSImage * _oldFullscreenOnClickImage;
58

59 60
    NSShadow * _windowTitleShadow;
    NSDictionary * _windowTitleAttributesDictionary;
61 62 63 64 65 66 67 68 69

    BOOL b_nativeFullscreenMode;

    // state to determine correct image for green bubble
    BOOL b_alt_pressed;
    BOOL b_mouse_over;
}
@end

70
@implementation VLCMainWindowTitleView
71

72 73
- (id)init
{
74 75 76 77 78
    self = [super init];

    if (self) {
        _windowTitleAttributesDictionary = [NSDictionary dictionaryWithObjectsAndKeys: [NSColor whiteColor], NSForegroundColorAttributeName, [NSFont titleBarFontOfSize:12.0], NSFontAttributeName, nil];
    }
79

80
    return self;
81 82
}

83 84 85 86
- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver: self];
}
87 88 89

- (void)awakeFromNib
{
90
    b_nativeFullscreenMode = var_InheritBool(getIntf(), "macosx-nativefullscreenmode");
91

92
    if (!b_nativeFullscreenMode || OSX_YOSEMITE || OSX_EL_CAPITAN || OSX_SIERRA) {
93
        [_fullscreenButton setHidden: YES];
94 95
    }

96
    [self setAutoresizesSubviews: YES];
97
    [self setImagesLeft:imageFromRes(@"topbar-dark-left") middle: imageFromRes(@"topbar-dark-center-fill") right:imageFromRes(@"topbar-dark-right")];
98

99 100
    [self loadButtonIcons];
    [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(controlTintChanged:) name: NSControlTintDidChangeNotification object: nil];
101 102
}

103 104 105 106
- (void)controlTintChanged:(NSNotification *)notification
{
    [self loadButtonIcons];

107 108 109
    [_redButton setNeedsDisplay];
    [_yellowButton setNeedsDisplay];
    [_greenButton setNeedsDisplay];
110 111
}

112 113 114 115 116 117 118 119 120 121 122
- (void)informModifierPressed:(BOOL)b_is_altkey;
{
    BOOL b_state_changed = b_alt_pressed != b_is_altkey;

    b_alt_pressed = b_is_altkey;

    if (b_state_changed) {
        [self updateGreenButton];
    }
}

123
- (NSImage *)getButtonImage:(NSString *)o_id
124
{
125
    NSString *o_name = @"";
126
    if (OSX_YOSEMITE || OSX_EL_CAPITAN) {
127 128 129
        o_name = @"yosemite-";
    } else { // OSX_LION, OSX_MOUNTAIN_LION, OSX_MAVERICKS
        o_name = @"lion-";
130
    }
131

132 133 134 135 136 137 138 139 140 141 142
    o_name = [o_name stringByAppendingString:o_id];

    if ([NSColor currentControlTint] != NSBlueControlTint) {
        o_name = [o_name stringByAppendingString:@"-graphite"];
    }

    return [NSImage imageNamed:o_name];
}

- (void)loadButtonIcons
{
143 144 145 146 147 148 149 150 151
    _redImage = [self getButtonImage:@"window-close"];
    _redHoverImage = [self getButtonImage:@"window-close-over"];
    _redOnClickImage = [self getButtonImage:@"window-close-on"];
    _yellowImage = [self getButtonImage:@"window-minimize"];
    _yellowHoverImage = [self getButtonImage:@"window-minimize-over"];
    _yellowOnClickImage = [self getButtonImage:@"window-minimize-on"];
    _greenImage = [self getButtonImage:@"window-zoom"];
    _greenHoverImage = [self getButtonImage:@"window-zoom-over"];
    _greenOnClickImage = [self getButtonImage:@"window-zoom-on"];
152

153
    // these files are only available in the yosemite variant
154
    if (OSX_YOSEMITE || OSX_EL_CAPITAN) {
155 156 157
        _fullscreenImage = [self getButtonImage:@"window-fullscreen"];
        _fullscreenHoverImage = [self getButtonImage:@"window-fullscreen-over"];
        _fullscreenOnClickImage = [self getButtonImage:@"window-fullscreen-on"];
158 159
    }

160 161
    // old native fullscreen images are not available in graphite style
    // thus they are loaded directly here
162 163 164 165 166 167 168 169 170 171 172 173
    _oldFullscreenImage = [NSImage imageNamed:@"lion-window-fullscreen"];
    _oldFullscreenOnClickImage = [NSImage imageNamed:@"lion-window-fullscreen-on"];
    _oldFullscreenHoverImage = [NSImage imageNamed:@"lion-window-fullscreen-over"];

    [_redButton setImage: _redImage];
    [_redButton setAlternateImage: _redHoverImage];
    [[_redButton cell] setShowsBorderOnlyWhileMouseInside: YES];
    [[_redButton cell] setTag: 0];
    [_yellowButton setImage: _yellowImage];
    [_yellowButton setAlternateImage: _yellowHoverImage];
    [[_yellowButton cell] setShowsBorderOnlyWhileMouseInside: YES];
    [[_yellowButton cell] setTag: 1];
174 175

    [self updateGreenButton];
176 177
    [[_greenButton cell] setShowsBorderOnlyWhileMouseInside: YES];
    [[_greenButton cell] setTag: 2];
178

179 180 181 182
    [_fullscreenButton setImage: _oldFullscreenImage];
    [_fullscreenButton setAlternateImage: _oldFullscreenHoverImage];
    [[_fullscreenButton cell] setShowsBorderOnlyWhileMouseInside: YES];
    [[_fullscreenButton cell] setTag: 3];
183 184
}

185 186 187 188
- (void)updateGreenButton
{
    // default image for old version, or if native fullscreen is
    // disabled on yosemite, or if alt key is pressed
189
    if (!(OSX_YOSEMITE || OSX_EL_CAPITAN) || !b_nativeFullscreenMode || b_alt_pressed) {
190 191

        if (b_mouse_over) {
192 193
            [_greenButton setImage: _greenHoverImage];
            [_greenButton setAlternateImage: _greenOnClickImage];
194
        } else {
195 196
            [_greenButton setImage: _greenImage];
            [_greenButton setAlternateImage: _greenOnClickImage];
197 198 199 200
        }
    } else {

        if (b_mouse_over) {
201 202
            [_greenButton setImage: _fullscreenHoverImage];
            [_greenButton setAlternateImage: _fullscreenOnClickImage];
203
        } else {
204 205
            [_greenButton setImage: _fullscreenImage];
            [_greenButton setAlternateImage: _fullscreenOnClickImage];
206 207 208 209
        }
    }
}

210 211 212 213 214 215 216
- (BOOL)mouseDownCanMoveWindow
{
    return YES;
}

- (IBAction)buttonAction:(id)sender
{
217
    if (sender == _redButton)
218
        [[self window] performClose: sender];
219
    else if (sender == _yellowButton)
220
        [[self window] miniaturize: sender];
221
    else if (sender == _greenButton) {
222
        if ((OSX_YOSEMITE || OSX_EL_CAPITAN) && b_nativeFullscreenMode && !b_alt_pressed) {
223 224 225 226
            [[self window] toggleFullScreen:self];
        } else {
            [[self window] performZoom: sender];
        }
227
    } else if (sender == _fullscreenButton) {
228 229
        // same action as native fs button
        [[self window] toggleFullScreen:self];
230

231
    } else
232
        msg_Err(getIntf(), "unknown button action sender");
233 234 235

    [self setWindowButtonOver: NO];
    [self setWindowFullscreenButtonOver: NO];
236 237 238 239
}

- (void)setWindowTitle:(NSString *)title
{
240 241 242 243 244
    if (!_windowTitleShadow) {
        _windowTitleShadow = [[NSShadow alloc] init];
        [_windowTitleShadow setShadowColor:[NSColor colorWithCalibratedWhite:1.0 alpha:0.5]];
        [_windowTitleShadow setShadowOffset:NSMakeSize(0.0, -1.5)];
        [_windowTitleShadow setShadowBlurRadius:0.5];
245 246
    }

247
    NSMutableAttributedString *attributedTitleString = [[NSMutableAttributedString alloc] initWithString:title attributes: _windowTitleAttributesDictionary];
248 249
    NSUInteger i_titleLength = [title length];

250 251 252
    [attributedTitleString addAttribute:NSShadowAttributeName value:_windowTitleShadow range:NSMakeRange(0, i_titleLength)];
    [attributedTitleString setAlignment: NSCenterTextAlignment range:NSMakeRange(0, i_titleLength)];
    [_titleLabel setAttributedStringValue:attributedTitleString];
253 254
}

255 256
- (void)setWindowButtonOver:(BOOL)b_value
{
257
    b_mouse_over = b_value;
258
    if (b_value) {
259 260
        [_redButton setImage: _redHoverImage];
        [_yellowButton setImage: _yellowHoverImage];
261
    } else {
262 263
        [_redButton setImage: _redImage];
        [_yellowButton setImage: _yellowImage];
264
    }
265 266

    [self updateGreenButton];
267 268
}

269 270 271
- (void)setWindowFullscreenButtonOver:(BOOL)b_value
{
    if (b_value)
272
        [_fullscreenButton setImage: _oldFullscreenHoverImage];
273
    else
274
        [_fullscreenButton setImage: _oldFullscreenImage];
275
}
276

277
- (void)mouseDown:(NSEvent *)event
278
{
279
    NSPoint ml = [self convertPoint: [event locationInWindow] fromView: self];
280
    if (([[self window] frame].size.height - ml.y) <= 22. && [event clickCount] == 2) {
281 282 283 284 285 286 287 288
        //Get settings from "System Preferences" >  "Appearance" > "Double-click on windows title bar to minimize"
        NSString *const MDAppleMiniaturizeOnDoubleClickKey = @"AppleMiniaturizeOnDoubleClick";
        NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
        [userDefaults addSuiteNamed:NSGlobalDomain];

        if ([[userDefaults objectForKey:MDAppleMiniaturizeOnDoubleClickKey] boolValue])
            [[self window] miniaturize:self];
    }
289 290

    [super mouseDown: event];
291
}
292 293 294

- (NSButton*)closeButton
{
295
    return _redButton;
296 297 298 299
}

- (NSButton*)minimizeButton
{
300
    return _yellowButton;
301 302 303 304
}

- (NSButton*)zoomButton
{
305
    return _greenButton;
306 307
}

308 309
@end

310 311 312 313 314 315 316 317
/*****************************************************************************
 * VLCWindowButtonCell
 *
 * since the title bar cannot fetch these mouse events (the more top-level
 * NSButton is unable fetch them as well), we are using a subclass of the
 * button cell to do so. It's set in the nib for the respective objects.
 *****************************************************************************/

318 319 320 321
@implementation VLCWindowButtonCell

- (void)mouseEntered:(NSEvent *)theEvent
{
322 323 324 325
    if ([self tag] == 3)
        [(VLCMainWindowTitleView *)[[self controlView] superview] setWindowFullscreenButtonOver: YES];
    else
        [(VLCMainWindowTitleView *)[[self controlView] superview] setWindowButtonOver: YES];
326 327 328 329
}

- (void)mouseExited:(NSEvent *)theEvent
{
330 331 332 333
    if ([self tag] == 3)
        [(VLCMainWindowTitleView *)[[self controlView] superview] setWindowFullscreenButtonOver: NO];
    else
        [(VLCMainWindowTitleView *)[[self controlView] superview] setWindowButtonOver: NO];
334 335
}

336 337 338 339
/* accessibility stuff */
- (NSArray*)accessibilityAttributeNames {
    NSArray *theAttributeNames = [super accessibilityAttributeNames];
    id theControlView = [self controlView];
340
    return ([theControlView respondsToSelector: @selector(extendedAccessibilityAttributeNames:)] ? [theControlView extendedAccessibilityAttributeNames: theAttributeNames] : theAttributeNames); // ask the cell's control view (i.e., the button) for additional attribute values
341 342 343 344 345 346 347
}

- (id)accessibilityAttributeValue: (NSString*)theAttributeName {
    id theControlView = [self controlView];
    if ([theControlView respondsToSelector: @selector(extendedAccessibilityAttributeValue:)]) {
        id theValue = [theControlView extendedAccessibilityAttributeValue: theAttributeName];
        if (theValue) {
348
            return theValue; // if this is an extended attribute value we added, return that -- otherwise, fall back to super's implementation
349 350 351 352 353 354 355 356 357
        }
    }
    return [super accessibilityAttributeValue: theAttributeName];
}

- (BOOL)accessibilityIsAttributeSettable: (NSString*)theAttributeName {
    id theControlView = [self controlView];
    if ([theControlView respondsToSelector: @selector(extendedAccessibilityIsAttributeSettable:)]) {
        NSNumber *theValue = [theControlView extendedAccessibilityIsAttributeSettable: theAttributeName];
358
        if (theValue)
359
            return [theValue boolValue]; // same basic strategy we use in -accessibilityAttributeValue:
360 361 362 363
    }
    return [super accessibilityIsAttributeSettable: theAttributeName];
}

364
@end
365

366 367 368 369 370 371 372 373 374

/*****************************************************************************
 * VLCResizeControl
 *
 * For Leopard and Snow Leopard, we need to emulate the resize control on the
 * bottom right of the window, since it is gone by using the borderless window
 * mask. A proper fix would be Lion-only.
 *****************************************************************************/

375 376
@implementation VLCResizeControl

377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400
- (void)mouseDown:(NSEvent *)theEvent {
    BOOL keepOn = YES;

    while (keepOn) {
        theEvent = [[self window] nextEventMatchingMask: NSLeftMouseUpMask |
                    NSLeftMouseDraggedMask];

        switch ([theEvent type]) {
            case NSLeftMouseDragged:
            {
                NSRect windowFrame = [[self window] frame];
                CGFloat deltaX, deltaY, oldOriginY;
                deltaX = [theEvent deltaX];
                deltaY = [theEvent deltaY];
                oldOriginY = windowFrame.origin.y;

                windowFrame.origin.y = (oldOriginY + windowFrame.size.height) - (windowFrame.size.height + deltaY);
                windowFrame.size.width += deltaX;
                windowFrame.size.height += deltaY;

                NSSize winMinSize = [self window].minSize;
                if (windowFrame.size.width < winMinSize.width)
                    windowFrame.size.width = winMinSize.width;

401
                if (windowFrame.size.height < winMinSize.height) {
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416
                    windowFrame.size.height = winMinSize.height;
                    windowFrame.origin.y = oldOriginY;
                }

                [[self window] setFrame: windowFrame display: YES animate: NO];
                break;
            }
                break;
            case NSLeftMouseUp:
                keepOn = NO;
                break;
            default:
                /* Ignore any other kind of event. */
                break;
        }
417

418
    };
419

420
    return;
421 422 423
}

@end
424 425 426 427

/*****************************************************************************
 * VLCColorView
 *
428
 * since we are using a clear window color when using the black window
429 430 431 432 433 434 435 436 437 438 439
 * style, some filling is needed behind the video and some other elements
 *****************************************************************************/

@implementation VLCColorView

- (void)drawRect:(NSRect)rect {
    [[NSColor blackColor] setFill];
    NSRectFill(rect);
}

@end
440 441 442 443 444 445 446 447 448 449 450

/*****************************************************************************
 * custom window buttons to support the accessibility stuff
 *****************************************************************************/

@implementation VLCCustomWindowButtonPrototype
+ (Class)cellClass {
    return [VLCWindowButtonCell class];
}

- (NSArray*)extendedAccessibilityAttributeNames: (NSArray*)theAttributeNames {
451
    return ([theAttributeNames containsObject: NSAccessibilitySubroleAttribute] ? theAttributeNames : [theAttributeNames arrayByAddingObject: NSAccessibilitySubroleAttribute]); // run-of-the-mill button cells don't usually have a Subrole attribute, so we add that attribute
452 453 454 455 456 457 458
}

- (id)extendedAccessibilityAttributeValue: (NSString*)theAttributeName {
    return nil;
}

- (NSNumber*)extendedAccessibilityIsAttributeSettable: (NSString*)theAttributeName {
459
    return ([theAttributeName isEqualToString: NSAccessibilitySubroleAttribute] ? [NSNumber numberWithBool:NO] : nil); // make the Subrole attribute we added non-settable
460 461 462 463
}

- (void)accessibilityPerformAction: (NSString*)theActionName {
    if ([theActionName isEqualToString: NSAccessibilityPressAction]) {
464
        if ([self isEnabled])
465
            [self performClick: nil];
466
    } else
467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494
        [super accessibilityPerformAction: theActionName];
}

@end

@implementation VLCCustomWindowCloseButton
- (id)extendedAccessibilityAttributeValue: (NSString*)theAttributeName {
    return ([theAttributeName isEqualToString: NSAccessibilitySubroleAttribute] ? NSAccessibilityCloseButtonAttribute : nil);
}

@end


@implementation VLCCustomWindowMinimizeButton
- (id)extendedAccessibilityAttributeValue: (NSString*)theAttributeName {
    return ([theAttributeName isEqualToString: NSAccessibilitySubroleAttribute] ? NSAccessibilityMinimizeButtonAttribute : nil);
}

@end


@implementation VLCCustomWindowZoomButton
- (id)extendedAccessibilityAttributeValue: (NSString*)theAttributeName {
    return ([theAttributeName isEqualToString: NSAccessibilitySubroleAttribute] ? NSAccessibilityZoomButtonAttribute : nil);
}

@end

495

496 497 498 499 500
@implementation VLCCustomWindowFullscreenButton
- (id)extendedAccessibilityAttributeValue: (NSString*)theAttributeName {
    return ([theAttributeName isEqualToString: NSAccessibilitySubroleAttribute] ? NSAccessibilityFullScreenButtonAttribute : nil);
}
@end
501 502


503 504 505 506 507 508
@interface VLCWindowTitleTextField()
{
    NSMenu *_contextMenu;
}
@end

509 510 511 512 513
@implementation VLCWindowTitleTextField

- (void)showRightClickMenuWithEvent:(NSEvent *)o_event
{
    NSURL * representedURL = [[self window] representedURL];
514
    if (!representedURL)
515 516 517
        return;

    NSArray * pathComponents;
518
    pathComponents = [representedURL pathComponents];
519 520 521 522

    if (!pathComponents)
        return;

523
    _contextMenu = [[NSMenu alloc] initWithTitle: [[NSFileManager defaultManager] displayNameAtPath: [representedURL path]]];
524 525 526 527 528

    NSUInteger count = [pathComponents count];
    NSImage * icon;
    NSMenuItem * currentItem;
    NSMutableString * currentPath;
529
    NSSize iconSize = NSMakeSize(16., 16.);
530 531 532
    for (NSUInteger i = count - 1; i > 0; i--) {
        currentPath = [NSMutableString stringWithCapacity:1024];
        for (NSUInteger y = 0; y < i; y++)
533
            [currentPath appendFormat: @"/%@", [pathComponents objectAtIndex:y + 1]];
534

535 536
        [_contextMenu addItemWithTitle: [[NSFileManager defaultManager] displayNameAtPath: currentPath] action:@selector(revealInFinder:) keyEquivalent:@""];
        currentItem = [_contextMenu itemAtIndex:[_contextMenu numberOfItems] - 1];
537 538 539 540 541 542 543
        [currentItem setTarget: self];

        icon = [[NSWorkspace sharedWorkspace] iconForFile:currentPath];
        [icon setSize: iconSize];
        [currentItem setImage: icon];
    }

544
    if ([[pathComponents objectAtIndex:1] isEqualToString:@"Volumes"]) {
545
        /* we don't want to show the Volumes item, since the Cocoa does it neither */
546
        currentItem = [_contextMenu itemWithTitle:[[NSFileManager defaultManager] displayNameAtPath: @"/Volumes"]];
547
        if (currentItem)
548
            [_contextMenu removeItem: currentItem];
549 550
    } else {
        /* we're on the boot drive, so add it since it isn't part of the components */
551 552
        [_contextMenu addItemWithTitle: [[NSFileManager defaultManager] displayNameAtPath:@"/"] action:@selector(revealInFinder:) keyEquivalent:@""];
        currentItem = [_contextMenu itemAtIndex: [_contextMenu numberOfItems] - 1];
553 554 555 556 557 558 559
        icon = [[NSWorkspace sharedWorkspace] iconForFile:@"/"];
        [icon setSize: iconSize];
        [currentItem setImage: icon];
        [currentItem setTarget: self];
    }

    /* add the computer item */
560 561
    [_contextMenu addItemWithTitle:(NSString*)CFBridgingRelease(SCDynamicStoreCopyComputerName(NULL, NULL)) action:@selector(revealInFinder:) keyEquivalent:@""];
    currentItem = [_contextMenu itemAtIndex: [_contextMenu numberOfItems] - 1];
562 563 564 565 566
    icon = [NSImage imageNamed: NSImageNameComputer];
    [icon setSize: iconSize];
    [currentItem setImage: icon];
    [currentItem setTarget: self];

567
    // center the context menu similar to the white interface
568
    CGFloat menuWidth = [_contextMenu size].width;
569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590
    NSRect windowFrame = [[self window] frame];
    NSPoint point;

    CGFloat fullButtonWidth = 0.;
    if([[VLCMain sharedInstance] nativeFullscreenMode])
        fullButtonWidth = 20.;

    // assumes 60 px for the window buttons
    point.x = (windowFrame.size.width - 60. - fullButtonWidth) / 2. - menuWidth / 2. + 60. - 20.;
    point.y = windowFrame.size.height + 1.;
    if (point.x < 0)
        point.x = 10;

    NSEvent *fakeMouseEvent = [NSEvent mouseEventWithType:NSRightMouseDown
                                                 location:point
                                            modifierFlags:0
                                                timestamp:0
                                             windowNumber:[[self window] windowNumber]
                                                  context:nil
                                              eventNumber:0
                                               clickCount:0
                                                 pressure:0];
591
    [NSMenu popUpContextMenu: _contextMenu withEvent: fakeMouseEvent forView: [self superview]];
592 593 594 595
}

- (IBAction)revealInFinder:(id)sender
{
596 597
    NSUInteger count = [_contextMenu numberOfItems];
    NSUInteger selectedItem = [_contextMenu indexOfItem: sender];
598

599
    if (selectedItem == count - 1) { // the fake computer item
600 601 602 603 604 605 606 607
        [[NSWorkspace sharedWorkspace] selectFile: @"/" inFileViewerRootedAtPath: @""];
        return;
    }

    NSURL * representedURL = [[self window] representedURL];
    if (! representedURL)
        return;

608
    if (selectedItem == 0) { // the actual file, let's save time
609 610 611 612 613
        [[NSWorkspace sharedWorkspace] selectFile: [representedURL path] inFileViewerRootedAtPath: [representedURL path]];
        return;
    }

    NSArray * pathComponents;
614
    pathComponents = [representedURL pathComponents];
615 616 617 618 619 620
    if (!pathComponents)
        return;

    NSMutableString * currentPath;
    currentPath = [NSMutableString stringWithCapacity:1024];
    selectedItem = count - selectedItem;
621 622

    /* fix for non-startup volumes */
623
    if ([[pathComponents objectAtIndex:1] isEqualToString:@"Volumes"])
624 625
        selectedItem += 1;

626
    for (NSUInteger y = 1; y < selectedItem; y++)
627
        [currentPath appendFormat: @"/%@", [pathComponents objectAtIndex:y]];
628 629 630 631 632 633

    [[NSWorkspace sharedWorkspace] selectFile: currentPath inFileViewerRootedAtPath: currentPath];
}

- (void)rightMouseDown:(NSEvent *)o_event
{
634
    if ([o_event type] == NSRightMouseDown)
635 636 637 638 639 640
        [self showRightClickMenuWithEvent:o_event];

    [super mouseDown: o_event];
}

@end