diff --git a/main/announcement.js b/main/announcement.js index 1959b886..b6977533 100644 --- a/main/announcement.js +++ b/main/announcement.js @@ -3,7 +3,6 @@ module.exports = { } var electron = require('electron') -var get = require('simple-get') var config = require('../config') var log = require('./log') @@ -13,6 +12,7 @@ var ANNOUNCEMENT_URL = config.ANNOUNCEMENT_URL + '&platform=' + process.platform function init () { + var get = require('simple-get') get.concat(ANNOUNCEMENT_URL, onResponse) } diff --git a/main/dialog.js b/main/dialog.js new file mode 100644 index 00000000..1aaab35f --- /dev/null +++ b/main/dialog.js @@ -0,0 +1,53 @@ +module.exports = { + openSeedFile, + openSeedDirectory, + openTorrentFile, + openTorrentAddress +} + +var electron = require('electron') +var windows = require('./windows') + +// Prompts the user for a file, then creates a torrent. Only allows a single file +// selection. +function openSeedFile () { + electron.dialog.showOpenDialog({ + title: 'Select a file for the torrent file.', + properties: [ 'openFile' ] + }, function (selectedPaths) { + if (!Array.isArray(selectedPaths)) return + windows.main.send('dispatch', 'showCreateTorrent', selectedPaths) + }) +} + +// Prompts the user for a file or directory, then creates a torrent. Only allows a +// single selection. To create a multi-file torrent, the user must select a +// directory. +function openSeedDirectory () { + electron.dialog.showOpenDialog({ + title: 'Select a file or folder for the torrent file.', + properties: [ 'openFile', 'openDirectory' ] + }, function (selectedPaths) { + if (!Array.isArray(selectedPaths)) return + windows.main.send('dispatch', 'showCreateTorrent', selectedPaths) + }) +} + +// Prompts the user to choose a torrent file, then adds it. +function openTorrentFile () { + electron.dialog.showOpenDialog(windows.main.win, { + title: 'Select a .torrent file to open.', + filters: [{ name: 'Torrent Files', extensions: ['torrent'] }], + properties: [ 'openFile', 'multiSelections' ] + }, function (selectedPaths) { + if (!Array.isArray(selectedPaths)) return + selectedPaths.forEach(function (selectedPath) { + windows.main.send('dispatch', 'addTorrent', selectedPath) + }) + }) +} + +// Prompts the user for the URL of a torrent file, then downloads and adds it +function openTorrentAddress () { + windows.main.send('showOpenTorrentAddress') +} diff --git a/main/index.js b/main/index.js index 92f7dacb..79ad6389 100644 --- a/main/index.js +++ b/main/index.js @@ -8,6 +8,7 @@ var ipcMain = electron.ipcMain var announcement = require('./announcement') var config = require('../config') var crashReporter = require('../crash-reporter') +var dialog = require('./dialog') var handlers = require('./handlers') var ipc = require('./ipc') var log = require('./log') @@ -60,8 +61,8 @@ function init () { app.on('ready', function () { isReady = true - windows.createMainWindow() - windows.createWebTorrentHiddenWindow() + windows.main.create() + windows.webtorrent.create() menu.init() // To keep app startup fast, some code is delayed. @@ -79,13 +80,13 @@ function init () { app.isQuitting = true e.preventDefault() - windows.main.send('dispatch', 'saveState') /* try to save state on exit */ + windows.main.send('dispatch', 'saveState') // try to save state on exit ipcMain.once('savedState', () => app.quit()) - setTimeout(() => app.quit(), 2000) /* quit after 2 secs, at most */ + setTimeout(() => app.quit(), 2000) // quit after 2 secs, at most }) app.on('activate', function () { - if (isReady) windows.createMainWindow() + if (isReady) windows.main.create() }) } @@ -101,11 +102,11 @@ function onOpen (e, torrentId) { if (app.ipcReady) { windows.main.send('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. + // 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 setTimeout(function () { - windows.focusWindow(windows.main) + windows.main.focus() }, 100) } else { argv.push(torrentId) @@ -114,10 +115,11 @@ function onOpen (e, torrentId) { function onAppOpen (newArgv) { newArgv = sliceArgv(newArgv) + console.log(newArgv) if (app.ipcReady) { log('Second app instance opened, but was prevented:', newArgv) - windows.focusWindow(windows.main) + windows.main.focus() processArgv(newArgv) } else { @@ -130,27 +132,22 @@ function sliceArgv (argv) { } function processArgv (argv) { - var pathsToOpen = [] + var paths = [] argv.forEach(function (arg) { if (arg === '-n') { - menu.showOpenSeedFiles() + dialog.openSeedDirectory() } else if (arg === '-o') { - menu.showOpenTorrentFile() + dialog.openTorrentFile() } else if (arg === '-u') { - menu.showOpenTorrentAddress() + dialog.openTorrentAddress() } else if (arg.startsWith('-psn')) { // Ignore OS X launchd "process serial number" argument - // More: https://github.com/feross/webtorrent-desktop/issues/214 + // Issue: https://github.com/feross/webtorrent-desktop/issues/214 } else { - pathsToOpen.push(arg) + paths.push(arg) } }) - if (pathsToOpen.length > 0) openFilePaths(pathsToOpen) -} - -// Send files to the renderer process -// Opening files means either adding torrents, creating and seeding a torrent -// from files, or adding subtitles -function openFilePaths (paths) { - windows.main.send('dispatch', 'onOpen', paths) + if (paths.length > 0) { + windows.main.send('dispatch', 'onOpen', paths) + } } diff --git a/main/ipc.js b/main/ipc.js index 17bec585..6498f21e 100644 --- a/main/ipc.js +++ b/main/ipc.js @@ -5,24 +5,23 @@ module.exports = { var electron = require('electron') var app = electron.app -var ipcMain = electron.ipcMain var log = require('./log') var menu = require('./menu') -var windows = require('./windows') +var powerSaveBlocker = require('./power-save-blocker') var shortcuts = require('./shortcuts') var vlc = require('./vlc') +var windows = require('./windows') -// has to be a number, not a boolean, and undefined throws an error -var powerSaveBlockerId = 0 - -// messages from the main process, to be sent once the WebTorrent process starts +// Messages from the main process, to be sent once the WebTorrent process starts var messageQueueMainToWebTorrent = [] // holds a ChildProcess while we're playing a video in VLC, null otherwise var vlcProcess function init () { + var ipcMain = electron.ipcMain + ipcMain.on('ipcReady', function (e) { windows.main.show() app.ipcReady = true @@ -39,7 +38,7 @@ function init () { }) }) - ipcMain.on('showOpenTorrentFile', menu.showOpenTorrentFile) + ipcMain.on('showOpenTorrentFile', () => menu.showOpenTorrentFile()) ipcMain.on('setBounds', function (e, bounds, maximize) { setBounds(bounds, maximize) @@ -58,11 +57,11 @@ function init () { }) ipcMain.on('toggleFullScreen', function (e, flag) { - menu.toggleFullScreen(flag) + windows.main.toggleFullScreen(flag) }) ipcMain.on('setTitle', function (e, title) { - windows.main.setTitle(title) + windows.main.win.setTitle(title) }) ipcMain.on('openItem', function (e, path) { @@ -75,9 +74,8 @@ function init () { electron.shell.showItemInFolder(path) }) - ipcMain.on('blockPowerSave', blockPowerSave) - - ipcMain.on('unblockPowerSave', unblockPowerSave) + ipcMain.on('blockPowerSave', () => powerSaveBlocker.start()) + ipcMain.on('unblockPowerSave', () => powerSaveBlocker.stop()) ipcMain.on('onPlayerOpen', function () { menu.onPlayerOpen() @@ -174,7 +172,7 @@ function init () { function setBounds (bounds, maximize) { // Do nothing in fullscreen - if (!windows.main || windows.main.isFullScreen()) { + if (!windows.main.win || windows.main.win.isFullScreen()) { log('setBounds: not setting bounds because we\'re in full screen') return } @@ -182,19 +180,19 @@ function setBounds (bounds, maximize) { // Maximize or minimize, if the second argument is present var willBeMaximized if (maximize === true) { - if (!windows.main.isMaximized()) { + if (!windows.main.win.isMaximized()) { log('setBounds: maximizing') - windows.main.maximize() + windows.main.win.maximize() } willBeMaximized = true } else if (maximize === false) { - if (windows.main.isMaximized()) { + if (windows.main.win.isMaximized()) { log('setBounds: unmaximizing') - windows.main.unmaximize() + windows.main.win.unmaximize() } willBeMaximized = false } else { - willBeMaximized = windows.main.isMaximized() + willBeMaximized = windows.main.win.isMaximized() } // Assuming we're not maximized or maximizing, set the window size @@ -202,12 +200,12 @@ function setBounds (bounds, maximize) { 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.getBounds()) + 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.setBounds(bounds, true) + windows.main.win.setBounds(bounds, true) } else { log('setBounds: not setting bounds because of window maximization') } @@ -215,9 +213,8 @@ function setBounds (bounds, maximize) { function setAspectRatio (aspectRatio) { log('setAspectRatio %o', aspectRatio) - if (windows.main) { - windows.main.setAspectRatio(aspectRatio) - } + if (!windows.main.win) return + windows.main.win.setAspectRatio(aspectRatio) } // Display string in dock badging area (OS X) @@ -231,19 +228,6 @@ function setBadge (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) { - windows.main.setProgressBar(progress) - } -} - -function blockPowerSave () { - powerSaveBlockerId = electron.powerSaveBlocker.start('prevent-display-sleep') - log('blockPowerSave %d', powerSaveBlockerId) -} - -function unblockPowerSave () { - if (electron.powerSaveBlocker.isStarted(powerSaveBlockerId)) { - electron.powerSaveBlocker.stop(powerSaveBlockerId) - log('unblockPowerSave %d', powerSaveBlockerId) - } + if (!windows.main.win) return + windows.main.win.setProgressBar(progress) } diff --git a/main/log.js b/main/log.js index bc064135..08bc7b12 100644 --- a/main/log.js +++ b/main/log.js @@ -10,11 +10,16 @@ module.exports.error = error var electron = require('electron') +var config = require('../config') var windows = require('./windows') var app = electron.app function log (...args) { + if (!config.IS_PRODUCTION) { + // In development, also log to the console + console.log(...args) + } if (app.ipcReady) { windows.main.send('log', ...args) } else { diff --git a/main/menu.js b/main/menu.js index 6a3b8891..730383d1 100644 --- a/main/menu.js +++ b/main/menu.js @@ -4,13 +4,7 @@ module.exports = { onPlayerOpen, onToggleFullScreen, onWindowHide, - onWindowShow, - - // TODO: move these out of menu.js -- they don't belong here - showOpenSeedFiles, - showOpenTorrentAddress, - showOpenTorrentFile, - toggleFullScreen + onWindowShow } var electron = require('electron') @@ -18,6 +12,7 @@ var electron = require('electron') var app = electron.app var config = require('../config') +var dialog = require('./dialog') var log = require('./log') var windows = require('./windows') @@ -33,100 +28,76 @@ function init () { } } -function toggleFullScreen (flag) { - log('toggleFullScreen %s', flag) - if (windows.main && windows.main.isVisible()) { - flag = flag != null ? flag : !windows.main.isFullScreen() - if (flag) { - // Allows the window to use the full screen in fullscreen mode (OS X). - windows.main.setAspectRatio(0) - } - windows.main.setFullScreen(flag) - } -} - // Sets whether the window should always show on top of other windows function toggleFloatOnTop (flag) { + if (!windows.main.win) return log('toggleFloatOnTop %s', flag) - if (windows.main) { - flag = flag != null ? flag : !windows.main.isAlwaysOnTop() - windows.main.setAlwaysOnTop(flag) - getMenuItem('Float on Top').checked = 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') - if (windows.main) { - windows.main.toggleDevTools() - } + windows.main.toggleDevTools() } function showWebTorrentWindow () { log('showWebTorrentWindow') windows.webtorrent.show() - windows.webtorrent.webContents.openDevTools({ detach: true }) + windows.webtorrent.win.webContents.openDevTools({ detach: true }) } function playPause () { - if (windows.main) { - windows.main.send('dispatch', 'playPause') - } + if (!windows.main.win) return + windows.main.send('dispatch', 'playPause') } function increaseVolume () { - if (windows.main) { - windows.main.send('dispatch', 'changeVolume', 0.1) - } + if (!windows.main.win) return + windows.main.send('dispatch', 'changeVolume', 0.1) } function decreaseVolume () { - if (windows.main) { - windows.main.send('dispatch', 'changeVolume', -0.1) - } + if (!windows.main.win) return + windows.main.send('dispatch', 'changeVolume', -0.1) } function openSubtitles () { - if (windows.main) { - windows.main.send('dispatch', 'openSubtitles') - } + if (!windows.main.win) return + windows.main.send('dispatch', 'openSubtitles') } function skipForward () { - if (windows.main) { - windows.main.send('dispatch', 'skip', 1) - } + if (!windows.main.win) return + windows.main.send('dispatch', 'skip', 1) } function skipBack () { - if (windows.main) { - windows.main.send('dispatch', 'skip', -1) - } + if (!windows.main.win) return + windows.main.send('dispatch', 'skip', -1) } function increasePlaybackRate () { - if (windows.main) { - windows.main.send('dispatch', 'changePlaybackRate', 1) - } + if (!windows.main.win) return + windows.main.send('dispatch', 'changePlaybackRate', 1) } function decreasePlaybackRate () { - if (windows.main) { - windows.main.send('dispatch', 'changePlaybackRate', -1) - } + if (!windows.main.win) return + windows.main.send('dispatch', 'changePlaybackRate', -1) } // Open the preferences window function showPreferences () { - if (windows.main) { - windows.main.send('dispatch', 'preferences') - } + if (!windows.main.win) return + windows.main.send('dispatch', 'preferences') } function escapeBack () { - if (windows.main) { - windows.main.send('dispatch', 'escapeBack') - } + if (!windows.main.win) return + windows.main.send('dispatch', 'escapeBack') } function onWindowShow () { @@ -166,8 +137,10 @@ function onPlayerClose () { } function onToggleFullScreen (isFullScreen) { - isFullScreen = isFullScreen != null ? isFullScreen : windows.main.isFullScreen() - windows.main.setMenuBarVisibility(!isFullScreen) + if (isFullScreen == null) { + isFullScreen = windows.main.win.isFullScreen() + } + windows.main.win.setMenuBarVisibility(!isFullScreen) getMenuItem('Full Screen').checked = isFullScreen windows.main.send('fullscreenChanged', isFullScreen) } @@ -181,49 +154,6 @@ function getMenuItem (label) { } } -// Prompts the user for a file, then creates a torrent. Only allows a single file -// selection. -function showOpenSeedFile () { - electron.dialog.showOpenDialog({ - title: 'Select a file for the torrent file.', - properties: [ 'openFile' ] - }, function (selectedPaths) { - if (!Array.isArray(selectedPaths)) return - windows.main.send('dispatch', 'showCreateTorrent', selectedPaths) - }) -} - -// Prompts the user for a file or directory, then creates a torrent. Only allows a single -// selection. To create a multi-file torrent, the user must select a directory. -function showOpenSeedFiles () { - electron.dialog.showOpenDialog({ - title: 'Select a file or folder for the torrent file.', - properties: [ 'openFile', 'openDirectory' ] - }, function (selectedPaths) { - if (!Array.isArray(selectedPaths)) return - windows.main.send('dispatch', 'showCreateTorrent', selectedPaths) - }) -} - -// Prompts the user to choose a torrent file, then adds it to the app -function showOpenTorrentFile () { - electron.dialog.showOpenDialog(windows.main, { - title: 'Select a .torrent file to open.', - filters: [{ name: 'Torrent Files', extensions: ['torrent'] }], - properties: [ 'openFile', 'multiSelections' ] - }, function (selectedPaths) { - if (!Array.isArray(selectedPaths)) return - selectedPaths.forEach(function (selectedPath) { - windows.main.send('dispatch', 'addTorrent', selectedPath) - }) - }) -} - -// Prompts the user for the URL of a torrent file, then downloads and adds it -function showOpenTorrentAddress () { - windows.main.send('showOpenTorrentAddress') -} - function getAppMenuTemplate () { var template = [ { @@ -234,17 +164,17 @@ function getAppMenuTemplate () { ? 'Create New Torrent...' : 'Create New Torrent from Folder...', accelerator: 'CmdOrCtrl+N', - click: showOpenSeedFiles + click: () => dialog.openSeedDirectory() }, { label: 'Open Torrent File...', accelerator: 'CmdOrCtrl+O', - click: showOpenTorrentFile + click: () => dialog.openTorrentFile() }, { label: 'Open Torrent Address...', accelerator: 'CmdOrCtrl+U', - click: showOpenTorrentAddress + click: () => dialog.openTorrentAddress() }, { type: 'separator' @@ -300,7 +230,7 @@ function getAppMenuTemplate () { accelerator: process.platform === 'darwin' ? 'Ctrl+Command+F' : 'F11', - click: () => toggleFullScreen() + click: () => windows.toggleFullScreen() }, { label: 'Float on Top', @@ -505,7 +435,7 @@ function getAppMenuTemplate () { // File menu (Windows, Linux) template[0].submenu.unshift({ label: 'Create New Torrent from File...', - click: showOpenSeedFile + click: () => dialog.openSeedFile() }) // Help menu (Windows, Linux) @@ -515,7 +445,7 @@ function getAppMenuTemplate () { }, { label: 'About ' + config.APP_NAME, - click: windows.createAboutWindow + click: () => windows.about.create() } ) } @@ -537,17 +467,17 @@ function getDockMenuTemplate () { { label: 'Create New Torrent...', accelerator: 'CmdOrCtrl+N', - click: showOpenSeedFiles + click: () => dialog.openSeedDirectory() }, { label: 'Open Torrent File...', accelerator: 'CmdOrCtrl+O', - click: showOpenTorrentFile + click: () => dialog.openTorrentFile() }, { label: 'Open Torrent Address...', accelerator: 'CmdOrCtrl+U', - click: showOpenTorrentAddress + click: () => dialog.openTorrentAddress() } ] } diff --git a/main/power-save-blocker.js b/main/power-save-blocker.js new file mode 100644 index 00000000..9511ccf1 --- /dev/null +++ b/main/power-save-blocker.js @@ -0,0 +1,25 @@ +module.exports = { + start, + stop +} + +var electron = require('electron') +var log = require('./log') + +var powerSaveBlockerId = 0 + +function start () { + // Stop the previous power saver block, if one exists. + stop() + + powerSaveBlockerId = electron.powerSaveBlocker.start('prevent-display-sleep') + log('powerSaveBlocker.start %d', powerSaveBlockerId) +} + +function stop () { + if (!electron.powerSaveBlocker.isStarted(powerSaveBlockerId)) { + return + } + electron.powerSaveBlocker.stop(powerSaveBlockerId) + log('powerSaveBlocker.stop %d', powerSaveBlockerId) +} diff --git a/main/tray.js b/main/tray.js index f0b40a99..a0cb2d1d 100644 --- a/main/tray.js +++ b/main/tray.js @@ -1,9 +1,10 @@ module.exports = { + hasTray, init, - hasTray + onWindowHide, + onWindowShow } -var cp = require('child_process') var electron = require('electron') var app = electron.app @@ -11,41 +12,32 @@ var app = electron.app var config = require('../config') var windows = require('./windows') -var trayIcon +var tray function init () { - // OS X has no tray icon - if (process.platform === 'darwin') return - - // On Linux, asynchronously check for libappindicator1 if (process.platform === 'linux') { - checkLinuxTraySupport(function (supportsTray) { - if (supportsTray) createTrayIcon() - }) + initLinux() } - - // Windows always supports minimize-to-tray - if (process.platform === 'win32') createTrayIcon() + if (process.platform === 'win32') { + initWin32() + } + // OS X apps generally do not have menu bar icons } -function hasTray () { - return !!trayIcon +function initLinux () { + // Check for libappindicator1 support before creating tray icon + checkLinuxTraySupport(function (supportsTray) { + if (supportsTray) createTray() + }) } -function createTrayIcon () { - trayIcon = new electron.Tray(getIconPath()) - - // On Windows, left click to open the app, right click for context menu - // On Linux, any click (right or left) opens the context menu - trayIcon.on('click', showApp) - - // Show the tray context menu, and keep the available commands up to date - updateTrayMenu() - windows.main.on('show', updateTrayMenu) - windows.main.on('hide', updateTrayMenu) +function initWin32 () { + createTray() } function checkLinuxTraySupport (cb) { + var cp = require('child_process') + // Check that we're on Ubuntu (or another debian system) and that we have // libappindicator1. If WebTorrent was installed from the deb file, we should // always have it. If it was installed from the zip file, we might not. @@ -57,18 +49,54 @@ 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) + + // Show the tray context menu, and keep the available commands up to date + updateTrayMenu() +} + +function onWindowHide () { + updateTrayMenu() +} + +function onWindowShow () { + updateTrayMenu() +} + function updateTrayMenu () { - var showHideMenuItem - if (windows.main.isVisible()) { - showHideMenuItem = { label: 'Hide to tray', click: hideApp } - } else { - showHideMenuItem = { label: 'Show', click: showApp } - } + if (!tray) return + var contextMenu = electron.Menu.buildFromTemplate([ - showHideMenuItem, - { label: 'Quit', click: () => app.quit() } + getToggleItem(), + { + label: 'Quit', + click: () => app.quit() + } ]) - trayIcon.setContextMenu(contextMenu) + tray.setContextMenu(contextMenu) + + function getToggleItem () { + if (windows.main.win.isVisible()) { + return { + label: 'Hide to tray', + click: hideApp + } + } else { + return { + label: 'Show WebTorrent', + click: showApp + } + } + } } function showApp () { diff --git a/main/windows.js b/main/windows.js deleted file mode 100644 index 62e15aa6..00000000 --- a/main/windows.js +++ /dev/null @@ -1,145 +0,0 @@ -var windows = module.exports = { - about: null, - main: null, - createAboutWindow, - createWebTorrentHiddenWindow, - createMainWindow, - focusWindow -} - -var electron = require('electron') - -var app = electron.app - -var config = require('../config') -var menu = require('./menu') -var tray = require('./tray') - -function createAboutWindow () { - if (windows.about) { - return focusWindow(windows.about) - } - var win = windows.about = new electron.BrowserWindow({ - backgroundColor: '#ECECEC', - show: false, - center: true, - resizable: false, - icon: getIconPath(), - title: process.platform !== 'darwin' - ? 'About ' + config.APP_WINDOW_TITLE - : '', - useContentSize: true, // Specify web page size without OS chrome - width: 300, - height: 170, - minimizable: false, - maximizable: false, - fullscreen: false, - skipTaskbar: true - }) - win.loadURL(config.WINDOW_ABOUT) - - // No window menu - win.setMenu(null) - - win.webContents.on('did-finish-load', function () { - win.show() - }) - - win.once('closed', function () { - windows.about = null - }) -} - -function createWebTorrentHiddenWindow () { - var win = windows.webtorrent = new electron.BrowserWindow({ - backgroundColor: '#1E1E1E', - show: false, - center: true, - title: 'webtorrent-hidden-window', - useContentSize: true, - width: 150, - height: 150, - minimizable: false, - maximizable: false, - resizable: false, - fullscreenable: false, - fullscreen: false, - skipTaskbar: true - }) - win.loadURL(config.WINDOW_WEBTORRENT) - - // Prevent killing the WebTorrent process - win.on('close', function (e) { - if (!app.isQuitting) { - e.preventDefault() - win.hide() - } - }) - - win.once('closed', function () { - windows.webtorrent = null - }) -} - -var HEADER_HEIGHT = 37 -var TORRENT_HEIGHT = 100 - -function createMainWindow () { - if (windows.main) { - return focusWindow(windows.main) - } - var win = windows.main = new electron.BrowserWindow({ - backgroundColor: '#1E1E1E', - darkTheme: true, // Forces dark theme (GTK+3) - icon: getIconPath(), // Window icon (Windows, Linux) - minWidth: config.WINDOW_MIN_WIDTH, - minHeight: config.WINDOW_MIN_HEIGHT, - show: false, // Hide window until renderer sends 'ipcReady' event - title: config.APP_WINDOW_TITLE, - titleBarStyle: 'hidden-inset', // Hide OS chrome, except traffic light buttons (OS X) - useContentSize: true, // Specify web page size without OS chrome - width: 500, - height: HEADER_HEIGHT + (TORRENT_HEIGHT * 6) // header height + 5 torrents - }) - win.loadURL(config.WINDOW_MAIN) - if (process.platform === 'darwin') { - win.setSheetOffset(HEADER_HEIGHT) - } - - win.webContents.on('dom-ready', function () { - menu.onToggleFullScreen() - }) - - win.on('blur', menu.onWindowHide) - win.on('focus', menu.onWindowShow) - - win.on('enter-full-screen', () => menu.onToggleFullScreen(true)) - win.on('leave-full-screen', () => menu.onToggleFullScreen(false)) - - win.on('close', function (e) { - if (process.platform !== 'darwin' && !tray.hasTray()) { - app.quit() - } else if (!app.isQuitting) { - e.preventDefault() - win.hide() - win.send('dispatch', 'backToList') - } - }) - - win.once('closed', function () { - windows.main = null - }) -} - -function focusWindow (win) { - if (win.isMinimized()) { - win.restore() - } - win.show() // shows and gives focus -} - -function getIconPath () { - return process.platform === 'win32' - ? config.APP_ICON + '.ico' - : config.APP_ICON + '.png' -} diff --git a/main/windows/about.js b/main/windows/about.js new file mode 100644 index 00000000..0022c6e9 --- /dev/null +++ b/main/windows/about.js @@ -0,0 +1,50 @@ +var about = module.exports = { + create, + win: null +} + +var electron = require('electron') + +var config = require('../../config') +var util = require('./util') + +function create () { + if (about.win) { + return util.focusWindow(about.win) + } + + var win = about.win = new electron.BrowserWindow({ + backgroundColor: '#ECECEC', + center: true, + fullscreen: false, + height: 170, + icon: getIconPath(), + maximizable: false, + minimizable: false, + resizable: false, + show: false, + skipTaskbar: true, + useContentSize: true, + width: 300 + }) + + win.loadURL(config.WINDOW_ABOUT) + + // No menu on the About window + win.setMenu(null) + + // TODO: can this be removed? + win.webContents.on('did-finish-load', function () { + win.show() + }) + + win.once('closed', function () { + about.win = null + }) +} + +function getIconPath () { + return process.platform === 'win32' + ? config.APP_ICON + '.ico' + : config.APP_ICON + '.png' +} diff --git a/main/windows/index.js b/main/windows/index.js new file mode 100644 index 00000000..bee0c1ec --- /dev/null +++ b/main/windows/index.js @@ -0,0 +1,3 @@ +exports.about = require('./about') +exports.main = require('./main') +exports.webtorrent = require('./webtorrent') diff --git a/main/windows/main.js b/main/windows/main.js new file mode 100644 index 00000000..29c52b06 --- /dev/null +++ b/main/windows/main.js @@ -0,0 +1,115 @@ +var main = module.exports = { + create, + focus, + hide, + send, + show, + toggleFullScreen, + win: null +} + +var electron = require('electron') + +var app = electron.app + +var config = require('../../config') +var log = require('../log') +var menu = require('../menu') +var tray = require('../tray') +var util = require('./util') + +var HEADER_HEIGHT = 37 +var TORRENT_HEIGHT = 100 + +function create () { + if (main.win) { + return util.focusWindow(main.win) + } + var win = main.win = new electron.BrowserWindow({ + backgroundColor: '#1E1E1E', + darkTheme: true, // Forces dark theme (GTK+3) + icon: getIconPath(), // Window icon (Windows, Linux) + minWidth: config.WINDOW_MIN_WIDTH, + minHeight: config.WINDOW_MIN_HEIGHT, + show: false, // Hide window until renderer sends 'ipcReady' + title: config.APP_WINDOW_TITLE, + titleBarStyle: 'hidden-inset', // Hide title bar (OS X) + useContentSize: true, // Specify web page size without OS chrome + width: 500, + height: HEADER_HEIGHT + (TORRENT_HEIGHT * 6) // header height + 5 torrents + }) + + win.loadURL(config.WINDOW_MAIN) + + if (win.setSheetOffset) win.setSheetOffset(HEADER_HEIGHT) + + win.webContents.on('dom-ready', function () { + menu.onToggleFullScreen() + }) + + win.on('blur', function () { + menu.onWindowHide() + tray.onWindowHide() + }) + + win.on('focus', function () { + menu.onWindowShow() + tray.onWindowShow() + }) + + win.on('enter-full-screen', () => menu.onToggleFullScreen(true)) + win.on('leave-full-screen', () => menu.onToggleFullScreen(false)) + + win.on('close', function (e) { + if (process.platform !== 'darwin' && !tray.hasTray()) { + app.quit() + } 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 toggleFullScreen (flag) { + if (!main.win || !main.win.isVisible()) { + return + } + + if (flag == null) flag = !main.win.isFullScreen() + + log('toggleFullScreen %s', flag) + + if (flag) { + // Fullscreen behaves oddly unless the aspect ratio is disabled. (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 focus () { + if (!main.win) return + util.focusWindow(main.win) +} diff --git a/main/windows/util.js b/main/windows/util.js new file mode 100644 index 00000000..d927ed25 --- /dev/null +++ b/main/windows/util.js @@ -0,0 +1,11 @@ +module.exports = { + focusWindow +} + +function focusWindow (win) { + if (win.isMinimized()) { + // TODO: can this be removed? + win.restore() + } + win.show() // shows and gives focus +} diff --git a/main/windows/webtorrent.js b/main/windows/webtorrent.js new file mode 100644 index 00000000..7d6b66f4 --- /dev/null +++ b/main/windows/webtorrent.js @@ -0,0 +1,48 @@ +var webtorrent = module.exports = { + create, + send, + show, + win: null +} + +var config = require('../../config') +var electron = require('electron') + +function create () { + var win = webtorrent.win = new electron.BrowserWindow({ + backgroundColor: '#1E1E1E', + center: true, + fullscreen: false, + fullscreenable: false, + height: 150, + maximizable: false, + minimizable: false, + resizable: false, + show: false, + skipTaskbar: true, + title: 'webtorrent-hidden-window', + useContentSize: true, + width: 150 + }) + + win.loadURL(config.WINDOW_WEBTORRENT) + + // Prevent killing the WebTorrent process + win.on('close', function (e) { + if (electron.app.isQuitting) { + return + } + e.preventDefault() + win.hide() + }) +} + +function show () { + if (!webtorrent.win) return + webtorrent.win.show() +} + +function send (...args) { + if (!webtorrent.win) return + webtorrent.win.send(...args) +} diff --git a/renderer/main.js b/renderer/main.js index fe97964f..5c834024 100644 --- a/renderer/main.js +++ b/renderer/main.js @@ -606,7 +606,8 @@ function saveState () { update() } -// Called when the user drag-drops files onto the app +// Called when the user adds files (.torrent, files to seed, subtitles) to the app +// via any method (drag-drop, drag to app icon, command line) function onOpen (files) { if (!Array.isArray(files)) files = [ files ] @@ -674,12 +675,13 @@ function addTorrent (torrentId) { } function addSubtitles (files, autoSelect) { - // Subtitles are only supported while playing video + // Subtitles are only supported when playing video files if (state.playing.type !== 'video') return + if (files.length === 0) return // Read the files concurrently, then add all resulting subtitle tracks - var jobs = files.map((file) => (cb) => loadSubtitle(file, cb)) - parallel(jobs, function (err, tracks) { + var tasks = files.map((file) => (cb) => loadSubtitle(file, cb)) + parallel(tasks, function (err, tracks) { if (err) return onError(err) for (var i = 0; i < tracks.length; i++) {