From 47a38daee20ef77cc98bc13bb7a7c1d690fd635c Mon Sep 17 00:00:00 2001 From: Micha Hanselmann Date: Wed, 31 Jul 2019 10:52:50 -0700 Subject: [PATCH] feat: migrate custom macOS tray view to native one (#18981) * restore stash revert some things work others dont tracking area for rescue manual popup restore drag n drop cleanup * fix: make tray not block main process (#18880) * fix: make tray not block main process * make AtomMenuModel refcounted * add support for ansi codes in title add remove TODOs * chore: use ScopedPumpMessagesInPrivateModes in tray (#18977) * chore: use ScopedPumpMessagesInPrivateModes in tray * revert refcounting of AtomMenuModel * Prefer WeakPtr for posting tasks to handle unexpected destruction * cleanup .h * cleanup .mm * add imports add missing include * fix: crash when tray popup called twice (#18999) * remove highlightMode and TODOs * remove unnecessary copy --- docs/api/tray.md | 33 --- lib/browser/api/tray.js | 3 - shell/browser/api/atom_api_tray.cc | 33 --- shell/browser/api/atom_api_tray.h | 1 - shell/browser/ui/tray_icon.cc | 2 - shell/browser/ui/tray_icon.h | 8 - shell/browser/ui/tray_icon_cocoa.h | 12 +- shell/browser/ui/tray_icon_cocoa.mm | 317 +++++----------------------- 8 files changed, 51 insertions(+), 358 deletions(-) diff --git a/docs/api/tray.md b/docs/api/tray.md index 0411b93867..c299f086d9 100644 --- a/docs/api/tray.md +++ b/docs/api/tray.md @@ -206,39 +206,6 @@ Sets the title displayed next to the tray icon in the status bar (Support ANSI c Returns `String` - the title displayed next to the tray icon in the status bar -#### `tray.setHighlightMode(mode)` _macOS_ - -* `mode` String - Highlight mode with one of the following values: - * `selection` - Highlight the tray icon when it is clicked and also when - its context menu is open. This is the default. - * `always` - Always highlight the tray icon. - * `never` - Never highlight the tray icon. - -Sets when the tray's icon background becomes highlighted (in blue). - -**[Deprecated](breaking-changes.md#tray)** - -**Note:** You can use `highlightMode` with a [`BrowserWindow`](browser-window.md) -by toggling between `'never'` and `'always'` modes when the window visibility -changes. - -```javascript -const { BrowserWindow, Tray } = require('electron') - -const win = new BrowserWindow({ width: 800, height: 600 }) -const tray = new Tray('/path/to/my/icon') - -tray.on('click', () => { - win.isVisible() ? win.hide() : win.show() -}) -win.on('show', () => { - tray.setHighlightMode('always') -}) -win.on('hide', () => { - tray.setHighlightMode('never') -}) -``` - #### `tray.setIgnoreDoubleClickEvents(ignore)` _macOS_ * `ignore` Boolean diff --git a/lib/browser/api/tray.js b/lib/browser/api/tray.js index 135923d248..b7402858bf 100644 --- a/lib/browser/api/tray.js +++ b/lib/browser/api/tray.js @@ -6,7 +6,4 @@ const { Tray } = process.electronBinding('tray') Object.setPrototypeOf(Tray.prototype, EventEmitter.prototype) -// Deprecations -Tray.prototype.setHighlightMode = deprecate.removeFunction(Tray.prototype.setHighlightMode, 'setHighlightMode') - module.exports = Tray diff --git a/shell/browser/api/atom_api_tray.cc b/shell/browser/api/atom_api_tray.cc index 9700440937..9ef5a2b3ce 100644 --- a/shell/browser/api/atom_api_tray.cc +++ b/shell/browser/api/atom_api_tray.cc @@ -18,34 +18,6 @@ #include "shell/common/node_includes.h" #include "ui/gfx/image/image.h" -namespace mate { - -template <> -struct Converter { - static bool FromV8(v8::Isolate* isolate, - v8::Local val, - electron::TrayIcon::HighlightMode* out) { - using HighlightMode = electron::TrayIcon::HighlightMode; - std::string mode; - if (ConvertFromV8(isolate, val, &mode)) { - if (mode == "always") { - *out = HighlightMode::ALWAYS; - return true; - } - if (mode == "selection") { - *out = HighlightMode::SELECTION; - return true; - } - if (mode == "never") { - *out = HighlightMode::NEVER; - return true; - } - } - return false; - } -}; -} // namespace mate - namespace electron { namespace api { @@ -169,10 +141,6 @@ std::string Tray::GetTitle() { #endif } -void Tray::SetHighlightMode(TrayIcon::HighlightMode mode) { - tray_icon_->SetHighlightMode(mode); -} - void Tray::SetIgnoreDoubleClickEvents(bool ignore) { #if defined(OS_MACOSX) tray_icon_->SetIgnoreDoubleClickEvents(ignore); @@ -235,7 +203,6 @@ void Tray::BuildPrototype(v8::Isolate* isolate, .SetMethod("setToolTip", &Tray::SetToolTip) .SetMethod("setTitle", &Tray::SetTitle) .SetMethod("getTitle", &Tray::GetTitle) - .SetMethod("setHighlightMode", &Tray::SetHighlightMode) .SetMethod("setIgnoreDoubleClickEvents", &Tray::SetIgnoreDoubleClickEvents) .SetMethod("getIgnoreDoubleClickEvents", diff --git a/shell/browser/api/atom_api_tray.h b/shell/browser/api/atom_api_tray.h index 4d9dc12552..eafb27bf1f 100644 --- a/shell/browser/api/atom_api_tray.h +++ b/shell/browser/api/atom_api_tray.h @@ -70,7 +70,6 @@ class Tray : public mate::TrackableObject, public TrayIconObserver { void SetToolTip(const std::string& tool_tip); void SetTitle(const std::string& title); std::string GetTitle(); - void SetHighlightMode(TrayIcon::HighlightMode mode); void SetIgnoreDoubleClickEvents(bool ignore); bool GetIgnoreDoubleClickEvents(); void DisplayBalloon(mate::Arguments* args, const mate::Dictionary& options); diff --git a/shell/browser/ui/tray_icon.cc b/shell/browser/ui/tray_icon.cc index 555eb05ed6..70db482fb8 100644 --- a/shell/browser/ui/tray_icon.cc +++ b/shell/browser/ui/tray_icon.cc @@ -12,8 +12,6 @@ TrayIcon::~TrayIcon() {} void TrayIcon::SetPressedImage(ImageType image) {} -void TrayIcon::SetHighlightMode(TrayIcon::HighlightMode mode) {} - void TrayIcon::DisplayBalloon(ImageType icon, const base::string16& title, const base::string16& contents) {} diff --git a/shell/browser/ui/tray_icon.h b/shell/browser/ui/tray_icon.h index 8169180c60..b062d70c2f 100644 --- a/shell/browser/ui/tray_icon.h +++ b/shell/browser/ui/tray_icon.h @@ -39,14 +39,6 @@ class TrayIcon { // status icon (e.g. Ubuntu Unity). virtual void SetToolTip(const std::string& tool_tip) = 0; - // Sets the status icon highlight mode. This only works on macOS. - enum class HighlightMode { - ALWAYS, // Always highlight the tray icon - NEVER, // Never highlight the tray icon - SELECTION // Highlight the tray icon when clicked or the menu is opened - }; - virtual void SetHighlightMode(HighlightMode mode); - #if defined(OS_MACOSX) // Set/Get flag determining whether to ignore double click events. virtual void SetIgnoreDoubleClickEvents(bool ignore) = 0; diff --git a/shell/browser/ui/tray_icon_cocoa.h b/shell/browser/ui/tray_icon_cocoa.h index a158d796ce..7b38fa84c5 100644 --- a/shell/browser/ui/tray_icon_cocoa.h +++ b/shell/browser/ui/tray_icon_cocoa.h @@ -17,7 +17,7 @@ namespace electron { -class TrayIconCocoa : public TrayIcon, public AtomMenuModel::Observer { +class TrayIconCocoa : public TrayIcon { public: TrayIconCocoa(); ~TrayIconCocoa() override; @@ -27,7 +27,6 @@ class TrayIconCocoa : public TrayIcon, public AtomMenuModel::Observer { void SetToolTip(const std::string& tool_tip) override; void SetTitle(const std::string& title) override; std::string GetTitle() override; - void SetHighlightMode(TrayIcon::HighlightMode mode) override; void SetIgnoreDoubleClickEvents(bool ignore) override; bool GetIgnoreDoubleClickEvents() override; void PopUpOnUI(AtomMenuModel* menu_model); @@ -36,20 +35,13 @@ class TrayIconCocoa : public TrayIcon, public AtomMenuModel::Observer { void SetContextMenu(AtomMenuModel* menu_model) override; gfx::Rect GetBounds() override; - protected: - // AtomMenuModel::Observer: - void OnMenuWillClose() override; - private: - // Atom custom view for NSStatusItem. + // Electron custom view for NSStatusItem. base::scoped_nsobject status_item_view_; // Status menu shown when right-clicking the system icon. base::scoped_nsobject menu_; - // Used for unregistering observer. - AtomMenuModel* menu_model_ = nullptr; // weak ref. - base::WeakPtrFactory weak_factory_; DISALLOW_COPY_AND_ASSIGN(TrayIconCocoa); diff --git a/shell/browser/ui/tray_icon_cocoa.mm b/shell/browser/ui/tray_icon_cocoa.mm index 12303bf35e..96ff2ffc58 100644 --- a/shell/browser/ui/tray_icon_cocoa.mm +++ b/shell/browser/ui/tray_icon_cocoa.mm @@ -7,42 +7,22 @@ #include #include -#include "base/mac/sdk_forward_declarations.h" #include "base/message_loop/message_loop.h" +#include "base/message_loop/message_pump_mac.h" #include "base/strings/sys_string_conversions.h" #include "base/task/post_task.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" -#include "shell/browser/mac/atom_application.h" #include "shell/browser/ui/cocoa/NSString+ANSI.h" #include "shell/browser/ui/cocoa/atom_menu_controller.h" -#include "ui/display/screen.h" #include "ui/events/cocoa/cocoa_event_utils.h" -#include "ui/gfx/image/image.h" #include "ui/gfx/mac/coordinate_conversion.h" #include "ui/native_theme/native_theme.h" -namespace { - -// By default, macOS sets 4px to tray image as left and right padding margin. -const CGFloat kHorizontalMargin = 4; -// macOS tends to make the title 2px lower. -const CGFloat kVerticalTitleMargin = 2; - -} // namespace - @interface StatusItemView : NSView { electron::TrayIconCocoa* trayIcon_; // weak AtomMenuController* menuController_; // weak - electron::TrayIcon::HighlightMode highlight_mode_; BOOL ignoreDoubleClickEvents_; - BOOL forceHighlight_; - BOOL inMouseEventSequence_; - BOOL ANSI_; - base::scoped_nsobject image_; - base::scoped_nsobject alternateImage_; - base::scoped_nsobject title_; - base::scoped_nsobject attributedTitle_; base::scoped_nsobject statusItem_; base::scoped_nsobject trackingArea_; } @@ -60,10 +40,7 @@ const CGFloat kVerticalTitleMargin = 2; - (id)initWithIcon:(electron::TrayIconCocoa*)icon { trayIcon_ = icon; menuController_ = nil; - highlight_mode_ = electron::TrayIcon::HighlightMode::SELECTION; ignoreDoubleClickEvents_ = NO; - forceHighlight_ = NO; - inMouseEventSequence_ = NO; if ((self = [super initWithFrame:CGRectZero])) { [self registerForDraggedTypes:@[ @@ -75,157 +52,47 @@ const CGFloat kVerticalTitleMargin = 2; NSStatusItem* item = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength]; statusItem_.reset([item retain]); - [statusItem_ setView:self]; - // Finalize setup by sizing our views + [[statusItem_ button] addSubview:self]; // inject custom view [self updateDimensions]; - - // Add NSTrackingArea for listening to mouseEnter, mouseExit, and mouseMove - // events - trackingArea_.reset([[NSTrackingArea alloc] - initWithRect:[self bounds] - options:NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | - NSTrackingActiveAlways - owner:self - userInfo:nil]); - [self addTrackingArea:trackingArea_]; } return self; } - (void)updateDimensions { - NSStatusBar* bar = [NSStatusBar systemStatusBar]; - [self setFrame:NSMakeRect(0, 0, [self fullWidth], [bar thickness])]; - [self setNeedsDisplay:YES]; + [self setFrame:[statusItem_ button].frame]; +} + +- (void)updateTrackingAreas { + // Use NSTrackingArea for listening to mouseEnter, mouseExit, and mouseMove + // events. + [self removeTrackingArea:trackingArea_]; + trackingArea_.reset([[NSTrackingArea alloc] + initWithRect:[self bounds] + options:NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | + NSTrackingActiveAlways + owner:self + userInfo:nil]); + [self addTrackingArea:trackingArea_]; } - (void)removeItem { - // Turn off tracking events to prevent crash + // Turn off tracking events to prevent crash. if (trackingArea_) { [self removeTrackingArea:trackingArea_]; trackingArea_.reset(); } [[NSStatusBar systemStatusBar] removeStatusItem:statusItem_]; - [statusItem_ setView:nil]; + [self removeFromSuperview]; statusItem_.reset(); } -- (void)drawRect:(NSRect)dirtyRect { - // Draw the tray icon and title that align with NSStatusItem, layout: - // ---------------- - // | icon | title | - /// ---------------- - - CGFloat thickness = [[statusItem_ statusBar] thickness]; - - // Draw the system bar background. - [statusItem_ drawStatusBarBackgroundInRect:self.bounds - withHighlight:[self shouldHighlight]]; - - // Determine which image to use. - NSImage* image = image_.get(); - if (inMouseEventSequence_ && alternateImage_) { - image = alternateImage_.get(); - } - // Apply the higlight color if the image is a template image. When this moves - // to using the new [NSStatusItem button] API, this should work automagically. - if ([image isTemplate] == YES) { - NSImage* imageWithColor = [[image copy] autorelease]; - [imageWithColor lockFocus]; - [[self colorWithHighlight:[self isHighlighted]] set]; - CGRect imageBounds = CGRectMake(0, 0, image.size.width, image.size.height); - NSRectFillUsingOperation(imageBounds, NSCompositeSourceAtop); - [imageWithColor unlockFocus]; - image = imageWithColor; - } - - // Draw the image - [image - drawInRect:CGRectMake(roundf(([self iconWidth] - image.size.width) / 2), - roundf((thickness - image.size.height) / 2), - image.size.width, image.size.height)]; - - if (title_) { - // Draw title. - NSRect titleDrawRect = NSMakeRect([self iconWidth], -kVerticalTitleMargin, - [self titleWidth], thickness); - [attributedTitle_ drawInRect:titleDrawRect]; - } -} - -- (BOOL)isDarkMode { - if (@available(macOS 10.14, *)) { - return ui::NativeTheme::GetInstanceForNativeUi()->SystemDarkModeEnabled(); - } - NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; - NSString* mode = [defaults stringForKey:@"AppleInterfaceStyle"]; - return mode && [mode isEqualToString:@"Dark"]; -} - -- (BOOL)isHighlighted { - BOOL highlight = [self shouldHighlight]; - return highlight | [self isDarkMode]; -} - -// The width of the full status item. -- (CGFloat)fullWidth { - if (title_) - return [self iconWidth] + [self titleWidth] + kHorizontalMargin; - else - return [self iconWidth]; -} - -// The width of the icon. -- (CGFloat)iconWidth { - if (!image_ && title_) - return kHorizontalMargin; - CGFloat thickness = [[NSStatusBar systemStatusBar] thickness]; - CGFloat imageHeight = [image_ size].height; - CGFloat imageWidth = [image_ size].width; - CGFloat iconWidth = imageWidth; - if (imageWidth < thickness) { - // Image's width must be larger than menu bar's height. - iconWidth = thickness; - } else { - CGFloat verticalMargin = thickness - imageHeight; - // Image must have same horizontal vertical margin. - if (verticalMargin > 0 && imageWidth != imageHeight) - iconWidth = imageWidth + verticalMargin; - CGFloat horizontalMargin = thickness - imageWidth; - // Image must have at least kHorizontalMargin horizontal margin on each - // side. - if (horizontalMargin < 2 * kHorizontalMargin) - iconWidth = imageWidth + 2 * kHorizontalMargin; - } - return iconWidth; -} - -// The width of the title. -- (CGFloat)titleWidth { - if (!title_) - return 0; - return [attributedTitle_ size].width; -} - -- (NSColor*)colorWithHighlight:(BOOL)highlight { - return highlight ? [NSColor whiteColor] - : [NSColor colorWithRed:0.265625 - green:0.25390625 - blue:0.234375 - alpha:1.0]; -} - - (void)setImage:(NSImage*)image { - image_.reset([image copy]); + [[statusItem_ button] setImage:[image copy]]; [self updateDimensions]; } - (void)setAlternateImage:(NSImage*)image { - alternateImage_.reset([image copy]); -} - -- (void)setHighlight:(electron::TrayIcon::HighlightMode)mode { - highlight_mode_ = mode; - [self setNeedsDisplay:YES]; + [[statusItem_ button] setAlternateImage:[image copy]]; } - (void)setIgnoreDoubleClickEvents:(BOOL)ignore { @@ -237,83 +104,44 @@ const CGFloat kVerticalTitleMargin = 2; } - (void)setTitle:(NSString*)title { - if (title.length > 0) { - title_.reset([title copy]); - ANSI_ = [title containsANSICodes]; + if ([title containsANSICodes]) { + [[statusItem_ button] + setAttributedTitle:[title attributedStringParsingANSICodes]]; } else { - title_.reset(); - ANSI_ = NO; + [[statusItem_ button] setTitle:[title copy]]; } - [self updateAttributedTitle]; + + // Fix icon margins. + if (title.length > 0) { + [[statusItem_ button] setImagePosition:NSImageLeft]; + } else { + [[statusItem_ button] setImagePosition:NSImageOnly]; + } + [self updateDimensions]; } - (NSString*)title { - return title_; -} - -- (void)updateAttributedTitle { - NSDictionary* attributes = - @{NSFontAttributeName : [NSFont menuBarFontOfSize:0]}; - - if (ANSI_) { - NSCharacterSet* whites = [NSCharacterSet whitespaceCharacterSet]; - NSString* title = [title_ stringByTrimmingCharactersInSet:whites]; - attributedTitle_.reset([title attributedStringParsingANSICodes]); - [attributedTitle_ addAttributes:attributes - range:NSMakeRange(0, [attributedTitle_ length])]; - return; - } - - // check title_ being nil - NSString* title = @""; - if (title_) - title = title_; - - attributedTitle_.reset([[NSMutableAttributedString alloc] - initWithString:title - attributes:attributes]); - - // NSFontAttributeName:[NSFont menuBarFontOfSize:0], - // NSForegroundColorAttributeName:[self colorWithHighlight: highlight] - [attributedTitle_ addAttributes:attributes - range:NSMakeRange(0, [attributedTitle_ length])]; - [attributedTitle_ addAttribute:NSForegroundColorAttributeName - value:[self colorWithHighlight:[self isHighlighted]] - range:NSMakeRange(0, [attributedTitle_ length])]; + return [statusItem_ button].title; } - (void)setMenuController:(AtomMenuController*)menu { menuController_ = menu; + [statusItem_ setMenu:[menuController_ menu]]; } - (void)mouseDown:(NSEvent*)event { - inMouseEventSequence_ = YES; - [self setNeedsDisplay:YES]; + // Pass click to superclass to show menu. Custom mouseUp handler won't be + // invoked. + if (menuController_) { + [super mouseDown:event]; + } else { + [[statusItem_ button] highlight:YES]; + } } - (void)mouseUp:(NSEvent*)event { - if (!inMouseEventSequence_) { - // If the menu is showing, when user clicked the tray icon, the `mouseDown` - // event will be dissmissed, we need to close the menu at this time. - [self setNeedsDisplay:YES]; - return; - } - inMouseEventSequence_ = NO; - - // Show menu when there is a context menu. - // NB(hokein): Make tray's behavior more like official one's. - // When the tray icon gets clicked quickly multiple times, the - // event.clickCount doesn't always return 1. Instead, it returns a value that - // counts the clicked times. - // So we don't check the clickCount here, just pop up the menu for each click - // event. - if (menuController_) - [statusItem_ popUpStatusItemMenu:[menuController_ menu]]; - - // Don't emit click events when menu is showing. - if (menuController_) - return; + [[statusItem_ button] highlight:NO]; // If we are ignoring double click events, we should ignore the `clickCount` // value and immediately emit a click event. @@ -332,8 +160,6 @@ const CGFloat kVerticalTitleMargin = 2; trayIcon_->NotifyDoubleClicked( gfx::ScreenRectFromNSRect(event.window.frame), ui::EventFlagsFromModifiers([event modifierFlags])); - - [self setNeedsDisplay:YES]; } - (void)popUpContextMenu:(electron::AtomMenuModel*)menu_model { @@ -345,12 +171,10 @@ const CGFloat kVerticalTitleMargin = 2; base::scoped_nsobject menuController( [[AtomMenuController alloc] initWithModel:menu_model useDefaultAccelerator:NO]); - forceHighlight_ = YES; // Should highlight when showing menu. - [self setNeedsDisplay:YES]; - - [statusItem_ popUpStatusItemMenu:[menuController menu]]; - forceHighlight_ = NO; - [self setNeedsDisplay:YES]; + // Hacky way to mimic design of ordinary tray menu. + [statusItem_ setMenu:[menuController menu]]; + [[statusItem_ button] performClick:self]; + [statusItem_ setMenu:[menuController_ menu]]; return; } @@ -358,13 +182,7 @@ const CGFloat kVerticalTitleMargin = 2; // Ensure the UI can update while the menu is fading out. base::ScopedPumpMessagesInPrivateModes pump_private; - // Redraw the tray icon to show highlight if it is enabled. - [self setNeedsDisplay:YES]; - - [statusItem_ popUpStatusItemMenu:[menuController_ menu]]; - // The popUpStatusItemMenu returns only after the showing menu is closed. - // When it returns, we need to redraw the tray icon to not show highlight. - [self setNeedsDisplay:YES]; + [[statusItem_ button] performClick:self]; } } @@ -437,24 +255,6 @@ const CGFloat kVerticalTitleMargin = 2; return YES; } -- (void)setNeedsDisplay:(BOOL)display { - [self updateAttributedTitle]; - [super setNeedsDisplay:display]; -} - -- (BOOL)shouldHighlight { - using HighlightMode = electron::TrayIcon::HighlightMode; - switch (highlight_mode_) { - case HighlightMode::ALWAYS: - return true; - case HighlightMode::NEVER: - return false; - case HighlightMode::SELECTION: - BOOL isMenuOpen = menuController_ && [menuController_ isMenuOpen]; - return forceHighlight_ || inMouseEventSequence_ || isMenuOpen; - } -} - @end namespace electron { @@ -465,12 +265,10 @@ TrayIconCocoa::TrayIconCocoa() : weak_factory_(this) { TrayIconCocoa::~TrayIconCocoa() { [status_item_view_ removeItem]; - if (menu_model_) - menu_model_->RemoveObserver(this); } void TrayIconCocoa::SetImage(const gfx::Image& image) { - [status_item_view_ setImage:image.IsEmpty() ? nil : image.AsNSImage()]; + [status_item_view_ setImage:image.AsNSImage()]; } void TrayIconCocoa::SetPressedImage(const gfx::Image& image) { @@ -489,10 +287,6 @@ std::string TrayIconCocoa::GetTitle() { return base::SysNSStringToUTF8([status_item_view_ title]); } -void TrayIconCocoa::SetHighlightMode(TrayIcon::HighlightMode mode) { - [status_item_view_ setHighlight:mode]; -} - void TrayIconCocoa::SetIgnoreDoubleClickEvents(bool ignore) { [status_item_view_ setIgnoreDoubleClickEvents:ignore]; } @@ -514,31 +308,18 @@ void TrayIconCocoa::PopUpContextMenu(const gfx::Point& pos, } void TrayIconCocoa::SetContextMenu(AtomMenuModel* menu_model) { - // Substribe to MenuClosed event. - if (menu_model_) - menu_model_->RemoveObserver(this); - - menu_model_ = menu_model; - if (menu_model) { - menu_model->AddObserver(this); // Create native menu. menu_.reset([[AtomMenuController alloc] initWithModel:menu_model useDefaultAccelerator:NO]); } else { menu_.reset(); } - [status_item_view_ setMenuController:menu_.get()]; } gfx::Rect TrayIconCocoa::GetBounds() { - auto bounds = gfx::ScreenRectFromNSRect([status_item_view_ window].frame); - return bounds; -} - -void TrayIconCocoa::OnMenuWillClose() { - [status_item_view_ setNeedsDisplay:YES]; + return gfx::ScreenRectFromNSRect([status_item_view_ window].frame); } // static