diff --git a/atom/browser/api/lib/browser-window.coffee b/atom/browser/api/lib/browser-window.coffee index 283e99641f47..2a92cfc55f88 100644 --- a/atom/browser/api/lib/browser-window.coffee +++ b/atom/browser/api/lib/browser-window.coffee @@ -45,6 +45,9 @@ BrowserWindow::_init = -> @on 'focus', (event) => app.emit 'browser-window-focus', event, this + # Notify the creation of the window. + app.emit 'browser-window-created', {}, this + BrowserWindow.getFocusedWindow = -> windows = BrowserWindow.getAllWindows() return window for window in windows when window.isFocused() diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 64f7c11f997b..9555914c899d 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -357,6 +357,17 @@ NativeWindowMac::NativeWindowMac( styleMask |= NSTexturedBackgroundWindowMask; } + std::string titleBarStyle = "default"; + options.Get(switches::kTitleBarStyle, &titleBarStyle); + + if (base::mac::IsOSYosemiteOrLater()) { + // New title bar styles are available in Yosemite or newer + if ((titleBarStyle == "hidden") || (titleBarStyle == "hidden-inset")) { + styleMask |= NSFullSizeContentViewWindowMask; + styleMask |= NSUnifiedTitleAndToolbarWindowMask; + } + } + window_.reset([[AtomNSWindow alloc] initWithContentRect:cocoa_bounds styleMask:styleMask @@ -382,6 +393,20 @@ NativeWindowMac::NativeWindowMac( // We will manage window's lifetime ourselves. [window_ setReleasedWhenClosed:NO]; + // Configure title bar look on Yosemite or newer + if (base::mac::IsOSYosemiteOrLater()) { + if ((titleBarStyle == "hidden") || (titleBarStyle == "hidden-inset")) { + [window_ setTitlebarAppearsTransparent:YES]; + [window_ setTitleVisibility:NSWindowTitleHidden]; + if (titleBarStyle == "hidden-inset") { + NSToolbar *toolbar = [[NSToolbar alloc] initWithIdentifier:@"titlebarStylingToolbar"]; + toolbar.showsBaselineSeparator = NO; + [window_ setToolbar:toolbar]; + [toolbar release]; + } + } + } + // On OS X the initial window size doesn't include window frame. bool use_content_size = false; options.Get(switches::kUseContentSize, &use_content_size); diff --git a/atom/common/lib/init.coffee b/atom/common/lib/init.coffee index 88b32d8c0254..4bc3e36986c0 100644 --- a/atom/common/lib/init.coffee +++ b/atom/common/lib/init.coffee @@ -37,13 +37,18 @@ wrapWithActivateUvLoop = (func) -> process.activateUvLoop() func.apply this, arguments process.nextTick = wrapWithActivateUvLoop process.nextTick -global.setImmediate = wrapWithActivateUvLoop timers.setImmediate -global.clearImmediate = timers.clearImmediate -# setTimeout needs to update the polling timeout of the event loop, when called -# under Chromium's event loop the node's event loop won't get a chance to update -# the timeout, so we have to force the node's event loop to recalculate the -# timeout in browser process. if process.type is 'browser' + # setTimeout needs to update the polling timeout of the event loop, when + # called under Chromium's event loop the node's event loop won't get a chance + # to update the timeout, so we have to force the node's event loop to + # recalculate the timeout in browser process. global.setTimeout = wrapWithActivateUvLoop timers.setTimeout global.setInterval = wrapWithActivateUvLoop timers.setInterval + global.setImmediate = wrapWithActivateUvLoop timers.setImmediate + global.clearImmediate = wrapWithActivateUvLoop timers.clearImmediate +else + # There are no setImmediate under renderer process by default, so we need to + # manually setup them here. + global.setImmediate = setImmediate + global.clearImmediate = clearImmediate diff --git a/atom/common/options_switches.cc b/atom/common/options_switches.cc index ce5398e447f6..c70e1ba4afa6 100644 --- a/atom/common/options_switches.cc +++ b/atom/common/options_switches.cc @@ -42,6 +42,9 @@ const char kAcceptFirstMouse[] = "accept-first-mouse"; // Whether window size should include window frame. const char kUseContentSize[] = "use-content-size"; +// The requested title bar style for the window +const char kTitleBarStyle[] = "title-bar-style"; + // The WebPreferences. const char kWebPreferences[] = "web-preferences"; diff --git a/atom/common/options_switches.h b/atom/common/options_switches.h index c9298618bdfb..e62f3116661a 100644 --- a/atom/common/options_switches.h +++ b/atom/common/options_switches.h @@ -30,6 +30,7 @@ extern const char kAlwaysOnTop[]; extern const char kNodeIntegration[]; extern const char kAcceptFirstMouse[]; extern const char kUseContentSize[]; +extern const char kTitleBarStyle[]; extern const char kWebPreferences[]; extern const char kZoomFactor[]; extern const char kAutoHideMenuBar[]; diff --git a/docs-translations/zh-CN/api/accelerator.md b/docs-translations/zh-CN/api/accelerator.md new file mode 100644 index 000000000000..8858d18e856e --- /dev/null +++ b/docs-translations/zh-CN/api/accelerator.md @@ -0,0 +1,46 @@ +# Accelerator + +An accelerator is a string that represents a keyboard shortcut. It can contain +multiple modifiers and key codes, combined by the `+` character. + +Examples: + +* `Command+A` +* `Ctrl+Shift+Z` + +## Platform notice + +On Linux and Windows, the `Command` key does not have any effect so +use `CommandOrControl` which represents `Command` on OS X and `Control` on +Linux and Windows to define some accelerators. + +The `Super` key is mapped to the `Windows` key on Windows and Linux and +`Cmd` on OS X. + +## Available modifiers + +* `Command` (or `Cmd` for short) +* `Control` (or `Ctrl` for short) +* `CommandOrControl` (or `CmdOrCtrl` for short) +* `Alt` +* `Shift` +* `Super` + +## Available key codes + +* `0` to `9` +* `A` to `Z` +* `F1` to `F24` +* Punctuations like `~`, `!`, `@`, `#`, `$`, etc. +* `Plus` +* `Space` +* `Backspace` +* `Delete` +* `Insert` +* `Return` (or `Enter` as alias) +* `Up`, `Down`, `Left` and `Right` +* `Home` and `End` +* `PageUp` and `PageDown` +* `Escape` (or `Esc` for short) +* `VolumeUp`, `VolumeDown` and `VolumeMute` +* `MediaNextTrack`, `MediaPreviousTrack`, `MediaStop` and `MediaPlayPause` diff --git a/docs-translations/zh-CN/api/global-shortcut.md b/docs-translations/zh-CN/api/global-shortcut.md new file mode 100644 index 000000000000..ff0b28832a10 --- /dev/null +++ b/docs-translations/zh-CN/api/global-shortcut.md @@ -0,0 +1,60 @@ +# global-shortcut + +`global-shortcut` 模块可以便捷的为您设置(注册/注销)各种自定义操作的快捷键. + +**Note**: 使用此模块注册的快捷键是系统全局的(QQ截图那种), 不要在应用模块(app module)响应 `ready` +消息前使用此模块(注册快捷键). + +```javascript +var app = require('app'); +var globalShortcut = require('global-shortcut'); + +app.on('ready', function() { + // Register a 'ctrl+x' shortcut listener. + var ret = globalShortcut.register('ctrl+x', function() { + console.log('ctrl+x is pressed'); + }) + + if (!ret) { + console.log('registration failed'); + } + + // Check whether a shortcut is registered. + console.log(globalShortcut.isRegistered('ctrl+x')); +}); + +app.on('will-quit', function() { + // Unregister a shortcut. + globalShortcut.unregister('ctrl+x'); + + // Unregister all shortcuts. + globalShortcut.unregisterAll(); +}); +``` + +## Methods + +`global-shortcut` 模块包含以下函数: + +### `globalShortcut.register(accelerator, callback)` + +* `accelerator` [Accelerator](accelerator.md) +* `callback` Function + +注册 `accelerator` 快捷键. 当用户按下注册的快捷键时将会调用 `callback` 函数. + +### `globalShortcut.isRegistered(accelerator)` + +* `accelerator` [Accelerator](accelerator.md) + +查询 `accelerator` 快捷键是否已经被注册过了,将会返回 `true`(已被注册) 或 `false`(未注册). + +### `globalShortcut.unregister(accelerator)` + +* `accelerator` [Accelerator](accelerator.md) + +注销全局快捷键 `accelerator`. + +### `globalShortcut.unregisterAll()` + +注销本应用注册的所有全局快捷键. diff --git a/docs/api/app.md b/docs/api/app.md index 42a5dfc24249..799db98882fe 100644 --- a/docs/api/app.md +++ b/docs/api/app.md @@ -118,6 +118,15 @@ Returns: Emitted when a [browserWindow](browser-window.md) gets focused. +### Event: 'browser-window-created' + +Returns: + +* `event` Event +* `window` BrowserWindow + +Emitted when a new [browserWindow](browser-window.md) is created. + ### Event: 'select-certificate' Emitted when a client certificate is requested. diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index 785980f08082..a9f046774af6 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -70,6 +70,16 @@ Properties `width` and `height` are required. Linux. * `standard-window` Boolean - Uses the OS X's standard window instead of the textured window. Defaults to `true`. +* `title-bar-style` String, OS X - specifies the style of window title bar. + This option is supported on OS X 10.10 Yosemite and newer. There are three + possible values: + * `default` or not specified results in the standard gray opaque Mac title + bar. + * `hidden` results in a hidden title bar and a full size content window, yet + the title bar still has the standard window controls ("traffic lights") in + the top left. + * `hidden-inset` results in a hidden title bar with an alternative look + where the traffic light buttons are slightly more inset from the window edge. * `web-preferences` Object - Settings of web page's features, properties: * `node-integration` Boolean - Whether node integration is enabled. Default is `true`. diff --git a/docs/api/frameless-window.md b/docs/api/frameless-window.md index a326bbd8c196..8d64a6fcd7c8 100644 --- a/docs/api/frameless-window.md +++ b/docs/api/frameless-window.md @@ -13,6 +13,20 @@ var BrowserWindow = require('browser-window'); var win = new BrowserWindow({ width: 800, height: 600, frame: false }); ``` +### Alternatives on Mac + +On Mac OS X 10.10 Yosemite and newer, there's an alternative way to specify +a chromeless window. Instead of setting `frame` to `false` which disables +both the titlebar and window controls, you may want to have the title bar +hidden and your content extend to the full window size, yet still preserve +the window controls ("traffic lights") for standard window actions. +You can do so by specifying the new `title-bar-style` option: + +```javascript +var BrowserWindow = require('browser-window'); +var win = new BrowserWindow({ width: 800, height: 600, 'title-bar-style': 'hidden' }); +``` + ## Transparent window By setting the `transparent` option to `true`, you can also make the frameless diff --git a/docs/api/menu.md b/docs/api/menu.md index 49d6361bcf0b..f48b07e7e40a 100644 --- a/docs/api/menu.md +++ b/docs/api/menu.md @@ -170,11 +170,11 @@ if (process.platform == 'darwin') { { label: 'Hide Others', accelerator: 'Command+Shift+H', - role: 'hideothers:' + role: 'hideothers' }, { label: 'Show All', - role: 'unhide:' + role: 'unhide' }, { type: 'separator' diff --git a/spec/api-app-spec.coffee b/spec/api-app-spec.coffee index 5c6591cadf50..38ef22ac80bd 100644 --- a/spec/api-app-spec.coffee +++ b/spec/api-app-spec.coffee @@ -26,19 +26,30 @@ describe 'app module', -> assert.equal app.getName(), 'test-name' app.setName 'Electron Test' - describe 'focus/blur event', -> + describe 'BrowserWindow events', -> w = null - beforeEach -> - w.destroy() if w? - w = new BrowserWindow(show: false, width: 400, height: 400) afterEach -> w.destroy() if w? w = null - it 'should emit focus event', (done) -> + + it 'should emit browser-window-focus event when window is focused', (done) -> + app.once 'browser-window-focus', (e, window) -> + assert.equal w.id, window.id + done() + w = new BrowserWindow(show: false) + w.emit 'focus' + + it 'should emit browser-window-blur event when window is blured', (done) -> app.once 'browser-window-blur', (e, window) -> assert.equal w.id, window.id done() - app.once 'browser-window-focus', (e, window) -> - assert.equal w.id, window.id - w.emit 'blur' - w.emit 'focus' + w = new BrowserWindow(show: false) + w.emit 'blur' + + it 'should emit browser-window-created event when window is created', (done) -> + app.once 'browser-window-created', (e, window) -> + setImmediate -> + assert.equal w.id, window.id + done() + w = new BrowserWindow(show: false) + w.emit 'blur' diff --git a/spec/api-browser-window-spec.coffee b/spec/api-browser-window-spec.coffee index 15cd621ba271..3e4e2d5db5e2 100644 --- a/spec/api-browser-window-spec.coffee +++ b/spec/api-browser-window-spec.coffee @@ -4,6 +4,7 @@ path = require 'path' remote = require 'remote' http = require 'http' url = require 'url' +os = require 'os' BrowserWindow = remote.require 'browser-window' @@ -160,6 +161,22 @@ describe 'browser-window module', -> assert.equal size[0], 400 assert.equal size[1], 400 + describe '"title-bar-style" option', -> + return if process.platform isnt 'darwin' + return if parseInt(os.release().split('.')[0]) < 14 # only run these tests on Yosemite or newer + + it 'creates browser window with hidden title bar', -> + w.destroy() + w = new BrowserWindow(show: false, width: 400, height: 400, 'title-bar-style': 'hidden') + contentSize = w.getContentSize() + assert.equal contentSize[1], 400 + + it 'creates browser window with hidden inset title bar', -> + w.destroy() + w = new BrowserWindow(show: false, width: 400, height: 400, 'title-bar-style': 'hidden-inset') + contentSize = w.getContentSize() + assert.equal contentSize[1], 400 + describe '"enable-larger-than-screen" option', -> return if process.platform is 'linux' diff --git a/spec/fixtures/module/preload-node-off.js b/spec/fixtures/module/preload-node-off.js new file mode 100644 index 000000000000..9020f4513a10 --- /dev/null +++ b/spec/fixtures/module/preload-node-off.js @@ -0,0 +1,7 @@ +setImmediate(function() { + try { + console.log([typeof process, typeof setImmediate, typeof global].join(' ')); + } catch (e) { + console.log(e.message); + } +}); diff --git a/spec/webview-spec.coffee b/spec/webview-spec.coffee index 3eeacb0ad0e5..ddb203399b8e 100644 --- a/spec/webview-spec.coffee +++ b/spec/webview-spec.coffee @@ -3,13 +3,13 @@ path = require 'path' http = require 'http' describe ' tag', -> + @timeout 10000 + fixtures = path.join __dirname, 'fixtures' webview = null - beforeEach -> webview = new WebView - afterEach -> document.body.removeChild webview @@ -84,6 +84,14 @@ describe ' tag', -> webview.src = "file://#{fixtures}/pages/e.html" document.body.appendChild webview + it 'preload script can still use "process" in required modules when nodeintegration is off', (done) -> + webview.addEventListener 'console-message', (e) -> + assert.equal e.message, 'object function object' + done() + webview.setAttribute 'preload', "#{fixtures}/module/preload-node-off.js" + webview.src = "file://#{fixtures}/api/blank.html" + document.body.appendChild webview + it 'receives ipc message in preload script', (done) -> message = 'boom!' listener = (e) -> diff --git a/vendor/brightray b/vendor/brightray index 9b3695cfd5c4..1cfc13fec13a 160000 --- a/vendor/brightray +++ b/vendor/brightray @@ -1 +1 @@ -Subproject commit 9b3695cfd5c48a4cdc90e84a863851001ce8dd10 +Subproject commit 1cfc13fec13a36f3682ee702c32dc2cf22363143 diff --git a/vendor/node b/vendor/node index 9da7dd871c31..fdb584a0b42e 160000 --- a/vendor/node +++ b/vendor/node @@ -1 +1 @@ -Subproject commit 9da7dd871c313d318bc1447a83ba3c7618bbbc18 +Subproject commit fdb584a0b42e89885f74ed68f279318b0fbff37f