From 66bbf00b7a5c8f197f1ba744827e1916e1fd60d6 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Sun, 16 Nov 2014 19:47:04 +0800 Subject: [PATCH 01/23] OVERRIDE => override in browser.h --- atom/browser/browser.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/atom/browser/browser.h b/atom/browser/browser.h index d46c2922b610..c409ce45a900 100644 --- a/atom/browser/browser.h +++ b/atom/browser/browser.h @@ -100,8 +100,8 @@ class Browser : public WindowListObserver { private: // WindowListObserver implementations: - virtual void OnWindowCloseCancelled(NativeWindow* window) OVERRIDE; - virtual void OnWindowAllClosed() OVERRIDE; + void OnWindowCloseCancelled(NativeWindow* window) override; + void OnWindowAllClosed() override; // Observers of the browser. ObserverList observers_; From 49ac363eef94a198205f39d1ef1efaab9ffb59f2 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Sun, 16 Nov 2014 20:24:29 +0800 Subject: [PATCH 02/23] cocoa: Enable modifying initialized menu --- atom/browser/ui/cocoa/atom_menu_controller.h | 3 +++ atom/browser/ui/cocoa/atom_menu_controller.mm | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/atom/browser/ui/cocoa/atom_menu_controller.h b/atom/browser/ui/cocoa/atom_menu_controller.h index cc03f151e4b4..da10e1b0ba66 100644 --- a/atom/browser/ui/cocoa/atom_menu_controller.h +++ b/atom/browser/ui/cocoa/atom_menu_controller.h @@ -39,6 +39,9 @@ class MenuModel; // to the contents of the model after calling this will not be noticed. - (id)initWithModel:(ui::MenuModel*)model; +// Populate current NSMenu with |model|. +- (void)populateWithModel:(ui::MenuModel*)model; + // Programmatically close the constructed menu. - (void)cancel; diff --git a/atom/browser/ui/cocoa/atom_menu_controller.mm b/atom/browser/ui/cocoa/atom_menu_controller.mm index 24f6a1f5d4af..5013f5a9ee8a 100644 --- a/atom/browser/ui/cocoa/atom_menu_controller.mm +++ b/atom/browser/ui/cocoa/atom_menu_controller.mm @@ -93,6 +93,22 @@ int EventFlagsFromNSEvent(NSEvent* event) { [super dealloc]; } +- (void)populateWithModel:(ui::MenuModel*)model { + if (!menu_) + return; + + model_ = model; + [menu_ removeAllItems]; + + const int count = model->GetItemCount(); + for (int index = 0; index < count; index++) { + if (model->GetTypeAt(index) == ui::MenuModel::TYPE_SEPARATOR) + [self addSeparatorToMenu:menu_ atIndex:index]; + else + [self addItemToMenu:menu_ atIndex:index fromModel:model]; + } +} + - (void)cancel { if (isMenuOpen_) { [menu_ cancelTracking]; From af728427282ecd1673df658e817553737106520e Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Sun, 16 Nov 2014 21:06:16 +0800 Subject: [PATCH 03/23] cocoa: Enable creating empty menu --- atom/browser/ui/cocoa/atom_menu_controller.mm | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/atom/browser/ui/cocoa/atom_menu_controller.mm b/atom/browser/ui/cocoa/atom_menu_controller.mm index 5013f5a9ee8a..69a7b56826d7 100644 --- a/atom/browser/ui/cocoa/atom_menu_controller.mm +++ b/atom/browser/ui/cocoa/atom_menu_controller.mm @@ -251,10 +251,13 @@ int EventFlagsFromNSEvent(NSEvent* event) { } - (NSMenu*)menu { - if (!menu_ && model_) { - menu_.reset([[self menuFromModel:model_] retain]); - [menu_ setDelegate:self]; - } + if (menu_) + return menu_.get(); + + menu_.reset([[NSMenu alloc] initWithTitle:@""]); + [menu_ setDelegate:self]; + if (model_) + [self populateWithModel:model_]; return menu_.get(); } From 651dabf47e8a7ccbd8ff9a479c284bb6bac50dcb Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Sun, 16 Nov 2014 22:34:29 +0800 Subject: [PATCH 04/23] Fix displaying context menu for devtools --- atom/renderer/lib/init.coffee | 2 ++ atom/renderer/lib/inspector.coffee | 14 ++++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/atom/renderer/lib/init.coffee b/atom/renderer/lib/init.coffee index 69e76e98e155..ebf69ac3a65b 100644 --- a/atom/renderer/lib/init.coffee +++ b/atom/renderer/lib/init.coffee @@ -37,9 +37,11 @@ for arg in process.argv if location.protocol is 'chrome-devtools:' # Override some inspector APIs. require path.join(__dirname, 'inspector') + nodeIntegration = 'true' else if location.protocol is 'chrome-extension:' # Add implementations of chrome API. require path.join(__dirname, 'chrome-api') + nodeIntegration = 'true' else # Override default web functions. require path.join(__dirname, 'override') diff --git a/atom/renderer/lib/inspector.coffee b/atom/renderer/lib/inspector.coffee index 8b6f748e00e1..87906e69949f 100644 --- a/atom/renderer/lib/inspector.coffee +++ b/atom/renderer/lib/inspector.coffee @@ -1,7 +1,7 @@ window.onload = -> # Use menu API to show context menu. - InspectorFrontendHost.showContextMenu = (event, items) -> - createMenu items, event + InspectorFrontendHost.showContextMenuAtPoint = (x, y, items, document) -> + createMenu items # Use dialog API to override file chooser dialog. WebInspector.createFileSelectorElement = (callback) -> @@ -32,17 +32,19 @@ convertToMenuTemplate = (items) -> label: item.label enabled: item.enabled if item.id? - transformed.click = -> WebInspector.contextMenuItemSelected item.id + transformed.click = -> InspectorFrontendAPI.contextMenuItemSelected item.id template.push transformed template -createMenu = (items, event) -> +createMenu = (items) -> remote = require 'remote' Menu = remote.require 'menu' menu = Menu.buildFromTemplate convertToMenuTemplate(items) - menu.popup remote.getCurrentWindow() - event.consume true + # The menu is expected to show asynchronously. + setImmediate -> + menu.popup remote.getCurrentWindow() + InspectorFrontendAPI.contextMenuCleared() showFileChooserDialog = (callback) -> remote = require 'remote' From ba4f502b1e9eb8bb2f3d8d27a0c2087b4035acaa Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Sun, 16 Nov 2014 22:45:29 +0800 Subject: [PATCH 05/23] OVERRIDE => override in atom_api_app.h --- atom/browser/api/atom_api_app.h | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/atom/browser/api/atom_api_app.h b/atom/browser/api/atom_api_app.h index 9be7b8aca817..a9e2a17a13dd 100644 --- a/atom/browser/api/atom_api_app.h +++ b/atom/browser/api/atom_api_app.h @@ -33,20 +33,19 @@ class App : public mate::EventEmitter, App(); virtual ~App(); - // BrowserObserver implementations: - virtual void OnWillQuit(bool* prevent_default) OVERRIDE; - virtual void OnWindowAllClosed() OVERRIDE; - virtual void OnQuit() OVERRIDE; - virtual void OnOpenFile(bool* prevent_default, - const std::string& file_path) OVERRIDE; - virtual void OnOpenURL(const std::string& url) OVERRIDE; - virtual void OnActivateWithNoOpenWindows() OVERRIDE; - virtual void OnWillFinishLaunching() OVERRIDE; - virtual void OnFinishLaunching() OVERRIDE; + // BrowserObserver: + void OnWillQuit(bool* prevent_default) override; + void OnWindowAllClosed() override; + void OnQuit() override; + void OnOpenFile(bool* prevent_default, const std::string& file_path) override; + void OnOpenURL(const std::string& url) override; + void OnActivateWithNoOpenWindows() override; + void OnWillFinishLaunching() override; + void OnFinishLaunching() override; - // mate::Wrappable implementations: - virtual mate::ObjectTemplateBuilder GetObjectTemplateBuilder( - v8::Isolate* isolate); + // mate::Wrappable: + mate::ObjectTemplateBuilder GetObjectTemplateBuilder( + v8::Isolate* isolate) override; private: base::FilePath GetDataPath(); From 0e94977d424873762e42e11d6ca1e719b071ddaf Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Sun, 16 Nov 2014 23:04:31 +0800 Subject: [PATCH 06/23] Add app.dock.setMenu API --- atom/browser/api/atom_api_app.cc | 23 ++++++++++--------- atom/browser/api/lib/app.coffee | 1 + atom/browser/atom_browser_main_parts_mac.mm | 2 +- atom/browser/browser.h | 7 ++++++ atom/browser/browser_mac.mm | 6 +++++ atom/browser/mac/atom_application_delegate.h | 9 ++++++++ atom/browser/mac/atom_application_delegate.mm | 14 +++++++++++ atom/browser/ui/cocoa/atom_menu_controller.mm | 3 ++- 8 files changed, 52 insertions(+), 13 deletions(-) diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index 4ba87d9cfa7f..829fed189010 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -7,6 +7,7 @@ #include #include +#include "atom/browser/api/atom_api_menu.h" #include "atom/browser/atom_browser_context.h" #include "atom/browser/browser.h" #include "atom/common/native_mate_converters/file_path_converter.h" @@ -191,12 +192,15 @@ int DockBounce(const std::string& type) { request_id = Browser::Get()->DockBounce(Browser::BOUNCE_INFORMATIONAL); return request_id; } + +void DockSetMenu(atom::api::Menu* menu) { + Browser::Get()->DockSetMenu(menu->model()); +} #endif void Initialize(v8::Handle exports, v8::Handle unused, v8::Handle context, void* priv) { v8::Isolate* isolate = context->GetIsolate(); - Browser* browser = Browser::Get(); CommandLine* command_line = CommandLine::ForCurrentProcess(); mate::Dictionary dict(isolate, exports); @@ -206,20 +210,17 @@ void Initialize(v8::Handle exports, v8::Handle unused, base::Bind(&CommandLine::AppendArg, base::Unretained(command_line))); #if defined(OS_MACOSX) + auto browser = base::Unretained(Browser::Get()); dict.SetMethod("dockBounce", &DockBounce); dict.SetMethod("dockCancelBounce", - base::Bind(&Browser::DockCancelBounce, - base::Unretained(browser))); + base::Bind(&Browser::DockCancelBounce, browser)); dict.SetMethod("dockSetBadgeText", - base::Bind(&Browser::DockSetBadgeText, - base::Unretained(browser))); + base::Bind(&Browser::DockSetBadgeText, browser)); dict.SetMethod("dockGetBadgeText", - base::Bind(&Browser::DockGetBadgeText, - base::Unretained(browser))); - dict.SetMethod("dockHide", - base::Bind(&Browser::DockHide, base::Unretained(browser))); - dict.SetMethod("dockShow", - base::Bind(&Browser::DockShow, base::Unretained(browser))); + base::Bind(&Browser::DockGetBadgeText, browser)); + dict.SetMethod("dockHide", base::Bind(&Browser::DockHide, browser)); + dict.SetMethod("dockShow", base::Bind(&Browser::DockShow, browser)); + dict.SetMethod("dockSetMenu", &DockSetMenu); #endif } diff --git a/atom/browser/api/lib/app.coffee b/atom/browser/api/lib/app.coffee index a9962ca9cf6a..51fd66098ac0 100644 --- a/atom/browser/api/lib/app.coffee +++ b/atom/browser/api/lib/app.coffee @@ -26,6 +26,7 @@ if process.platform is 'darwin' getBadge: bindings.dockGetBadgeText hide: bindings.dockHide show: bindings.dockShow + setMenu: bindings.dockSetMenu # Be compatible with old API. app.once 'ready', -> app.emit 'finish-launching' diff --git a/atom/browser/atom_browser_main_parts_mac.mm b/atom/browser/atom_browser_main_parts_mac.mm index 587c7a26a19e..564dd2cd54e3 100644 --- a/atom/browser/atom_browser_main_parts_mac.mm +++ b/atom/browser/atom_browser_main_parts_mac.mm @@ -20,7 +20,7 @@ void AtomBrowserMainParts::PreMainMessageLoopStart() { // Force the NSApplication subclass to be used. NSApplication* application = [AtomApplication sharedApplication]; - AtomApplicationDelegate* delegate = [AtomApplicationDelegate alloc]; + AtomApplicationDelegate* delegate = [[AtomApplicationDelegate alloc] init]; [NSApp setDelegate:(id)delegate]; base::FilePath frameworkPath = brightray::MainApplicationBundlePath() diff --git a/atom/browser/browser.h b/atom/browser/browser.h index c409ce45a900..5cc05d1a4fcc 100644 --- a/atom/browser/browser.h +++ b/atom/browser/browser.h @@ -13,6 +13,10 @@ #include "atom/browser/browser_observer.h" #include "atom/browser/window_list_observer.h" +namespace ui { +class MenuModel; +} + namespace atom { // This class is used for control application-wide operations. @@ -60,6 +64,9 @@ class Browser : public WindowListObserver { // Hide/Show dock. void DockHide(); void DockShow(); + + // Set docks' menu. + void DockSetMenu(ui::MenuModel* model); #endif // defined(OS_MACOSX) // Tell the application to open a file. diff --git a/atom/browser/browser_mac.mm b/atom/browser/browser_mac.mm index 0e5c46a37a78..3d1b293d2ffc 100644 --- a/atom/browser/browser_mac.mm +++ b/atom/browser/browser_mac.mm @@ -5,6 +5,7 @@ #include "atom/browser/browser.h" #import "atom/browser/mac/atom_application.h" +#import "atom/browser/mac/atom_application_delegate.h" #include "atom/browser/native_window.h" #include "atom/browser/window_list.h" #import "base/mac/bundle_locations.h" @@ -60,4 +61,9 @@ void Browser::DockShow() { TransformProcessType(&psn, kProcessTransformToForegroundApplication); } +void Browser::DockSetMenu(ui::MenuModel* model) { + AtomApplicationDelegate* delegate = [NSApp delegate]; + [delegate setApplicationDockMenu:model]; +} + } // namespace atom diff --git a/atom/browser/mac/atom_application_delegate.h b/atom/browser/mac/atom_application_delegate.h index 437d76a772ca..3e5c59c3ff3d 100644 --- a/atom/browser/mac/atom_application_delegate.h +++ b/atom/browser/mac/atom_application_delegate.h @@ -4,7 +4,16 @@ #import +#import "atom/browser/ui/cocoa/atom_menu_controller.h" + @interface AtomApplicationDelegate : NSObject { + @private + base::scoped_nsobject menu_controller_; } +- (id)init; + +// Sets the menu that will be returned in "applicationDockMenu:". +- (void)setApplicationDockMenu:(ui::MenuModel*)model; + @end diff --git a/atom/browser/mac/atom_application_delegate.mm b/atom/browser/mac/atom_application_delegate.mm index 3ffa4a7ae99c..16dcf6fd9523 100644 --- a/atom/browser/mac/atom_application_delegate.mm +++ b/atom/browser/mac/atom_application_delegate.mm @@ -10,6 +10,16 @@ @implementation AtomApplicationDelegate +- (id)init { + self = [super init]; + menu_controller_.reset([[AtomMenuController alloc] init]); + return self; +} + +- (void)setApplicationDockMenu:(ui::MenuModel*)model { + [menu_controller_ populateWithModel:model]; +} + - (void)applicationWillFinishLaunching:(NSNotification*)notify { atom::Browser::Get()->WillFinishLaunching(); } @@ -18,6 +28,10 @@ atom::Browser::Get()->DidFinishLaunching(); } +- (NSMenu*)applicationDockMenu:(NSApplication*)sender { + return [menu_controller_ menu]; +} + - (BOOL)application:(NSApplication*)sender openFile:(NSString*)filename { std::string filename_str(base::SysNSStringToUTF8(filename)); diff --git a/atom/browser/ui/cocoa/atom_menu_controller.mm b/atom/browser/ui/cocoa/atom_menu_controller.mm index 69a7b56826d7..176f2db7e145 100644 --- a/atom/browser/ui/cocoa/atom_menu_controller.mm +++ b/atom/browser/ui/cocoa/atom_menu_controller.mm @@ -70,7 +70,8 @@ int EventFlagsFromNSEvent(NSEvent* event) { @synthesize model = model_; - (id)init { - self = [super init]; + if ((self = [super init])) + [self menu]; return self; } From 6aa69a06c802ba4bcc8a24d9c27c52be161c0d8c Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 17 Nov 2014 09:52:24 +0800 Subject: [PATCH 07/23] mac: Release application delegate on exit --- atom/browser/atom_browser_main_parts_mac.mm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/atom/browser/atom_browser_main_parts_mac.mm b/atom/browser/atom_browser_main_parts_mac.mm index 564dd2cd54e3..d31dde15dd68 100644 --- a/atom/browser/atom_browser_main_parts_mac.mm +++ b/atom/browser/atom_browser_main_parts_mac.mm @@ -41,7 +41,8 @@ void AtomBrowserMainParts::PreMainMessageLoopStart() { } void AtomBrowserMainParts::PostDestroyThreads() { - [[AtomApplication sharedApplication] setDelegate:nil]; + [[NSApp delegate] release]; + [NSApp setDelegate:nil]; } } // namespace atom From c23ba7b5046ef145f7343dda1e14b9f1ef8c7f78 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 17 Nov 2014 13:05:06 +0800 Subject: [PATCH 08/23] mac: Add app.addRecentDocument API --- atom/browser/api/atom_api_app.cc | 2 ++ atom/browser/browser.h | 7 +++++++ atom/browser/browser_linux.cc | 3 +++ atom/browser/browser_mac.mm | 6 ++++++ atom/browser/browser_win.cc | 3 +++ 5 files changed, 21 insertions(+) diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index 829fed189010..f42b1e0d0c8f 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -158,6 +158,8 @@ mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder( .SetMethod("getName", base::Bind(&Browser::GetName, browser)) .SetMethod("setName", base::Bind(&Browser::SetName, browser)) .SetMethod("isReady", base::Bind(&Browser::is_ready, browser)) + .SetMethod("addRecentDocument", + base::Bind(&Browser::AddRecentDocument, browser)) .SetMethod("getDataPath", &App::GetDataPath) .SetMethod("resolveProxy", &App::ResolveProxy) .SetMethod("setDesktopName", &App::SetDesktopName); diff --git a/atom/browser/browser.h b/atom/browser/browser.h index 5cc05d1a4fcc..e058ec25e251 100644 --- a/atom/browser/browser.h +++ b/atom/browser/browser.h @@ -13,6 +13,10 @@ #include "atom/browser/browser_observer.h" #include "atom/browser/window_list_observer.h" +namespace base { +class FilePath; +} + namespace ui { class MenuModel; } @@ -48,6 +52,9 @@ class Browser : public WindowListObserver { // Overrides the application name. void SetName(const std::string& name); + // Add the |path| to recent documents list. + void AddRecentDocument(const base::FilePath& path); + #if defined(OS_MACOSX) // Bounce the dock icon. enum BounceType { diff --git a/atom/browser/browser_linux.cc b/atom/browser/browser_linux.cc index 5ede610813b8..fceb127f20d0 100644 --- a/atom/browser/browser_linux.cc +++ b/atom/browser/browser_linux.cc @@ -24,6 +24,9 @@ void Browser::Focus() { } } +void Browser::AddRecentDocument(const base::FilePath& path) { +} + std::string Browser::GetExecutableFileVersion() const { return ATOM_VERSION_STRING; } diff --git a/atom/browser/browser_mac.mm b/atom/browser/browser_mac.mm index 3d1b293d2ffc..1cb1f6f8faab 100644 --- a/atom/browser/browser_mac.mm +++ b/atom/browser/browser_mac.mm @@ -9,6 +9,7 @@ #include "atom/browser/native_window.h" #include "atom/browser/window_list.h" #import "base/mac/bundle_locations.h" +#import "base/mac/foundation_util.h" #include "base/strings/sys_string_conversions.h" namespace atom { @@ -17,6 +18,11 @@ void Browser::Focus() { [[AtomApplication sharedApplication] activateIgnoringOtherApps:YES]; } +void Browser::AddRecentDocument(const base::FilePath& path) { + NSURL* u = [NSURL fileURLWithPath:base::mac::FilePathToNSString(path)]; + [[NSDocumentController sharedDocumentController] noteNewRecentDocumentURL:u]; +} + std::string Browser::GetExecutableFileVersion() const { NSDictionary* infoDictionary = base::mac::OuterBundle().infoDictionary; NSString *version = [infoDictionary objectForKey:@"CFBundleVersion"]; diff --git a/atom/browser/browser_win.cc b/atom/browser/browser_win.cc index 4cbf0f9647dd..4d90933a9db1 100644 --- a/atom/browser/browser_win.cc +++ b/atom/browser/browser_win.cc @@ -39,6 +39,9 @@ void Browser::Focus() { EnumWindows(&WindowsEnumerationHandler, reinterpret_cast(&pid)); } +void Browser::AddRecentDocument(const base::FilePath& path) { +} + std::string Browser::GetExecutableFileVersion() const { base::FilePath path; if (PathService::Get(base::FILE_EXE, &path)) { From 78322b5231a049a49b25c3b30bef2bd5e1005ee2 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 17 Nov 2014 15:53:18 +0800 Subject: [PATCH 09/23] win: Implement Browser::AddRecentDocument --- atom/browser/browser_win.cc | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/atom/browser/browser_win.cc b/atom/browser/browser_win.cc index 4d90933a9db1..85be2d32433a 100644 --- a/atom/browser/browser_win.cc +++ b/atom/browser/browser_win.cc @@ -4,14 +4,19 @@ #include "atom/browser/browser.h" +#include #include +#include +#include #include "base/base_paths.h" #include "base/file_version_info.h" #include "base/files/file_path.h" #include "base/memory/scoped_ptr.h" #include "base/path_service.h" +#include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" +#include "base/win/windows_version.h" #include "atom/common/atom_version.h" namespace atom { @@ -40,6 +45,18 @@ void Browser::Focus() { } void Browser::AddRecentDocument(const base::FilePath& path) { + if (base::win::GetVersion() < base::win::VERSION_WIN7) + return; + + CComPtr item; + HRESULT hr = SHCreateItemFromParsingName( + path.value().c_str(), NULL, IID_PPV_ARGS(&item)); + if (SUCCEEDED(hr)) { + SHARDAPPIDINFO info; + info.psi = item; + info.pszAppID = L"Atom"; + SHAddToRecentDocs(SHARD_APPIDINFO, &info); + } } std::string Browser::GetExecutableFileVersion() const { From 528f7bd45f8271f24a3c1a64bd6c911f9f6548d7 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 17 Nov 2014 15:55:49 +0800 Subject: [PATCH 10/23] win: Set app user model ID This ID is used by Windows to identify your application. --- atom/browser/browser.cc | 4 ++++ atom/browser/browser.h | 13 +++++++++++++ atom/browser/browser_win.cc | 8 +++++++- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/atom/browser/browser.cc b/atom/browser/browser.cc index 4761c7ca81f0..b658de410209 100644 --- a/atom/browser/browser.cc +++ b/atom/browser/browser.cc @@ -70,6 +70,10 @@ std::string Browser::GetName() const { void Browser::SetName(const std::string& name) { name_override_ = name; + +#if defined(OS_WIN) + SetAppUserModelID(name); +#endif } bool Browser::OpenFile(const std::string& file_path) { diff --git a/atom/browser/browser.h b/atom/browser/browser.h index e058ec25e251..aa3b3c07aa56 100644 --- a/atom/browser/browser.h +++ b/atom/browser/browser.h @@ -13,6 +13,10 @@ #include "atom/browser/browser_observer.h" #include "atom/browser/window_list_observer.h" +#if defined(OS_WIN) +#include "base/strings/string16.h" +#endif + namespace base { class FilePath; } @@ -76,6 +80,11 @@ class Browser : public WindowListObserver { void DockSetMenu(ui::MenuModel* model); #endif // defined(OS_MACOSX) +#if defined(OS_WIN) + // Set the application user model ID, called when "SetName" is called. + void SetAppUserModelID(const std::string& name); +#endif + // Tell the application to open a file. bool OpenFile(const std::string& file_path); @@ -126,6 +135,10 @@ class Browser : public WindowListObserver { std::string version_override_; std::string name_override_; +#if defined(OS_WIN) + base::string16 app_user_model_id_; +#endif + DISALLOW_COPY_AND_ASSIGN(Browser); }; diff --git a/atom/browser/browser_win.cc b/atom/browser/browser_win.cc index 85be2d32433a..91550ace4a7d 100644 --- a/atom/browser/browser_win.cc +++ b/atom/browser/browser_win.cc @@ -54,11 +54,17 @@ void Browser::AddRecentDocument(const base::FilePath& path) { if (SUCCEEDED(hr)) { SHARDAPPIDINFO info; info.psi = item; - info.pszAppID = L"Atom"; + info.pszAppID = app_user_model_id_.c_str(); SHAddToRecentDocs(SHARD_APPIDINFO, &info); } } +void Browser::SetAppUserModelID(const std::string& name) { + app_user_model_id_ = base::UTF8ToUTF16( + base::StringPrintf("atom-shell.app.%s", name)); + SetCurrentProcessExplicitAppUserModelID(app_user_model_id_.c_str()); +} + std::string Browser::GetExecutableFileVersion() const { base::FilePath path; if (PathService::Get(base::FILE_EXE, &path)) { From 48412769df0a9cdae3cdde67b86159feb2f6a9a2 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 17 Nov 2014 16:13:47 +0800 Subject: [PATCH 11/23] win: Add app.clearRecentDocuments API --- atom/browser/api/atom_api_app.cc | 2 ++ atom/browser/browser.h | 3 +++ atom/browser/browser_linux.cc | 3 +++ atom/browser/browser_mac.mm | 3 +++ atom/browser/browser_win.cc | 10 ++++++++++ 5 files changed, 21 insertions(+) diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index f42b1e0d0c8f..8305b6a320ed 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -160,6 +160,8 @@ mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder( .SetMethod("isReady", base::Bind(&Browser::is_ready, browser)) .SetMethod("addRecentDocument", base::Bind(&Browser::AddRecentDocument, browser)) + .SetMethod("clearRecentDocuments", + base::Bind(&Browser::ClearRecentDocuments, browser)) .SetMethod("getDataPath", &App::GetDataPath) .SetMethod("resolveProxy", &App::ResolveProxy) .SetMethod("setDesktopName", &App::SetDesktopName); diff --git a/atom/browser/browser.h b/atom/browser/browser.h index aa3b3c07aa56..6fed3eec0c65 100644 --- a/atom/browser/browser.h +++ b/atom/browser/browser.h @@ -59,6 +59,9 @@ class Browser : public WindowListObserver { // Add the |path| to recent documents list. void AddRecentDocument(const base::FilePath& path); + // Clear the recent documents list. + void ClearRecentDocuments(); + #if defined(OS_MACOSX) // Bounce the dock icon. enum BounceType { diff --git a/atom/browser/browser_linux.cc b/atom/browser/browser_linux.cc index fceb127f20d0..7534aa2182d9 100644 --- a/atom/browser/browser_linux.cc +++ b/atom/browser/browser_linux.cc @@ -27,6 +27,9 @@ void Browser::Focus() { void Browser::AddRecentDocument(const base::FilePath& path) { } +void Browser::ClearRecentDocuments() { +} + std::string Browser::GetExecutableFileVersion() const { return ATOM_VERSION_STRING; } diff --git a/atom/browser/browser_mac.mm b/atom/browser/browser_mac.mm index 1cb1f6f8faab..797c560728fa 100644 --- a/atom/browser/browser_mac.mm +++ b/atom/browser/browser_mac.mm @@ -23,6 +23,9 @@ void Browser::AddRecentDocument(const base::FilePath& path) { [[NSDocumentController sharedDocumentController] noteNewRecentDocumentURL:u]; } +void Browser::ClearRecentDocuments() { +} + std::string Browser::GetExecutableFileVersion() const { NSDictionary* infoDictionary = base::mac::OuterBundle().infoDictionary; NSString *version = [infoDictionary objectForKey:@"CFBundleVersion"]; diff --git a/atom/browser/browser_win.cc b/atom/browser/browser_win.cc index 91550ace4a7d..c5e3aadc8be3 100644 --- a/atom/browser/browser_win.cc +++ b/atom/browser/browser_win.cc @@ -59,6 +59,16 @@ void Browser::AddRecentDocument(const base::FilePath& path) { } } +void Browser::ClearRecentDocuments() { + CComPtr destinations; + if (FAILED(destinations.CoCreateInstance(CLSID_ApplicationDestinations, + NULL, CLSCTX_INPROC_SERVER))) + return; + if (FAILED(destinations->SetAppID(app_user_model_id_.c_str()))) + return; + destinations->RemoveAllDestinations(); +} + void Browser::SetAppUserModelID(const std::string& name) { app_user_model_id_ = base::UTF8ToUTF16( base::StringPrintf("atom-shell.app.%s", name)); From 47c18fef7fbdf21e3c785d9586bec02c68b55962 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 17 Nov 2014 17:19:41 +0800 Subject: [PATCH 12/23] win: Add app.addUserTasks API --- atom/browser/api/atom_api_app.cc | 23 +++++++++++++++++ atom/browser/browser.h | 12 +++++++++ atom/browser/browser_win.cc | 43 ++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+) diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index 8305b6a320ed..12668dbf344c 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -33,6 +33,25 @@ using atom::Browser; +namespace mate { + +template<> +struct Converter { + static bool FromV8(v8::Isolate* isolate, v8::Handle val, + Browser::UserTask* out) { + mate::Dictionary dict; + if (!ConvertFromV8(isolate, val, &dict)) + return false; + return dict.Get("program", &(out->program)) && + dict.Get("arguments", &(out->arguments)) && + dict.Get("title", &(out->title)) && + dict.Get("description", &(out->description)); + } +}; + +} // namespace mate + + namespace atom { namespace api { @@ -162,6 +181,10 @@ mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder( base::Bind(&Browser::AddRecentDocument, browser)) .SetMethod("clearRecentDocuments", base::Bind(&Browser::ClearRecentDocuments, browser)) +#if defined(OS_WIN) + .SetMethod("addUserTasks", + base::Bind(&Browser::AddUserTasks, browser)) +#endif .SetMethod("getDataPath", &App::GetDataPath) .SetMethod("resolveProxy", &App::ResolveProxy) .SetMethod("setDesktopName", &App::SetDesktopName); diff --git a/atom/browser/browser.h b/atom/browser/browser.h index 6fed3eec0c65..69f61da84f2c 100644 --- a/atom/browser/browser.h +++ b/atom/browser/browser.h @@ -6,6 +6,7 @@ #define ATOM_BROWSER_BROWSER_H_ #include +#include #include "base/basictypes.h" #include "base/compiler_specific.h" @@ -14,6 +15,7 @@ #include "atom/browser/window_list_observer.h" #if defined(OS_WIN) +#include "base/files/file_path.h" #include "base/strings/string16.h" #endif @@ -84,6 +86,16 @@ class Browser : public WindowListObserver { #endif // defined(OS_MACOSX) #if defined(OS_WIN) + struct UserTask { + base::FilePath program; + base::string16 arguments; + base::string16 title; + base::string16 description; + }; + + // Add a custom task to jump list. + void AddUserTasks(const std::vector& tasks); + // Set the application user model ID, called when "SetName" is called. void SetAppUserModelID(const std::string& name); #endif diff --git a/atom/browser/browser_win.cc b/atom/browser/browser_win.cc index c5e3aadc8be3..9e4db535b232 100644 --- a/atom/browser/browser_win.cc +++ b/atom/browser/browser_win.cc @@ -5,6 +5,7 @@ #include "atom/browser/browser.h" #include +#include #include #include #include @@ -16,6 +17,7 @@ #include "base/path_service.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" +#include "base/win/win_util.h" #include "base/win/windows_version.h" #include "atom/common/atom_version.h" @@ -69,6 +71,47 @@ void Browser::ClearRecentDocuments() { destinations->RemoveAllDestinations(); } +void Browser::AddUserTasks(const std::vector& tasks) { + CComPtr destinations; + if (FAILED(destinations.CoCreateInstance(CLSID_DestinationList))) + return; + if (FAILED(destinations->SetAppID(app_user_model_id_.c_str()))) + return; + + // Start a transaction that updates the JumpList of this application. + UINT max_slots; + CComPtr removed; + if (FAILED(destinations->BeginList(&max_slots, IID_PPV_ARGS(&removed)))) + return; + + CComPtr collection; + if (FAILED(collection.CoCreateInstance(CLSID_EnumerableObjectCollection))) + return; + + for (auto& task : tasks) { + CComPtr link; + if (FAILED(link.CoCreateInstance(CLSID_ShellLink)) || + FAILED(link->SetPath(task.program.value().c_str())) || + FAILED(link->SetArguments(task.arguments.c_str())) || + FAILED(link->SetDescription(task.description.c_str()))) + return; + + CComQIPtr property_store = link; + if (!base::win::SetStringValueForPropertyStore(property_store, PKEY_Title, + task.title.c_str())) + return; + + if (FAILED(collection->AddObject(link))) + return; + } + + // When the list is empty "AddUserTasks" could fail, so we don't check return + // value for it. + CComQIPtr task_array = collection; + destinations->AddUserTasks(task_array); + destinations->CommitList(); +} + void Browser::SetAppUserModelID(const std::string& name) { app_user_model_id_ = base::UTF8ToUTF16( base::StringPrintf("atom-shell.app.%s", name)); From 0db2769781214ada34b7017b3c258324b7232d20 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 17 Nov 2014 17:26:44 +0800 Subject: [PATCH 13/23] Only "title" and "program" are required for AddUserTasks --- atom/browser/api/atom_api_app.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index 12668dbf344c..ce56c0da30c1 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -42,10 +42,12 @@ struct Converter { mate::Dictionary dict; if (!ConvertFromV8(isolate, val, &dict)) return false; - return dict.Get("program", &(out->program)) && - dict.Get("arguments", &(out->arguments)) && - dict.Get("title", &(out->title)) && - dict.Get("description", &(out->description)); + if (!dict.Get("program", &(out->program)) || + !dict.Get("title", &(out->title))) + return false; + dict.Get("arguments", &(out->arguments)); + dict.Get("description", &(out->description)); + return true; } }; From 0b1b0940d23c174b5437d5cceb42ca1e62d6e2fe Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 17 Nov 2014 17:35:51 +0800 Subject: [PATCH 14/23] Enable setting icon for addUserTasks --- atom/browser/api/atom_api_app.cc | 5 +++++ atom/browser/browser.h | 2 ++ atom/browser/browser_win.cc | 5 +++++ 3 files changed, 12 insertions(+) diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index ce56c0da30c1..d6f807246158 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -35,6 +35,7 @@ using atom::Browser; namespace mate { +#if defined(OS_WIN) template<> struct Converter { static bool FromV8(v8::Isolate* isolate, v8::Handle val, @@ -45,11 +46,15 @@ struct Converter { if (!dict.Get("program", &(out->program)) || !dict.Get("title", &(out->title))) return false; + if (dict.Get("iconPath", &(out->icon_path)) && + !dict.Get("iconIndex", &(out->icon_index))) + return false; dict.Get("arguments", &(out->arguments)); dict.Get("description", &(out->description)); return true; } }; +#endif } // namespace mate diff --git a/atom/browser/browser.h b/atom/browser/browser.h index 69f61da84f2c..a22680acdc90 100644 --- a/atom/browser/browser.h +++ b/atom/browser/browser.h @@ -91,6 +91,8 @@ class Browser : public WindowListObserver { base::string16 arguments; base::string16 title; base::string16 description; + base::FilePath icon_path; + int icon_index; }; // Add a custom task to jump list. diff --git a/atom/browser/browser_win.cc b/atom/browser/browser_win.cc index 9e4db535b232..c8620f26578f 100644 --- a/atom/browser/browser_win.cc +++ b/atom/browser/browser_win.cc @@ -96,6 +96,11 @@ void Browser::AddUserTasks(const std::vector& tasks) { FAILED(link->SetDescription(task.description.c_str()))) return; + if (!task.icon_path.empty() && + FAILED(link->SetIconLocation(task.icon_path.value().c_str(), + task.icon_index))) + return; + CComQIPtr property_store = link; if (!base::win::SetStringValueForPropertyStore(property_store, PKEY_Title, task.title.c_str())) From f706bb45cbf7582e0c14a3045457fa448a71fdb6 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 17 Nov 2014 18:48:02 +0800 Subject: [PATCH 15/23] docs: app.dock.setMenu --- docs/api/app.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/api/app.md b/docs/api/app.md index b9a837d77bb2..09916921067c 100644 --- a/docs/api/app.md +++ b/docs/api/app.md @@ -185,3 +185,13 @@ Hides the dock icon. Shows the dock icon. **Note:** This API is only available on Mac. + +## app.dock.setMenu(menu) + +* `menu` Menu + +Sets the application [dock menu][dock-menu]. + +**Note:** This API is only available on Mac. + +[dock-menu]:https://developer.apple.com/library/mac/documentation/Carbon/Conceptual/customizing_docktile/concepts/dockconcepts.html#//apple_ref/doc/uid/TP30000986-CH2-TPXREF103 From bf66aeb8eed4bb2bccbf0c52f611c01e92aa86fe Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 17 Nov 2014 19:02:37 +0800 Subject: [PATCH 16/23] docs: Recent documents API --- docs/api/app.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/api/app.md b/docs/api/app.md index 09916921067c..6d1ce4b01660 100644 --- a/docs/api/app.md +++ b/docs/api/app.md @@ -123,6 +123,19 @@ preferred over `name` by atom-shell. Resolves the proxy information for `url`, the `callback` would be called with `callback(proxy)` when the request is done. +## app.addRecentDocument(path) + +* `path` String + +Adds `path` to recent documents list. + +This list is managed by the system, on Windows you can visit the list from task +bar, and on Mac you can visit it from dock menu. + +## app.clearRecentDocuments() + +Clears the recent documents list. + ## app.commandLine.appendSwitch(switch, [value]) Append a switch [with optional value] to Chromium's command line. From ee9964c1415d3876297ba58753527bd4fa00f3ef Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 17 Nov 2014 19:32:11 +0800 Subject: [PATCH 17/23] AddUserTasks => setUserTasks --- atom/browser/api/atom_api_app.cc | 4 ++-- atom/browser/browser.h | 2 +- atom/browser/browser_win.cc | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index d6f807246158..6b0d7e478ecb 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -189,8 +189,8 @@ mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder( .SetMethod("clearRecentDocuments", base::Bind(&Browser::ClearRecentDocuments, browser)) #if defined(OS_WIN) - .SetMethod("addUserTasks", - base::Bind(&Browser::AddUserTasks, browser)) + .SetMethod("setUserTasks", + base::Bind(&Browser::SetUserTasks, browser)) #endif .SetMethod("getDataPath", &App::GetDataPath) .SetMethod("resolveProxy", &App::ResolveProxy) diff --git a/atom/browser/browser.h b/atom/browser/browser.h index a22680acdc90..d079d53a6dea 100644 --- a/atom/browser/browser.h +++ b/atom/browser/browser.h @@ -96,7 +96,7 @@ class Browser : public WindowListObserver { }; // Add a custom task to jump list. - void AddUserTasks(const std::vector& tasks); + void SetUserTasks(const std::vector& tasks); // Set the application user model ID, called when "SetName" is called. void SetAppUserModelID(const std::string& name); diff --git a/atom/browser/browser_win.cc b/atom/browser/browser_win.cc index c8620f26578f..781d905792f0 100644 --- a/atom/browser/browser_win.cc +++ b/atom/browser/browser_win.cc @@ -71,7 +71,7 @@ void Browser::ClearRecentDocuments() { destinations->RemoveAllDestinations(); } -void Browser::AddUserTasks(const std::vector& tasks) { +void Browser::SetUserTasks(const std::vector& tasks) { CComPtr destinations; if (FAILED(destinations.CoCreateInstance(CLSID_DestinationList))) return; From afde383e28d39efad6ff36a2c3c8a06624aa3389 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 17 Nov 2014 19:50:34 +0800 Subject: [PATCH 18/23] docs: app.setUserTasks --- docs/api/app.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/docs/api/app.md b/docs/api/app.md index 6d1ce4b01660..b7cb5f35aa08 100644 --- a/docs/api/app.md +++ b/docs/api/app.md @@ -136,6 +136,30 @@ bar, and on Mac you can visit it from dock menu. Clears the recent documents list. +## app.setUserTasks(tasks) + +* `tasks` Array - Array of `Task` objects + +Adds `tasks` to the [Tasks][tasks] category of JumpList on Windows. + +The `tasks` is an array of `Task` objects in following format: + +* `Task` Object + * `program` String - Path of the program to execute, usually you should + specify `process.execPath` which opens current program + * `arguments` String - The arguments of command line when `program` is + executed + * `title` String - The string to be displayed in a JumpList + * `description` String - Description of this task + * `iconPath` String - The absolute path to an icon to be displayed in a + JumpList, it can be arbitrary resource file that contains an icon, usually + you can specify `process.execPath` to show the icon of the program + * `iconIndex` Integer - The icon index in the icon file. If an icon file + consists of two or more icons, set this value to identify the icon. If an + icon file consists of one icon, this value is 0 + +**Note:** This API is only available on Windows. + ## app.commandLine.appendSwitch(switch, [value]) Append a switch [with optional value] to Chromium's command line. @@ -208,3 +232,4 @@ Sets the application [dock menu][dock-menu]. **Note:** This API is only available on Mac. [dock-menu]:https://developer.apple.com/library/mac/documentation/Carbon/Conceptual/customizing_docktile/concepts/dockconcepts.html#//apple_ref/doc/uid/TP30000986-CH2-TPXREF103 +[tasks]:http://msdn.microsoft.com/en-us/library/windows/desktop/dd378460(v=vs.85).aspx#tasks From 21fa395b610e4d9df3e6a35c651028f9c05ed676 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 17 Nov 2014 21:40:07 +0800 Subject: [PATCH 19/23] docs: Add "Desktop environment integration" --- docs/README.md | 1 + .../desktop-environment-integration.md | 135 ++++++++++++++++++ 2 files changed, 136 insertions(+) create mode 100644 docs/tutorial/desktop-environment-integration.md diff --git a/docs/README.md b/docs/README.md index ed7d803b72da..0d00200def5c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -4,6 +4,7 @@ * [Application distribution](tutorial/application-distribution.md) * [Application packaging](tutorial/application-packaging.md) * [Using native node modules](tutorial/using-native-node-modules.md) +* [Desktop environment integration](tutorial/desktop-environment-integration.md) * [Debugging browser process](tutorial/debugging-browser-process.md) * [Using Selenium and WebDriver](tutorial/using-selenium-and-webdriver.md) * [DevTools extension](tutorial/devtools-extension.md) diff --git a/docs/tutorial/desktop-environment-integration.md b/docs/tutorial/desktop-environment-integration.md new file mode 100644 index 000000000000..dd450e7e7901 --- /dev/null +++ b/docs/tutorial/desktop-environment-integration.md @@ -0,0 +1,135 @@ +# Desktop environment integration + +Different operating systems provide different features on integrating desktop +applications into their desktop environments, for example, on Windows +applications can put shortcuts in the JumpList of task bar, and on Mac +applications can put a custom menu in the dock menu. + +This guide introduces how to integrate your application into those desktop +environments with atom-shell APIs. + +## Recent documents + +Windows and Mac OS X have provided easy access to recent documents opened by the +application via JumpList and dock menu. + +__JumpList:__ + +![JumpList Recent Files](http://i.msdn.microsoft.com/dynimg/IC420538.png) + +__Application dock menu:__ + + + +To add a file to recent documents, you can use `app.addRecentDocument` API: + +```javascript +var app = require('app'); +app.addRecentDocument('/Users/aryastark/github/atom-shell/README.md'); +``` + +And you can use `app.clearRecentDocuments` API to empty the recent documents +list: + +```javascript +app.clearRecentDocuments(); +``` + +### Windows notes + +In order to be able to use this feature on Windows, your application has to be +registered as handler of the file type of the document, otherwise the file won't +appear in JumpList even after you have added it. You can find everything on +registering your application in [Application Registration][app-registration]. + +When a user clicks a file from JumpList, a new instance of your application will +be started with the path of file appended in command line. + +### OS X notes + +When a file is requested from the recent documents menu, the `open-file` event +of `app` module would be emitted for it. + +## Custom dock menu (OS X) + +OS X enables developers to specify a custom menu for dock, which usually +contains some shortcuts for commonly used features of your application: + +__Dock menu of Terminal.app:__ + + + +To set your custom dock menu, you can use the `app.dock.setMenu` API, which is +only available on OS X: + +```javascript +var app = require('app'); +var Menu = require('menu'); +var dockMenu = Menu.buildFromTemplate([ + { label: 'New Window', click: function() { console.log('New Window'); } }, + { label: 'New Window with Settings', submenu: [ + { label: 'Basic' }, + { label: 'Pro'}, + ]}, + { label: 'New Command...'}, +]); +app.dock.setMenu(dockMenu); +``` + +## User tasks (Windows) + +On Windows you can specify custom actions in the `Tasks` category of JumpList, +as quoted from MSDN: + +> Applications define tasks based on both the program's features and the key +> things a user is expected to do with them. Tasks should be context-free, in +> that the application does not need to be running for them to work. They +> should also be the statistically most common actions that a normal user would +> perform in an application, such as compose an email message or open the +> calendar in a mail program, create a new document in a word processor, launch +> an application in a certain mode, or launch one of its subcommands. An +> application should not clutter the menu with advanced features that standard +> users won't need or one-time actions such as registration. Do not use tasks +> for promotional items such as upgrades or special offers. +> +> It is strongly recommended that the task list be static. It should remain the +> same regardless of the state or status of the application. While it is +> possible to vary the list dynamically, you should consider that this could +> confuse the user who does not expect that portion of the destination list to +> change. + +__Tasks of Internet Explorer:__ + +![IE](http://i.msdn.microsoft.com/dynimg/IC420539.png) + +Unlike the dock menu in OS X which is a real menu, user tasks in Windows work +like application shortcuts that when user clicks a task a program would be +executed with specified arguments. + +To set user tasks for your application, you can use `app.setUserTasks` API: + +```javascript +var app = require('app'); +app.setUserTasks([ + { + program: process.execPath, + arguments: '--new-window', + iconPath: process.execPath, + iconIndex: 0, + title: 'New Window' + description: 'Create a new winodw', + } +]); +``` + +To clean your tasks list, just call `app.setUserTasks` with empty array: + +```javascript +app.setUserTasks([]); +``` + +The user tasks will still show even after your application closes, so the icon +and program path specified for a task should exist until your application is +uninstalled. + +[app-registration]:http://msdn.microsoft.com/en-us/library/windows/desktop/ee872121(v=vs.85).aspx From 2513358eb534f3d849a818e647152c628e5ec72d Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 17 Nov 2014 22:00:56 +0800 Subject: [PATCH 20/23] docs: Add notes on Unity launcher --- docs/tutorial/desktop-environment-integration.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/tutorial/desktop-environment-integration.md b/docs/tutorial/desktop-environment-integration.md index dd450e7e7901..9d99f0ebd9ac 100644 --- a/docs/tutorial/desktop-environment-integration.md +++ b/docs/tutorial/desktop-environment-integration.md @@ -132,4 +132,10 @@ The user tasks will still show even after your application closes, so the icon and program path specified for a task should exist until your application is uninstalled. +## Unity integration (Linux) + +In Unity, you can add custom entries to its launcher via modifying `.desktop` +file, see [Adding shortcuts to a launcher][unity-launcher]. + [app-registration]:http://msdn.microsoft.com/en-us/library/windows/desktop/ee872121(v=vs.85).aspx +[unity-launcher]:https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles#Adding_shortcuts_to_a_launcher From 2f36216cb0e337941d36380332ee91313224dc60 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 18 Nov 2014 10:16:17 +0800 Subject: [PATCH 21/23] docs: Some tunes on desktop-environment-integration.md --- .../desktop-environment-integration.md | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/docs/tutorial/desktop-environment-integration.md b/docs/tutorial/desktop-environment-integration.md index 9d99f0ebd9ac..d6c5ac90cabd 100644 --- a/docs/tutorial/desktop-environment-integration.md +++ b/docs/tutorial/desktop-environment-integration.md @@ -8,9 +8,9 @@ applications can put a custom menu in the dock menu. This guide introduces how to integrate your application into those desktop environments with atom-shell APIs. -## Recent documents +## Recent documents (Windows & OS X) -Windows and Mac OS X have provided easy access to recent documents opened by the +Windows and OS X have provided easy access to recent documents opened by the application via JumpList and dock menu. __JumpList:__ @@ -21,15 +21,16 @@ __Application dock menu:__ -To add a file to recent documents, you can use `app.addRecentDocument` API: +To add a file to recent documents, you can use +[app.addRecentDocument][addrecentdocument] API: ```javascript var app = require('app'); app.addRecentDocument('/Users/aryastark/github/atom-shell/README.md'); ``` -And you can use `app.clearRecentDocuments` API to empty the recent documents -list: +And you can use [app.clearRecentDocuments](clearrecentdocuments) API to empty +the recent documents list: ```javascript app.clearRecentDocuments(); @@ -106,7 +107,8 @@ Unlike the dock menu in OS X which is a real menu, user tasks in Windows work like application shortcuts that when user clicks a task a program would be executed with specified arguments. -To set user tasks for your application, you can use `app.setUserTasks` API: +To set user tasks for your application, you can use +[app.setUserTasks][setusertaskstasks] API: ```javascript var app = require('app'); @@ -132,10 +134,17 @@ The user tasks will still show even after your application closes, so the icon and program path specified for a task should exist until your application is uninstalled. -## Unity integration (Linux) +## Unity launcher shortcuts (Linux) In Unity, you can add custom entries to its launcher via modifying `.desktop` file, see [Adding shortcuts to a launcher][unity-launcher]. +__Launcher shortcuts of Audacious:__ + +![audacious](https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles?action=AttachFile&do=get&target=shortcuts.png) + +[addrecentdocument]:../api/app.md#appaddrecentdocumentpath +[clearrecentdocuments]:../api/app.md#appclearrecentdocuments +[setusertaskstasks]:../api/app.md#appsetusertaskstasks [app-registration]:http://msdn.microsoft.com/en-us/library/windows/desktop/ee872121(v=vs.85).aspx [unity-launcher]:https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles#Adding_shortcuts_to_a_launcher From 95662d423337a3f137177e8273265ecaa80f54db Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 18 Nov 2014 10:54:08 +0800 Subject: [PATCH 22/23] docs: Progress bar in taskbar --- .../desktop-environment-integration.md | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/docs/tutorial/desktop-environment-integration.md b/docs/tutorial/desktop-environment-integration.md index d6c5ac90cabd..2bc440343b80 100644 --- a/docs/tutorial/desktop-environment-integration.md +++ b/docs/tutorial/desktop-environment-integration.md @@ -143,8 +143,34 @@ __Launcher shortcuts of Audacious:__ ![audacious](https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles?action=AttachFile&do=get&target=shortcuts.png) +## Progress bar in taskbar (Windows & Unity) + +On Windows, a taskbar button can be used to display a progress bar. This enables +a window to provide progress information to the user without that user having to +switch to the window itself. + +The Unity DE also has a simililar feature that allows you to specify progress +bar in the lancher. + +__Progress bar in taskbar button:__ + +![Taskbar Progress Bar](https://cloud.githubusercontent.com/assets/639601/5081682/16691fda-6f0e-11e4-9676-49b6418f1264.png) + +__Progress bar in Unity launcher:__ + +![Unity Launcher](https://cloud.githubusercontent.com/assets/639601/5081747/4a0a589e-6f0f-11e4-803f-91594716a546.png) + +To set the progress bar for a Window, you can use the +[BrowserWindow.setProgressBar](setprogressbar) API: + +```javascript +var window = new BrowserWindow({...}); +window.setProgresssBar(0.5); +``` + [addrecentdocument]:../api/app.md#appaddrecentdocumentpath [clearrecentdocuments]:../api/app.md#appclearrecentdocuments [setusertaskstasks]:../api/app.md#appsetusertaskstasks +[setprogressbar]:../api/browser-window.md#browserwindowsetprogressbarprogress [app-registration]:http://msdn.microsoft.com/en-us/library/windows/desktop/ee872121(v=vs.85).aspx [unity-launcher]:https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles#Adding_shortcuts_to_a_launcher From 32b8366d301dab11a2d58ca04e4b82e31c3b9c12 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Tue, 18 Nov 2014 11:27:08 +0800 Subject: [PATCH 23/23] docs: Represented file of window --- .../desktop-environment-integration.md | 41 +++++++++++++++---- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/docs/tutorial/desktop-environment-integration.md b/docs/tutorial/desktop-environment-integration.md index 2bc440343b80..2afeb92a92ac 100644 --- a/docs/tutorial/desktop-environment-integration.md +++ b/docs/tutorial/desktop-environment-integration.md @@ -19,7 +19,7 @@ __JumpList:__ __Application dock menu:__ - + To add a file to recent documents, you can use [app.addRecentDocument][addrecentdocument] API: @@ -161,16 +161,41 @@ __Progress bar in Unity launcher:__ ![Unity Launcher](https://cloud.githubusercontent.com/assets/639601/5081747/4a0a589e-6f0f-11e4-803f-91594716a546.png) To set the progress bar for a Window, you can use the -[BrowserWindow.setProgressBar](setprogressbar) API: +[BrowserWindow.setProgressBar][setprogressbar] API: ```javascript var window = new BrowserWindow({...}); window.setProgresssBar(0.5); ``` -[addrecentdocument]:../api/app.md#appaddrecentdocumentpath -[clearrecentdocuments]:../api/app.md#appclearrecentdocuments -[setusertaskstasks]:../api/app.md#appsetusertaskstasks -[setprogressbar]:../api/browser-window.md#browserwindowsetprogressbarprogress -[app-registration]:http://msdn.microsoft.com/en-us/library/windows/desktop/ee872121(v=vs.85).aspx -[unity-launcher]:https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles#Adding_shortcuts_to_a_launcher +## Represented file of window (OS X) + +On OS X a window can set its represented file, so the file's icon can show in +title bar, and when users Command-Click or Control-Click on the tile a path +popup will show. + +You can also set edited state of a window so the file icon can indicate whether +the document in this window has been modified. + +__Represented file popup menu:__ + + + +To set the represented file of window, you can use the +[BrowserWindow.setRepresentedFilename][setrepresentedfilename] and +[BrowserWindow.setDocumentEdited][setdocumentedited] APIs: + +```javascript +var window = new BrowserWindow({...}); +window.setRepresentedFilename('/etc/passwd'); +window.setDocumentEdited(true); +``` + +[addrecentdocument]: ../api/app.md#appaddrecentdocumentpath +[clearrecentdocuments]: ../api/app.md#appclearrecentdocuments +[setusertaskstasks]: ../api/app.md#appsetusertaskstasks +[setprogressbar]: ../api/browser-window.md#browserwindowsetprogressbarprogress +[setrepresentedfilename]: ../api/browser-window.md#browserwindowsetrepresentedfilenamefilename +[setdocumentedited]: ../api/browser-window.md#browserwindowsetdocumenteditededited +[app-registration]: http://msdn.microsoft.com/en-us/library/windows/desktop/ee872121(v=vs.85).aspx +[unity-launcher]: https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles#Adding_shortcuts_to_a_launcher