Compare commits

...

24 Commits

Author SHA1 Message Date
John Kleinschmidt
01ca2252cd Bump v1.7.8 2017-09-24 10:34:18 +09:00
John Kleinschmidt
53db3862c0 Merge pull request #10591 from electron/disable-app-importcertificate-tests
disable flaky app.importCertificate and select-client-certificate tests
2017-09-24 10:25:57 +09:00
John Kleinschmidt
6099ab222e Change GitHub upload to use JS GitHub lib 2017-09-24 10:17:15 +09:00
Zeke Sikelianos
830cc7ecd1 disable select-client-certificate spec 2017-09-24 10:00:34 +09:00
Zeke Sikelianos
eef8ff09e2 disable flaky app.importCertificate tests 2017-09-24 09:49:48 +09:00
Samuel Attard
b15392e1c1 Backporting changes for 1.7.8 (#10586)
* Fix app.makeSingleInstance hanging on posix systems

Wait for the IO thread to be a thing before attempting to listen on the socket

Fixes #9880

* Move OnBrowserReady call to PreMainMessageLoopRun to account for timing issues on macOS

* Woops, how did that happen ;)

* Refactor as per @zcbenz comments

Also fix issue where we run the single instance callback *not* on the UI thread,
this apparently results in a hung process.

* Appease the linting gods

* Create watcher when message loop is ready

* spec: Add test case for app.makeSingleInstance

* Fix missing extension when saving a file without filters

