Move unrelated code out of menu.js and ipc.js

This commit is contained in:
Feross Aboukhadijeh
2016-05-29 01:09:42 -07:00
parent d4efebd694
commit 62cb304971
16 changed files with 469 additions and 403 deletions

View File

@@ -5,8 +5,10 @@ module.exports = {
openTorrentAddress
}
var config = require('../config')
var electron = require('electron')
var config = require('../config')
var log = require('./log')
var windows = require('./windows')
/**
@@ -14,6 +16,7 @@ var windows = require('./windows')
*/
function openSeedFile () {
if (!windows.main.win) return
log('openSeedFile')
var opts = {
title: 'Select a file for the torrent.',
properties: [ 'openFile' ]
@@ -22,7 +25,7 @@ function openSeedFile () {
electron.dialog.showOpenDialog(windows.main.win, opts, function (selectedPaths) {
resetTitle()
if (!Array.isArray(selectedPaths)) return
windows.main.send('dispatch', 'showCreateTorrent', selectedPaths)
windows.main.dispatch('showCreateTorrent', selectedPaths)
})
}
@@ -33,6 +36,7 @@ function openSeedFile () {
*/
function openSeedDirectory () {
if (!windows.main.win) return
log('openSeedDirectory')
var opts = process.platform === 'darwin'
? {
title: 'Select a file or folder for the torrent.',
@@ -46,7 +50,7 @@ function openSeedDirectory () {
electron.dialog.showOpenDialog(windows.main.win, opts, function (selectedPaths) {
resetTitle()
if (!Array.isArray(selectedPaths)) return
windows.main.send('dispatch', 'showCreateTorrent', selectedPaths)
windows.main.dispatch('showCreateTorrent', selectedPaths)
})
}
@@ -55,6 +59,7 @@ function openSeedDirectory () {
*/
function openTorrentFile () {
if (!windows.main.win) return
log('openTorrentFile')
var opts = {
title: 'Select a .torrent file to open.',
filters: [{ name: 'Torrent Files', extensions: ['torrent'] }],
@@ -65,7 +70,7 @@ function openTorrentFile () {
resetTitle()
if (!Array.isArray(selectedPaths)) return
selectedPaths.forEach(function (selectedPath) {
windows.main.send('dispatch', 'addTorrent', selectedPath)
windows.main.dispatch('addTorrent', selectedPath)
})
})
}
@@ -74,7 +79,8 @@ function openTorrentFile () {
* Show modal dialog to open a torrent URL (magnet uri, http torrent link, etc.)
*/
function openTorrentAddress () {
windows.main.send('showOpenTorrentAddress')
log('openTorrentAddress')
windows.main.dispatch('openTorrentAddress')
}
/**
@@ -82,7 +88,7 @@ function openTorrentAddress () {
*/
function setTitle (title) {
if (process.platform === 'darwin') {
windows.main.send('dispatch', 'setTitle', title)
windows.main.dispatch('setTitle', title)
}
}

59
main/dock.js Normal file
View File

@@ -0,0 +1,59 @@
module.exports = {
downloadFinished,
init,
setBadge
}
var electron = require('electron')
var app = electron.app
var dialog = require('./dialog')
var log = require('./log')
/**
* Add a right-click menu to the dock icon. (OS X)
*/
function init () {
if (!app.dock) return
var menu = electron.Menu.buildFromTemplate(getMenuTemplate())
app.dock.setMenu(menu)
}
/**
* Bounce the Downloads stack if `path` is inside the Downloads folder. (OS X)
*/
function downloadFinished (path) {
if (!app.dock) return
log(`downloadFinished: ${path}`)
app.dock.downloadFinished(path)
}
/**
* Display string in dock badging area. (OS X)
*/
function setBadge (text) {
if (!app.dock) return
log(`setBadge: ${text}`)
app.dock.setBadge(String(text))
}
function getMenuTemplate () {
return [
{
label: 'Create New Torrent...',
accelerator: 'CmdOrCtrl+N',
click: () => dialog.openSeedDirectory()
},
{
label: 'Open Torrent File...',
accelerator: 'CmdOrCtrl+O',
click: () => dialog.openTorrentFile()
},
{
label: 'Open Torrent Address...',
accelerator: 'CmdOrCtrl+U',
click: () => dialog.openTorrentAddress()
}
]
}

View File

@@ -9,6 +9,7 @@ var announcement = require('./announcement')
var config = require('../config')
var crashReporter = require('../crash-reporter')
var dialog = require('./dialog')
var dock = require('./dock')
var handlers = require('./handlers')
var ipc = require('./ipc')
var log = require('./log')
@@ -61,8 +62,8 @@ function init () {
app.on('ready', function () {
isReady = true
windows.main.create()
windows.webtorrent.create()
windows.main.init()
windows.webtorrent.init()
menu.init()
// To keep app startup fast, some code is delayed.
@@ -80,20 +81,21 @@ function init () {
app.isQuitting = true
e.preventDefault()
windows.main.send('dispatch', 'saveState') // try to save state on exit
windows.main.dispatch('saveState') // try to save state on exit
ipcMain.once('savedState', () => app.quit())
setTimeout(() => app.quit(), 2000) // quit after 2 secs, at most
})
app.on('activate', function () {
if (isReady) windows.main.create()
if (isReady) windows.main.show()
})
}
function delayedInit () {
announcement.init()
tray.init()
dock.init()
handlers.install()
tray.init()
updater.init()
}
@@ -101,7 +103,7 @@ function onOpen (e, torrentId) {
e.preventDefault()
if (app.ipcReady) {
windows.main.send('dispatch', 'onOpen', torrentId)
windows.main.dispatch('onOpen', torrentId)
// Magnet links opened from Chrome won't focus the app without a setTimeout.
// The confirmation dialog Chrome shows causes Chrome to steal back the focus.
// Electron issue: https://github.com/atom/electron/issues/4338
@@ -148,6 +150,6 @@ function processArgv (argv) {
}
})
if (paths.length > 0) {
windows.main.send('dispatch', 'onOpen', paths)
windows.main.dispatch('onOpen', paths)
}
}

View File

@@ -6,9 +6,12 @@ var electron = require('electron')
var app = electron.app
var dialog = require('./dialog')
var dock = require('./dock')
var log = require('./log')
var menu = require('./menu')
var powerSaveBlocker = require('./power-save-blocker')
var shell = require('./shell')
var shortcuts = require('./shortcuts')
var vlc = require('./vlc')
var windows = require('./windows')
@@ -20,15 +23,15 @@ var messageQueueMainToWebTorrent = []
var vlcProcess
function init () {
var ipcMain = electron.ipcMain
var ipc = electron.ipcMain
ipcMain.on('ipcReady', function (e) {
ipc.on('ipcReady', function (e) {
windows.main.show()
app.ipcReady = true
app.emit('ipcReady')
})
ipcMain.on('ipcReadyWebTorrent', function (e) {
ipc.on('ipcReadyWebTorrent', function (e) {
app.ipcReadyWebTorrent = true
log('sending %d queued messages from the main win to the webtorrent window',
messageQueueMainToWebTorrent.length)
@@ -38,109 +41,111 @@ function init () {
})
})
ipcMain.on('showOpenTorrentFile', () => menu.showOpenTorrentFile())
/**
* Dialog
*/
ipcMain.on('setBounds', function (e, bounds, maximize) {
setBounds(bounds, maximize)
})
ipc.on('openTorrentFile', () => dialog.openTorrentFile())
ipcMain.on('setAspectRatio', function (e, aspectRatio) {
setAspectRatio(aspectRatio)
})
/**
* Dock
*/
ipcMain.on('setBadge', function (e, text) {
setBadge(text)
})
ipc.on('setBadge', (e, ...args) => dock.setBadge(...args))
ipc.on('downloadFinished', (e, ...args) => dock.downloadFinished(...args))
ipcMain.on('setProgress', function (e, progress) {
setProgress(progress)
})
/**
* Events
*/
ipcMain.on('toggleFullScreen', function (e, flag) {
windows.main.toggleFullScreen(flag)
})
ipcMain.on('setTitle', function (e, title) {
windows.main.win.setTitle(title)
})
ipcMain.on('openItem', function (e, path) {
ipc.on('show', (e, ...args) => windows.main.show(...args))
log('open item: ' + path)
electron.shell.openItem(path)
})
ipcMain.on('showItemInFolder', function (e, path) {
log('show item in folder: ' + path)
electron.shell.showItemInFolder(path)
})
ipcMain.on('blockPowerSave', () => powerSaveBlocker.start())
ipcMain.on('unblockPowerSave', () => powerSaveBlocker.stop())
ipcMain.on('onPlayerOpen', function () {
ipc.on('onPlayerOpen', function () {
menu.onPlayerOpen()
shortcuts.onPlayerOpen()
})
ipcMain.on('onPlayerClose', function () {
ipc.on('onPlayerClose', function () {
menu.onPlayerClose()
shortcuts.onPlayerOpen()
})
ipcMain.on('downloadFinished', function (e, filePath) {
if (app.dock) {
// Bounces the Downloads stack if the filePath is inside the Downloads folder.
app.dock.downloadFinished(filePath)
}
})
/**
* Power Save Blocker
*/
ipcMain.on('checkForVLC', function (e) {
ipc.on('blockPowerSave', () => powerSaveBlocker.start())
ipc.on('unblockPowerSave', () => powerSaveBlocker.stop())
/**
* Shell
*/
ipc.on('openItem', (e, ...args) => shell.openItem(...args))
ipc.on('showItemInFolder', (e, ...args) => shell.showItemInFolder(...args))
/**
* Windows: Main
*/
var main = windows.main
ipc.on('setAspectRatio', (e, ...args) => main.setAspectRatio(...args))
ipc.on('setBounds', (e, ...args) => main.setBounds(...args))
ipc.on('setProgress', (e, ...args) => main.setProgress(...args))
ipc.on('setTitle', (e, ...args) => main.setTitle(...args))
ipc.on('show', () => main.show())
ipc.on('toggleFullScreen', (e, ...args) => main.toggleFullScreen(...args))
/**
* VLC
* TODO: Move most of this code to vlc.js
*/
ipc.on('checkForVLC', function (e) {
vlc.checkForVLC(function (isInstalled) {
windows.main.send('checkForVLC', isInstalled)
})
})
ipcMain.on('vlcPlay', function (e, url) {
ipc.on('vlcPlay', function (e, url) {
var args = ['--play-and-exit', '--video-on-top', '--no-video-title-show', '--quiet', url]
console.log('Running vlc ' + args.join(' '))
log('Running vlc ' + args.join(' '))
vlc.spawn(args, function (err, proc) {
if (err) return windows.main.send('dispatch', 'vlcNotFound')
if (err) return windows.main.dispatch('vlcNotFound')
vlcProcess = proc
// If it works, close the modal after a second
var closeModalTimeout = setTimeout(() =>
windows.main.send('dispatch', 'exitModal'), 1000)
windows.main.dispatch('exitModal'), 1000)
vlcProcess.on('close', function (code) {
clearTimeout(closeModalTimeout)
if (!vlcProcess) return // Killed
console.log('VLC exited with code ', code)
log('VLC exited with code ', code)
if (code === 0) {
windows.main.send('dispatch', 'backToList')
windows.main.dispatch('backToList')
} else {
windows.main.send('dispatch', 'vlcNotFound')
windows.main.dispatch('vlcNotFound')
}
vlcProcess = null
})
vlcProcess.on('error', function (e) {
console.log('VLC error', e)
log('VLC error', e)
})
})
})
ipcMain.on('vlcQuit', function () {
ipc.on('vlcQuit', function () {
if (!vlcProcess) return
console.log('Killing VLC, pid ' + vlcProcess.pid)
log('Killing VLC, pid ' + vlcProcess.pid)
vlcProcess.kill('SIGKILL') // kill -9
vlcProcess = null
})
// Capture all events
var oldEmit = ipcMain.emit
ipcMain.emit = function (name, e, ...args) {
var oldEmit = ipc.emit
ipc.emit = function (name, e, ...args) {
// Relay messages between the main window and the WebTorrent hidden window
if (name.startsWith('wt-') && !app.isQuitting) {
if (e.sender.browserWindowOptions.title === 'webtorrent-hidden-window') {
@@ -163,68 +168,6 @@ function init () {
}
// Emit all other events normally
oldEmit.call(ipcMain, name, e, ...args)
oldEmit.call(ipc, name, e, ...args)
}
}
function setBounds (bounds, maximize) {
// Do nothing in fullscreen
if (!windows.main.win || windows.main.win.isFullScreen()) {
log('setBounds: not setting bounds because we\'re in full screen')
return
}
// Maximize or minimize, if the second argument is present
var willBeMaximized
if (maximize === true) {
if (!windows.main.win.isMaximized()) {
log('setBounds: maximizing')
windows.main.win.maximize()
}
willBeMaximized = true
} else if (maximize === false) {
if (windows.main.win.isMaximized()) {
log('setBounds: unmaximizing')
windows.main.win.unmaximize()
}
willBeMaximized = false
} else {
willBeMaximized = windows.main.win.isMaximized()
}
// Assuming we're not maximized or maximizing, set the window size
if (!willBeMaximized) {
log('setBounds: setting bounds to ' + JSON.stringify(bounds))
if (bounds.x === null && bounds.y === null) {
// X and Y not specified? By default, center on current screen
var scr = electron.screen.getDisplayMatching(windows.main.win.getBounds())
bounds.x = Math.round(scr.bounds.x + scr.bounds.width / 2 - bounds.width / 2)
bounds.y = Math.round(scr.bounds.y + scr.bounds.height / 2 - bounds.height / 2)
log('setBounds: centered to ' + JSON.stringify(bounds))
}
windows.main.win.setBounds(bounds, true)
} else {
log('setBounds: not setting bounds because of window maximization')
}
}
function setAspectRatio (aspectRatio) {
log('setAspectRatio %o', aspectRatio)
if (!windows.main.win) return
windows.main.win.setAspectRatio(aspectRatio)
}
// Display string in dock badging area (OS X)
function setBadge (text) {
log('setBadge %s', text)
if (app.dock) {
app.dock.setBadge(String(text))
}
}
// Show progress bar. Valid range is [0, 1]. Remove when < 0; indeterminate when > 1.
function setProgress (progress) {
log('setProgress %s', progress)
if (!windows.main.win) return
windows.main.win.setProgressBar(progress)
}

View File

@@ -2,9 +2,10 @@ module.exports = {
init,
onPlayerClose,
onPlayerOpen,
onToggleAlwaysOnTop,
onToggleFullScreen,
onWindowHide,
onWindowShow
onWindowBlur,
onWindowFocus
}
var electron = require('electron')
@@ -13,148 +14,66 @@ var app = electron.app
var config = require('../config')
var dialog = require('./dialog')
var log = require('./log')
var shell = require('./shell')
var windows = require('./windows')
var appMenu
var menu
function init () {
appMenu = electron.Menu.buildFromTemplate(getAppMenuTemplate())
electron.Menu.setApplicationMenu(appMenu)
if (app.dock) {
var dockMenu = electron.Menu.buildFromTemplate(getDockMenuTemplate())
app.dock.setMenu(dockMenu)
}
}
// Sets whether the window should always show on top of other windows
function toggleFloatOnTop (flag) {
if (!windows.main.win) return
log('toggleFloatOnTop %s', flag)
flag = flag != null ? flag : !windows.main.isAlwaysOnTop()
windows.main.setAlwaysOnTop(flag)
getMenuItem('Float on Top').checked = flag
}
function toggleDevTools () {
if (!windows.main.win) return
log('toggleDevTools')
windows.main.toggleDevTools()
}
function showWebTorrentWindow () {
log('showWebTorrentWindow')
windows.webtorrent.show()
windows.webtorrent.win.webContents.openDevTools({ detach: true })
}
function playPause () {
if (!windows.main.win) return
windows.main.send('dispatch', 'playPause')
}
function increaseVolume () {
if (!windows.main.win) return
windows.main.send('dispatch', 'changeVolume', 0.1)
}
function decreaseVolume () {
if (!windows.main.win) return
windows.main.send('dispatch', 'changeVolume', -0.1)
}
function openSubtitles () {
if (!windows.main.win) return
windows.main.send('dispatch', 'openSubtitles')
}
function skipForward () {
if (!windows.main.win) return
windows.main.send('dispatch', 'skip', 1)
}
function skipBack () {
if (!windows.main.win) return
windows.main.send('dispatch', 'skip', -1)
}
function increasePlaybackRate () {
if (!windows.main.win) return
windows.main.send('dispatch', 'changePlaybackRate', 1)
}
function decreasePlaybackRate () {
if (!windows.main.win) return
windows.main.send('dispatch', 'changePlaybackRate', -1)
}
// Open the preferences window
function showPreferences () {
if (!windows.main.win) return
windows.main.send('dispatch', 'preferences')
}
function escapeBack () {
if (!windows.main.win) return
windows.main.send('dispatch', 'escapeBack')
}
function onWindowShow () {
log('onWindowShow')
getMenuItem('Full Screen').enabled = true
getMenuItem('Float on Top').enabled = true
}
function onWindowHide () {
log('onWindowHide')
getMenuItem('Full Screen').enabled = false
getMenuItem('Float on Top').enabled = false
}
function onPlayerOpen () {
log('onPlayerOpen')
getMenuItem('Play/Pause').enabled = true
getMenuItem('Increase Volume').enabled = true
getMenuItem('Decrease Volume').enabled = true
getMenuItem('Add Subtitles File...').enabled = true
getMenuItem('Step Forward').enabled = true
getMenuItem('Step Backward').enabled = true
getMenuItem('Increase Speed').enabled = true
getMenuItem('Decrease Speed').enabled = true
menu = electron.Menu.buildFromTemplate(getMenuTemplate())
electron.Menu.setApplicationMenu(menu)
}
function onPlayerClose () {
log('onPlayerClose')
getMenuItem('Play/Pause').enabled = false
getMenuItem('Increase Volume').enabled = false
getMenuItem('Decrease Volume').enabled = false
getMenuItem('Add Subtitles File...').enabled = false
getMenuItem('Step Forward').enabled = false
getMenuItem('Step Backward').enabled = false
getMenuItem('Increase Speed').enabled = false
getMenuItem('Decrease Speed').enabled = false
getMenuItem('Add Subtitles File...').enabled = false
}
function onToggleFullScreen (isFullScreen) {
if (isFullScreen == null) {
isFullScreen = windows.main.win.isFullScreen()
}
windows.main.win.setMenuBarVisibility(!isFullScreen)
getMenuItem('Full Screen').checked = isFullScreen
windows.main.send('fullscreenChanged', isFullScreen)
function onPlayerOpen () {
getMenuItem('Play/Pause').enabled = true
getMenuItem('Increase Volume').enabled = true
getMenuItem('Decrease Volume').enabled = true
getMenuItem('Step Forward').enabled = true
getMenuItem('Step Backward').enabled = true
getMenuItem('Increase Speed').enabled = true
getMenuItem('Decrease Speed').enabled = true
getMenuItem('Add Subtitles File...').enabled = true
}
function onToggleAlwaysOnTop (flag) {
getMenuItem('Float on Top').checked = flag
}
function onToggleFullScreen (flag) {
getMenuItem('Full Screen').checked = flag
}
function onWindowBlur () {
getMenuItem('Full Screen').enabled = false
getMenuItem('Float on Top').enabled = false
}
function onWindowFocus () {
getMenuItem('Full Screen').enabled = true
getMenuItem('Float on Top').enabled = true
}
function getMenuItem (label) {
for (var i = 0; i < appMenu.items.length; i++) {
var menuItem = appMenu.items[i].submenu.items.find(function (item) {
for (var i = 0; i < menu.items.length; i++) {
var menuItem = menu.items[i].submenu.items.find(function (item) {
return item.label === label
})
if (menuItem) return menuItem
}
}
function getAppMenuTemplate () {
function getMenuTemplate () {
var template = [
{
label: 'File',
@@ -217,7 +136,7 @@ function getAppMenuTemplate () {
{
label: 'Preferences',
accelerator: 'CmdOrCtrl+,',
click: () => showPreferences()
click: () => windows.main.dispatch('preferences')
}
]
},
@@ -235,7 +154,7 @@ function getAppMenuTemplate () {
{
label: 'Float on Top',
type: 'checkbox',
click: () => toggleFloatOnTop()
click: () => windows.toggleAlwaysOnTop()
},
{
type: 'separator'
@@ -243,7 +162,7 @@ function getAppMenuTemplate () {
{
label: 'Go Back',
accelerator: 'Esc',
click: escapeBack
click: () => windows.main.dispatch('escapeBack')
},
{
type: 'separator'
@@ -256,14 +175,14 @@ function getAppMenuTemplate () {
accelerator: process.platform === 'darwin'
? 'Alt+Command+I'
: 'Ctrl+Shift+I',
click: toggleDevTools
click: () => windows.main.toggleDevTools()
},
{
label: 'Show WebTorrent Process',
accelerator: process.platform === 'darwin'
? 'Alt+Command+P'
: 'Ctrl+Shift+P',
click: showWebTorrentWindow
click: () => windows.webtorrent.toggleDevTools()
}
]
}
@@ -275,7 +194,7 @@ function getAppMenuTemplate () {
{
label: 'Play/Pause',
accelerator: 'Space',
click: playPause,
click: () => windows.main.dispatch('playPause'),
enabled: false
},
{
@@ -284,13 +203,13 @@ function getAppMenuTemplate () {
{
label: 'Increase Volume',
accelerator: 'CmdOrCtrl+Up',
click: increaseVolume,
click: () => windows.main.dispatch('changeVolume', 0.1),
enabled: false
},
{
label: 'Decrease Volume',
accelerator: 'CmdOrCtrl+Down',
click: decreaseVolume,
click: () => windows.main.dispatch('changeVolume', -0.1),
enabled: false
},
{
@@ -299,13 +218,13 @@ function getAppMenuTemplate () {
{
label: 'Step Forward',
accelerator: 'CmdOrCtrl+Alt+Right',
click: skipForward,
click: () => windows.main.dispatch('skip', 1),
enabled: false
},
{
label: 'Step Backward',
accelerator: 'CmdOrCtrl+Alt+Left',
click: skipBack,
click: () => windows.main.dispatch('skip', -1),
enabled: false
},
{
@@ -314,13 +233,13 @@ function getAppMenuTemplate () {
{
label: 'Increase Speed',
accelerator: 'CmdOrCtrl+=',
click: increasePlaybackRate,
click: () => windows.main.dispatch('changePlaybackRate', 1),
enabled: false
},
{
label: 'Decrease Speed',
accelerator: 'CmdOrCtrl+-',
click: decreasePlaybackRate,
click: () => windows.main.dispatch('changePlaybackRate', -1),
enabled: false
},
{
@@ -328,7 +247,7 @@ function getAppMenuTemplate () {
},
{
label: 'Add Subtitles File...',
click: openSubtitles,
click: () => windows.main.dispatch('openSubtitles'),
enabled: false
}
]
@@ -339,18 +258,18 @@ function getAppMenuTemplate () {
submenu: [
{
label: 'Learn more about ' + config.APP_NAME,
click: () => electron.shell.openExternal(config.HOME_PAGE_URL)
click: () => shell.openExternal(config.HOME_PAGE_URL)
},
{
label: 'Contribute on GitHub',
click: () => electron.shell.openExternal(config.GITHUB_URL)
click: () => shell.openExternal(config.GITHUB_URL)
},
{
type: 'separator'
},
{
label: 'Report an Issue...',
click: () => electron.shell.openExternal(config.GITHUB_URL_ISSUES)
click: () => shell.openExternal(config.GITHUB_URL_ISSUES)
}
]
}
@@ -371,7 +290,7 @@ function getAppMenuTemplate () {
{
label: 'Preferences',
accelerator: 'Cmd+,',
click: () => showPreferences()
click: () => windows.main.dispatch('preferences')
},
{
type: 'separator'
@@ -430,7 +349,8 @@ function getAppMenuTemplate () {
})
}
// In Linux and Windows it is not possible to open both folders and files
// On Windows and Linux, open dialogs do not support selecting both files and
// folders and files, so add an extra menu item so there is one for each type.
if (process.platform === 'linux' || process.platform === 'win32') {
// File menu (Windows, Linux)
template[0].submenu.unshift({
@@ -445,12 +365,12 @@ function getAppMenuTemplate () {
},
{
label: 'About ' + config.APP_NAME,
click: () => windows.about.create()
click: () => windows.about.init()
}
)
}
// Add "File > Quit" menu item so Linux distros where the system tray icon is missing
// will have a way to quit the app.
// Add "File > Quit" menu item so Linux distros where the system tray icon is
// missing will have a way to quit the app.
if (process.platform === 'linux') {
// File menu (Linux)
template[0].submenu.push({
@@ -461,23 +381,3 @@ function getAppMenuTemplate () {
return template
}
function getDockMenuTemplate () {
return [
{
label: 'Create New Torrent...',
accelerator: 'CmdOrCtrl+N',
click: () => dialog.openSeedDirectory()
},
{
label: 'Open Torrent File...',
accelerator: 'CmdOrCtrl+O',
click: () => dialog.openTorrentFile()
},
{
label: 'Open Torrent Address...',
accelerator: 'CmdOrCtrl+U',
click: () => dialog.openTorrentAddress()
}
]
}

View File

@@ -6,20 +6,25 @@ module.exports = {
var electron = require('electron')
var log = require('./log')
var powerSaveBlockerId = 0
var blockId = 0
/**
* Block the system from entering low-power (sleep) mode or turning off the
* display.
*/
function start () {
// Stop the previous power saver block, if one exists.
stop()
powerSaveBlockerId = electron.powerSaveBlocker.start('prevent-display-sleep')
log('powerSaveBlocker.start %d', powerSaveBlockerId)
stop() // Stop the previous power saver block, if one exists.
blockId = electron.powerSaveBlocker.start('prevent-display-sleep')
log(`powerSaveBlocker.start: ${blockId}`)
}
/**
* Stop blocking the system from entering low-power mode.
*/
function stop () {
if (!electron.powerSaveBlocker.isStarted(powerSaveBlockerId)) {
if (!electron.powerSaveBlocker.isStarted(blockId)) {
return
}
electron.powerSaveBlocker.stop(powerSaveBlockerId)
log('powerSaveBlocker.stop %d', powerSaveBlockerId)
electron.powerSaveBlocker.stop(blockId)
log(`powerSaveBlocker.stop: ${blockId}`)
}

32
main/shell.js Normal file
View File

@@ -0,0 +1,32 @@
module.exports = {
openExternal,
openItem,
showItemInFolder
}
var electron = require('electron')
var log = require('./log')
/**
* Open the given external protocol URL in the desktops default manner.
*/
function openExternal (url) {
log(`openExternal: ${url}`)
electron.shell.openExternal(url)
}
/**
* Open the given file in the desktops default manner.
*/
function openItem (path) {
log(`openItem: ${path}`)
electron.shell.openItem(path)
}
/**
* Show the given file in a file manager. If possible, select the file.
*/
function showItemInFolder (path) {
log(`showItemInFolder: ${path}`)
electron.shell.showItemInFolder(path)
}

View File

@@ -7,13 +7,14 @@ var electron = require('electron')
var windows = require('./windows')
function onPlayerOpen () {
// Register special "media key" for play/pause, available on some keyboards
// Register play/pause media key, available on some keyboards.
electron.globalShortcut.register(
'MediaPlayPause',
() => windows.main.send('dispatch', 'playPause')
() => windows.main.dispatch('playPause')
)
}
function onPlayerClose () {
// Return the media key to the OS, so other apps can use it.
electron.globalShortcut.unregister('MediaPlayPause')
}

View File

@@ -12,8 +12,8 @@ var app = electron.app
var handlers = require('./handlers')
var exeName = path.basename(process.execPath)
var updateDotExe = path.join(process.execPath, '..', '..', 'Update.exe')
var EXE_NAME = path.basename(process.execPath)
var UPDATE_EXE = path.join(process.execPath, '..', '..', 'Update.exe')
function handleEvent (cmd) {
if (cmd === '--squirrel-install') {
@@ -102,12 +102,12 @@ function spawn (command, args, cb) {
// Spawn Squirrel's Update.exe with the given arguments and invoke the callback when the
// command completes.
function spawnUpdate (args, cb) {
spawn(updateDotExe, args, cb)
spawn(UPDATE_EXE, args, cb)
}
// Create desktop/start menu shortcuts using the Squirrel Update.exe command line API
function createShortcuts (cb) {
spawnUpdate(['--createShortcut', exeName], cb)
spawnUpdate(['--createShortcut', EXE_NAME], cb)
}
// Update desktop/start menu shortcuts using the Squirrel Update.exe command line API
@@ -135,5 +135,5 @@ function updateShortcuts (cb) {
// Remove desktop/start menu shortcuts using the Squirrel Update.exe command line API
function removeShortcuts (cb) {
spawnUpdate(['--removeShortcut', exeName], cb)
spawnUpdate(['--removeShortcut', EXE_NAME], cb)
}

View File

@@ -1,8 +1,8 @@
module.exports = {
hasTray,
init,
onWindowHide,
onWindowShow
onWindowBlur,
onWindowFocus
}
var electron = require('electron')
@@ -24,8 +24,24 @@ function init () {
// OS X apps generally do not have menu bar icons
}
/**
* Returns true if there a tray icon is active.
*/
function hasTray () {
return !!tray
}
function onWindowBlur () {
if (!tray) return
updateTrayMenu()
}
function onWindowFocus () {
if (!tray) return
updateTrayMenu()
}
function initLinux () {
// Check for libappindicator1 support before creating tray icon
checkLinuxTraySupport(function (supportsTray) {
if (supportsTray) createTray()
})
@@ -35,6 +51,9 @@ function initWin32 () {
createTray()
}
/**
* Check for libappindicator1 support before creating tray icon
*/
function checkLinuxTraySupport (cb) {
var cp = require('child_process')
@@ -49,65 +68,46 @@ function checkLinuxTraySupport (cb) {
})
}
function hasTray () {
return !!tray
}
function createTray () {
tray = new electron.Tray(getIconPath())
// On Windows, left click opens the app, right click opens the context menu.
// On Linux, any click (left or right) opens the context menu.
tray.on('click', showApp)
tray.on('click', () => windows.main.show())
// Show the tray context menu, and keep the available commands up to date
updateTrayMenu()
}
function onWindowHide () {
updateTrayMenu()
}
function onWindowShow () {
updateTrayMenu()
}
function updateTrayMenu () {
if (!tray) return
var contextMenu = electron.Menu.buildFromTemplate(getMenuTemplate)
tray.setContextMenu(contextMenu)
}
var contextMenu = electron.Menu.buildFromTemplate([
function getMenuTemplate () {
return [
getToggleItem(),
{
label: 'Quit',
click: () => app.quit()
}
])
tray.setContextMenu(contextMenu)
]
function getToggleItem () {
if (windows.main.win.isVisible()) {
return {
label: 'Hide to tray',
click: hideApp
click: () => windows.main.hide()
}
} else {
return {
label: 'Show WebTorrent',
click: showApp
click: () => windows.main.show()
}
}
}
}
function showApp () {
windows.main.show()
}
function hideApp () {
windows.main.hide()
windows.main.send('dispatch', 'backToList')
}
function getIconPath () {
return process.platform === 'win32'
? config.APP_ICON + '.ico'

View File

@@ -21,27 +21,27 @@ function init () {
}
}
// The Electron auto-updater does not support Linux yet, so manually check for updates and
// `show the user a modal notification.
// The Electron auto-updater does not support Linux yet, so manually check for
// updates and show the user a modal notification.
function initLinux () {
get.concat(AUTO_UPDATE_URL, onResponse)
}
function onResponse (err, res, data) {
if (err) return log(`Update error: ${err.message}`)
if (res.statusCode === 200) {
// Update available
try {
data = JSON.parse(data)
} catch (err) {
return log(`Update error: Invalid JSON response: ${err.message}`)
}
windows.main.send('dispatch', 'updateAvailable', data.version)
} else if (res.statusCode === 204) {
// No update available
} else {
// Unexpected status code
log(`Update error: Unexpected status code: ${res.statusCode}`)
function onResponse (err, res, data) {
if (err) return log(`Update error: ${err.message}`)
if (res.statusCode === 200) {
// Update available
try {
data = JSON.parse(data)
} catch (err) {
return log(`Update error: Invalid JSON response: ${err.message}`)
}
windows.main.dispatch('updateAvailable', data.version)
} else if (res.statusCode === 204) {
// No update available
} else {
// Unexpected status code
log(`Update error: Unexpected status code: ${res.statusCode}`)
}
}

View File

@@ -1,12 +1,12 @@
var about = module.exports = {
create,
init,
win: null
}
var config = require('../../config')
var electron = require('electron')
function create () {
function init () {
if (about.win) {
return about.win.show()
}

View File

@@ -1,8 +1,15 @@
var main = module.exports = {
create,
dispatch,
hide,
init,
send,
setAspectRatio,
setBounds,
setProgress,
setTitle,
show,
toggleAlwaysOnTop,
toggleDevTools,
toggleFullScreen,
win: null
}
@@ -19,7 +26,7 @@ var tray = require('../tray')
var HEADER_HEIGHT = 37
var TORRENT_HEIGHT = 100
function create () {
function init () {
if (main.win) {
return main.win.show()
}
@@ -42,21 +49,30 @@ function create () {
if (win.setSheetOffset) win.setSheetOffset(HEADER_HEIGHT)
win.webContents.on('dom-ready', function () {
menu.onToggleFullScreen()
menu.onToggleFullScreen(main.win.isFullScreen())
})
win.on('blur', function () {
menu.onWindowHide()
tray.onWindowHide()
menu.onWindowBlur()
tray.onWindowBlur()
})
win.on('focus', function () {
menu.onWindowShow()
tray.onWindowShow()
menu.onWindowFocus()
tray.onWindowFocus()
})
win.on('enter-full-screen', () => menu.onToggleFullScreen(true))
win.on('leave-full-screen', () => menu.onToggleFullScreen(false))
win.on('enter-full-screen', function () {
menu.onToggleFullScreen(true)
send('fullscreenChanged', true)
win.setMenuBarVisibility(false)
})
win.on('leave-full-screen', function () {
menu.onToggleFullScreen(false)
send('fullscreenChanged', false)
win.setMenuBarVisibility(true)
})
win.on('close', function (e) {
if (process.platform !== 'darwin' && !tray.hasTray()) {
@@ -64,15 +80,115 @@ function create () {
} else if (!app.isQuitting) {
e.preventDefault()
win.hide()
win.send('dispatch', 'backToList')
}
})
}
function getIconPath () {
return process.platform === 'win32'
? config.APP_ICON + '.ico'
: config.APP_ICON + '.png'
function dispatch (...args) {
send('dispatch', ...args)
}
function hide () {
if (!main.win) return
main.win.send('dispatch', 'backToList')
main.win.hide()
}
function send (...args) {
if (!main.win) return
main.win.send(...args)
}
/**
* Enforce window aspect ratio. Remove with 0. (OS X)
*/
function setAspectRatio (aspectRatio) {
if (!main.win) return
main.win.setAspectRatio(aspectRatio)
}
/**
* Change the size of the window.
* TODO: Clean this up? Seems overly complicated.
*/
function setBounds (bounds, maximize) {
// Do nothing in fullscreen
if (!main.win || main.win.isFullScreen()) {
log('setBounds: not setting bounds because we\'re in full screen')
return
}
// Maximize or minimize, if the second argument is present
var willBeMaximized
if (maximize === true) {
if (!main.win.isMaximized()) {
log('setBounds: maximizing')
main.win.maximize()
}
willBeMaximized = true
} else if (maximize === false) {
if (main.win.isMaximized()) {
log('setBounds: unmaximizing')
main.win.unmaximize()
}
willBeMaximized = false
} else {
willBeMaximized = main.win.isMaximized()
}
// Assuming we're not maximized or maximizing, set the window size
if (!willBeMaximized) {
log('setBounds: setting bounds to ' + JSON.stringify(bounds))
if (bounds.x === null && bounds.y === null) {
// X and Y not specified? By default, center on current screen
var scr = electron.screen.getDisplayMatching(main.win.getBounds())
bounds.x = Math.round(scr.bounds.x + scr.bounds.width / 2 - bounds.width / 2)
bounds.y = Math.round(scr.bounds.y + scr.bounds.height / 2 - bounds.height / 2)
log('setBounds: centered to ' + JSON.stringify(bounds))
}
main.win.setBounds(bounds, true)
} else {
log('setBounds: not setting bounds because of window maximization')
}
}
/**
* Set progress bar to [0, 1]. Indeterminate when > 1. Remove with < 0.
*/
function setProgress (progress) {
if (!main.win) return
main.win.setProgressBar(progress)
}
function setTitle (title) {
if (!main.win) return
main.win.setTitle(title)
}
function show () {
if (!main.win) return
main.win.show()
}
// Sets whether the window should always show on top of other windows
function toggleAlwaysOnTop (flag) {
if (!main.win) return
if (flag == null) {
flag = !main.isAlwaysOnTop()
}
log(`toggleAlwaysOnTop ${flag}`)
main.setAlwaysOnTop(flag)
menu.onToggleAlwaysOnTop(flag)
}
function toggleDevTools () {
if (!main.win) return
log('toggleDevTools')
if (main.win.webContents.isDevToolsOpened()) {
main.win.webContents.closeDevTools()
} else {
main.win.webContents.openDevTools({ detach: true })
}
}
function toggleFullScreen (flag) {
@@ -82,29 +198,18 @@ function toggleFullScreen (flag) {
if (flag == null) flag = !main.win.isFullScreen()
log('toggleFullScreen %s', flag)
log(`toggleFullScreen ${flag}`)
if (flag) {
// Fullscreen behaves oddly unless the aspect ratio is disabled. (OS X)
// Fullscreen and aspect ratio do not play well together. (OS X)
main.win.setAspectRatio(0)
}
main.win.setFullScreen(flag)
}
function send (...args) {
if (!main.win) return
main.win.send(...args)
}
function show () {
if (!main.win) return
main.win.show()
}
function hide () {
if (!main.win) return
main.win.hide()
}
function getIconPath () {
return process.platform === 'win32'
? config.APP_ICON + '.ico'
: config.APP_ICON + '.png'
}

View File

@@ -1,14 +1,17 @@
var webtorrent = module.exports = {
create,
init,
send,
show,
toggleDevTools,
win: null
}
var config = require('../../config')
var electron = require('electron')
function create () {
var config = require('../../config')
var log = require('../log')
function init () {
var win = webtorrent.win = new electron.BrowserWindow({
backgroundColor: '#1E1E1E',
center: true,
@@ -46,3 +49,14 @@ function send (...args) {
if (!webtorrent.win) return
webtorrent.win.send(...args)
}
function toggleDevTools () {
if (!webtorrent.win) return
log('toggleDevTools')
if (webtorrent.win.webContents.isDevToolsOpened()) {
webtorrent.win.webContents.closeDevTools()
webtorrent.win.hide()
} else {
webtorrent.win.webContents.openDevTools({ detach: true })
}
}

View File

@@ -224,12 +224,16 @@ function dispatch (action, ...args) {
if (action === 'addTorrent') {
addTorrent(args[0] /* torrent */)
}
if (action === 'showOpenTorrentFile') {
ipcRenderer.send('showOpenTorrentFile') /* open torrent file */
if (action === 'openTorrentFile') {
ipcRenderer.send('openTorrentFile') /* open torrent file */
}
if (action === 'showCreateTorrent') {
showCreateTorrent(args[0] /* paths */)
}
if (action === 'openTorrentAddress') {
state.modal = { id: 'open-torrent-address-modal' }
update()
}
if (action === 'createTorrent') {
createTorrent(args[0] /* options */)
}
@@ -511,11 +515,6 @@ function setupIpc () {
ipcRenderer.on('dispatch', (e, ...args) => dispatch(...args))
ipcRenderer.on('showOpenTorrentAddress', function (e) {
state.modal = { id: 'open-torrent-address-modal' }
update()
})
ipcRenderer.on('fullscreenChanged', function (e, isFullScreen) {
state.window.isFullScreen = isFullScreen
if (!isFullScreen) {

View File

@@ -39,7 +39,7 @@ function Header (state) {
<i
class='icon add'
title='Add torrent'
onclick=${dispatcher('showOpenTorrentFile')}>
onclick=${dispatcher('openTorrentFile')}>
add
</i>
`