-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.js
More file actions
201 lines (171 loc) · 6.33 KB
/
main.js
File metadata and controls
201 lines (171 loc) · 6.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
const { app, BrowserWindow, ipcMain, dialog, screen } = require('electron');
const path = require('path');
const screenshot = require('screenshot-desktop');
const fs = require('fs');
const { windowManager } = require('node-window-manager');
const sharp = require('sharp');
// Disable hardware acceleration to prevent common GPU crashes.
app.disableHardwareAcceleration();
let mainWindow;
function createWindow() {
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
preload: path.join(__dirname, 'preload.js')
},
icon: path.join(__dirname, 'icon.ico')
});
mainWindow.loadFile('index.html');
// Open DevTools in development
// mainWindow.webContents.openDevTools();
}
app.whenReady().then(createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
// Get list of windows
ipcMain.handle('get-windows', async () => {
try {
const windows = windowManager.getWindows();
// Filter out windows that are not visible or don't have titles
const visibleWindows = windows.filter(window => {
const title = window.getTitle();
return title &&
title.trim() !== '' &&
window.isVisible() &&
!title.includes('Program Manager') &&
!title.includes('Desktop Window Manager') &&
title !== 'Window Screenshot App'; // Don't capture our own window
});
// Map to a format our frontend expects
const windowList = visibleWindows.map(window => ({
id: window.id,
name: window.getTitle(),
processName: window.path || window.getPath() || 'Unknown Process',
bounds: window.getBounds()
}));
// Also add display options
const displays = await screenshot.listDisplays();
const displayList = displays.map((display, index) => ({
id: `display_${display.id || index}`,
name: `Display ${index + 1} (${display.name || 'Primary'})`,
processName: 'Full Display',
isDisplay: true
}));
return [...displayList, ...windowList];
} catch (error) {
console.error('Error getting windows:', error);
// Fallback to displays only
try {
const displays = await screenshot.listDisplays();
return displays.map((display, index) => ({
id: `display_${display.id || index}`,
name: `Display ${index + 1}`,
processName: 'Full Display',
isDisplay: true
}));
} catch (displayError) {
console.error('Error getting displays:', displayError);
return [];
}
}
});
// Handle request to select a folder
ipcMain.handle('select-folder', async () => {
const result = await dialog.showOpenDialog(mainWindow, {
properties: ['openDirectory']
});
if (result.canceled) {
return null; // User cancelled the dialog
} else {
return result.filePaths[0]; // Return the selected folder path
}
});
// Capture screenshot of specific window
ipcMain.handle('capture-window', async (event, { displayId, savePath }) => {
try {
let img;
// Check if it's a display or a specific window
if (displayId.startsWith('display_')) {
// Capture full display
const id = displayId.replace('display_', '');
img = await screenshot({
screen: id,
format: 'png'
});
} else {
// Reworked window capture logic
const win = windowManager.getWindows().find(w => w.id == displayId);
if (!win) {
return { success: false, error: 'Window not found' };
}
win.bringToTop();
await new Promise(resolve => setTimeout(resolve, 250));
const windowBounds = win.getBounds();
const targetDisplay = screen.getDisplayMatching(windowBounds);
const allDisplaysForScreenshot = await screenshot.listDisplays();
const screenshotDisplay = allDisplaysForScreenshot.find(d =>
d.left === targetDisplay.bounds.x &&
d.top === targetDisplay.bounds.y &&
d.right === targetDisplay.bounds.x + targetDisplay.bounds.width &&
d.bottom === targetDisplay.bounds.y + targetDisplay.bounds.height
);
if (!screenshotDisplay) {
throw new Error('Could not find a matching display for the screenshot library.');
}
const displayImg = await screenshot({ screen: screenshotDisplay.id, format: 'png' });
const cropLeft = Math.floor(windowBounds.x - targetDisplay.bounds.x);
const cropTop = Math.floor(windowBounds.y - targetDisplay.bounds.y);
const cropWidth = Math.floor(windowBounds.width);
const cropHeight = Math.floor(windowBounds.height);
const metadata = await sharp(displayImg).metadata();
if (cropLeft < 0 || cropTop < 0 || cropLeft + cropWidth > metadata.width || cropTop + cropHeight > metadata.height) {
throw new Error('Window bounds are outside the display. Cannot capture.');
}
if (cropWidth <= 0 || cropHeight <= 0) {
throw new Error('Invalid crop area: Window has zero or negative size.');
}
img = await sharp(displayImg)
.extract({ left: cropLeft, top: cropTop, width: cropWidth, height: cropHeight })
.toBuffer();
}
// Use the provided save path, or default to the Downloads folder if none is given.
const finalSavePath = savePath || app.getPath('downloads');
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const filename = `window-screenshot-${timestamp}.png`;
const filepath = path.join(finalSavePath, filename);
fs.writeFileSync(filepath, img);
return {
success: true,
filepath: filepath,
filename: filename
};
} catch (error) {
console.error('Error capturing screenshot:', error);
return {
success: false,
error: error.message
};
}
});
// Show save dialog (remains for any future use, but not currently wired up)
ipcMain.handle('show-save-dialog', async () => {
const result = await dialog.showSaveDialog(mainWindow, {
defaultPath: `window-screenshot-${new Date().toISOString().replace(/[:.]/g, '-')}.png`,
filters: [
{ name: 'PNG Images', extensions: ['png'] },
{ name: 'All Files', extensions: ['*'] }
]
});
return result;
});