Skip to content

Commit

Permalink
Merge pull request #8120 from electron/implement-window-methods-in-ma…
Browse files Browse the repository at this point in the history
…in-process

Implement window methods in main process
  • Loading branch information
kevinsawicki committed Dec 5, 2016
2 parents c27633d + d6d85ad commit a9d4d9a
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 48 deletions.
4 changes: 2 additions & 2 deletions docs/api/dialog.md
Expand Up @@ -106,8 +106,8 @@ will be passed via `callback(filename)`
* `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
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
used as `cancelId`, not matter whether it is already specified.
buttons. On macOS and Windows the index of the "Cancel" button will always
be used as `cancelId` even if it is specified.
* `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
others as command links in the dialog. This can make the dialog appear in
Expand Down
31 changes: 31 additions & 0 deletions lib/browser/rpc-server.js
Expand Up @@ -416,3 +416,34 @@ ipcMain.on('ELECTRON_BROWSER_SEND_TO', function (event, sendToAll, webContentsId
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
})
6 changes: 4 additions & 2 deletions lib/common/init.js
@@ -1,11 +1,13 @@
const timers = require('timers')

const {binding} = process

process.atomBinding = function (name) {
try {
return process.binding(`atom_${process.type}_${name}`)
return binding(`atom_${process.type}_${name}`)
} catch (error) {
if (/No such module/.test(error.message)) {
return process.binding(`atom_common_${name}`)
return binding(`atom_common_${name}`)
} else {
throw error
}
Expand Down
1 change: 1 addition & 0 deletions lib/common/parse-features-string.js
Expand Up @@ -2,6 +2,7 @@
// - `features` input string
// - `emit` function(key, value) - called for each parsed KV
module.exports = function parseFeaturesString (features, emit) {
features = `${features}`
// split the string by ','
features.split(/,\s*/).forEach((feature) => {
// expected form is either a key by itself or a key/value pair in the form of
Expand Down
14 changes: 7 additions & 7 deletions lib/renderer/api/remote.js
Expand Up @@ -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.
Expand All @@ -102,14 +102,14 @@ const setObjectMembers = function (ref, object, metaId, members) {

let descriptor = { enumerable: member.enumerable }
if (member.type === 'method') {
const remoteMemberFunction = function () {
const remoteMemberFunction = function (...args) {
if (this && this.constructor === remoteMemberFunction) {
// 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)
} else {
// 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)
}
}
Expand Down Expand Up @@ -220,17 +220,17 @@ const metaToValue = function (meta) {

if (meta.type === 'function') {
// A shadow class to represent the remote function object.
let remoteFunction = function () {
let remoteFunction = function (...args) {
if (this && this.constructor === remoteFunction) {
// 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
// with the returned object.
// http://stackoverflow.com/questions/1978049/what-values-can-a-constructor-return-to-avoid-returning-this
return metaToValue(obj)
} else {
// 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)
}
}
Expand Down
61 changes: 24 additions & 37 deletions lib/renderer/override.js
@@ -1,32 +1,36 @@
'use strict'

const ipcRenderer = require('electron').ipcRenderer
const remote = require('electron').remote
const {ipcRenderer} = require('electron')
const parseFeaturesString = require('../common/parse-features-string')

const {defineProperty} = Object

// Helper function to resolve relative url.
var a = window.top.document.createElement('a')
var resolveURL = function (url) {
const a = window.top.document.createElement('a')
const resolveURL = function (url) {
a.href = url
return a.href
}

// Window object returned by "window.open".
var BrowserWindowProxy = (function () {
const BrowserWindowProxy = (function () {
BrowserWindowProxy.proxies = {}

BrowserWindowProxy.getOrCreate = function (guestId) {
var base = this.proxies
base[guestId] != null ? base[guestId] : base[guestId] = new BrowserWindowProxy(guestId)
return base[guestId]
let proxy = this.proxies[guestId]
if (proxy == null) {
proxy = new BrowserWindowProxy(guestId)
this.proxies[guestId] = proxy
}
return proxy
}

BrowserWindowProxy.remove = function (guestId) {
delete this.proxies[guestId]
}

function BrowserWindowProxy (guestId1) {
Object.defineProperty(this, 'guestId', {
defineProperty(this, 'guestId', {
configurable: false,
enumerable: true,
writeable: false,
Expand Down Expand Up @@ -56,7 +60,7 @@ var BrowserWindowProxy = (function () {
ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', this.guestId, 'print')
}

Object.defineProperty(BrowserWindowProxy.prototype, 'location', {
defineProperty(BrowserWindowProxy.prototype, 'location', {
get: function () {
return ipcRenderer.sendSync('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD_SYNC', this.guestId, 'getURL')
},
Expand All @@ -83,13 +87,13 @@ var BrowserWindowProxy = (function () {
if (process.guestInstanceId == null) {
// Override default window.close.
window.close = function () {
return remote.getCurrentWindow().close()
ipcRenderer.sendSync('ELECTRON_BROWSER_WINDOW_CLOSE')
}
}

// Make the browser window or guest view emit "new-window" event.
window.open = function (url, frameName, features) {
var guestId, j, len1, name, options, additionalFeatures
let guestId, j, len1, name, options, additionalFeatures
if (frameName == null) {
frameName = ''
}
Expand Down Expand Up @@ -160,29 +164,12 @@ window.open = function (url, frameName, features) {
}
}

// Use the dialog API to implement alert().
window.alert = function (message = '', title = '') {
remote.dialog.showMessageBox(remote.getCurrentWindow(), {
message: String(message),
title: String(title),
buttons: ['OK']
})
window.alert = function (message, title) {
ipcRenderer.sendSync('ELECTRON_BROWSER_WINDOW_ALERT', message, title)
}

// And the confirm().
window.confirm = function (message, title) {
var buttons, cancelId
if (title == null) {
title = ''
}
buttons = ['OK', 'Cancel']
cancelId = 1
return !remote.dialog.showMessageBox(remote.getCurrentWindow(), {
message: message,
title: title,
buttons: buttons,
cancelId: cancelId
})
return ipcRenderer.sendSync('ELECTRON_BROWSER_WINDOW_CONFIRM', message, title)
}

// But we do not support prompt().
Expand All @@ -206,11 +193,11 @@ ipcRenderer.on('ELECTRON_GUEST_WINDOW_POSTMESSAGE', function (event, sourceId, m
})

// Forward history operations to browser.
var sendHistoryOperation = function (...args) {
const sendHistoryOperation = function (...args) {
ipcRenderer.send('ELECTRON_NAVIGATION_CONTROLLER', ...args)
}

var getHistoryOperation = function (...args) {
const getHistoryOperation = function (...args) {
return ipcRenderer.sendSync('ELECTRON_SYNC_NAVIGATION_CONTROLLER', ...args)
}

Expand All @@ -226,7 +213,7 @@ window.history.go = function (offset) {
sendHistoryOperation('goToOffset', offset)
}

Object.defineProperty(window.history, 'length', {
defineProperty(window.history, 'length', {
get: function () {
return getHistoryOperation('length')
}
Expand All @@ -244,13 +231,13 @@ ipcRenderer.on('ELECTRON_RENDERER_WINDOW_VISIBILITY_CHANGE', function (event, vi
})

// Make document.hidden and document.visibilityState return the correct value.
Object.defineProperty(document, 'hidden', {
defineProperty(document, 'hidden', {
get: function () {
return cachedVisibilityState !== 'visible'
}
})

Object.defineProperty(document, 'visibilityState', {
defineProperty(document, 'visibilityState', {
get: function () {
return cachedVisibilityState
}
Expand Down

0 comments on commit a9d4d9a

Please sign in to comment.