Merge pull request #8120 from electron/implement-window-methods-in-main-process

Implement window methods in main process
This commit is contained in:
Kevin Sawicki 2016-12-05 09:29:11 -08:00 committed by GitHub
commit a9d4d9ad85
6 changed files with 69 additions and 48 deletions

View file

@ -106,8 +106,8 @@ will be passed via `callback(filename)`
* `cancelId` Integer (optional) - The value will be returned when user cancels the dialog * `cancelId` Integer (optional) - The value will be returned when user cancels the dialog
instead of clicking the buttons of the dialog. By default it is the index instead of clicking the buttons of the dialog. By default it is the index
of the buttons that have "cancel" or "no" as label, or 0 if there is no such of the buttons that have "cancel" or "no" as label, or 0 if there is no such
buttons. On macOS and Windows the index of "Cancel" button will always be buttons. On macOS and Windows the index of the "Cancel" button will always
used as `cancelId`, not matter whether it is already specified. be used as `cancelId` even if it is specified.
* `noLink` Boolean (optional) - On Windows Electron will try to figure out which one of * `noLink` Boolean (optional) - On Windows Electron will try to figure out which one of
the `buttons` are common buttons (like "Cancel" or "Yes"), and show the the `buttons` are common buttons (like "Cancel" or "Yes"), and show the
others as command links in the dialog. This can make the dialog appear in others as command links in the dialog. This can make the dialog appear in

View file

@ -416,3 +416,34 @@ ipcMain.on('ELECTRON_BROWSER_SEND_TO', function (event, sendToAll, webContentsId
contents.send(channel, ...args) contents.send(channel, ...args)
} }
}) })
// Implements window.alert(message, title)
ipcMain.on('ELECTRON_BROWSER_WINDOW_ALERT', function (event, message, title) {
if (message == null) message = ''
if (title == null) title = ''
event.returnValue = electron.dialog.showMessageBox(event.sender.getOwnerBrowserWindow(), {
message: `${message}`,
title: `${title}`,
buttons: ['OK']
})
})
// Implements window.confirm(message, title)
ipcMain.on('ELECTRON_BROWSER_WINDOW_CONFIRM', function (event, message, title) {
if (message == null) message = ''
if (title == null) title = ''
event.returnValue = !electron.dialog.showMessageBox(event.sender.getOwnerBrowserWindow(), {
message: `${message}`,
title: `${title}`,
buttons: ['OK', 'Cancel'],
cancelId: 1
})
})
// Implements window.close()
ipcMain.on('ELECTRON_BROWSER_WINDOW_CLOSE', function (event) {
event.sender.getOwnerBrowserWindow().close()
event.returnValue = null
})

View file

