/**
* @fileoverview Main entry point for the CTrace GUI Electron application.
*
* This file initializes the Electron app, creates the main window, and sets up
* all IPC handlers for communication between the main and renderer processes.
*
* @author CTrace GUI Team
* @version 1.0.0
*/
const { app, BrowserWindow, nativeImage, dialog, shell } = require('electron');
const path = require('path');
const os = require('os');
const { spawn } = require('child_process');
// Import IPC handlers
const { setupFileHandlers } = require('./main/ipc/fileHandlers');
const { setupEditorHandlers } = require('./main/ipc/editorHandlers');
const { setupCtraceHandlers } = require('./main/ipc/ctraceHandlers');
const { setupAssistantHandlers } = require('./main/ipc/assistantHandlers');
/**
* Creates and configures the main application window.
*
* This function sets up the BrowserWindow with appropriate dimensions,
* icon, and security settings. It loads the main HTML file and configures
* the window appearance.
*
* @function createWindow
* @returns {BrowserWindow} The created main window instance
*
* @example
* const mainWindow = createWindow();
*/
function createWindow () {
const iconPath = path.join(__dirname, '../assets/ctrace.png');
const iconApp = nativeImage.createFromPath(iconPath);
const win = new BrowserWindow({
width: 1200,
height: 800,
minWidth: 800,
minHeight: 600,
icon: iconApp,
frame: false, // Custom frame for consistency across platforms
titleBarStyle: 'hidden', // Hide native title bar
titleBarOverlay: {
color: '#0d1117', // Match VS Code dark theme
symbolColor: '#ffffff',
height: 30
},
webPreferences: {
nodeIntegration: true, // allows require() in renderer
contextIsolation: false, // disables security isolation
webSecurity: false // For loading local fonts
}
});
win.loadFile('src/index.html');
// Custom window controls for frameless window
win.on('maximize', () => {
win.webContents.send('window-maximized', true);
});
win.on('unmaximize', () => {
win.webContents.send('window-maximized', false);
});
return win;
}
/**
* Creates the Visualyzer window as a separate, movable window
* @returns {BrowserWindow} The created visualyzer window instance
*/
function createVisualizerWindow() {
const iconPath = path.join(__dirname, '../assets/ctrace.png');
const iconApp = nativeImage.createFromPath(iconPath);
const vizWin = new BrowserWindow({
width: 1000,
height: 700,
minWidth: 600,
minHeight: 500,
icon: iconApp,
title: 'CTrace Visualyzer',
backgroundColor: '#0d1117',
autoHideMenuBar: true,
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
webSecurity: false
}
});
vizWin.loadFile('src/visualyzer.html');
vizWin.setMenuBarVisibility(false);
// Open DevTools in development (optional)
// vizWin.webContents.openDevTools();
return vizWin;
}
/**
* Detects if WSL (Windows Subsystem for Linux) is available on Windows.
*
* @async
* @function detectWSL
* @returns {Promise<boolean>} True if WSL is available, false otherwise
*/
/**
* Comprehensive WSL status detection
* @returns {Promise<Object>} Object with available, hasDistros, error, and distributions properties
*/
async function detectWSLStatus() {
return new Promise((resolve) => {
if (os.platform() !== 'win32') {
resolve({ available: true, hasDistros: true, distributions: ['linux'] });
return;
}
// First check if WSL command exists
const statusChild = spawn('wsl', ['--status'], { stdio: 'pipe', windowsHide: true });
let statusOutput = '';
let statusError = '';
statusChild.stdout.on('data', (data) => {
statusOutput += data.toString();
});
statusChild.stderr.on('data', (data) => {
statusError += data.toString();
});
statusChild.on('error', () => {
resolve({ available: false, hasDistros: false, error: 'WSL is not installed' });
});
statusChild.on('close', (statusCode) => {
if (statusCode !== 0) {
resolve({ available: false, hasDistros: false, error: 'WSL is not available' });
return;
}
// WSL exists, now check for installed distributions
const listChild = spawn('wsl', ['--list', '--quiet'], { stdio: 'pipe', windowsHide: true });
let listOutput = '';
listChild.stdout.on('data', (data) => {
listOutput += data.toString();
});
listChild.on('error', () => {
resolve({ available: true, hasDistros: false, error: 'Cannot check WSL distributions' });
});
listChild.on('close', (listCode) => {
const distributions = listOutput.trim().split('\n')
.map(line => line.trim())
.filter(line => line.length > 0 && !line.includes('Windows Subsystem'))
.filter(line => !line.toLowerCase().includes('docker'));
const hasDistros = distributions.length > 0 && !statusError.includes('no installed distributions');
if (!hasDistros) {
const errorMsg = statusError.includes('no installed distributions') || listOutput.includes('no installed distributions')
? 'WSL is installed but no Linux distributions are available'
: 'No WSL distributions found';
resolve({ available: true, hasDistros: false, error: errorMsg, distributions: [] });
} else {
resolve({ available: true, hasDistros: true, distributions });
}
});
// Timeout for list command
setTimeout(() => {
listChild.kill();
resolve({ available: true, hasDistros: false, error: 'Timeout checking WSL distributions', distributions: [] });
}, 10000);
});
// Timeout for status command
setTimeout(() => {
statusChild.kill();
resolve({ available: false, hasDistros: false, error: 'Timeout checking WSL status' });
}, 10000);
});
}
/**
* Legacy function for backward compatibility
* @returns {Promise<boolean>}
*/
async function detectWSL() {
const status = await detectWSLStatus();
return status.available && status.hasDistros;
}
/**
* Shows enhanced WSL installation dialog based on WSL status
* @param {Object} wslStatus - Current WSL status
* @returns {Promise<boolean>} True if user wants to proceed, false otherwise
*/
async function showWSLSetupDialog(wslStatus) {
if (!wslStatus.available) {
// WSL not installed at all
const result = await dialog.showMessageBox({
type: 'warning',
title: 'WSL Required for CTrace',
message: 'Windows Subsystem for Linux (WSL) is required for CTrace functionality.',
detail: 'CTrace uses a Linux binary that requires WSL to run on Windows.\n\nWould you like to install WSL now? This requires administrator privileges and a system restart.',
buttons: ['Install WSL Automatically', 'Install Manually', 'Continue Without WSL', 'Exit Application'],
defaultId: 0,
cancelId: 3,
icon: nativeImage.createFromPath(path.join(__dirname, '../assets/ctrace.png'))
});
if (result.response === 0) {
// Automatic installation
await installWSLAutomatically();
return true;
} else if (result.response === 1) {
// Manual installation
showManualInstallationInstructions();
return true;
} else if (result.response === 2) {
// Continue without WSL
await showLimitedFunctionalityDialog();
return true;
} else {
// Exit application
return false;
}
} else if (!wslStatus.hasDistros) {
// WSL installed but no distributions
const result = await dialog.showMessageBox({
type: 'info',
title: 'WSL Distribution Required',
message: 'WSL is installed but no Linux distributions are available.',
detail: 'CTrace requires a Linux distribution to run. Ubuntu is recommended.\n\nWould you like to install Ubuntu now?',
buttons: ['Install Ubuntu', 'Choose Different Distribution', 'Continue Without CTrace', 'Exit Application'],
defaultId: 0,
cancelId: 3,
icon: nativeImage.createFromPath(path.join(__dirname, '../assets/ctrace.png'))
});
if (result.response === 0) {
// Install Ubuntu
await installWSLDistribution('Ubuntu');
return true;
} else if (result.response === 1) {
// Show distribution options
await showDistributionOptions();
return true;
} else if (result.response === 2) {
// Continue without CTrace
await showLimitedFunctionalityDialog();
return true;
} else {
// Exit application
return false;
}
}
return true; // WSL is fully available
}
/**
* Install WSL automatically using PowerShell
*/
async function installWSLAutomatically() {
try {
console.log('Attempting to install WSL automatically...');
// Show progress dialog
dialog.showMessageBox({
type: 'info',
title: 'Installing WSL',
message: 'Installing Windows Subsystem for Linux...',
detail: 'This may take a few minutes. Please wait and follow any prompts that appear.',
buttons: ['OK']
});
// Run WSL installation command with Ubuntu
const child = spawn('powershell', [
'-Command',
'Start-Process',
'powershell',
'-ArgumentList', '"wsl --install Ubuntu"',
'-Verb', 'RunAs'
], { stdio: 'pipe', windowsHide: true });
child.on('error', (err) => {
console.error('Failed to start WSL installation:', err);
dialog.showErrorBox(
'Installation Failed',
`Failed to start WSL installation: ${err.message}\n\nPlease try manual installation instead.`
);
});
child.on('close', (code) => {
console.log(`WSL installation completed with code: ${code}`);
dialog.showMessageBox({
type: 'info',
title: 'WSL Installation Started',
message: 'WSL and Ubuntu installation has been initiated!',
detail: 'Please follow any prompts that appear. You may need to:\n\n1. Allow administrator access\n2. Restart your computer when prompted\n3. Complete Ubuntu setup (username/password)\n4. Restart this application\n\nThe installation will continue in the background.',
buttons: ['Got it!']
});
});
} catch (error) {
console.error('Error during WSL installation:', error);
dialog.showErrorBox(
'Installation Error',
`Failed to install WSL: ${error.message}\n\nPlease try manual installation instead.`
);
}
}
/**
* Show manual installation instructions
*/
function showManualInstallationInstructions() {
dialog.showMessageBox({
type: 'info',
title: 'Manual WSL Installation',
message: 'Manual Installation Instructions',
detail: `To install WSL manually:\n\n` +
`1. Open PowerShell as Administrator\n` +
` (Right-click Start → "Windows PowerShell (Admin)")\n\n` +
`2. Run: wsl --install Ubuntu\n\n` +
`3. Restart your computer when prompted\n\n` +
`4. Complete Ubuntu setup (create username/password)\n\n` +
`5. Restart this application\n\n` +
`For more details, the Microsoft documentation will open next.`,
buttons: ['Open Documentation', 'Got it']
}).then((result) => {
if (result.response === 0) {
shell.openExternal('https://docs.microsoft.com/en-us/windows/wsl/install');
}
});
}
/**
* Install a specific WSL distribution
*/
async function installWSLDistribution(distroName) {
try {
console.log(`Installing WSL distribution: ${distroName}`);
const child = spawn('powershell', [
'-Command',
'Start-Process',
'powershell',
'-ArgumentList', `"wsl --install ${distroName}"`,
'-Verb', 'RunAs'
], { stdio: 'ignore', windowsHide: true });
child.on('error', (err) => {
console.error(`Failed to install ${distroName}:`, err);
dialog.showErrorBox(
'Installation Failed',
`Failed to install ${distroName}. Please try installing manually:\n\n1. Open PowerShell as Administrator\n2. Run: wsl --install ${distroName}`
);
});
child.on('close', (code) => {
console.log(`${distroName} installation completed with code: ${code}`);
dialog.showMessageBox({
type: 'info',
title: 'Distribution Installation',
message: `${distroName} installation has been initiated.`,
detail: 'Please follow the setup instructions when they appear. After setup is complete, restart this application to use CTrace.'
});
});
} catch (error) {
console.error(`Error installing ${distroName}:`, error);
dialog.showErrorBox(
'Installation Error',
`Failed to install ${distroName}: ${error.message}`
);
}
}
/**
* Show available WSL distributions for installation
*/
async function showDistributionOptions() {
try {
// Get list of available distributions
const child = spawn('wsl', ['--list', '--online'], { stdio: 'pipe', windowsHide: true });
let output = '';
child.stdout.on('data', (data) => {
output += data.toString();
});
child.on('close', (code) => {
if (code === 0 && output) {
dialog.showMessageBox({
type: 'info',
title: 'Available WSL Distributions',
message: 'Available Linux Distributions',
detail: `${output}\n\nRecommended: Ubuntu\n\nTo install a distribution:\n1. Open PowerShell\n2. Run: wsl --install <DistributionName>\n3. Follow setup instructions`,
buttons: ['Install Ubuntu', 'Install Manually', 'Cancel']
}).then((result) => {
if (result.response === 0) {
installWSLDistribution('Ubuntu');
} else if (result.response === 1) {
showManualInstallationInstructions();
}
});
} else {
dialog.showErrorBox(
'Cannot List Distributions',
'Unable to get list of available distributions. Please install Ubuntu manually with:\n\nwsl --install Ubuntu'
);
}
});
} catch (error) {
dialog.showErrorBox(
'Error',
`Failed to get distribution list: ${error.message}`
);
}
}
/**
* Show limited functionality dialog
*/
async function showLimitedFunctionalityDialog() {
await dialog.showMessageBox({
type: 'info',
title: 'Limited Functionality - CTrace GUI',
message: 'Running without WSL',
detail: 'CTrace GUI will run with limited functionality:\n\n✅ File editing and management\n✅ Syntax highlighting\n✅ Project navigation\n❌ CTrace static analysis\n❌ Code analysis reports\n\nTo enable full functionality, install WSL and restart the application.',
buttons: ['Continue'],
defaultId: 0
});
}
//hot reload
try {
require('electron-reload')(__dirname, {
electron: require(path.join(__dirname, '../node_modules/electron')),
hardResetMethod: 'exit'
});
} catch (e) {
console.log("electron-reload not active");
}
/**
* Sets up IPC handlers for custom window controls.
*
* This function handles window minimize, maximize, and close operations
* for the custom frameless window title bar.
*
* @function setupWindowControls
* @param {BrowserWindow} window - The main window instance
*/
function setupWindowControls(window) {
const { ipcMain } = require('electron');
// Window minimize
ipcMain.on('window-minimize', () => {
window.minimize();
});
// Window maximize/restore toggle
ipcMain.on('window-maximize-toggle', () => {
if (window.isMaximized()) {
window.unmaximize();
} else {
window.maximize();
}
});
// Window close
ipcMain.on('window-close', () => {
window.close();
});
// Open Visualyzer window
ipcMain.on('open-visualyzer', () => {
createVisualizerWindow();
});
// WSL status check handler
ipcMain.on('check-wsl-status', async (event) => {
if (os.platform() === 'win32') {
const wslStatus = await detectWSLStatus();
event.sender.send('wsl-status', wslStatus);
} else {
event.sender.send('wsl-status', {
available: true,
hasDistros: true,
platform: os.platform()
});
}
});
// Handle manual WSL installation request from renderer
ipcMain.on('install-wsl', async () => {
if (os.platform() === 'win32') {
await installWSLAutomatically();
}
});
// Handle WSL distribution installation request
ipcMain.on('install-wsl-distro', async (event, distroName) => {
if (os.platform() === 'win32') {
await installWSLDistribution(distroName || 'Ubuntu');
}
});
// Handle WSL setup dialog request
ipcMain.on('show-wsl-setup', async () => {
if (os.platform() === 'win32') {
const wslStatus = await detectWSLStatus();
await showWSLSetupDialog(wslStatus);
}
});
}
// Global reference to main window
let mainWindow;
app.whenReady().then(async () => {
// Create window first
mainWindow = createWindow();
// Setup IPC handlers
setupFileHandlers(mainWindow);
setupEditorHandlers();
setupCtraceHandlers();
setupAssistantHandlers(mainWindow);
setupWindowControls(mainWindow);
// Check WSL status on Windows after window is ready
if (os.platform() === 'win32') {
// Give the window time to load, then check WSL
setTimeout(async () => {
const wslStatus = await detectWSLStatus();
console.log('WSL Status detected:', wslStatus);
// Send status to renderer
if (mainWindow && mainWindow.webContents) {
mainWindow.webContents.send('wsl-status', wslStatus);
}
// Show setup dialog if WSL is not fully ready
if (!wslStatus.available || !wslStatus.hasDistros) {
const shouldContinue = await showWSLSetupDialog(wslStatus);
if (!shouldContinue) {
app.quit();
return;
}
}
}, 2000);
} else {
// On non-Windows platforms, send ready status
mainWindow.webContents.once('did-finish-load', () => {
mainWindow.webContents.send('wsl-status', {
available: true,
hasDistros: true,
platform: os.platform()
});
});
}
});