DawnLauncher/electron/main/main/index.ts

742 lines
21 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import {
BrowserWindow,
Display,
Menu,
Tray,
app,
screen,
shell,
} from "electron";
import { createSettingWindow } from "../setting";
import { join } from "node:path";
import cacheData from "../commons/cacheData";
import {
getMainBackgorunColor,
getWindowInScreen,
sendToWebContent,
} from "../commons";
import { release } from "node:os";
// 窗口
let mainWindow: BrowserWindow | null = null;
/**
* 主窗口
*/
function createMainWindow() {
// 预热
global.addon.hasRunas(process.execPath);
// 如果窗口存在先关闭窗口
if (mainWindow && !mainWindow.isDestroyed() && mainWindow.isVisible()) {
mainWindow.close();
mainWindow = null;
global.mainWindow = null;
}
// 创建窗口
mainWindow = global.mainWindow = new BrowserWindow({
title: "Dawn Launcher",
width: 800,
height: 600,
frame: false,
show: false,
maximizable: false,
minimizable: false,
fullscreenable: false,
transparent: global.setting.appearance.transparency < 1,
skipTaskbar: global.setting.general.hideTaskbar,
backgroundColor:
global.setting.appearance.transparency === 1
? getMainBackgorunColor()
: null,
icon: join(process.env.VITE_PUBLIC, "logo.ico"),
webPreferences: {
spellcheck: false,
backgroundThrottling: false,
preload: join(__dirname, "../preload/index.js"),
devTools: process.env.NODE_ENV === "development",
},
});
if (process.env.VITE_DEV_SERVER_URL) {
mainWindow.loadURL(process.env.VITE_DEV_SERVER_URL);
} else {
mainWindow.loadFile(join(process.env.DIST, "index.html"));
}
// 加载完毕
mainWindow.webContents.on("did-finish-load", () => {
// 设置窗口无动画
global.addon.removeWindowAnimation(
mainWindow.getNativeWindowHandle().readInt32LE(0)
);
// 恢复上一次的位置
let bounds = cacheData.cacheStore.get("mainWindowBounds");
if (bounds) {
mainWindow.setBounds(bounds);
}
// 永远居中不可移动
if (global.setting.general.alwaysCenter) {
mainWindow.setMovable(false);
} else {
mainWindow.setMovable(!global.setting.general.fixedPosition);
}
// 永远置顶
if (global.setting.general.alwaysTop) {
mainWindow.setAlwaysOnTop(true, "screen-saver");
}
// 锁定尺寸
mainWindow.setResizable(!global.setting.general.lockSize);
// 托盘
createTray(!global.setting.general.hideTray);
// 永远居中
alwaysCenter();
// 判断窗口位置
let displays = getWindowInScreen(mainWindow);
if (displays.length === 0) {
// 代表窗口的位置不再任一屏幕内,将窗口位置移动到主窗口
mainWindow.center();
}
// 边缘吸附
edgeAdsorb(null);
});
mainWindow.webContents.setWindowOpenHandler(({ url }) => {
if (url.startsWith("https:")) shell.openExternal(url);
return { action: "deny" };
});
// 显示窗口
mainWindow.on("show", () => {
// 显示窗口时将输入法切换为英文模式
if (global.setting.general.switchEnglish) {
global.addon.switchEnglish(
mainWindow.getNativeWindowHandle().readInt32LE(0)
);
}
// 边缘吸附
edgeAdsorb(null);
});
// 失去焦点
mainWindow.on("blur", () => {
if (global.setting.general.edgeAutoHide && global.blurHide) {
autoHide(0, false);
}
if (
mainWindow.isVisible() &&
global.setting.general.hideLoseFocus &&
!global.setting.general.alwaysTop
) {
// 如果当前还有打开的子窗口就不执行失去焦点隐藏
if (
mainWindow.getChildWindows().length === 0 &&
!global.mainWindowShowDialog
) {
hideMainWindow();
}
}
});
// 窗口移动完毕
mainWindow.on("moved", () => {
// 边缘吸附
edgeAdsorb(null);
// 永远居中
alwaysCenter();
// 记录位置
cacheData.cacheStore.set("mainWindowBounds", mainWindow.getBounds());
});
// 改变窗口大小完毕
mainWindow.on("resized", () => {
// 边缘吸附
edgeAdsorb(null);
// 永远居中
alwaysCenter();
// 记录位置
cacheData.cacheStore.set("mainWindowBounds", mainWindow.getBounds());
});
// 窗口隐藏事件
mainWindow.on("hide", () => {
// 收起子分类
if (global.setting.classification.hideWindowCollapseSubClassification) {
sendToWebContent("mainWindow", "onCollapseSubClassification", {});
}
});
// 创建鼠标hook
let mousedownClassName = null;
addon.createMouseHook((...args: any[]) => {
let res = JSON.parse(args[1]);
let event: string = res.event;
let x: number = res.x;
let y: number = res.y;
let className: string =
!res.class_name || res.class_name.trim() === ""
? null
: res.class_name.trim();
// 1左键 2右键 3滚轮
let button: number = res.button;
if (event === "mousemove") {
// 鼠标移动
if (!global.blurHide) {
// 停靠在桌面边缘时自动隐藏
autoHide(20, true);
}
} else if (event === "mousedown") {
// 鼠标按下
if (button === 1) {
mousedownClassName = className;
}
} else if (event === "mouseup") {
// 鼠标抬起
if (button === 1) {
// 双击任务栏
doubleClickTaskbar(mousedownClassName, className);
} else if (button === 3) {
// 中间单击
showHideMouseWheelClick();
}
}
});
// 禁用标题栏右键
mainWindow.hookWindowMessage(278, function (e) {
// 窗口禁用
mainWindow.setEnabled(false);
// 延时太快会立刻启动,太慢会妨碍窗口其他操作,可自行测试最佳时间
setTimeout(() => {
mainWindow.setEnabled(true);
}, 100);
return true;
});
}
/**
* 显示窗口之前
* @param blurHide
* @param autoHide
* @param selectedClassificationId
*/
function showMainWindowBefore(
blurHide: boolean,
autoHide = false,
selectedClassificationId: number | null = null
) {
// 向主窗口发送通知
sendToWebContent("mainWindow", "onShowMainWindowBefore", {
blurHide,
autoHide,
selectedClassificationId,
});
}
/**
* 显示窗口
* @param blurHide
* @param autoHide
*/
function showMainWindow(blurHide: boolean, autoHide = false) {
// flag
let flag = true;
// 是否开启勿扰模式
if (global.setting.general.notDisturb) {
if (global.addon.isFullscreen()) {
flag = false;
}
}
if (!autoHide) {
// 显示时跟随鼠标位置
showFollowMousePosition();
}
if (flag) {
if (!global.setting.general.alwaysTop) {
mainWindow.setAlwaysOnTop(true, "screen-saver");
}
global.mainWindow.show();
global.mainWindow.focus();
if (!global.setting.general.alwaysTop) {
mainWindow.setAlwaysOnTop(false);
}
global.blurHide = blurHide;
}
}
/**
* 隐藏窗口
*/
function hideMainWindow() {
if (global.mainWindow.isVisible()) {
global.mainWindow.hide();
global.blurHide = false;
}
}
/**
* 托盘
*/
function createTray(show: boolean) {
if (show) {
// 销毁托盘
if (global.tray && !global.tray.isDestroyed()) {
global.tray.destroy();
global.tray = null;
}
// 创建托盘
global.tray = new Tray(join(process.env.VITE_PUBLIC, "tray.ico"));
// 菜单
let contextMenu = Menu.buildFromTemplate([
{
label: global.language.displayMainWindow,
click: function () {
showMainWindowBefore(true);
},
},
{
label: global.language.settings,
click: function () {
createSettingWindow();
},
},
{
label: global.language.exit,
click: function () {
app.quit();
},
},
]);
global.tray.setToolTip("Dawn Launcher");
global.tray.setContextMenu(contextMenu);
// 点击托盘
global.tray.on("click", () => {
showMainWindowBefore(true);
});
} else {
// 销毁托盘
if (global.tray && !global.tray.isDestroyed()) {
global.tray.destroy();
global.tray = null;
}
}
}
/**
* 边缘吸附
* @param display
* @param workArea
* @returns
*/
function edgeAdsorb(display: Display | null, workArea = false) {
// 如果勾选停靠在桌面边缘时自动隐藏,放行
if (
global.mainWindow.isDestroyed() ||
(!global.setting.general.edgeAdsorb && !global.setting.general.edgeAutoHide)
) {
return;
}
try {
// 清空方向
global.mainWindowDirection = null;
// 屏幕
let displays = display ? [display] : getWindowInScreen(mainWindow);
if (displays.length > 1 || displays.length === 0) {
return;
}
// 屏幕区域
let displayBounds = workArea ? displays[0].workArea : displays[0].bounds;
// 窗口位置信息
let bounds = global.mainWindow.getBounds();
if (bounds.x <= displayBounds.x && bounds.y <= displayBounds.y) {
// 左上角
global.mainWindow.setBounds({ x: displayBounds.x, y: displayBounds.y });
global.mainWindowDirection = "leftTop";
global.blurHide = false;
} else if (
bounds.x + bounds.width >= displayBounds.x + displayBounds.width &&
bounds.y <= displayBounds.y
) {
// 右上角
global.mainWindow.setBounds({
x: displayBounds.x + displayBounds.width - bounds.width,
y: displayBounds.y,
});
global.mainWindowDirection = "rightTop";
global.blurHide = false;
} else if (
bounds.x <= displayBounds.x &&
bounds.y + bounds.height >= displayBounds.y + displayBounds.height
) {
// 左下角
global.mainWindow.setBounds({
x: displayBounds.x,
y: displayBounds.y + displayBounds.height - bounds.height,
});
global.mainWindowDirection = "leftBottom";
global.blurHide = false;
} else if (
bounds.x + bounds.width >= displayBounds.x + displayBounds.width &&
bounds.y + bounds.height >= displayBounds.y + displayBounds.height
) {
// 右下角
global.mainWindow.setBounds({
x: displayBounds.x + displayBounds.width - bounds.width,
y: displayBounds.y + displayBounds.height - bounds.height,
});
global.mainWindowDirection = "rightBottom";
global.blurHide = false;
} else if (bounds.x <= displayBounds.x) {
// 左侧
global.mainWindow.setBounds({ x: displayBounds.x });
global.mainWindowDirection = "left";
global.blurHide = false;
} else if (
bounds.x + bounds.width >=
displayBounds.x + displayBounds.width
) {
// 右侧
global.mainWindow.setBounds({
x: displayBounds.x + displayBounds.width - bounds.width,
});
global.mainWindowDirection = "right";
global.blurHide = false;
} else if (
bounds.y + bounds.height >=
displayBounds.y + displayBounds.height
) {
// 底部
global.mainWindow.setBounds({
y: displayBounds.y + displayBounds.height - bounds.height,
});
global.mainWindowDirection = "bottom";
global.blurHide = false;
} else if (bounds.y <= displayBounds.y) {
// 顶部
global.mainWindow.setBounds({ y: displayBounds.y });
global.mainWindowDirection = "top";
global.blurHide = false;
}
} catch (e) {
if (process.env.NODE_ENV === "development") {
console.log(e);
}
global.mainWindow.setBounds({ x: 1, y: 1 });
}
}
/**
* 显示时跟随鼠标位置
*/
function showFollowMousePosition() {
// 当永远居中、固定位置勾选后不能使用显示时跟随鼠标位置
if (
!global.setting.general.alwaysCenter &&
!global.setting.general.fixedPosition &&
global.setting.general.showFollowMousePosition
) {
// 获取鼠标位置
let point = screen.getCursorScreenPoint();
// 窗口位置信息
let bounds = global.mainWindow.getBounds();
let x = Math.round(bounds.width / 2);
let y = Math.round(bounds.height / 2);
// 设置窗口位置
global.mainWindow.setPosition(point.x - x, point.y - y);
// 调整窗口位置并显示时会出现闪屏的情况
// https://github.com/electron/electron/issues/10862
for (let i = 0; i < 10; i++) {
global.mainWindow.setSize(bounds.width, bounds.height);
}
// 获取当前鼠标所在屏幕
let display = screen.getDisplayNearestPoint(point);
// 边缘吸附
edgeAdsorb(display, true);
}
}
/**
* 中间单击显示/隐藏窗口
*/
function showHideMouseWheelClick() {
if (global.setting.general.showHideMouseWheelClick) {
if (global.mainWindow.isVisible()) {
hideMainWindow();
} else {
showMainWindowBefore(true);
}
}
}
/**
* 永远居中
*/
function alwaysCenter() {
if (global.setting.general.alwaysCenter) {
mainWindow.center();
}
}
/**
* 边缘自动隐藏
* @param size
* @param timer 是否启用延迟显示/隐藏
* @returns
*/
function autoHide(size: number, timer: boolean) {
if (global.mainWindow.isDestroyed() || !global.setting.general.edgeAutoHide) {
return;
}
// 当有子窗口时不自动隐藏
if (mainWindow.getChildWindows().length > 0 || global.mainWindowShowDialog) {
return;
}
let x = screen.getCursorScreenPoint().x;
let y = screen.getCursorScreenPoint().y;
try {
// 屏幕
let displays = getWindowInScreen(mainWindow);
if (displays.length > 1 || displays.length === 0) {
return;
}
// 屏幕区域
let displayBounds = displays[0].bounds;
// 窗口位置信息
let bounds = mainWindow.getBounds();
if (mainWindow.isVisible()) {
let flag = false;
if (bounds.x === displayBounds.x && bounds.y === displayBounds.y) {
// 左上角
flag =
x >= bounds.x + bounds.width + size ||
y >= bounds.y + bounds.height + size;
} else if (
bounds.x + bounds.width === displayBounds.x + displayBounds.width &&
bounds.y === displayBounds.y
) {
// 右上角
flag = x <= bounds.x - size || y >= bounds.y + bounds.height + size;
} else if (
bounds.x === displayBounds.x &&
bounds.y + bounds.height === displayBounds.y + displayBounds.height
) {
// 左下角
flag = x >= bounds.x + bounds.width + size || y <= bounds.y - size;
} else if (
bounds.x + bounds.width === displayBounds.x + displayBounds.width &&
bounds.y + bounds.height === displayBounds.y + displayBounds.height
) {
// 右下角
flag = x <= bounds.x - size || y <= bounds.y - size;
} else if (
bounds.x + bounds.width >=
displayBounds.x + displayBounds.width
) {
// 右侧
flag =
x <= bounds.x - size ||
y <= bounds.y - size ||
y >= bounds.y + bounds.height + size;
} else if (bounds.x === displayBounds.x) {
// 左侧
flag =
x > bounds.x + bounds.width + size ||
y <= bounds.y - size ||
y >= bounds.y + bounds.height + size;
} else if (
bounds.y + bounds.height >=
displayBounds.y + displayBounds.height
) {
// 底部
flag =
y < bounds.y - size ||
x <= bounds.x - size ||
x >= bounds.x + bounds.width + size;
} else if (bounds.y === displayBounds.y) {
// 顶部
flag =
y > bounds.y + bounds.height + size ||
x <= bounds.x - size ||
x >= bounds.x + bounds.width + size;
}
if (flag && !global.classificationRightMenu && !global.itemRightMenu) {
if (
timer &&
global.setting.general.delayHideMs > 0 &&
!global.autoHideTimer
) {
// 延迟隐藏
global.autoHideTimer = setTimeout(function () {
hideMainWindow();
}, global.setting.general.delayHideMs);
} else if (!timer || global.setting.general.delayHideMs === 0) {
// 隐藏
hideMainWindow();
}
} else {
// 清空timer
clearTimeout(global.autoHideTimer);
global.autoHideTimer = null;
}
} else {
if (global.mainWindowDirection) {
let flag = false;
if (
global.mainWindowDirection === "leftTop" &&
x === displayBounds.x &&
y === displayBounds.y
) {
// 左上角
flag = true;
} else if (
global.mainWindowDirection === "rightTop" &&
x === displayBounds.x + displayBounds.width - 1 &&
y === displayBounds.y
) {
// 右上角
flag = true;
} else if (
global.mainWindowDirection === "leftBottom" &&
x === displayBounds.x &&
y === displayBounds.y + displayBounds.height - 1
) {
// 左下角
flag = true;
} else if (
global.mainWindowDirection === "rightBottom" &&
x === displayBounds.x + displayBounds.width - 1 &&
y === displayBounds.y + displayBounds.height - 1
) {
// 右下角
flag = true;
} else if (
global.mainWindowDirection === "left" &&
x <= displayBounds.x &&
y >= bounds.y &&
y <= bounds.y + bounds.height
) {
// 左侧
flag = true;
} else if (
global.mainWindowDirection === "right" &&
x >= bounds.x + bounds.width - 1 &&
y >= bounds.y &&
y <= bounds.y + bounds.height
) {
// 右侧
flag = true;
} else if (
global.mainWindowDirection === "bottom" &&
y >= bounds.y + bounds.height - 1 &&
x >= bounds.x &&
x <= bounds.x + bounds.width
) {
// 底部
flag = true;
} else if (
global.mainWindowDirection === "top" &&
y <= displayBounds.y &&
x >= bounds.x &&
x <= bounds.x + bounds.width
) {
// 顶部
flag = true;
}
if (flag) {
if (
timer &&
global.setting.general.delayDisplayMs > 0 &&
!global.autoHideTimer
) {
// 延迟显示
global.autoHideTimer = setTimeout(function () {
showMainWindowBefore(false, true);
}, global.setting.general.delayDisplayMs);
} else if (!timer || global.setting.general.delayDisplayMs === 0) {
// 显示
showMainWindowBefore(false, true);
}
} else {
// 清空timer
clearTimeout(global.autoHideTimer);
global.autoHideTimer = null;
}
}
}
} catch (e) {
if (process.env.NODE_ENV === "development") {
console.log(e);
}
global.mainWindow.setBounds({ x: 1, y: 1 });
}
}
/**
* 双击任务栏显示/隐藏
*/
function doubleClickTaskbar(
mousedownClassName: string | null,
className: string | null
) {
// 必须开启设置
if (!global.setting.general.showHideDoubleClickTaskbar) {
return;
}
// 获取屏幕
let displays = getWindowInScreen(mainWindow);
if (
displays.length > 1 ||
displays.length === 0 ||
(className !== "Shell_TrayWnd" && className !== "Shell_SecondaryTrayWnd")
) {
// 清除timeout
clearTimeout(global.doubleClickTaskbarTimer);
// 清空计数
global.doubleClickTaskbarCounter = 0;
return;
}
// 必须是指定Class
if (
(release().startsWith("10.0.1") &&
global.addon.getCursorPosWindowClassName().indexOf("MSTask") >= 0) ||
(release().startsWith("10.0.2") &&
global.addon.getCursorPosWindowClassName() !== "TrayNotifyWnd")
) {
// 监听双击
if (!global.doubleClickTaskbarCounter) {
global.doubleClickTaskbarCounter = 0;
}
// +1
global.doubleClickTaskbarCounter++;
if (
global.doubleClickTaskbarCounter &&
global.doubleClickTaskbarCounter === 2 &&
(mousedownClassName === "Shell_TrayWnd" ||
mousedownClassName === "Shell_SecondaryTrayWnd")
) {
// 清除timeout
clearTimeout(global.doubleClickTaskbarTimer);
// 清空计数
global.doubleClickTaskbarCounter = 0;
// 显示或隐藏
if (mainWindow.isVisible()) {
hideMainWindow();
} else {
showMainWindowBefore(false);
}
} else {
// 间隔为500毫秒如果超过500毫秒就代表不是双击
global.doubleClickTaskbarTimer = setTimeout(function () {
global.doubleClickTaskbarCounter = 0;
}, 500);
}
} else {
// 清除timeout
clearTimeout(global.doubleClickTaskbarTimer);
// 清空计数
global.doubleClickTaskbarCounter = 0;
}
}
export {
createMainWindow,
showMainWindowBefore,
showMainWindow,
hideMainWindow,
createTray,
edgeAdsorb,
getWindowInScreen,
showHideMouseWheelClick,
alwaysCenter,
autoHide,
};