diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index 942485397081..858e6ef197e8 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -134,6 +134,13 @@ void App::ResolveProxy(const GURL& url, ResolveProxyCallback callback) { new ResolveProxyHelper(url, callback); } +void App::SetDesktopName(const std::string& desktop_name) { +#if defined(OS_LINUX) + scoped_ptr env(base::Environment::Create()); + env->SetVar("CHROME_DESKTOP", desktop_name); +#endif +} + mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder( v8::Isolate* isolate) { Browser* browser = Browser::Get(); @@ -151,7 +158,8 @@ mate::ObjectTemplateBuilder App::GetObjectTemplateBuilder( .SetMethod("setName", base::Bind(&Browser::SetName, base::Unretained(browser))) .SetMethod("getDataPath", &App::GetDataPath) - .SetMethod("resolveProxy", &App::ResolveProxy); + .SetMethod("resolveProxy", &App::ResolveProxy) + .SetMethod("setDesktopName", &App::SetDesktopName); } // static diff --git a/atom/browser/api/atom_api_app.h b/atom/browser/api/atom_api_app.h index 91aa16b8207a..0fcbf2c0a907 100644 --- a/atom/browser/api/atom_api_app.h +++ b/atom/browser/api/atom_api_app.h @@ -50,6 +50,7 @@ class App : public mate::EventEmitter, private: base::FilePath GetDataPath(); void ResolveProxy(const GURL& url, ResolveProxyCallback callback); + void SetDesktopName(const std::string& desktop_name); DISALLOW_COPY_AND_ASSIGN(App); }; diff --git a/atom/browser/api/atom_api_window.cc b/atom/browser/api/atom_api_window.cc index 9b7cb204df3b..40498153c3fe 100644 --- a/atom/browser/api/atom_api_window.cc +++ b/atom/browser/api/atom_api_window.cc @@ -366,6 +366,10 @@ void Window::Print(mate::Arguments* args) { window_->Print(settings.silent, settings.print_backgournd); } +void Window::SetProgressBar(double progress) { + window_->SetProgressBar(progress); +} + mate::Handle Window::GetWebContents(v8::Isolate* isolate) const { return WebContents::Create(isolate, window_->GetWebContents()); } @@ -428,6 +432,7 @@ void Window::BuildPrototype(v8::Isolate* isolate, .SetMethod("isWebViewFocused", &Window::IsWebViewFocused) .SetMethod("capturePage", &Window::CapturePage) .SetMethod("print", &Window::Print) + .SetMethod("setProgressBar", &Window::SetProgressBar) .SetMethod("_getWebContents", &Window::GetWebContents) .SetMethod("_getDevToolsWebContents", &Window::GetDevToolsWebContents); } diff --git a/atom/browser/api/atom_api_window.h b/atom/browser/api/atom_api_window.h index e558b5ce00d3..25ea3700cf81 100644 --- a/atom/browser/api/atom_api_window.h +++ b/atom/browser/api/atom_api_window.h @@ -103,6 +103,7 @@ class Window : public mate::EventEmitter, bool IsDocumentEdited(); void CapturePage(mate::Arguments* args); void Print(mate::Arguments* args); + void SetProgressBar(double progress); // APIs for WebContents. mate::Handle GetWebContents(v8::Isolate* isolate) const; diff --git a/atom/browser/lib/init.coffee b/atom/browser/lib/init.coffee index be752382b831..d25179c1ba49 100644 --- a/atom/browser/lib/init.coffee +++ b/atom/browser/lib/init.coffee @@ -77,6 +77,12 @@ setImmediate -> else if packageJson.name? app.setName packageJson.name + # Set application's desktop name. + if packageJson.desktopName? + app.setDesktopName packageJson.desktopName + else + app.setDesktopName '#{app.getName()}.desktop' + # Load the chrome extension support. require './chrome-extension.js' diff --git a/atom/browser/native_window.h b/atom/browser/native_window.h index 1da62ce3f7bd..929c1aabc5bb 100644 --- a/atom/browser/native_window.h +++ b/atom/browser/native_window.h @@ -140,6 +140,7 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate, virtual void SetMenu(ui::MenuModel* menu); virtual bool HasModalDialog(); virtual gfx::NativeWindow GetNativeWindow() = 0; + virtual void SetProgressBar(double progress) = 0; virtual bool IsClosed() const { return is_closed_; } virtual void OpenDevTools(); diff --git a/atom/browser/native_window_mac.h b/atom/browser/native_window_mac.h index 0f3e26f9a387..ecdabc800cd5 100644 --- a/atom/browser/native_window_mac.h +++ b/atom/browser/native_window_mac.h @@ -65,6 +65,7 @@ class NativeWindowMac : public NativeWindow { virtual bool IsDocumentEdited() OVERRIDE; virtual bool HasModalDialog() OVERRIDE; virtual gfx::NativeWindow GetNativeWindow() OVERRIDE; + virtual void SetProgressBar(double progress) OVERRIDE; // Returns true if |point| in local Cocoa coordinate system falls within // the draggable region. diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 587dcc602ed3..c5fd5522d6d2 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -193,6 +193,39 @@ static const CGFloat kAtomWindowCornerRadius = 4.0; @end +@interface AtomProgressBar : NSProgressIndicator +@end + +@implementation AtomProgressBar + +- (void)drawRect:(NSRect)dirtyRect { + if (self.style != NSProgressIndicatorBarStyle) + return; + // Draw edges of rounded rect. + NSRect rect = NSInsetRect([self bounds], 1.0, 1.0); + CGFloat radius = rect.size.height / 2; + NSBezierPath* bezier_path = [NSBezierPath bezierPathWithRoundedRect:rect xRadius:radius yRadius:radius]; + [bezier_path setLineWidth:2.0]; + [[NSColor grayColor] set]; + [bezier_path stroke]; + + // Fill the rounded rect. + rect = NSInsetRect(rect, 2.0, 2.0); + radius = rect.size.height / 2; + bezier_path = [NSBezierPath bezierPathWithRoundedRect:rect xRadius:radius yRadius:radius]; + [bezier_path setLineWidth:1.0]; + [bezier_path addClip]; + + // Calculate the progress width. + rect.size.width = floor(rect.size.width * ([self doubleValue] / [self maxValue])); + + // Fill the progress bar with color blue. + [[NSColor colorWithSRGBRed:0.2 green:0.6 blue:1 alpha:1] set]; + NSRectFill(rect); +} + +@end + namespace atom { NativeWindowMac::NativeWindowMac(content::WebContents* web_contents, @@ -517,6 +550,39 @@ gfx::NativeWindow NativeWindowMac::GetNativeWindow() { return window_; } +void NativeWindowMac::SetProgressBar(double progress) { + NSDockTile* dock_tile = [NSApp dockTile]; + + // For the first time API invoked, we need to create a ContentView in DockTile. + if (dock_tile.contentView == NULL) { + NSImageView* image_view = [[NSImageView alloc] init]; + [image_view setImage:[NSApp applicationIconImage]]; + [dock_tile setContentView:image_view]; + + NSProgressIndicator* progress_indicator = [[AtomProgressBar alloc] + initWithFrame:NSMakeRect(0.0f, 0.0f, dock_tile.size.width, 15.0)]; + [progress_indicator setStyle:NSProgressIndicatorBarStyle]; + [progress_indicator setIndeterminate:NO]; + [progress_indicator setBezeled:YES]; + [progress_indicator setMinValue:0]; + [progress_indicator setMaxValue:1]; + [progress_indicator setHidden:NO]; + [image_view addSubview:progress_indicator]; + } + + NSProgressIndicator* progress_indicator = + static_cast([[[dock_tile contentView] subviews] + objectAtIndex:0]); + if (progress < 0) { + [progress_indicator setHidden:YES]; + } else if (progress > 1) { + [progress_indicator setIndeterminate:YES]; + } else { + [progress_indicator setDoubleValue:progress]; + } + [dock_tile display]; +} + bool NativeWindowMac::IsWithinDraggableRegion(NSPoint point) const { if (!draggable_region_) return false; diff --git a/atom/browser/native_window_views.cc b/atom/browser/native_window_views.cc index 3892b7181b94..08c23cc3d153 100644 --- a/atom/browser/native_window_views.cc +++ b/atom/browser/native_window_views.cc @@ -43,7 +43,9 @@ #elif defined(OS_WIN) #include "atom/browser/ui/views/win_frame_view.h" #include "base/win/scoped_comptr.h" +#include "base/win/windows_version.h" #include "ui/base/win/shell.h" +#include "ui/views/win/hwnd_util.h" #endif namespace atom { @@ -479,6 +481,33 @@ gfx::NativeWindow NativeWindowViews::GetNativeWindow() { return window_->GetNativeWindow(); } +void NativeWindowViews::SetProgressBar(double progress) { +#if defined(OS_WIN) + if (base::win::GetVersion() < base::win::VERSION_WIN7) + return; + base::win::ScopedComPtr taskbar; + if (FAILED(taskbar.CreateInstance(CLSID_TaskbarList, NULL, + CLSCTX_INPROC_SERVER) || + FAILED(taskbar->HrInit()))) { + return; + } + HWND frame = views::HWNDForNativeWindow(GetNativeWindow()); + if (progress > 1.0) { + taskbar->SetProgressState(frame, TBPF_INDETERMINATE); + } else if (progress < 0) { + taskbar->SetProgressState(frame, TBPF_NOPROGRESS); + } else if (progress >= 0) { + taskbar->SetProgressValue(frame, + static_cast(progress * 100), + progress); + } +#elif defined(USE_X11) + if (unity::IsRunning()) { + unity::SetProgressFraction(progress); + } +#endif +} + gfx::AcceleratedWidget NativeWindowViews::GetAcceleratedWidget() { return GetNativeWindow()->GetHost()->GetAcceleratedWidget(); } diff --git a/atom/browser/native_window_views.h b/atom/browser/native_window_views.h index 3d81a68be224..b38769c39265 100644 --- a/atom/browser/native_window_views.h +++ b/atom/browser/native_window_views.h @@ -71,6 +71,7 @@ class NativeWindowViews : public NativeWindow, virtual bool IsKiosk() OVERRIDE; virtual void SetMenu(ui::MenuModel* menu_model) OVERRIDE; virtual gfx::NativeWindow GetNativeWindow() OVERRIDE; + virtual void SetProgressBar(double value) OVERRIDE; gfx::AcceleratedWidget GetAcceleratedWidget(); diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index f8928327e5be..de8da2e32eec 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -488,6 +488,19 @@ Sets the `menu` as the window top menu. __Note:__ This API is not available on OS X. +### BrowserWindow.setProgressBar(progress) + +* `progress` Double + +Sets progress value in progress bar. Valid range is [0, 1.0]. + +Remove progress bar when progress < 0; +Change to indeterminate mode when progress > 1. + +On Linux platform, only supports Unity desktop environment, you need to specify +the `*.desktop` file name to `desktopName` field in `package.json`. By default, +it will assume `app.getName().desktop`. + ## Class: WebContents A `WebContents` is responsible for rendering and controlling a web page.