@ -1,11 +1,13 @@
const timers = require('timers') const timers = require('timers')
const {binding} = process
process.atomBinding = function (name) { process.atomBinding = function (name) {
try { try {
return process.binding(`atom_${process.type}_${name}`) return binding(`atom_${process.type}_${name}`)
} catch (error) { } catch (error) {
if (/No such module/.test(error.message)) { if (/No such module/.test(error.message)) {
return process.binding(`atom_common_${name}`) return binding(`atom_common_${name}`)
} else { } else {
throw error throw error
} }

View file

@ -2,6 +2,7 @@
// - `features` input string // - `features` input string
// - `emit` function(key, value) - called for each parsed KV // - `emit` function(key, value) - called for each parsed KV
module.exports = function parseFeaturesString (features, emit) { module.exports = function parseFeaturesString (features, emit) {
features = `${features}`
// split the string by ',' // split the string by ','
features.split(/,\s*/).forEach((feature) => { features.split(/,\s*/).forEach((feature) => {
// expected form is either a key by itself or a key/value pair in the form of // expected form is either a key by itself or a key/value pair in the form of

View file

@ -88,7 +88,7 @@ const wrapArgs = function (args, visited) {
} }
} }
} }
return Array.prototype.slice.call(args).map(valueToMeta) return args.map(valueToMeta)
} }
// Populate object's members from descriptors. // Populate object's members from descriptors.
@ -102,14 +102,14 @@ const setObjectMembers = function (ref, object, metaId, members) {
let descriptor = { enumerable: member.enumerable } let descriptor = { enumerable: member.enumerable }
if (member.type === 'method') { if (member.type === 'method') {
const remoteMemberFunction = function () { const remoteMemberFunction = function (...args) {
if (this && this.constructor === remoteMemberFunction) { if (this && this.constructor === remoteMemberFunction) {
// Constructor call. // Constructor call.
let ret = ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_CONSTRUCTOR', metaId, member.name, wrapArgs(arguments)) let ret = ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_CONSTRUCTOR', metaId, member.name, wrapArgs(args))
return metaToValue(ret) return metaToValue(ret)
} else { } else {
// Call member function. // Call member function.
let ret = ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_CALL', metaId, member.name, wrapArgs(arguments)) let ret = ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_CALL', metaId, member.name, wrapArgs(args))
return metaToValue(ret) return metaToValue(ret)
} }
} }
@ -220,17 +220,17 @@ const metaToValue = function (meta) {
if (meta.type === 'function') { if (meta.type === 'function') {
// A shadow class to represent the remote function object. // A shadow class to represent the remote function object.
let remoteFunction = function () { let remoteFunction = function (...args) {
if (this && this.constructor === remoteFunction) { if (this && this.constructor === remoteFunction) {
// Constructor call. // Constructor call.
let obj = ipcRenderer.sendSync('ELECTRON_BROWSER_CONSTRUCTOR', meta.id, wrapArgs(arguments)) let obj = ipcRenderer.sendSync('ELECTRON_BROWSER_CONSTRUCTOR', meta.id, wrapArgs(args))
// Returning object in constructor will replace constructed object // Returning object in constructor will replace constructed object
// with the returned object. // with the returned object.
// http://stackoverflow.com/questions/1978049/what-values-can-a-constructor-return-to-avoid-returning-this // http://stackoverflow.com/questions/1978049/what-values-can-a-constructor-return-to-avoid-returning-this
return metaToValue(obj) return metaToValue(obj)
} else { } else {
// Function call. // Function call.
let obj = ipcRenderer.sendSync('ELECTRON_BROWSER_FUNCTION_CALL', meta.id, wrapArgs(arguments)) let obj = ipcRenderer.sendSync('ELECTRON_BROWSER_FUNCTION_CALL', meta.id, wrapArgs(args))
return metaToValue(obj) return metaToValue(obj)
} }
} }

View file

@ -1,24 +1,28 @@
'use strict' 'use strict'
const ipcRenderer = require('electron').ipcRenderer const {ipcRenderer} = require('electron')
const remote = require('electron').remote
const parseFeaturesString = require('../common/parse-features-string') const parseFeaturesString = require('../common/parse-features-string')
const {defineProperty} = Object
// Helper function to resolve relative url. // Helper function to resolve relative url.
var a = window.top.document.createElement('a') const a = window.top.document.createElement('a')
var resolveURL = function (url) { const resolveURL = function (url) {
a.href = url a.href = url
return a.href return a.href
} }
// Window object returned by "window.open". // Window object returned by "window.open".
var BrowserWindowProxy = (function () { const BrowserWindowProxy = (function () {
BrowserWindowProxy.proxies = {} BrowserWindowProxy.proxies = {}
BrowserWindowProxy.getOrCreate = function (guestId) { BrowserWindowProxy.getOrCreate = function (guestId) {
var base = this.proxies let proxy = this.proxies[guestId]
base[guestId] != null ? base[guestId] : base[guestId] = new BrowserWindowProxy(guestId) if (proxy == null) {
return base[guestId] proxy = new BrowserWindowProxy(guestId)
this.proxies[guestId] = proxy
}
return proxy
} }
BrowserWindowProxy.remove = function (guestId) { BrowserWindowProxy.remove = function (guestId) {
@ -26,7 +30,7 @@ var BrowserWindowProxy = (function () {
} }
function BrowserWindowProxy (guestId1) { function BrowserWindowProxy (guestId1) {
Object.defineProperty(this, 'guestId', { defineProperty(this, 'guestId', {
configurable: false, configurable: false,
enumerable: true, enumerable: true,
writeable: false, writeable: false,
@ -56,7 +60,7 @@ var BrowserWindowProxy = (function () {
ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', this.guestId, 'print') ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', this.guestId, 'print')
} }
Object.defineProperty(BrowserWindowProxy.prototype, 'location', { defineProperty(BrowserWindowProxy.prototype, 'location', {
get: function () { get: function () {
return ipcRenderer.sendSync('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD_SYNC', this.guestId, 'getURL') return ipcRenderer.sendSync('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD_SYNC', this.guestId, 'getURL')
}, },
@ -83,13 +87,13 @@ var BrowserWindowProxy = (function () {
if (process.guestInstanceId == null) { if (process.guestInstanceId == null) {
// Override default window.close. // Override default window.close.
window.close = function () { window.close = function () {
return remote.getCurrentWindow().close() ipcRenderer.sendSync('ELECTRON_BROWSER_WINDOW_CLOSE')
} }
} }
// Make the browser window or guest view emit "new-window" event. // Make the browser window or guest view emit "new-window" event.
window.open = function (url, frameName, features) { window.open = function (url, frameName, features) {
var guestId, j, len1, name, options, additionalFeatures let guestId, j, len1, name, options, additionalFeatures
if (frameName == null) { if (frameName == null) {
frameName = '' frameName = ''
} }
@ -160,29 +164,12 @@ window.open = function (url, frameName, features) {
} }
} }
// Use the dialog API to implement alert(). window.alert = function (message, title) {
window.alert = function (message = '', title = '') { ipcRenderer.sendSync('ELECTRON_BROWSER_WINDOW_ALERT', message, title)
remote.dialog.showMessageBox(remote.getCurrentWindow(), {
message: String(message),
title: String(title),
buttons: ['OK']
})
} }
// And the confirm().
window.confirm = function (message, title) { window.confirm = function (message, title) {
var buttons, cancelId return ipcRenderer.sendSync('ELECTRON_BROWSER_WINDOW_CONFIRM', message, title)
if (title == null) {
title = ''
}
buttons = ['OK', 'Cancel']
cancelId = 1
return !remote.dialog.showMessageBox(remote.getCurrentWindow(), {
message: message,
title: title,
buttons: buttons,
cancelId: cancelId
})
} }
// But we do not support prompt(). // But we do not support prompt().
@ -206,11 +193,11 @@ ipcRenderer.on('ELECTRON_GUEST_WINDOW_POSTMESSAGE', function (event, sourceId, m
}) })
// Forward history operations to browser. // Forward history operations to browser.
var sendHistoryOperation = function (...args) { const sendHistoryOperation = function (...args) {
ipcRenderer.send('ELECTRON_NAVIGATION_CONTROLLER', ...args) ipcRenderer.send('ELECTRON_NAVIGATION_CONTROLLER', ...args)
} }
var getHistoryOperation = function (...args) { const getHistoryOperation = function (...args) {
return ipcRenderer.sendSync('ELECTRON_SYNC_NAVIGATION_CONTROLLER', ...args) return ipcRenderer.sendSync('ELECTRON_SYNC_NAVIGATION_CONTROLLER', ...args)
} }
@ -226,7 +213,7 @@ window.history.go = function (offset) {
sendHistoryOperation('goToOffset', offset) sendHistoryOperation('goToOffset', offset)
} }
Object.defineProperty(window.history, 'length', { defineProperty(window.history, 'length', {
get: function () { get: function () {
return getHistoryOperation('length') return getHistoryOperation('length')
} }
@ -244,13 +231,13 @@ ipcRenderer.on('ELECTRON_RENDERER_WINDOW_VISIBILITY_CHANGE', function (event, vi
}) })
// Make document.hidden and document.visibilityState return the correct value. // Make document.hidden and document.visibilityState return the correct value.
Object.defineProperty(document, 'hidden', { defineProperty(document, 'hidden', {
get: function () { get: function () {
return cachedVisibilityState !== 'visible' return cachedVisibilityState !== 'visible'
} }
}) })
Object.defineProperty(document, 'visibilityState', { defineProperty(document, 'visibilityState', {
get: function () { get: function () {
return cachedVisibilityState return cachedVisibilityState
} }