{"action":"created","comment":{"url":"https://api.github.com/repos/atom/electron/pulls/comments/34776719","id":34776719,"diff_hunk":"@@ -9,81 +9,216 @@\n #include \"ui/gfx/image/image.h\"\n #include \"ui/gfx/screen.h\"\n \n-@interface StatusItemController : NSObject {\n+const CGFloat kStatusItemLength = 26;\n+const CGFloat kMargin = 3;\n+\n+@interface StatusItemView : NSView {\n   atom::TrayIconCocoa* trayIcon_; // weak\n+  AtomMenuController* menuController_; // weak\n+  BOOL isHighlightEnable_;\n+  BOOL inMouseEventSequence_;\n+  base::scoped_nsobject<NSImage> image_;\n+  base::scoped_nsobject<NSImage> alternateImage_;\n+  base::scoped_nsobject<NSString> title_;\n+  base::scoped_nsobject<NSStatusItem> statusItem_;\n }\n-- (id)initWithIcon:(atom::TrayIconCocoa*)icon;\n-- (void)handleClick:(id)sender;\n-- (void)handleDoubleClick:(id)sender;\n \n-@end // @interface StatusItemController\n+@end  // @interface StatusItemView\n \n-@implementation StatusItemController\n+@implementation StatusItemView\n \n - (id)initWithIcon:(atom::TrayIconCocoa*)icon {\n   trayIcon_ = icon;\n+  isHighlightEnable_ = YES;\n+  statusItem_.reset([[[NSStatusBar systemStatusBar] statusItemWithLength:\n+      NSVariableStatusItemLength] retain]);\n+  NSRect frame = NSMakeRect(0,\n+                            0,\n+                            kStatusItemLength,\n+                            [[statusItem_ statusBar] thickness]);\n+  if ((self = [super initWithFrame:frame])) {\n+    [statusItem_ setView:self];\n+  }\n   return self;\n }\n \n-- (void)handleClick:(id)sender {\n-  // Get the frame of the NSStatusItem.\n-  NSRect frame = [NSApp currentEvent].window.frame;\n-  gfx::Rect bounds(frame.origin.x, 0, NSWidth(frame), NSHeight(frame));\n-  // Flip coordinates to gfx (0,0 in top-left corner) using current screen.\n-  NSScreen* screen = [[NSScreen screens] objectAtIndex:0];\n-  bounds.set_y(NSHeight([screen frame]) - NSMaxY(frame));\n+- (void)removeItem {\n+  [[NSStatusBar systemStatusBar] removeStatusItem:statusItem_];\n+  statusItem_.reset();\n+}\n+\n+- (void)drawRect:(NSRect)dirtyRect {\n+  // Draw the tray icon and title that align with NSSStatusItem, layout:\n+  //   ----------------\n+  //   | icon | title |\n+  ///  ----------------\n+  BOOL highlight = [self shouldHighlight];\n+  CGFloat titleWidth = [self titleWidth];\n+  // Calculate the total icon bounds.\n+  NSRect statusItemBounds = NSMakeRect(0,\n+                                       0,\n+                                       kStatusItemLength + titleWidth,\n+                                       [[statusItem_ statusBar] thickness]);\n+  [statusItem_ drawStatusBarBackgroundInRect:statusItemBounds\n+                               withHighlight:highlight];\n+  [statusItem_ setLength:titleWidth + kStatusItemLength];\n+  if (title_) {\n+    NSRect titleDrawRect = NSMakeRect(kStatusItemLength,\n+                                      0,\n+                                      titleWidth + kStatusItemLength,\n+                                      [[statusItem_ statusBar] thickness]);\n+    [title_ drawInRect:titleDrawRect\n+        withAttributes:[self titleAttributes]];\n+  }\n+\n+  NSRect iconRect = NSMakeRect(0,\n+                               0,\n+                               kStatusItemLength,\n+                               [[statusItem_ statusBar] thickness]);\n+  if (highlight && alternateImage_) {\n+    [alternateImage_ drawInRect:NSInsetRect(iconRect, kMargin, kMargin)\n+                       fromRect:NSZeroRect\n+                      operation:NSCompositeSourceOver\n+                       fraction:1];\n+  } else {\n+    [image_ drawInRect:NSInsetRect(iconRect, kMargin, kMargin)\n+              fromRect:NSZeroRect\n+             operation:NSCompositeSourceOver\n+              fraction:1];\n+  }\n+}\n+\n+- (CGFloat) titleWidth {\n+  if (!title_) return 0;\n+  NSAttributedString* attributes =\n+      [[NSAttributedString alloc] initWithString:title_\n+                                      attributes:[self titleAttributes]];\n+  return [attributes size].width;\n+}\n+\n+- (NSDictionary *)titleAttributes {\n+  NSFont* font = [NSFont menuBarFontOfSize:0];\n+  NSColor* foregroundColor = [NSColor blackColor];\n+\n+  return [NSDictionary dictionaryWithObjectsAndKeys:\n+          font, NSFontAttributeName,\n+          foregroundColor, NSForegroundColorAttributeName,\n+          nil];\n+}\n+\n+- (void)setImage:(NSImage*)image {\n+  image_.reset([image copy]);\n+}\n+\n+- (void)setAlternateImage:(NSImage*)image {\n+  alternateImage_.reset([image copy]);\n+}\n+\n+- (void)setHighlight:(BOOL)highlight {\n+  isHighlightEnable_ = highlight;\n+}\n \n-  trayIcon_->NotifyClicked(bounds);\n+-(void)setTitle:(NSString*) title {\n+  title_.reset([title copy]);\n }\n \n-- (void)handleDoubleClick:(id)sender {\n-  trayIcon_->NotifyDoubleClicked();\n+- (void)setMenuController:(AtomMenuController*)menu {\n+  menuController_ = menu;\n }\n \n+-(void)mouseDown:(NSEvent *)event {\n+  inMouseEventSequence_ = YES;\n+  [self setNeedsDisplay:YES];\n+}\n+\n+-(void)mouseUp:(NSEvent *)event {\n+  if (!inMouseEventSequence_) {\n+     // If the menu is showing, when user clicked the tray icon, the `mouseDown`\n+     // event will be dissmissed, we need to close the menu at this time.\n+     [self setNeedsDisplay:YES];\n+     return;\n+  }\n+  inMouseEventSequence_ = NO;\n+  if (event.clickCount == 1) {\n+    if (menuController_) {\n+      [statusItem_ popUpStatusItemMenu:[menuController_ menu]];\n+    }\n+\n+    trayIcon_->NotifyClicked([self getBoundsFromEvent:event]);\n+  }\n+\n+  if (event.clickCount == 2 && !menuController_) {\n+    trayIcon_->NotifyDoubleClicked();\n+  }\n+  [self setNeedsDisplay:YES];\n+}\n+\n+- (void)popContextMenu {\n+  if (menuController_ && ![menuController_ isMenuOpen]) {\n+    // redraw the dray icon to show highlight if it is enabled.\n+    [self setNeedsDisplay:YES];\n+    [statusItem_ popUpStatusItemMenu:[menuController_ menu]];\n+    // The popUpStatusItemMenu returns only after the showing menu is closed.\n+    // When it returns, we need to redraw the tray icon to not show highlight.\n+    [self setNeedsDisplay:YES];\n+  }\n+}\n+\n+- (void)rightMouseUp:(NSEvent*)event {\n+  trayIcon_->NotifyRightClicked([self getBoundsFromEvent:event]);\n+}\n+\n+-(BOOL) shouldHighlight {","path":"atom/browser/ui/tray_icon_cocoa.mm","position":null,"original_position":179,"commit_id":"2cd6ad1a9712cdf9cf97564de1d3c382ce2f7c3f","original_commit_id":"17628b3e40a8793cc4e65f5e4bc62948520ee1cd","user":{"login":"hokein","id":2557445,"avatar_url":"https://avatars.githubusercontent.com/u/2557445?v=3","gravatar_id":"","url":"https://api.github.com/users/hokein","html_url":"https://github.com/hokein","followers_url":"https://api.github.com/users/hokein/followers","following_url":"https://api.github.com/users/hokein/following{/other_user}","gists_url":"https://api.github.com/users/hokein/gists{/gist_id}","starred_url":"https://api.github.com/users/hokein/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hokein/subscriptions","organizations_url":"https://api.github.com/users/hokein/orgs","repos_url":"https://api.github.com/users/hokein/repos","events_url":"https://api.github.com/users/hokein/events{/privacy}","received_events_url":"https://api.github.com/users/hokein/received_events","type":"User","site_admin":false},"body":"Done.","created_at":"2015-07-16T11:08:05Z","updated_at":"2015-07-16T11:08:05Z","html_url":"https://github.com/atom/electron/pull/2232#discussion_r34776719","pull_request_url":"https://api.github.com/repos/atom/electron/pulls/2232","_links":{"self":{"href":"https://api.github.com/repos/atom/electron/pulls/comments/34776719"},"html":{"href":"https://github.com/atom/electron/pull/2232#discussion_r34776719"},"pull_request":{"href":"https://api.github.com/repos/atom/electron/pulls/2232"}}},"pull_request":{"url":"https://api.github.com/repos/atom/electron/pulls/2232","id":40012925,"html_url":"https://github.com/atom/electron/pull/2232","diff_url":"https://github.com/atom/electron/pull/2232.diff","patch_url":"https://github.com/atom/electron/pull/2232.patch","issue_url":"https://api.github.com/repos/atom/electron/issues/2232","number":2232,"state":"open","locked":false,"title":"Introduce custom status item view on OS X.","user":{"login":"hokein","id":2557445,"avatar_url":"https://avatars.githubusercontent.com/u/2557445?v=3","gravatar_id":"","url":"https://api.github.com/users/hokein","html_url":"https://github.com/hokein","followers_url":"https://api.github.com/users/hokein/followers","following_url":"https://api.github.com/users/hokein/following{/other_user}","gists_url":"https://api.github.com/users/hokein/gists{/gist_id}","starred_url":"https://api.github.com/users/hokein/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hokein/subscriptions","organizations_url":"https://api.github.com/users/hokein/orgs","repos_url":"https://api.github.com/users/hokein/repos","events_url":"https://api.github.com/users/hokein/events{/privacy}","received_events_url":"https://api.github.com/users/hokein/received_events","type":"User","site_admin":false},"body":"Fixes #1499,  #1393, #1975.\r\n\r\nThis PR implements:\r\n\r\n* Implement `right-clicked` event on OS X and Windows. As a side effect, the 'clicked' event will also be emitted even the tray has context menu.\r\n* Implement `popContextMenu` API on OS X and Windows. \r\n","created_at":"2015-07-15T11:32:52Z","updated_at":"2015-07-16T11:08:05Z","closed_at":null,"merged_at":null,"merge_commit_sha":"2b0951b6f31d03863d2eae43040820f6e41e5194","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/atom/electron/pulls/2232/commits","review_comments_url":"https://api.github.com/repos/atom/electron/pulls/2232/comments","review_comment_url":"https://api.github.com/repos/atom/electron/pulls/comments{/number}","comments_url":"https://api.github.com/repos/atom/electron/issues/2232/comments","statuses_url":"https://api.github.com/repos/atom/electron/statuses/2cd6ad1a9712cdf9cf97564de1d3c382ce2f7c3f","head":{"label":"atom:status_item_view","ref":"status_item_view","sha":"2cd6ad1a9712cdf9cf97564de1d3c382ce2f7c3f","user":{"login":"atom","id":1089146,"avatar_url":"https://avatars.githubusercontent.com/u/1089146?v=3","gravatar_id":"","url":"https://api.github.com/users/atom","html_url":"https://github.com/atom","followers_url":"https://api.github.com/users/atom/followers","following_url":"https://api.github.com/users/atom/following{/other_user}","gists_url":"https://api.github.com/users/atom/gists{/gist_id}","starred_url":"https://api.github.com/users/atom/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/atom/subscriptions","organizations_url":"https://api.github.com/users/atom/orgs","repos_url":"https://api.github.com/users/atom/repos","events_url":"https://api.github.com/users/atom/events{/privacy}","received_events_url":"https://api.github.com/users/atom/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"name":"electron","full_name":"atom/electron","owner":{"login":"atom","id":1089146,"avatar_url":"https://avatars.githubusercontent.com/u/1089146?v=3","gravatar_id":"","url":"https://api.github.com/users/atom","html_url":"https://github.com/atom","followers_url":"https://api.github.com/users/atom/followers","following_url":"https://api.github.com/users/atom/following{/other_user}","gists_url":"https://api.github.com/users/atom/gists{/gist_id}","starred_url":"https://api.github.com/users/atom/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/atom/subscriptions","organizations_url":"https://api.github.com/users/atom/orgs","repos_url":"https://api.github.com/users/atom/repos","events_url":"https://api.github.com/users/atom/events{/privacy}","received_events_url":"https://api.github.com/users/atom/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/atom/electron","description":"Build cross platform desktop apps with web technologies","fork":false,"url":"https://api.github.com/repos/atom/electron","forks_url":"https://api.github.com/repos/atom/electron/forks","keys_url":"https://api.github.com/repos/atom/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/atom/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/atom/electron/teams","hooks_url":"https://api.github.com/repos/atom/electron/hooks","issue_events_url":"https://api.github.com/repos/atom/electron/issues/events{/number}","events_url":"https://api.github.com/repos/atom/electron/events","assignees_url":"https://api.github.com/repos/atom/electron/assignees{/user}","branches_url":"https://api.github.com/repos/atom/electron/branches{/branch}","tags_url":"https://api.github.com/repos/atom/electron/tags","blobs_url":"https://api.github.com/repos/atom/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/atom/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/atom/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/atom/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/atom/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/atom/electron/languages","stargazers_url":"https://api.github.com/repos/atom/electron/stargazers","contributors_url":"https://api.github.com/repos/atom/electron/contributors","subscribers_url":"https://api.github.com/repos/atom/electron/subscribers","subscription_url":"https://api.github.com/repos/atom/electron/subscription","commits_url":"https://api.github.com/repos/atom/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/atom/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/atom/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/atom/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/atom/electron/contents/{+path}","compare_url":"https://api.github.com/repos/atom/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/atom/electron/merges","archive_url":"https://api.github.com/repos/atom/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/atom/electron/downloads","issues_url":"https://api.github.com/repos/atom/electron/issues{/number}","pulls_url":"https://api.github.com/repos/atom/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/atom/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/atom/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/atom/electron/labels{/name}","releases_url":"https://api.github.com/repos/atom/electron/releases{/id}","created_at":"2013-04-12T01:47:36Z","updated_at":"2015-07-16T10:58:10Z","pushed_at":"2015-07-16T10:49:17Z","git_url":"git://github.com/atom/electron.git","ssh_url":"git@github.com:atom/electron.git","clone_url":"https://github.com/atom/electron.git","svn_url":"https://github.com/atom/electron","homepage":"http://electron.atom.io","size":22005,"stargazers_count":13917,"watchers_count":13917,"language":"C++","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":1097,"mirror_url":null,"open_issues_count":209,"forks":1097,"open_issues":209,"watchers":13917,"default_branch":"master"}},"base":{"label":"atom:master","ref":"master","sha":"4baaf03ac700cb8c9e21bc1a9271cc913bb66fa1","user":{"login":"atom","id":1089146,"avatar_url":"https://avatars.githubusercontent.com/u/1089146?v=3","gravatar_id":"","url":"https://api.github.com/users/atom","html_url":"https://github.com/atom","followers_url":"https://api.github.com/users/atom/followers","following_url":"https://api.github.com/users/atom/following{/other_user}","gists_url":"https://api.github.com/users/atom/gists{/gist_id}","starred_url":"https://api.github.com/users/atom/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/atom/subscriptions","organizations_url":"https://api.github.com/users/atom/orgs","repos_url":"https://api.github.com/users/atom/repos","events_url":"https://api.github.com/users/atom/events{/privacy}","received_events_url":"https://api.github.com/users/atom/received_events","type":"Organization","site_admin":false},"repo":{"id":9384267,"name":"electron","full_name":"atom/electron","owner":{"login":"atom","id":1089146,"avatar_url":"https://avatars.githubusercontent.com/u/1089146?v=3","gravatar_id":"","url":"https://api.github.com/users/atom","html_url":"https://github.com/atom","followers_url":"https://api.github.com/users/atom/followers","following_url":"https://api.github.com/users/atom/following{/other_user}","gists_url":"https://api.github.com/users/atom/gists{/gist_id}","starred_url":"https://api.github.com/users/atom/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/atom/subscriptions","organizations_url":"https://api.github.com/users/atom/orgs","repos_url":"https://api.github.com/users/atom/repos","events_url":"https://api.github.com/users/atom/events{/privacy}","received_events_url":"https://api.github.com/users/atom/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/atom/electron","description":"Build cross platform desktop apps with web technologies","fork":false,"url":"https://api.github.com/repos/atom/electron","forks_url":"https://api.github.com/repos/atom/electron/forks","keys_url":"https://api.github.com/repos/atom/electron/keys{/key_id}","collaborators_url":"https://api.github.com/repos/atom/electron/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/atom/electron/teams","hooks_url":"https://api.github.com/repos/atom/electron/hooks","issue_events_url":"https://api.github.com/repos/atom/electron/issues/events{/number}","events_url":"https://api.github.com/repos/atom/electron/events","assignees_url":"https://api.github.com/repos/atom/electron/assignees{/user}","branches_url":"https://api.github.com/repos/atom/electron/branches{/branch}","tags_url":"https://api.github.com/repos/atom/electron/tags","blobs_url":"https://api.github.com/repos/atom/electron/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/atom/electron/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/atom/electron/git/refs{/sha}","trees_url":"https://api.github.com/repos/atom/electron/git/trees{/sha}","statuses_url":"https://api.github.com/repos/atom/electron/statuses/{sha}","languages_url":"https://api.github.com/repos/atom/electron/languages","stargazers_url":"https://api.github.com/repos/atom/electron/stargazers","contributors_url":"https://api.github.com/repos/atom/electron/contributors","subscribers_url":"https://api.github.com/repos/atom/electron/subscribers","subscription_url":"https://api.github.com/repos/atom/electron/subscription","commits_url":"https://api.github.com/repos/atom/electron/commits{/sha}","git_commits_url":"https://api.github.com/repos/atom/electron/git/commits{/sha}","comments_url":"https://api.github.com/repos/atom/electron/comments{/number}","issue_comment_url":"https://api.github.com/repos/atom/electron/issues/comments{/number}","contents_url":"https://api.github.com/repos/atom/electron/contents/{+path}","compare_url":"https://api.github.com/repos/atom/electron/compare/{base}...{head}","merges_url":"https://api.github.com/repos/atom/electron/merges","archive_url":"https://api.github.com/repos/atom/electron/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/atom/electron/downloads","issues_url":"https://api.github.com/repos/atom/electron/issues{/number}","pulls_url":"https://api.github.com/repos/atom/electron/pulls{/number}","milestones_url":"https://api.github.com/repos/atom/electron/milestones{/number}","notifications_url":"https://api.github.com/repos/atom/electron/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/atom/electron/labels{/name}","releases_url":"https://api.github.com/repos/atom/electron/releases{/id}","created_at":"2013-04-12T01:47:36Z","updated_at":"2015-07-16T10:58:10Z","pushed_at":"2015-07-16T10:49:17Z","git_url":"git://github.com/atom/electron.git","ssh_url":"git@github.com:atom/electron.git","clone_url":"https://github.com/atom/electron.git","svn_url":"https://github.com/atom/electron","homepage":"http://electron.atom.io","size":22005,"stargazers_count":13917,"watchers_count":13917,"language":"C++","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":1097,"mirror_url":null,"open_issues_count":209,"forks":1097,"open_issues":209,"watchers":13917,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/atom/electron/pulls/2232"},"html":{"href":"https://github.com/atom/electron/pull/2232"},"issue":{"href":"https://api.github.com/repos/atom/electron/issues/2232"},"comments":{"href":"https://api.github.com/repos/atom/electron/issues/2232/comments"},"review_comments":{"href":"https://api.github.com/repos/atom/electron/pulls/2232/comments"},"review_comment":{"href":"https://api.github.com/repos/atom/electron/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/atom/electron/pulls/2232/commits"},"statuses":{"href":"https://api.github.com/repos/atom/electron/statuses/2cd6ad1a9712cdf9cf97564de1d3c382ce2f7c3f"}}}}