Added settings page and alternate provider support.
This commit is contained in:
parent
b022bca449
commit
bc62e0d059
6 changed files with 364 additions and 12 deletions
135
main.js
135
main.js
|
@ -1,6 +1,6 @@
|
||||||
if (require('electron-squirrel-startup')) return;
|
if (require('electron-squirrel-startup')) return;
|
||||||
|
|
||||||
const { app, BrowserWindow, globalShortcut, Tray, Menu, nativeImage, screen, clipboard, desktopCapturer } = require('electron');
|
const { app, BrowserWindow, globalShortcut, Tray, Menu, nativeImage, screen, clipboard, desktopCapturer, ipcMain } = require('electron');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const settingsManager = require('./src/settingsManager');
|
const settingsManager = require('./src/settingsManager');
|
||||||
const { handleSquirrelEvent } = require('./src/squirrelEvents');
|
const { handleSquirrelEvent } = require('./src/squirrelEvents');
|
||||||
|
@ -15,6 +15,7 @@ if (handleSquirrelEvent()) {
|
||||||
|
|
||||||
let tray = null;
|
let tray = null;
|
||||||
let isQuitting = false; // Flag to differentiate between closing the window and quitting the app
|
let isQuitting = false; // Flag to differentiate between closing the window and quitting the app
|
||||||
|
let settingsWindow = null;
|
||||||
|
|
||||||
async function captureAndPaste() {
|
async function captureAndPaste() {
|
||||||
const mainWindow = getMainWindow();
|
const mainWindow = getMainWindow();
|
||||||
|
@ -95,6 +96,33 @@ function createAppWindow() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
return mainWindow; // Ensure mainWindow is returned
|
||||||
|
}
|
||||||
|
|
||||||
|
function createSettingsWindow() {
|
||||||
|
if (settingsWindow) {
|
||||||
|
settingsWindow.focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
settingsWindow = new BrowserWindow({
|
||||||
|
width: 800,
|
||||||
|
height: 600,
|
||||||
|
webPreferences: {
|
||||||
|
preload: path.join(__dirname, 'preload.js'), // Optional: if you need preload for settings
|
||||||
|
nodeIntegration: true, // Required for ipcRenderer in settingsRenderer.js
|
||||||
|
contextIsolation: false, // Required for ipcRenderer in settingsRenderer.js
|
||||||
|
},
|
||||||
|
parent: getMainWindow(), // Optional: makes it a child of the main window
|
||||||
|
modal: false, // Set to true if you want it to be a modal dialog
|
||||||
|
autoHideMenuBar: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
settingsWindow.loadFile(path.join(__dirname, 'settings.html'));
|
||||||
|
|
||||||
|
settingsWindow.on('closed', () => {
|
||||||
|
settingsWindow = null;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function createTray() {
|
function createTray() {
|
||||||
|
@ -203,7 +231,34 @@ function createTray() {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{ type: 'separator' }, // Optional: adds a line before the build time and Quit
|
{ type: 'separator' },
|
||||||
|
{
|
||||||
|
label: 'Select Provider',
|
||||||
|
submenu: settingsManager.getAllSettings().providers.map(provider => ({
|
||||||
|
label: provider.name,
|
||||||
|
type: 'radio',
|
||||||
|
checked: settingsManager.getSetting('currentProvider') === provider.name,
|
||||||
|
click: () => {
|
||||||
|
settingsManager.updateSetting('currentProvider', provider.name);
|
||||||
|
const mainWindow = getMainWindow();
|
||||||
|
if (mainWindow) {
|
||||||
|
mainWindow.loadURL(provider.url);
|
||||||
|
}
|
||||||
|
// Rebuild tray to reflect change (important for radio button state)
|
||||||
|
if (tray) {
|
||||||
|
tray.destroy();
|
||||||
|
createTray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
{ type: 'separator' },
|
||||||
|
{
|
||||||
|
label: 'Settings',
|
||||||
|
click: () => {
|
||||||
|
createSettingsWindow();
|
||||||
|
}
|
||||||
|
},
|
||||||
{ label: buildTime, enabled: false },
|
{ label: buildTime, enabled: false },
|
||||||
{
|
{
|
||||||
label: 'Quit',
|
label: 'Quit',
|
||||||
|
@ -233,6 +288,66 @@ Menu.setApplicationMenu(null)
|
||||||
app.on('ready', () => {
|
app.on('ready', () => {
|
||||||
console.log(process.argv);
|
console.log(process.argv);
|
||||||
|
|
||||||
|
// IPC Handlers for settings
|
||||||
|
ipcMain.on('get-all-settings', (event) => {
|
||||||
|
event.returnValue = settingsManager.getAllSettings();
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on('update-setting', (event, { key, value }) => {
|
||||||
|
settingsManager.updateSetting(key, value);
|
||||||
|
// Optionally, notify other windows if needed, e.g., main window for 'isAlwaysOnTop'
|
||||||
|
if (key === 'isAlwaysOnTop') {
|
||||||
|
const mainWindow = getMainWindow();
|
||||||
|
if (mainWindow) {
|
||||||
|
mainWindow.setAlwaysOnTop(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (key === 'launchOnStartup') {
|
||||||
|
app.setLoginItemSettings({
|
||||||
|
openAtLogin: value,
|
||||||
|
path: app.getPath('exe'),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// If currentProvider changes, update the main window URL
|
||||||
|
if (key === 'currentProvider') {
|
||||||
|
const mainWindow = getMainWindow();
|
||||||
|
if (mainWindow) {
|
||||||
|
const providerUrl = settingsManager.getCurrentProviderUrl();
|
||||||
|
mainWindow.loadURL(providerUrl);
|
||||||
|
}
|
||||||
|
// Rebuild tray to reflect change in provider selection
|
||||||
|
if (tray) {
|
||||||
|
tray.destroy();
|
||||||
|
createTray(); // This will rebuild the menu with the correct checked state
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Notify settings window to reload if changes can affect it directly
|
||||||
|
if (settingsWindow) {
|
||||||
|
settingsWindow.webContents.send('settings-updated');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on('add-provider', (event, provider) => {
|
||||||
|
settingsManager.addProvider(provider);
|
||||||
|
if (settingsWindow) {
|
||||||
|
settingsWindow.webContents.send('settings-updated'); // Refresh provider list
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on('delete-provider', (event, index) => {
|
||||||
|
settingsManager.deleteProvider(index);
|
||||||
|
if (settingsWindow) {
|
||||||
|
settingsWindow.webContents.send('settings-updated'); // Refresh provider list
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on('update-provider', (event, { index, name, url }) => {
|
||||||
|
settingsManager.updateProvider(index, { name, url });
|
||||||
|
if (settingsWindow) {
|
||||||
|
settingsWindow.webContents.send('settings-updated'); // Refresh provider list
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
let firstRunWindow = null;
|
let firstRunWindow = null;
|
||||||
|
|
||||||
// Check for Squirrel events (like first run)
|
// Check for Squirrel events (like first run)
|
||||||
|
@ -284,6 +399,15 @@ app.on('ready', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
createTray();
|
createTray();
|
||||||
|
|
||||||
|
// Listen for current-provider-changed event to update the main window URL
|
||||||
|
ipcMain.on('current-provider-changed', () => {
|
||||||
|
const mainWindow = getMainWindow();
|
||||||
|
if (mainWindow) {
|
||||||
|
const providerUrl = settingsManager.getCurrentProviderUrl();
|
||||||
|
mainWindow.loadURL(providerUrl);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.on('will-quit', () => {
|
app.on('will-quit', () => {
|
||||||
|
@ -311,13 +435,6 @@ app.on('activate', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
app.on('web-contents-created', (event, webContents) => {
|
app.on('web-contents-created', (event, webContents) => {
|
||||||
webContents.on('will-navigate', (event) => {
|
|
||||||
// Only allow navigation to `google.com` or subdomains
|
|
||||||
const url = new URL(webContents.getURL());
|
|
||||||
if (url.hostname !== 'google.com' && !url.hostname.endsWith('.google.com')) {
|
|
||||||
event.preventDefault();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const assetsDir = path.join(__dirname, 'assets');
|
const assetsDir = path.join(__dirname, 'assets');
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "gemini-native",
|
"name": "gemini-native",
|
||||||
"version": "1.20250517.174518",
|
"version": "1.20250519.193208",
|
||||||
"description": "A native Electron application for Google Gemini.",
|
"description": "A native Electron application for Google Gemini.",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
84
settings.html
Normal file
84
settings.html
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Settings</title>
|
||||||
|
<meta http-equiv="Content-Security-Policy" content="script-src 'self';">
|
||||||
|
<style>
|
||||||
|
body { font-family: sans-serif; margin: 20px; background-color: #f4f4f4; color: #333; }
|
||||||
|
.container { background-color: #fff; padding: 20px; border-radius: 8px; box-shadow: 0 0 10px rgba(0,0,0,0.1); }
|
||||||
|
h1 { color: #333; }
|
||||||
|
.setting { margin-bottom: 15px; display: flex; align-items: center; }
|
||||||
|
.setting label { margin-left: 10px; flex-grow: 1;}
|
||||||
|
.setting input[type="checkbox"] { width: 18px; height: 18px; }
|
||||||
|
.section { margin-top: 20px; border-top: 1px solid #eee; padding-top: 20px; }
|
||||||
|
h2 { color: #555; margin-bottom: 10px;}
|
||||||
|
table { width: 100%; border-collapse: collapse; margin-top: 10px; }
|
||||||
|
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
|
||||||
|
th { background-color: #f0f0f0; }
|
||||||
|
.actions button { margin-right: 5px; padding: 5px 10px; cursor: pointer; }
|
||||||
|
.add-provider-form input[type="text"] { padding: 8px; margin-right: 10px; border: 1px solid #ccc; border-radius: 4px; }
|
||||||
|
.add-provider-form button { padding: 8px 15px; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<h1>Settings</h1>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<h2>General</h2>
|
||||||
|
<div class="setting">
|
||||||
|
<input type="checkbox" id="autoHideEnabled">
|
||||||
|
<label for="autoHideEnabled">Auto-Hide on Focus Loss</label>
|
||||||
|
</div>
|
||||||
|
<div class="setting">
|
||||||
|
<input type="checkbox" id="reloadOnPasteEnabled">
|
||||||
|
<label for="reloadOnPasteEnabled">Reload on Screenshot/Paste</label>
|
||||||
|
</div>
|
||||||
|
<div class="setting">
|
||||||
|
<input type="checkbox" id="isAlwaysOnTop">
|
||||||
|
<label for="isAlwaysOnTop">Always on Top</label>
|
||||||
|
</div>
|
||||||
|
<div class="setting">
|
||||||
|
<input type="checkbox" id="isFrameVisible">
|
||||||
|
<label for="isFrameVisible">Show Title Bar (Requires Restart)</label>
|
||||||
|
</div>
|
||||||
|
<div class="setting">
|
||||||
|
<input type="checkbox" id="launchOnStartup">
|
||||||
|
<label for="launchOnStartup">Launch on Startup</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<h2>Current Provider</h2>
|
||||||
|
<div class="setting">
|
||||||
|
<select id="currentProviderSelect" style="padding: 8px; border-radius: 4px; border: 1px solid #ccc; width: 100%;">
|
||||||
|
<!-- Options will be populated by settingsRenderer.js -->
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<h2>Providers</h2>
|
||||||
|
<table id="providersTable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>URL</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<!-- Provider rows will be inserted here -->
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div class="add-provider-form" style="margin-top: 15px;">
|
||||||
|
<input type="text" id="newProviderName" placeholder="Provider Name">
|
||||||
|
<input type="text" id="newProviderUrl" placeholder="Provider URL">
|
||||||
|
<button id="addProviderBtn">Add Provider</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="./src/settingsRenderer.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -9,7 +9,18 @@ const defaultSettings = {
|
||||||
reloadOnPasteEnabled: true,
|
reloadOnPasteEnabled: true,
|
||||||
isAlwaysOnTop: true,
|
isAlwaysOnTop: true,
|
||||||
isFrameVisible: false,
|
isFrameVisible: false,
|
||||||
launchOnStartup: false, // Added: Setting for launch on startup
|
launchOnStartup: false,
|
||||||
|
|
||||||
|
currentProvider: "Gemini",
|
||||||
|
|
||||||
|
providers: [
|
||||||
|
{name: "Gemini", url: "https://gemini.google.com"},
|
||||||
|
{name: "ChatGPT", url: "https://chat.openai.com"},
|
||||||
|
{name: "Bing Copilot", url: "https://www.bing.com/chat"},
|
||||||
|
{name: "Claude", url: "https://claude.ai"},
|
||||||
|
{name: "Qwen", url: "https://chat.qwen.ai/"},
|
||||||
|
{name: "Perplexity", url: "https://www.perplexity.ai"},
|
||||||
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
let currentSettings = { ...defaultSettings };
|
let currentSettings = { ...defaultSettings };
|
||||||
|
@ -63,5 +74,26 @@ module.exports = {
|
||||||
},
|
},
|
||||||
getAllSettings: () => {
|
getAllSettings: () => {
|
||||||
return { ...currentSettings };
|
return { ...currentSettings };
|
||||||
|
},
|
||||||
|
addProvider: (provider) => {
|
||||||
|
currentSettings.providers.push(provider);
|
||||||
|
saveSettings();
|
||||||
|
},
|
||||||
|
deleteProvider: (index) => {
|
||||||
|
if (index >= 0 && index < currentSettings.providers.length) {
|
||||||
|
currentSettings.providers.splice(index, 1);
|
||||||
|
saveSettings();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
updateProvider: (index, provider) => {
|
||||||
|
if (index >= 0 && index < currentSettings.providers.length) {
|
||||||
|
currentSettings.providers[index] = provider;
|
||||||
|
saveSettings();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getCurrentProviderUrl: () => {
|
||||||
|
const currentProviderName = currentSettings.currentProvider;
|
||||||
|
const provider = currentSettings.providers.find(p => p.name === currentProviderName);
|
||||||
|
return provider ? provider.url : (currentSettings.providers[0] ? currentSettings.providers[0].url : 'https://gemini.google.com'); // Fallback
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
117
src/settingsRenderer.js
Normal file
117
src/settingsRenderer.js
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
// This script will handle the renderer process for the settings.html page.
|
||||||
|
const { ipcRenderer } = require('electron');
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
loadSettings();
|
||||||
|
setupEventListeners();
|
||||||
|
});
|
||||||
|
|
||||||
|
function loadSettings() {
|
||||||
|
const settings = ipcRenderer.sendSync('get-all-settings'); // Synchronous call to get settings
|
||||||
|
|
||||||
|
// General settings
|
||||||
|
document.getElementById('autoHideEnabled').checked = settings.autoHideEnabled;
|
||||||
|
document.getElementById('reloadOnPasteEnabled').checked = settings.reloadOnPasteEnabled;
|
||||||
|
document.getElementById('isAlwaysOnTop').checked = settings.isAlwaysOnTop;
|
||||||
|
document.getElementById('isFrameVisible').checked = settings.isFrameVisible;
|
||||||
|
document.getElementById('launchOnStartup').checked = settings.launchOnStartup;
|
||||||
|
|
||||||
|
// Current Provider Dropdown
|
||||||
|
const currentProviderSelect = document.getElementById('currentProviderSelect');
|
||||||
|
currentProviderSelect.innerHTML = ''; // Clear existing options
|
||||||
|
settings.providers.forEach(provider => {
|
||||||
|
const option = document.createElement('option');
|
||||||
|
option.value = provider.name;
|
||||||
|
option.textContent = provider.name;
|
||||||
|
if (provider.name === settings.currentProvider) {
|
||||||
|
option.selected = true;
|
||||||
|
}
|
||||||
|
currentProviderSelect.appendChild(option);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Providers Table
|
||||||
|
const providersTableBody = document.getElementById('providersTable').getElementsByTagName('tbody')[0];
|
||||||
|
providersTableBody.innerHTML = ''; // Clear existing rows
|
||||||
|
|
||||||
|
settings.providers.forEach((provider, index) => {
|
||||||
|
const row = providersTableBody.insertRow();
|
||||||
|
row.insertCell().textContent = provider.name;
|
||||||
|
row.insertCell().textContent = provider.url;
|
||||||
|
|
||||||
|
const actionsCell = row.insertCell();
|
||||||
|
const deleteButton = document.createElement('button');
|
||||||
|
deleteButton.textContent = 'Delete';
|
||||||
|
deleteButton.onclick = () => deleteProvider(index);
|
||||||
|
actionsCell.appendChild(deleteButton);
|
||||||
|
|
||||||
|
// Add an edit button (optional, for more advanced CRUD)
|
||||||
|
// const editButton = document.createElement('button');
|
||||||
|
// editButton.textContent = 'Edit';
|
||||||
|
// editButton.onclick = () => editProvider(index);
|
||||||
|
// actionsCell.appendChild(editButton);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupEventListeners() {
|
||||||
|
// General settings listeners
|
||||||
|
document.getElementById('autoHideEnabled').addEventListener('change', (event) => {
|
||||||
|
ipcRenderer.send('update-setting', { key: 'autoHideEnabled', value: event.target.checked });
|
||||||
|
});
|
||||||
|
document.getElementById('reloadOnPasteEnabled').addEventListener('change', (event) => {
|
||||||
|
ipcRenderer.send('update-setting', { key: 'reloadOnPasteEnabled', value: event.target.checked });
|
||||||
|
});
|
||||||
|
document.getElementById('isAlwaysOnTop').addEventListener('change', (event) => {
|
||||||
|
ipcRenderer.send('update-setting', { key: 'isAlwaysOnTop', value: event.target.checked });
|
||||||
|
});
|
||||||
|
document.getElementById('isFrameVisible').addEventListener('change', (event) => {
|
||||||
|
ipcRenderer.send('update-setting', { key: 'isFrameVisible', value: event.target.checked });
|
||||||
|
});
|
||||||
|
document.getElementById('launchOnStartup').addEventListener('change', (event) => {
|
||||||
|
ipcRenderer.send('update-setting', { key: 'launchOnStartup', value: event.target.checked });
|
||||||
|
});
|
||||||
|
|
||||||
|
// Current provider select listener
|
||||||
|
document.getElementById('currentProviderSelect').addEventListener('change', (event) => {
|
||||||
|
ipcRenderer.send('update-setting', { key: 'currentProvider', value: event.target.value });
|
||||||
|
// Optionally, send a specific event if the main window needs to react immediately without a full settings reload signal
|
||||||
|
ipcRenderer.send('current-provider-changed');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Provider table listeners
|
||||||
|
document.getElementById('addProviderBtn').addEventListener('click', () => {
|
||||||
|
const nameInput = document.getElementById('newProviderName');
|
||||||
|
const urlInput = document.getElementById('newProviderUrl');
|
||||||
|
const name = nameInput.value.trim();
|
||||||
|
const url = urlInput.value.trim();
|
||||||
|
|
||||||
|
if (name && url) {
|
||||||
|
ipcRenderer.send('add-provider', { name, url });
|
||||||
|
nameInput.value = ''; // Clear input
|
||||||
|
urlInput.value = ''; // Clear input
|
||||||
|
loadSettings(); // Reload to show the new provider
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteProvider(index) {
|
||||||
|
ipcRenderer.send('delete-provider', index);
|
||||||
|
loadSettings(); // Reload to reflect deletion
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example of editProvider (requires more UI/logic for editing)
|
||||||
|
/*
|
||||||
|
function editProvider(index) {
|
||||||
|
const provider = ipcRenderer.sendSync('get-all-settings').providers[index];
|
||||||
|
const newName = prompt('Enter new name:', provider.name);
|
||||||
|
const newUrl = prompt('Enter new URL:', provider.url);
|
||||||
|
if (newName !== null && newUrl !== null) {
|
||||||
|
ipcRenderer.send('update-provider', { index, name: newName, url: newUrl });
|
||||||
|
loadSettings();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Listen for settings-updated from main process if other windows can change settings
|
||||||
|
ipcRenderer.on('settings-updated', () => {
|
||||||
|
loadSettings();
|
||||||
|
});
|
|
@ -39,7 +39,9 @@ function createWindow(onCloseCallback, onBlurCallback) {
|
||||||
});
|
});
|
||||||
|
|
||||||
positionWindowAtBottomCenter(mainWindow);
|
positionWindowAtBottomCenter(mainWindow);
|
||||||
mainWindow.loadURL('https://gemini.google.com');
|
// Load the URL of the current provider
|
||||||
|
const providerUrl = settingsManager.getCurrentProviderUrl();
|
||||||
|
mainWindow.loadURL(providerUrl);
|
||||||
mainWindow.setMenuBarVisibility(false);
|
mainWindow.setMenuBarVisibility(false);
|
||||||
|
|
||||||
mainWindow.on('close', onCloseCallback);
|
mainWindow.on('close', onCloseCallback);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue