Unverified Commit 6ae3c1ff authored by Thibaut Sardan's avatar Thibaut Sardan Committed by GitHub
Browse files

Merge pull request #440 from...

Merge pull request #440 from paritytech/luke-refactor-menu-and-no-close-minimise-window-for-taskbar-app

refactor: Update Fether menu for taskbar mode on non-macOS (add 'Quit', remove 'Close Window', remove 'Minimize') 
parents e641594e a48cc933
Pipeline #31748 passed with stages
in 9 minutes and 58 seconds
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
// This file is part of Parity.
//
// SPDX-License-Identifier: BSD-3-Clause
import electron from 'electron';
import { getContextTrayMenuTemplate } from '../template';
const { Menu } = electron;
let hasCalledInitMenu = false;
class FetherContextTrayMenu {
constructor (fetherApp) {
if (hasCalledInitMenu) {
throw new Error(
'Unable to initialise Fether context tray menu more than once'
);
}
this.setMenuTemplate(getContextTrayMenuTemplate(fetherApp));
this.buildMenuTemplate(this.menuTemplate);
}
setMenuTemplate = menuTemplate => {
this.menuTemplate = menuTemplate;
};
buildMenuTemplate = menuTemplate => {
this.builtMenu = Menu.buildFromTemplate(menuTemplate);
};
getMenu = () => {
return this.builtMenu;
};
}
export default FetherContextTrayMenu;
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
// This file is part of Parity.
//
// SPDX-License-Identifier: BSD-3-Clause
import electron from 'electron';
import { getContextWindowMenuTemplate } from '../template';
const { Menu } = electron;
let hasCalledInitMenu = false;
class FetherContextWindowMenu {
constructor (fetherApp) {
if (hasCalledInitMenu) {
throw new Error(
'Unable to initialise Fether context window menu more than once'
);
}
this.setMenuTemplate(getContextWindowMenuTemplate(fetherApp));
this.buildMenuTemplate(this.menuTemplate);
}
setMenuTemplate = menuTemplate => {
this.menuTemplate = menuTemplate;
};
buildMenuTemplate = menuTemplate => {
this.builtMenu = Menu.buildFromTemplate(menuTemplate);
};
getMenu = () => {
return this.builtMenu;
};
}
export default FetherContextWindowMenu;
......@@ -3,19 +3,8 @@
//
// SPDX-License-Identifier: BSD-3-Clause
import electron from 'electron';
import { template } from './template';
import FetherMenubarMenu from './menubar';
import FetherContextTrayMenu from './contextTray';
import FetherContextWindowMenu from './contextWindow';
const { Menu } = electron;
const menu = Menu.buildFromTemplate(template);
const getMenu = () => {
return Menu.getApplicationMenu();
};
const addMenu = () => {
Menu.setApplicationMenu(menu);
};
export { addMenu, getMenu };
export { FetherMenubarMenu, FetherContextTrayMenu, FetherContextWindowMenu };
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
// This file is part of Parity.
//
// SPDX-License-Identifier: BSD-3-Clause
import electron from 'electron';
import { getMenubarMenuTemplate } from '../template';
const { Menu } = electron;
let hasCalledInitMenu = false;
class FetherMenubarMenu {
constructor (fetherApp) {
if (hasCalledInitMenu) {
throw new Error(
'Unable to initialise Fether menubar menu more than once'
);
}
this.setMenuTemplate(getMenubarMenuTemplate(fetherApp));
this.buildMenuTemplate(this.menuTemplate);
}
setMenuTemplate = menuTemplate => {
this.menuTemplate = menuTemplate;
};
buildMenuTemplate = menuTemplate => {
this.builtMenu = Menu.buildFromTemplate(menuTemplate);
};
setMenu = customBuiltMenuTemplate => {
Menu.setApplicationMenu(customBuiltMenuTemplate || this.builtMenu);
};
getMenu = () => {
// return Menu.getApplicationMenu();
return this.builtMenu;
};
}
export default FetherMenubarMenu;
......@@ -5,40 +5,89 @@
import electron from 'electron';
const { app, shell } = electron;
const { shell } = electron;
// Create the Application's main menu
// https://github.com/electron/electron/blob/master/docs/api/menu.md#examples
export const template = [
{
const getMenubarMenuTemplate = fetherApp => {
// File menu
const fileTab =
process.platform === 'darwin'
? {
label: 'File',
submenu: [
{ role: 'about' },
{ type: 'separator' },
{ role: 'services', submenu: [] },
{ type: 'separator' },
{ role: 'hide' },
{ role: 'hideothers' },
{ role: 'unhide' },
{ type: 'separator' },
{ role: 'quit' }
]
}
: {
label: 'File',
submenu: [{ role: 'quit' }]
};
/**
* On win32 we need to use `webContents` to make some of the menu items
* functional (whereas it is not required on Linux and macOS).
* i.e on macOS/Linux `{ role: 'undo' }` suffices to add the Undo menu item,
* whereas on win32 we must use `webContents` as follows:
* `{ label: 'Undo', click: () => fetherApp.win.webContents.undo() }`.
* Since all items in the 'Edit' menu work with `webContents` we will use
* it to prevent code duplication
*/
const editTab = {
label: 'Edit',
submenu: [
{ role: 'cut' },
{ role: 'copy' },
{ role: 'paste' },
{ role: 'delete' },
{ role: 'selectall' }
{ label: 'Undo', click: () => fetherApp.win.webContents.undo() },
{ label: 'Redo', click: () => fetherApp.win.webContents.redo() },
{ type: 'separator' },
{ label: 'Cut', click: () => fetherApp.win.webContents.cut() },
{ label: 'Copy', click: () => fetherApp.win.webContents.copy() },
{ label: 'Paste', click: () => fetherApp.win.webContents.paste() },
{ type: 'separator' },
{ label: 'Delete', click: () => fetherApp.win.webContents.delete() },
{
label: 'Select All',
click: () => fetherApp.win.webContents.selectAll()
}
]
},
{
};
const viewTab = {
label: 'View',
submenu: [{ role: 'reload' }, { role: 'toggledevtools' }]
};
/**
* On win32 we need to use `webContents` to make some of the menu items
* functional (whereas it is not required on Linux and macOS).
* Note that some menu items are not available in `webContents`
* (i.e. resetzoom, zoomin, zoomout, togglefullscreen), however they
* add no benefit to users anyway
*/
const viewTabWindowsOS = {
label: 'View',
submenu: [
{ role: 'reload' },
{ role: 'forcereload' },
{ role: 'toggledevtools' },
{ type: 'separator' },
{ role: 'resetzoom' },
{ role: 'zoomin' },
{ role: 'zoomout' },
{ type: 'separator' },
{ role: 'togglefullscreen' }
{ label: 'Reload', click: () => fetherApp.win.webContents.reload() },
{
label: 'Toggle Developer Tools',
click: () => fetherApp.win.webContents.toggleDevTools()
}
]
},
{
};
const windowTab = {
role: 'window',
submenu: [{ role: 'minimize' }, { role: 'close' }]
},
{
};
const helpTab = {
role: 'help',
submenu: [
{
......@@ -48,40 +97,95 @@ export const template = [
}
}
]
}
];
};
if (process.platform === 'darwin') {
template.unshift({
label: app.getName(),
submenu: [
{ role: 'about' },
{ type: 'separator' },
{ role: 'services', submenu: [] },
let template = [
fileTab,
editTab,
process.platform === 'win32' ? viewTabWindowsOS : viewTab,
windowTab,
helpTab
];
if (process.platform === 'darwin') {
// Edit menu
template[1].submenu.push(
{ type: 'separator' },
{ role: 'hide' },
{ role: 'hideothers' },
{ role: 'unhide' },
{
label: 'Speech',
submenu: [{ role: 'startspeaking' }, { role: 'stopspeaking' }]
}
);
}
if (process.platform === 'darwin') {
// Window menu
template[3].submenu = [
{ role: 'close' },
{ role: 'minimize' },
{ role: 'zoom' },
{ type: 'separator' },
{ role: 'quit' }
]
});
// Edit menu
template[1].submenu.push(
{ type: 'separator' },
{
label: 'Speech',
submenu: [{ role: 'startspeaking' }, { role: 'stopspeaking' }]
{ role: 'front' }
];
}
if (fetherApp.options.withTaskbar) {
// Remove Window menu tab when running as taskbar app
template.splice(3, 1);
}
return template;
};
const getContextTrayMenuTemplate = fetherApp => {
if (fetherApp.options.withTaskbar) {
const template = [
{
label: 'Show/Hide Fether',
click () {
fetherApp.win.isVisible()
? fetherApp.win.hide()
: fetherApp.win.show();
}
},
{ label: 'Quit', role: 'quit' }
];
return template;
}
};
const getContextWindowMenuTemplate = fetherApp => {
let template = getMenubarMenuTemplate(fetherApp);
if (fetherApp.options.withTaskbar) {
// Remove File and Help menus in taskbar mode for window context menu
template.shift();
template.pop();
template.push({
role: 'help',
submenu: [
{
label: 'Learn More',
click () {
shell.openExternal('https://parity.io');
}
}
]
});
if (process.platform === 'darwin') {
template[2].submenu.push({ role: 'about' });
}
);
// Window menu
template[3].submenu = [
{ role: 'close' },
{ role: 'minimize' },
{ role: 'zoom' },
{ type: 'separator' },
{ role: 'front' }
];
}
template.push({ label: 'Quit', role: 'quit' });
}
return template;
};
export {
getContextTrayMenuTemplate,
getContextWindowMenuTemplate,
getMenubarMenuTemplate
};
......@@ -12,12 +12,19 @@ const pino = Pino();
/**
* Handle all asynchronous messages from renderer to main.
*/
export default async (fetherAppWindow, event, action, ...args) => {
export default async (fetherApp, event, action, ...args) => {
try {
if (!action) {
return;
}
switch (action) {
case 'app-right-click': {
if (!fetherApp.win) {
return;
}
fetherApp.contextWindowMenu.getMenu().popup({ window: fetherApp.win });
break;
}
case 'check-clock-sync': {
checkClockSync().then(t => {
event.sender.send('check-clock-sync-reply', t);
......
......@@ -17,20 +17,27 @@ function loadTray (fetherApp) {
app.dock.hide();
}
const defaultClickEvent = options.showOnRightClick
? 'right-click'
: 'click';
// Note: See https://github.com/RocketChat/Rocket.Chat.Electron/issues/44
if (process.platform === 'win32') {
showTrayBalloon(fetherApp);
}
tray.on(defaultClickEvent, () => onTrayClick(fetherApp));
tray.on('double-click', () => onTrayClick(fetherApp));
// Right click event handler does not work on Windows as intended
tray.setContextMenu(fetherApp.contextTrayMenu.getMenu());
// Right-click event listener does not work on Windows
tray.on('right-click', () => {
pino.info('Detected right click on Windows');
pino.info('Detected right-click on tray icon');
tray.popUpContextMenu();
fetherApp.win.focus();
});
// Single click event listener works on Windows
tray.on('click', () => {
pino.info('Detected single click on tray icon');
onTrayClick(fetherApp);
fetherApp.win.focus();
});
tray.setToolTip(options.tooltip);
tray.setHighlightMode('never');
......
......@@ -3,17 +3,27 @@
//
// SPDX-License-Identifier: BSD-3-Clause
import { addMenu } from '../menu';
import {
FetherContextTrayMenu,
FetherContextWindowMenu,
FetherMenubarMenu
} from '../menu';
import Pino from '../utils/pino';
const pino = Pino();
function setupMenu (fetherApp) {
// Add Fether menu
addMenu();
fetherApp.menubarMenu = new FetherMenubarMenu(fetherApp);
fetherApp.menubarMenu.setMenu();
if (fetherApp.options.withTaskbar) {
fetherApp.contextTrayMenu = new FetherContextTrayMenu(fetherApp);
}
fetherApp.contextWindowMenu = new FetherContextWindowMenu(fetherApp);
/**
* Toggle the Fether menu bar in the frame.
* Toggle the Fether menubar menu in window frame when options `frame: true`.
* If not shown by default then when shown it may crop the bottom
* of the window when menu open/close toggled on Windows.
*/
......
......@@ -11,7 +11,7 @@ const { ipcMain, session } = electron;
function setupRequestListeners (fetherApp) {
// Listen to messages from renderer process
ipcMain.on('asynchronous-message', (...args) => {
return messages(fetherApp.win, ...args);
return messages(fetherApp, ...args);
});
// WS calls have Origin `file://` by default, which is not trusted.
......
......@@ -25,7 +25,7 @@ function setupWin32Listeners (fetherApp) {
* Reference: https://nodejs.org/api/buffer.html
*/
if (wParam) {
pino.info('Detected ALT key pressed to toggle the Fether menu');
pino.info('Detected ALT key pressed');
// showTrayBalloon(fetherApp);
}
});
......
......@@ -18,15 +18,17 @@ const iconBalloonPath = path.join(
const pino = Pino();
// Supported only on Windows OS
function showTrayBalloon (fetherApp) {
const { tray } = fetherApp;
pino.info('Showing Tray Balloon');
tray.displayBalloon({
content: `Press ALT in the Fether window to toggle the menu`,
content:
'Click to toggle Fether window. Right-click Fether window to toggle Fether menu',
icon: iconBalloonPath,
title: 'Fether Menu'
title: 'Fether Window & Menu Usage'
});
}
......
......@@ -43,6 +43,9 @@ if (process.platform === 'win32') {
const windowPosition =
process.platform === 'win32' ? 'trayBottomCenter' : 'trayCenter';
let tooltip =
'Click to toggle Fether window. Right-click Fether window to toggle Fether menu';
// API docs: https://electronjs.org/docs/api/browser-window
const DEFAULT_OPTIONS = {
alwaysOnTop: false,
......@@ -67,11 +70,11 @@ const DEFAULT_OPTIONS = {
};
const TASKBAR_OPTIONS = {
height: 515,
frame: false,
height: 515,
// On Linux the user must click the tray icon and then click the tooltip
// to toggle the Fether window open/close
tooltip: 'Click to toggle Fether window',
tooltip: tooltip,
width: 352,
withTaskbar: true
};
......
......@@ -23,10 +23,13 @@ if (!['darwin', 'win32'].includes(process.platform)) {
app.disableHardwareAcceleration();
}
let fetherApp;
const options = fetherAppOptions(withTaskbar, {});
app.on('ready', () => {
return new FetherApp(app, options);
fetherApp = new FetherApp(app, options);
return fetherApp;
});
// Event triggered by clicking the Electron icon in the menu Dock
......@@ -44,7 +47,9 @@ app.on('activate', (event, hasVisibleWindows) => {
return;
}
return new FetherApp(app, options);
fetherApp = new FetherApp(app, options);
return fetherApp;
});
app.on('window-all-closed', () => {
......@@ -63,3 +68,5 @@ app.on('quit', () => {
pino.info('Leaving Fether');
killParity();
});
export { fetherApp };
......@@ -12,6 +12,7 @@ import {
Switch
} from 'react-router-dom';
import { inject, observer } from 'mobx-react';
import isElectron from 'is-electron';