Previously, when triggering the save dialog through e.g. `<a download>`
links (e.g. http://jsfiddle.net/koldev/cW7W5/), the extension was only
saved if Finder was set to show all extensions by default. We now always
display the extension to make sure that it is saved.

If we want to keep the extension hidden, we could also populate the
allowed file types array with the extension from the default filename,
but that would have interfered with how we set the filters.

* Try to make test less flaky

* Try simpler test

* Fix stdout detection

* Try longer timeout on test
2017-09-24 07:27:08 +09:00
John Kleinschmidt
fd1bb3f95d Merge pull request #10585 from electron/turbofan-fix
Apply turbofan-fix
2017-09-23 16:06:34 +09:00
John Kleinschmidt
53eb4d68c5 Apply turbofan-fix 2017-09-23 15:05:15 +09:00
John Kleinschmidt
331a1759d2 Fix CircleCI test step 2017-09-13 11:22:33 -04:00
John Kleinschmidt
b69d76258a Remove arm64 build
Arm64 builds are not built for 1.7.x
2017-09-13 10:50:53 -04:00
John Kleinschmidt
680bf0076b Bump v1.7.7 2017-08-30 13:06:59 -04:00
John Kleinschmidt
d42d856b9a Rerun builds 2017-08-30 09:42:23 -04:00
John Kleinschmidt
e6f6862ae8 Merge pull request #10390 from electron/render_widget_compositor_patch
Backport fix for flickering web contents on large monitors
2017-08-29 21:52:35 -04:00
John Kleinschmidt
44b4cc374b Update to latest build 2017-08-29 21:27:59 -04:00
John Kleinschmidt
9824c88d2d Backport fix for flickering web contents on large monitors 2017-08-29 13:43:02 -04:00
John Kleinschmidt
96bc46c255 Merge pull request #10365 from electron/fix_exit_crash
Fixed crash on process exit on Windows
2017-08-29 11:55:12 -04:00
John Kleinschmidt
873a8902af Merge pull request #10375 from electron/backport-notification-sounds
Backport #10293 (notification-sounds)
2017-08-29 10:52:26 -04:00
John Kleinschmidt
7dac300305 Merge pull request #10377 from electron/backfort-libuv-1419
Backport libuv/libuv#1419
2017-08-29 10:50:32 -04:00
John Kleinschmidt
2a536d2aa2 Merge pull request #10374 from electron/backport-drag-browser-view
Backport #10232 (drag-browser-view)
2017-08-29 09:34:58 -04:00
Cheng Zhao
ccd03c6675 Backport https://github.com/libuv/libuv/pull/1419
win, fs: support unusual reparse points

Allow for running uv_fs_stat and uv_fs_lstat on all reparse points. One
of such points is new OneDrive drive with "files on demand" feature
enabled.
2017-08-29 10:25:45 +09:00
Charlie Hess
5515092944 Merge pull request #10293 from electron/notification-sounds
Add support for soundName in main process notifications
2017-08-28 13:23:27 -07:00
Samuel Attard
fb7661d2d2 Merge pull request #10232 from electron/drag-browser-view
Add -webkit-app-region support to BrowserView
2017-08-28 13:19:09 -07:00
John Kleinschmidt
75b31f0bb6 Add CircleCI 2017-08-28 11:35:30 -04:00
Ales Pergl
cfee5ba8c8 Fixed crash on process exit on Windows 2017-08-28 16:28:07 +02:00
36 changed files with 419 additions and 40 deletions

41
.circleci/config.yml Normal file
View File

@@ -0,0 +1,41 @@
version: 2
jobs:
electron-linux-arm:
docker:
- image: electronbuilds/electron:0.0.3
environment:
TARGET_ARCH: arm
steps:
- checkout
- run: script/cibuild
electron-linux-ia32:
docker:
- image: electronbuilds/electron:0.0.3
environment:
TARGET_ARCH: ia32
steps:
- checkout
- run: script/cibuild
electron-linux-x64:
docker:
- image: electronbuilds/electron:0.0.3
environment:
TARGET_ARCH: x64
steps:
- checkout
- run: script/cibuild
workflows:
version: 2
build-arm:
jobs:
- electron-linux-arm
build-ia32:
jobs:
- electron-linux-ia32
build-x64:
jobs:
- electron-linux-x64

View File

@@ -95,6 +95,25 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t* cmd, int) {
}
}
#ifndef DEBUG
// Chromium has its own TLS subsystem which supports automatic destruction
// of thread-local data, and also depends on memory allocation routines
// provided by the CRT. The problem is that the auto-destruction mechanism
// uses a hidden feature of the OS loader which calls a callback on thread
// exit, but only after all loaded DLLs have been detached. Since the CRT is
// also a DLL, it happens that by the time Chromium's `OnThreadExit` function
// is called, the heap functions, though still in memory, no longer perform
// their duties, and when Chromium calls `free` on its buffer, it triggers
// an access violation error.
// We work around this problem by invoking Chromium's `OnThreadExit` in time
// from within the CRT's atexit facility, ensuring the heap functions are
// still active. The second invocation from the OS loader will be a no-op.
extern void NTAPI OnThreadExit(PVOID module, DWORD reason, PVOID reserved);
atexit([]() {
OnThreadExit(nullptr, DLL_THREAD_DETACH, nullptr);
});
#endif
if (run_as_node) {
// Now that argv conversion is done, we can finally start.
base::AtExitManager atexit_manager;

View File

@@ -575,6 +575,12 @@ void App::OnFinishLaunching(const base::DictionaryValue& launch_info) {
Emit("ready", launch_info);
}
void App::OnPreMainMessageLoopRun() {
if (process_singleton_) {
process_singleton_->OnBrowserReady();
}
}
void App::OnAccessibilitySupportChanged() {
Emit("accessibility-support-changed", IsAccessibilitySupportEnabled());
}

View File

@@ -94,6 +94,7 @@ class App : public AtomBrowserClient::Delegate,
base::FilePath GetAppPath() const;
void RenderProcessReady(content::RenderProcessHost* host);
void RenderProcessDisconnected(base::ProcessId host_pid);
void PreMainMessageLoopRun();
protected:
explicit App(v8::Isolate* isolate);
@@ -112,6 +113,7 @@ class App : public AtomBrowserClient::Delegate,
void OnLogin(LoginHandler* login_handler,
const base::DictionaryValue& request_details) override;
void OnAccessibilitySupportChanged() override;
void OnPreMainMessageLoopRun() override;
#if defined(OS_MACOSX)
void OnContinueUserActivity(
bool* prevent_default,

View File

@@ -67,6 +67,7 @@ Notification::Notification(v8::Isolate* isolate,
opts.Get("replyPlaceholder", &reply_placeholder_);
opts.Get("hasReply", &has_reply_);
opts.Get("actions", &actions_);
opts.Get("sound", &sound_);
}
}
@@ -113,6 +114,10 @@ std::vector<brightray::NotificationAction> Notification::GetActions() const {
return actions_;
}
base::string16 Notification::GetSound() const {
return sound_;
}
// Setters
void Notification::SetTitle(const base::string16& new_title) {
title_ = new_title;
@@ -143,6 +148,10 @@ void Notification::SetActions(
actions_ = actions;
}
void Notification::SetSound(const base::string16& new_sound) {
sound_ = new_sound;
}
void Notification::NotificationAction(int index) {
Emit("action", index);
}
@@ -181,6 +190,7 @@ void Notification::Show() {
options.has_reply = has_reply_;
options.reply_placeholder = reply_placeholder_;
options.actions = actions_;
options.sound = sound_;
notification_->Show(options);
}
}
@@ -207,7 +217,9 @@ void Notification::BuildPrototype(v8::Isolate* isolate,
.SetProperty("hasReply", &Notification::GetHasReply,
&Notification::SetHasReply)
.SetProperty("actions", &Notification::GetActions,
&Notification::SetActions);
&Notification::SetActions)
.SetProperty("sound", &Notification::GetSound,
&Notification::SetSound);
}
} // namespace api

