/ src / main / tray.ts
tray.ts
  1  import { app, screen, session, Menu, Tray, BrowserWindow } from 'electron'
  2  import Constants from './utils/Constants.ts'
  3  import { debounce } from './utils/Util.ts'
  4  let tray
  5  let trayOptions
  6  
  7  export function createTray(window: BrowserWindow, options) {
  8    trayOptions = options || Constants.DEFAULT_TRAY_OPTIONS
  9    // menu or trayWindow, you need to choose
 10    if (trayOptions.trayWindow) {
 11      trayOptions.menu = false
 12    }
 13  
 14    tray = new Tray(Constants.ASSETS_PATH.icon)
 15    tray.setToolTip(trayOptions.tooltip)
 16    if (trayOptions.menu) {
 17      tray.on('click', function (_event) {
 18        debounce(() => toggleWindow(window), 100)
 19      })
 20      const contextMenu = Menu.buildFromTemplate([
 21        {
 22          label: 'Open Dev Tools',
 23          click: () => {
 24            window.webContents.openDevTools()
 25          }
 26        },
 27        {
 28          label: 'Force Reload',
 29          click: () => {
 30            window.webContents.reloadIgnoringCache()
 31          }
 32        },
 33        {
 34          label: 'Clear Storage',
 35          click: () => {
 36            const sess = session.fromPartition(Constants.PARTITION_NAME)
 37            sess.clearStorageData({
 38              storages: ['cookies', 'cachestorage', 'localstorage', 'indexdb', 'serviceworkers']
 39            })
 40            window.webContents.reloadIgnoringCache()
 41          }
 42        },
 43        {
 44          label: 'Exit',
 45          click: () => {
 46            app.quit()
 47          }
 48        }
 49      ])
 50      // tray icon only with classic window
 51      tray.setContextMenu(contextMenu)
 52    } else {
 53      // handle click on tray icon
 54      tray.on('right-click', function (_event) {
 55        debounce(() => toggleWindow(window))
 56      })
 57      tray.on('click', function (_event) {
 58        debounce(() => toggleWindow(window))
 59      })
 60      // no menu for tray window
 61      // window.setMenu(null)
 62      // tray.setContextMenu(null)
 63    }
 64    // align at startup
 65    alignWindow(window)
 66    return tray
 67  }
 68  
 69  export function hideWindow(window: BrowserWindow) {
 70    window.hide()
 71    // if (!trayOptions.trayWindow) return;
 72    // hide window when click elsewhere on screen
 73    // window.on('blur', () => {
 74    //   // dont close if devtools
 75    //   if (!window.webContents.isDevToolsOpened()) {
 76    //     window.hide()
 77    //   }
 78    // })
 79  }
 80  
 81  export function toggleWindow(window: BrowserWindow) {
 82    if (window.isVisible()) {
 83      hideWindow(window)
 84    } else {
 85      showWindow(window)
 86    }
 87  }
 88  
 89  export function showWindow(window: BrowserWindow) {
 90    window.show()
 91    alignWindow(window)
 92  }
 93  
 94  export function alignWindow(window: BrowserWindow) {
 95    if (!trayOptions.trayWindow) return
 96  
 97    const b = window.getBounds()
 98    const position = calculateWindowPosition(b)
 99    window.setBounds({
100      width: b.width,
101      height: b.height,
102      x: position.x,
103      y: position.y
104    })
105  }
106  
107  function calculateWindowPosition(b) {
108    const margin = trayOptions.margin
109    const screenBounds = screen.getPrimaryDisplay().size
110    const trayBounds = tray.getBounds()
111    const bottom = trayBounds.y > screenBounds.height / 2
112    const x = Math.floor(trayBounds.x - b.width / 2 - margin.x + trayBounds.width / 2)
113    const y = bottom
114      ? Math.floor(trayBounds.y - b.height - margin.y + trayBounds.height / 2)
115      : Math.floor(trayBounds.y + margin.y + trayBounds.height / 2)
116    // constraint into screen
117    return {
118      x: Math.max(0, Math.min(screenBounds.width - b.width, x)),
119      y: Math.max(0, Math.min(screenBounds.height - b.height, y))
120    }
121  }