diff --git a/main/account_switcher.ts b/main/account_switcher.ts index a4ac1aa..f3f62e6 100644 --- a/main/account_switcher.ts +++ b/main/account_switcher.ts @@ -11,7 +11,7 @@ export default class AccountSwitcher extends EventEmitter { accounts: Account[]; current: Account; - constructor(private win: Electron.BrowserWindow, accounts: Account[]) { + constructor(accounts: Account[]) { super(); const submenu = [] as Electron.MenuItemOptions[]; @@ -25,7 +25,7 @@ export default class AccountSwitcher extends EventEmitter { label: name, type: 'radio', checked: false, - click: () => this.switchAccountTo(account), + click: () => this.switchTo(account), }); } @@ -49,18 +49,13 @@ export default class AccountSwitcher extends EventEmitter { Menu.setApplicationMenu(menu); } - switchAccountTo(account: Account) { + switchTo(account: Account) { if (this.current.name === account.name && this.current.host === account.host) { log.debug('Current account is already @' + account.name); return; } log.debug('Switch to account', account); - this.emit('will-switch', account); - - log.error('TODO: Switch partition'); - - this.win.webContents.send('mstdn:change-account', account); - this.emit('did-switch', account); + this.emit('switch', account, this.current); this.current = account; } } diff --git a/main/app.ts b/main/app.ts index 10dcd97..4e1bbb2 100644 --- a/main/app.ts +++ b/main/app.ts @@ -1,7 +1,7 @@ import * as path from 'path'; -import {app, Menu} from 'electron'; +import {app, Menu, globalShortcut} from 'electron'; import log from './log'; -import {Config} from './config'; +import {Config, Account} from './config'; import AccountSwitcher from './account_switcher'; import defaultMenu from './default_menu'; import Window from './window'; @@ -20,17 +20,30 @@ export class App { app.dock.setIcon(APP_ICON); } Menu.setApplicationMenu(defaultMenu()); - this.switcher = new AccountSwitcher(win.browser, this.config.accounts); - this.switcher.on('did-switch', () => this.open()); + this.switcher = new AccountSwitcher(this.config.accounts); + this.switcher.on('switch', this.onAccountSwitch); } - open() { + start() { const url = `https://${this.switcher.current.host}${this.switcher.current.default_page}`; this.win.open(url); log.debug('Open URL: ', url); } + + private onAccountSwitch = (next: Account) => { + this.win.close(); + if (this.config.hot_key) { + globalShortcut.unregister(this.config.hot_key); + } + Window.create(next, this.config, this.win.menubar) .then(win => { + this.win = win; + this.start(); + }); + } } export default function startApp(config: Config) { - return Window.create(config).then(win => new App(win, config)); + const default_account = config.accounts[0]; + return Window.create(default_account, config) + .then(win => new App(win, config)); } diff --git a/main/index.ts b/main/index.ts index a4d5a70..f1da477 100644 --- a/main/index.ts +++ b/main/index.ts @@ -3,6 +3,10 @@ import log from './log'; import startApp from './app'; import loadConfig from './config'; +// default_app sets app.on('all-window-closed', () => app.quit()) before +// loading this application. We need to disable the callback. +app.removeAllListeners(); + const appReady = new Promise(resolve => app.once('ready', resolve)); process.on('unhandledRejection', (reason: string) => { @@ -16,7 +20,7 @@ app.on('will-quit', () => { Promise.all([ loadConfig(), appReady -]).then(([config, _]) => startApp(config)).then(win => { - win.open(); +]).then(([config, _]) => startApp(config)).then(mstdn => { + mstdn.start(); log.debug('Application launched!'); }); diff --git a/main/window.ts b/main/window.ts index 19d4fd6..8fafa09 100644 --- a/main/window.ts +++ b/main/window.ts @@ -12,12 +12,17 @@ const APP_ICON = path.join(__dirname, '..', 'resources', 'icon', 'icon.png'); const PRELOAD_JS = path.join(__dirname, '..', 'renderer', 'preload.js'); export default class Window { - static create(config: Config) { - return (config.normal_window ? startNormalWindow : startMenuBar)(config); + static create(account: Account, config: Config, mb: Menubar.MenubarApp | null = null) { + if (config.normal_window) { + return startNormalWindow(account, config); + } else { + return startMenuBar(account, config, mb); + } } constructor( public browser: Electron.BrowserWindow, + public state: any /*XXX: ElectronWindowState.WindowState */, public account: Account, public menubar: Menubar.MenubarApp | null, ) { @@ -60,12 +65,16 @@ export default class Window { this.browser.loadURL(url); } - isMenubar() { - return this.menubar !== null; - } - close() { - log.error('TODO: close window'); + this.state.unmanage(); + this.browser.webContents.removeAllListeners(); + this.browser.removeAllListeners(); + if (this.menubar) { + // Note: + // menubar.windowClear() won't be called because all listners was removed + delete this.menubar.window; + } + this.browser.close(); } } @@ -75,14 +84,13 @@ function trayIcon(color: string) { }@2x.png`); } -function startNormalWindow(config: Config): Promise { +function startNormalWindow(account: Account, config: Config): Promise { log.debug('Setup a normal window'); return new Promise(resolve => { const state = windowState({ defaultWidth: 600, defaultHeight: 800, }); - const account = config.accounts[0]; const win = new BrowserWindow({ width: state.width, height: state.height, @@ -129,7 +137,7 @@ function startNormalWindow(config: Config): Promise { win.webContents.on('dom-ready', () => { log.debug('Send config to renderer procress'); - win.webContents.send('mstdn:config', config); + win.webContents.send('mstdn:config', config, account); }); win.webContents.once('dom-ready', () => { log.debug('Normal window application was launched'); @@ -150,20 +158,19 @@ function startNormalWindow(config: Config): Promise { tray.setHighlightMode('never'); } - resolve(new Window(win, account, null)); + resolve(new Window(win, state, account, null)); }); } -function startMenuBar(config: Config): Promise { +function startMenuBar(account: Account, config: Config, bar: Menubar.MenubarApp | null): Promise { log.debug('Setup a menubar window'); return new Promise(resolve => { const state = windowState({ defaultWidth: 350, defaultHeight: 420, }); - const account = config.accounts[0]; const icon = trayIcon(config.icon_color); - const mb = menubar({ + const mb = bar || menubar({ icon, width: state.width, height: state.height, @@ -180,7 +187,6 @@ function startMenuBar(config: Config): Promise { partition: partitionForAccount(account), }, }); - mb.once('ready', () => mb.showWindow()); mb.once('after-create-window', () => { log.debug('Menubar application was launched'); if (config.hot_key) { @@ -200,15 +206,24 @@ function startMenuBar(config: Config): Promise { } mb.window.webContents.on('dom-ready', () => { log.debug('Send config to renderer procress'); - mb.window.webContents.send('mstdn:config', config); + mb.window.webContents.send('mstdn:config', config, account); }); state.manage(mb.window); - resolve(new Window(mb.window, account, mb)); + resolve(new Window(mb.window, state, account, mb)); }); mb.once('after-close', () => { app.quit(); }); + if (bar) { + log.debug('recreate menubar window with different partition:', account); + const pref = mb.getOption('webPreferences'); + pref.partition = partitionForAccount(account); + mb.setOption('webPreferences', pref); + mb.showWindow(); + } else { + mb.once('ready', () => mb.showWindow()); + } }); } diff --git a/renderer/index.ts b/renderer/index.ts index 0039a04..f78c6d2 100644 --- a/renderer/index.ts +++ b/renderer/index.ts @@ -54,16 +54,8 @@ function setupKeybinds(keybinds: {[key: string]: string}, host: string) { let config: Config | null = null; -Ipc.on('mstdn:config', (c: Config) => { +Ipc.on('mstdn:config', (c: Config, a: Account) => { config = c; - const host = config.accounts[0].host; + const host = a.host; setupKeybinds(config.keymaps, host); }); - -Ipc.on('mstdn:change-account', (account: Account) => { - if (config === null) { - log.error('FATAL: config is null at receiving mstdn:change-account'); - return; - } - setupKeybinds(config.keymaps, account.host); -});