View File

@@ -54,6 +54,7 @@ class Notification : public mate::TrackableObject<Notification>,
base::string16 GetReplyPlaceholder() const;
bool GetHasReply() const;
std::vector<brightray::NotificationAction> GetActions() const;
base::string16 GetSound() const;
// Prop Setters
void SetTitle(const base::string16& new_title);
@@ -63,6 +64,7 @@ class Notification : public mate::TrackableObject<Notification>,
void SetReplyPlaceholder(const base::string16& new_reply_placeholder);
void SetHasReply(bool new_has_reply);
void SetActions(const std::vector<brightray::NotificationAction>& actions);
void SetSound(const base::string16& sound);
private:
base::string16 title_;
@@ -75,6 +77,7 @@ class Notification : public mate::TrackableObject<Notification>,
base::string16 reply_placeholder_;
bool has_reply_ = false;
std::vector<brightray::NotificationAction> actions_;
base::string16 sound_;
brightray::NotificationPresenter* presenter_;

View File

@@ -4,6 +4,7 @@
#include "atom/browser/atom_browser_main_parts.h"
#include "atom/browser/api/atom_api_app.h"
#include "atom/browser/api/trackable_object.h"
#include "atom/browser/atom_access_token_store.h"
#include "atom/browser/atom_browser_client.h"
@@ -183,6 +184,8 @@ void AtomBrowserMainParts::PreMainMessageLoopRun() {
std::unique_ptr<base::DictionaryValue> empty_info(new base::DictionaryValue);
Browser::Get()->DidFinishLaunching(*empty_info);
#endif
Browser::Get()->PreMainMessageLoopRun();
}
bool AtomBrowserMainParts::MainMessageLoopRun(int* result_code) {

View File

@@ -171,6 +171,12 @@ void Browser::RequestLogin(
observer.OnLogin(login_handler, *(request_details.get()));
}
void Browser::PreMainMessageLoopRun() {
for (BrowserObserver& observer : observers_) {
observer.OnPreMainMessageLoopRun();
}
}
void Browser::NotifyAndShutdown() {
if (is_shutdown_)
return;

View File

@@ -202,6 +202,8 @@ class Browser : public WindowListObserver {
void RequestLogin(LoginHandler* login_handler,
std::unique_ptr<base::DictionaryValue> request_details);
void PreMainMessageLoopRun();
void AddObserver(BrowserObserver* obs) {
observers_.AddObserver(obs);
}

View File

@@ -55,6 +55,9 @@ class BrowserObserver {
// The browser's accessibility suppport has changed.
virtual void OnAccessibilitySupportChanged() {}
// The app message loop is ready
virtual void OnPreMainMessageLoopRun() {}
#if defined(OS_MACOSX)
// The browser wants to resume a user activity via handoff. (macOS only)
virtual void OnContinueUserActivity(

View File

@@ -2,6 +2,8 @@
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include <vector>
#include "atom/browser/native_browser_view.h"
#include "atom/browser/api/atom_api_web_contents.h"

View File

@@ -5,6 +5,9 @@
#ifndef ATOM_BROWSER_NATIVE_BROWSER_VIEW_H_
#define ATOM_BROWSER_NATIVE_BROWSER_VIEW_H_
#include <vector>
#include "atom/common/draggable_region.h"
#include "base/macros.h"
#include "third_party/skia/include/core/SkColor.h"
@@ -38,6 +41,10 @@ class NativeBrowserView {
virtual void SetBounds(const gfx::Rect& bounds) = 0;
virtual void SetBackgroundColor(SkColor color) = 0;
// Called when the window needs to update its draggable region.
virtual void UpdateDraggableRegions(
const std::vector<gfx::Rect>& system_drag_exclude_areas) {}
protected:
explicit NativeBrowserView(
brightray::InspectableWebContentsView* web_contents_view);

View File

@@ -6,8 +6,11 @@
#define ATOM_BROWSER_NATIVE_BROWSER_VIEW_MAC_H_
#import <Cocoa/Cocoa.h>
#include <vector>
#include "atom/browser/native_browser_view.h"
#include "atom/common/draggable_region.h"
#include "base/mac/scoped_nsobject.h"
namespace atom {
@@ -20,6 +23,8 @@ class NativeBrowserViewMac : public NativeBrowserView {
void SetAutoResizeFlags(uint8_t flags) override;
void SetBounds(const gfx::Rect& bounds) override;
void SetBackgroundColor(SkColor color) override;
void UpdateDraggableRegions(
const std::vector<gfx::Rect>& system_drag_exclude_areas) override;
private:
DISALLOW_COPY_AND_ASSIGN(NativeBrowserViewMac);

View File

@@ -12,6 +12,101 @@
const NSAutoresizingMaskOptions kDefaultAutoResizingMask =
NSViewMaxXMargin | NSViewMinYMargin;
@interface DragRegionView : NSView
@property (assign) NSPoint initialLocation;
@end
@interface NSWindow ()
- (void)performWindowDragWithEvent:(NSEvent *)event;
@end
@implementation DragRegionView
- (BOOL)mouseDownCanMoveWindow
{
return NO;
}
- (NSView *)hitTest:(NSPoint)aPoint
{
// Pass-through events that don't hit one of the exclusion zones
for (NSView *exlusion_zones in [self subviews]) {
if ([exlusion_zones hitTest:aPoint])
return nil;
}
return self;
}
- (void)mouseDown:(NSEvent *)event
{
if ([self.window respondsToSelector:@selector(performWindowDragWithEvent)]) {
[self.window performWindowDragWithEvent:event];
return;
}
self.initialLocation = [event locationInWindow];
}
- (void)mouseDragged:(NSEvent *)theEvent
{
if ([self.window respondsToSelector:@selector(performWindowDragWithEvent)]) {
return;
}
NSPoint currentLocation = [NSEvent mouseLocation];
NSPoint newOrigin;
NSRect screenFrame = [[NSScreen mainScreen] frame];
NSRect windowFrame = [self.window frame];
newOrigin.x = currentLocation.x - self.initialLocation.x;
newOrigin.y = currentLocation.y - self.initialLocation.y;
// Don't let window get dragged up under the menu bar
if ((newOrigin.y + windowFrame.size.height) > (screenFrame.origin.y + screenFrame.size.height)) {
newOrigin.y = screenFrame.origin.y + (screenFrame.size.height - windowFrame.size.height);
}
// Move the window to the new location
[self.window setFrameOrigin:newOrigin];
}
// Debugging tips:
// Uncomment the following four lines to color DragRegionView bright red
// #ifdef DEBUG_DRAG_REGIONS
// - (void)drawRect:(NSRect)aRect
// {
// [[NSColor redColor] set];
// NSRectFill([self bounds]);
// }
// #endif
@end
@interface ExcludeDragRegionView : NSView
@end
@implementation ExcludeDragRegionView
- (BOOL)mouseDownCanMoveWindow {
return NO;
}
// Debugging tips:
// Uncomment the following four lines to color ExcludeDragRegionView bright red
// #ifdef DEBUG_DRAG_REGIONS
// - (void)drawRect:(NSRect)aRect
// {
// [[NSColor greenColor] set];
// NSRectFill([self bounds]);
// }
// #endif
@end
namespace atom {
NativeBrowserViewMac::NativeBrowserViewMac(
@@ -51,6 +146,59 @@ void NativeBrowserViewMac::SetBackgroundColor(SkColor color) {
view.layer.backgroundColor = skia::CGColorCreateFromSkColor(color);
}
void NativeBrowserViewMac::UpdateDraggableRegions(
const std::vector<gfx::Rect>& system_drag_exclude_areas) {
NSView* webView = GetInspectableWebContentsView()->GetNativeView();
NSInteger superViewHeight = NSHeight([webView.superview bounds]);
NSInteger webViewHeight = NSHeight([webView bounds]);
NSInteger webViewWidth = NSWidth([webView bounds]);
NSInteger webViewX = NSMinX([webView frame]);
NSInteger webViewY = 0;
// Apple's NSViews have their coordinate system originate at the bottom left,
// meaning that we need to be a bit smarter when it comes to calculating our
// current top offset
if (webViewHeight > superViewHeight) {
webViewY = std::abs(webViewHeight - superViewHeight - (std::abs(NSMinY([webView frame]))));
} else {
webViewY = superViewHeight - NSMaxY([webView frame]);
}
// Remove all DraggableRegionViews that are added last time.
// Note that [webView subviews] returns the view's mutable internal array and
// it should be copied to avoid mutating the original array while enumerating
// it.
base::scoped_nsobject<NSArray> subviews([[webView subviews] copy]);
for (NSView* subview in subviews.get())
if ([subview isKindOfClass:[DragRegionView class]])
[subview removeFromSuperview];
// Create one giant NSView that is draggable.
base::scoped_nsobject<NSView> dragRegion(
[[DragRegionView alloc] initWithFrame:NSZeroRect]);
[dragRegion setFrame:NSMakeRect(0,
0,
webViewWidth,
webViewHeight)];
// Then, on top of that, add "exclusion zones"
for (auto iter = system_drag_exclude_areas.begin();
iter != system_drag_exclude_areas.end();
++iter) {
base::scoped_nsobject<NSView> controlRegion(
[[ExcludeDragRegionView alloc] initWithFrame:NSZeroRect]);
[controlRegion setFrame:NSMakeRect(iter->x() - webViewX,
webViewHeight - iter->bottom() + webViewY,
iter->width(),
iter->height())];
[dragRegion addSubview:controlRegion];
}
// Add the DragRegion to the WebView
[webView addSubview:dragRegion];
}
// static
NativeBrowserView* NativeBrowserView::Create(
brightray::InspectableWebContentsView* web_contents_view) {

View File

@@ -154,7 +154,7 @@ class NativeWindowMac : public NativeWindow,
void UninstallView();
// Install the drag view, which will cover the whole window and decides
// whehter we can drag.
// whether we can drag.
void UpdateDraggableRegionViews(const std::vector<DraggableRegion>& regions);
void RegisterInputEventObserver(content::RenderViewHost* host);

View File

@@ -1767,6 +1767,10 @@ void NativeWindowMac::UpdateDraggableRegionViews(
std::vector<gfx::Rect> system_drag_exclude_areas =
CalculateNonDraggableRegions(regions, webViewWidth, webViewHeight);
if (browser_view_) {
browser_view_->UpdateDraggableRegions(system_drag_exclude_areas);
}
// Create and add a ControlRegionView for each region that needs to be
// excluded from the dragging.
for (std::vector<gfx::Rect>::const_iterator iter =

View File

@@ -17,9 +17,9 @@
<key>CFBundleIconFile</key>
<string>electron.icns</string>
<key>CFBundleVersion</key>
<string>1.7.6</string>
<string>1.7.8</string>
<key>CFBundleShortVersionString</key>
<string>1.7.6</string>
<string>1.7.8</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.developer-tools</string>
<key>LSMinimumSystemVersion</key>

View File

@@ -56,8 +56,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,7,6,0
PRODUCTVERSION 1,7,6,0
FILEVERSION 1,7,8,0
PRODUCTVERSION 1,7,8,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -74,12 +74,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "GitHub, Inc."
VALUE "FileDescription", "Electron"
VALUE "FileVersion", "1.7.6"
VALUE "FileVersion", "1.7.8"
VALUE "InternalName", "electron.exe"
VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved."
VALUE "OriginalFilename", "electron.exe"
VALUE "ProductName", "Electron"
VALUE "ProductVersion", "1.7.6"
VALUE "ProductVersion", "1.7.8"
VALUE "SquirrelAwareVersion", "1"
END
END

View File

@@ -40,7 +40,6 @@ void SetAllowedFileTypes(NSSavePanel* dialog, const Filters& filters) {
if ([file_type_set count])
file_types = [file_type_set allObjects];
[dialog setExtensionHidden:NO];
[dialog setAllowedFileTypes:file_types];
}
@@ -84,11 +83,14 @@ void SetupDialog(NSSavePanel* dialog,
SetAllowedFileTypes(dialog, settings.filters);
}
// Make sure the extension is always visible. Without this, the extension in
// the default filename will not be used in the saved file.
[dialog setExtensionHidden:NO];
if (default_dir)
[dialog setDirectoryURL:[NSURL fileURLWithPath:default_dir]];
if (default_filename)
[dialog setNameFieldStringValue:default_filename];
}
void SetupDialogForProperties(NSOpenPanel* dialog, int properties) {

View File

@@ -7,7 +7,7 @@
#define ATOM_MAJOR_VERSION 1
#define ATOM_MINOR_VERSION 7
#define ATOM_PATCH_VERSION 6
#define ATOM_PATCH_VERSION 8
#define ATOM_VERSION_IS_RELEASE 1

View File

@@ -39,6 +39,8 @@ void CocoaNotification::Show(const NotificationOptions& options) {
if (options.silent) {
[notification_ setSoundName:nil];
} else if (options.sound != nil) {
[notification_ setSoundName:base::SysUTF16ToNSString(options.sound)];
} else {
[notification_ setSoundName:NSUserNotificationDefaultSoundName];
}

View File

@@ -33,6 +33,7 @@ struct NotificationOptions {
bool silent;
bool has_reply;
base::string16 reply_placeholder;
base::string16 sound;
std::vector<NotificationAction> actions;
};

View File

@@ -74,6 +74,8 @@ class ProcessSingleton : public base::NonThreadSafe {
// TODO(brettw): Make the implementation of this method non-platform-specific
// by making Linux re-use the Windows implementation.
NotifyResult NotifyOtherProcessOrCreate();
void StartListeningOnSocket();
void OnBrowserReady();
// Sets ourself up as the singleton instance. Returns true on success. If
// false is returned, we are not the singleton instance and the caller must
@@ -173,6 +175,8 @@ class ProcessSingleton : public base::NonThreadSafe {
// because it posts messages between threads.
class LinuxWatcher;
scoped_refptr<LinuxWatcher> watcher_;
int sock_;
bool listen_on_ready_ = false;
#endif
DISALLOW_COPY_AND_ASSIGN(ProcessSingleton);

View File

@@ -55,6 +55,7 @@
#include <stddef.h>
#include "atom/browser/browser.h"
#include "atom/common/atom_command_line.h"
#include "base/base_paths.h"
@@ -719,8 +720,7 @@ ProcessSingleton::ProcessSingleton(
const base::FilePath& user_data_dir,
const NotificationCallback& notification_callback)
: notification_callback_(notification_callback),
current_pid_(base::GetCurrentProcId()),
watcher_(new LinuxWatcher(this)) {
current_pid_(base::GetCurrentProcId()) {
// The user_data_dir may have not been created yet.
base::CreateDirectoryAndGetError(user_data_dir, nullptr);
@@ -881,6 +881,23 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessOrCreate() {
base::TimeDelta::FromSeconds(kTimeoutInSeconds));
}
void ProcessSingleton::StartListeningOnSocket() {
watcher_ = new LinuxWatcher(this);
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
base::Bind(&ProcessSingleton::LinuxWatcher::StartListening,
watcher_,
sock_));
}
void ProcessSingleton::OnBrowserReady() {
if (listen_on_ready_) {
StartListeningOnSocket();
listen_on_ready_ = false;
}
}
ProcessSingleton::NotifyResult
ProcessSingleton::NotifyOtherProcessWithTimeoutOrCreate(
const base::CommandLine& command_line,
@@ -1031,13 +1048,13 @@ bool ProcessSingleton::Create() {
if (listen(sock, 5) < 0)
NOTREACHED() << "listen failed: " << base::safe_strerror(errno);
DCHECK(BrowserThread::IsMessageLoopValid(BrowserThread::IO));
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
base::Bind(&ProcessSingleton::LinuxWatcher::StartListening,
watcher_,
sock));
sock_ = sock;
if (BrowserThread::IsMessageLoopValid(BrowserThread::IO)) {
StartListeningOnSocket();
} else {
listen_on_ready_ = true;
}
return true;
}

View File

@@ -258,6 +258,9 @@ ProcessSingleton::NotifyOtherProcessOrCreate() {
return result;
}
void ProcessSingleton::StartListeningOnSocket() {}
void ProcessSingleton::OnBrowserReady() {}
// Look for a Chrome instance that uses the same profile directory. If there
// isn't one, create a message window with its title set to the profile
// directory path.

View File

@@ -37,6 +37,7 @@ Returns `Boolean` - Whether or not desktop notifications are supported on the cu
* `icon` [NativeImage](native-image.md) - (optional) An icon to use in the notification
* `hasReply` Boolean - (optional) Whether or not to add an inline reply option to the notification. _macOS_
* `replyPlaceholder` String - (optional) The placeholder to write in the inline reply input field. _macOS_
* `sound` String - (optional) The name of the sound file to play when the notification is shown. _macOS_
* `actions` [NotificationAction[]](structures/notification-action.md) - (optional) Actions to add to the notification. Please read the available actions and limitations in the `NotificationAction` documentation _macOS_
@@ -102,3 +103,18 @@ Immediately shows the notification to the user, please note this means unlike th
HTML5 Notification implementation, simply instantiating a `new Notification` does
not immediately show it to the user, you need to call this method before the OS
will display it.
### Playing Sounds
On macOS, you can specify the name of the sound you'd like to play when the
notification is shown. Any of the default sounds (under System Preferences >
Sound) can be used, in addition to custom sound files. Be sure that the sound
file is copied under the app bundle (e.g., `YourApp.app/Contents/Resources`),
or one of the following locations:
* `~/Library/Sounds`
* `/Library/Sounds`
* `/Network/Library/Sounds`
* `/System/Library/Sounds`
See the [`NSSound`](https://developer.apple.com/documentation/appkit/nssound) docs for more information.

View File

@@ -4,7 +4,7 @@
'product_name%': 'Electron',
'company_name%': 'GitHub, Inc',
'company_abbr%': 'github',
'version%': '1.7.6',
'version%': '1.7.8',
'js2c_input_dir': '<(SHARED_INTERMEDIATE_DIR)/js2c',
},
'includes': [

View File

@@ -1,6 +1,6 @@
{
"name": "electron",
"version": "1.7.6",
"version": "1.7.8",
"repository": "https://github.com/electron/electron",
"description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
"devDependencies": {

View File

@@ -63,10 +63,9 @@ def main():
deps += LINUX_DEPS_NO_ARM
execute(['sudo', 'apt-get', 'install'] + deps)
execute(['sh', '-e', '/etc/init.d/xvfb', 'start'])
if PLATFORM == 'linux':
if PLATFORM == 'linux' and target_arch == 'x64':
os.environ['DISPLAY'] = ':99.0'
execute(['sh', '-e', '/etc/init.d/xvfb', 'start'])
# CI's npm is not reliable.
npm = 'npm.cmd' if PLATFORM == 'win32' else 'npm'

View File

@@ -0,0 +1,21 @@
const GitHub = require('github')
const github = new GitHub()
github.authenticate({type: 'token', token: process.env.ELECTRON_GITHUB_TOKEN})
let filePath = process.argv[2]
let fileName = process.argv[3]
let releaseId = process.argv[4]
let githubOpts = {
owner: 'electron',
repo: 'electron',
id: releaseId,
filePath: filePath,
name: fileName
}
github.repos.uploadAsset(githubOpts).then(() => {
process.exit()
}).catch((err) => {
console.log(`Error uploading ${fileName} to GitHub:`, err)
process.exitCode = 1
})

View File

@@ -67,7 +67,7 @@ def main():
run_python_script('upload-index-json.py')
# Create and upload the Electron SHASUMS*.txt
release_electron_checksums(github, release)
release_electron_checksums(release)
# Press the publish button.
publish_release(github, release['id'])
@@ -198,11 +198,14 @@ def create_release_draft(github, tag):
return r
def release_electron_checksums(github, release):
def release_electron_checksums(release):
checksums = run_python_script('merge-electron-checksums.py',
'-v', ELECTRON_VERSION)
upload_io_to_github(github, release, 'SHASUMS256.txt',
StringIO(checksums.decode('utf-8')), 'text/plain')
filename = 'SHASUMS256.txt'
filepath = os.path.join(SOURCE_ROOT, filename)
with open(filepath, 'w') as sha_file:
sha_file.write(checksums.decode('utf-8'))
upload_io_to_github(release, filename, filepath)
def upload_electron(github, release, file_path):
@@ -217,8 +220,7 @@ def upload_electron(github, release, file_path):
pass
# Upload the file.
with open(file_path, 'rb') as f:
upload_io_to_github(github, release, filename, f, 'application/zip')
upload_io_to_github(release, filename, file_path)
# Upload the checksum file.
upload_sha256_checksum(release['tag_name'], file_path)
@@ -232,11 +234,11 @@ def upload_electron(github, release, file_path):
upload_electron(github, release, arm_file_path)
def upload_io_to_github(github, release, name, io, content_type):
params = {'name': name}
headers = {'Content-Type': content_type}
github.repos(ELECTRON_REPO).releases(release['id']).assets.post(
params=params, headers=headers, data=io, verify=False)
def upload_io_to_github(release, filename, filepath):
print 'Uploading %s to Github' % \
(filename)
script_path = os.path.join(SOURCE_ROOT, 'script', 'upload-to-github.js')
execute(['node', script_path, filepath, filename, str(release['id'])])
def upload_sha256_checksum(version, file_path):

View File

@@ -149,6 +149,34 @@ describe('app module', function () {
})
})
describe('app.makeSingleInstance', function () {
it('prevents the second launch of app', function (done) {
this.timeout(120000)
const appPath = path.join(__dirname, 'fixtures', 'api', 'singleton')
// First launch should exit with 0.
let secondLaunched = false
const first = ChildProcess.spawn(remote.process.execPath, [appPath])
let launchOnce = true
first.stdout.on('data', (data) => {
if (data.toString().trim() === 'launched' && launchOnce) {
launchOnce = false
// Second launch should exit with 1.
const second = ChildProcess.spawn(remote.process.execPath, [appPath])
second.once('exit', (code) => {
assert.ok(!secondLaunched)
assert.equal(code, 1)
secondLaunched = true
})
}
})
first.once('exit', (code) => {
assert.ok(secondLaunched)
assert.equal(code, 0)
done()
})
})
})
describe('app.relaunch', function () {
let server = null
const socketPath = process.platform === 'win32' ? '\\\\.\\pipe\\electron-app-relaunch' : '/tmp/electron-app-relaunch'
@@ -208,9 +236,10 @@ describe('app module', function () {
})
})
describe('app.importCertificate', function () {
xdescribe('app.importCertificate', function () {
if (process.platform !== 'linux') return
this.timeout(120000)
var w = null
afterEach(function () {
@@ -405,7 +434,7 @@ describe('app module', function () {
})
})
describe('select-client-certificate event', function () {
xdescribe('select-client-certificate event', function () {
let w = null
beforeEach(function () {

15
spec/fixtures/api/singleton/main.js vendored Normal file
View File

@@ -0,0 +1,15 @@
const {app} = require('electron')
console.log('launched')
process.on('uncaughtException', () => {
app.exit(2)
})
const shouldExit = app.makeSingleInstance(() => {
process.nextTick(() => app.exit(0))
})
if (shouldExit) {
app.exit(1)
}

View File

@@ -0,0 +1,5 @@
{
"name": "electron-app-singleton",
"main": "main.js"
}

2
vendor/node vendored