electron 自定义托盘

450 阅读2分钟

借鉴了 electron-tray-window

tray.js
const electron = require("electron");

const { BrowserWindow, ipcMain, Tray } = electron;

let tray = undefined;
let window = undefined;

//defaults
let width = 200;
let height = 300;

let margin_x = 0;
let margin_y = 0;
let framed = false;

function setOptions(options) {
  if (!validation(options)) return;

  init(options);
}

function validation(options) {
  if (typeof options !== "object") {
    console.log("!!!tray-window can not create without any [options]");
    return false;
  }
  if (!options.tray && !options.trayIconPath) {
    console.log(
      "!!!tray-window can not create without [tray] or [trayIconPath] parameters",
    );
    return false;
  }
  if (!options.window && !options.windowUrl) {
    console.log(
      "!!!tray-window can not create without [window] or [windowUrl] parameters",
    );
    return false;
  }

  return true;
}

function init(options) {
  setWindowSize(options);

  options.tray ? setTray(options.tray) : createTray(options.trayIconPath);
  options.window ? setWindow(options.window) : createWindow(options.windowUrl);

  tray.on("click", function (event) {
    ipcMain.emit("tray-window-clicked", { window: window, tray: tray });
    //toggleWindow();
  });
  tray.on("right-click", function (event) {
    ipcMain.emit("tray-window-right-click", { window: window, tray: tray });
    toggleWindow();
  });

  setWindowAutoHide();
  alignWindow();

  ipcMain.emit("tray-window-ready", { window: window, tray: tray });
}

function setWindowSize(options) {
  if (options.width) width = options.width;
  if (options.height) height = options.height;
  if (options.margin_x) margin_x = options.margin_x;
  if (options.margin_y) margin_y = options.margin_y;
  if (options.framed) framed = options.framed;
}

function createTray(trayIconPath) {
  tray = new Tray(trayIconPath);
}

function setTray(newTray) {
  tray = newTray;
}

function setWindow(newWindow) {
  window = newWindow;
  setWindowSize(window.getBounds());
}

function createWindow(windowUrl) {
  window = undefined;

  window = new BrowserWindow({
    width: width,
    height: height,
    maxWidth: width,
    maxHeight: height,
    show: false,
    frame: framed,
    fullscreenable: false,
    resizable: false,
    useContentSize: true,
    transparent: true,
    alwaysOnTop: true,
    webPreferences: {
      backgroundThrottling: false,
    },
  });
  window.setMenu(null);

  setWindowUrl(windowUrl);

  return window;
}

function setWindowUrl(windowUrl) {
  window.loadURL(windowUrl);
}

function setWindowAutoHide() {
  window.hide();
  window.on("blur", () => {
    if (!window.webContents.isDevToolsOpened()) {
      window.hide();
      ipcMain.emit("tray-window-hidden", { window: window, tray: tray });
    }
  });
  window.on("close", function (event) {
    event.preventDefault();
    window.hide();
  });
}

function toggleWindow() {
  if (window.isVisible()) {
    window.hide();
    ipcMain.emit("tray-window-hidden", { window: window, tray: tray });
    return;
  }

  showWindow();
  ipcMain.emit("tray-window-visible", { window: window, tray: tray });
}

function alignWindow() {
  const position = calculateWindowPosition();
  window.setBounds({
    width: width,
    height: height,
    x: position.x,
    y: position.y,
  });
}

function showWindow() {
  alignWindow();
  window.show();
}

function calculateWindowPosition() {
  const screenBounds = electron.screen.getPrimaryDisplay().size;
  const trayBounds = tray.getBounds();

  //where is the icon on the screen?
  let trayPos = 4; // 1:top-left 2:top-right 3:bottom-left 4.bottom-right
  trayPos = trayBounds.y > screenBounds.height / 2 ? trayPos : trayPos / 2;
  trayPos = trayBounds.x > screenBounds.width / 2 ? trayPos : trayPos - 1;

  let DEFAULT_MARGIN = { x: margin_x, y: margin_y };

  //calculate the new window position
  switch (trayPos) {
    case 1: // for TOP - LEFT
      x = Math.floor(trayBounds.x + DEFAULT_MARGIN.x + trayBounds.width / 2);
      y = Math.floor(trayBounds.y + DEFAULT_MARGIN.y + trayBounds.height / 2);
      break;

    case 2: // for TOP - RIGHT
      x = Math.floor(
        trayBounds.x - width - DEFAULT_MARGIN.x + trayBounds.width / 2,
      );
      y = Math.floor(trayBounds.y + DEFAULT_MARGIN.y + trayBounds.height / 2);
      break;

    case 3: // for BOTTOM - LEFT
      x = Math.floor(trayBounds.x + DEFAULT_MARGIN.x + trayBounds.width / 2);
      y = Math.floor(
        trayBounds.y - height - DEFAULT_MARGIN.y + trayBounds.height / 2,
      );
      break;

    case 4: // for BOTTOM - RIGHT
      x = Math.floor(
        trayBounds.x - width - DEFAULT_MARGIN.x + trayBounds.width / 2,
      );
      y = Math.floor(
        trayBounds.y - height - DEFAULT_MARGIN.y + trayBounds.height / 2,
      );
      break;
  }

  return { x: x, y: y };
}

module.exports = { setOptions, setTray, setWindow, setWindowSize };

import {
  setOptions,
  setTray,
  setWindow,
  setWindowSize,
} from "@/util/tray"; //引入自定义托盘文件
  app.whenReady().then(() => {
    const icon = nativeImage.createFromPath(
      path.join(__dirname, "../static/Logo.png"),
    );
    let t = null;
    tray = new Tray(icon);
    // tray.setTitle("TerraSync");
    tray.setToolTip("TerraSync Cliend");
    let traywin = new BrowserWindow({
      frame: false,
      hasShadow: true,
      resizable: false,
      webPreferences: {
        nodeIntegration: true, // 使用node
        contextIsolation: false, // 为了解决require 识别问题
      },
    });
    //traywin.webContents.openDevTools();
    traywin.loadURL(path.join(__dirname, "../static/tray/tray.html"));
    setOptions({ tray: tray, window: traywin });
    setWindowSize({
      width: 400, //optional
      height: 500, //optional
      margin_x: 0, //optional
      margin_y: 30, //optional
    });
    ipcMain.on("TerraSyncLang", (e, arg) => {
      traywin.webContents.send("lang", arg);
    });
    ipcMain.on("tray-window-ready", (e, a) => {
      console.log("托盘窗口已准备就绪");
    });
    ipcMain.on("tray-window-clicked", (e, a) => {
      win.show();
    });
    ipcMain.on("tray-window-right-click", (e, a) => {
      console.log("右键");
    });
    ipcMain.on("tray-window-visible", (e, a) => {
      console.log("tray-window-visible");
    });
    ipcMain.on("tray-window-hidden", (e, a) => {
      console.log("托盘窗口现在隐藏");
    });
    ipcMain.handle("tray_hide", (e, a) => {
      traywin.hide();
    });
  });

tray.png