cleanup comments, update translations, bump to 0.4.1
This commit is contained in:
parent
9edcc9841b
commit
7d8ab87eee
28 changed files with 412 additions and 1114 deletions
|
|
@ -25,9 +25,7 @@ function errorResult(err) {
|
|||
|
||||
const iconDir = id => path.join(DIRS.DATA, 'icons', id)
|
||||
|
||||
// `keep` spares one file (the icon just written): the icon protocol picks the
|
||||
// LAST icon.* alphabetically, so a leftover icon.png from an earlier pick
|
||||
// would otherwise keep showing the old icon.
|
||||
// `keep` spares the icon just written: the protocol picks the LAST icon.*.
|
||||
function clearIconDir(id, keep) {
|
||||
try {
|
||||
for (const f of fs.readdirSync(iconDir(id))) {
|
||||
|
|
@ -77,8 +75,7 @@ function registerIpc({ getWindow, onGamesChanged }) {
|
|||
ipcMain.handle('wines:setDisplayName', (e, id, name) => wines.setWineDisplayName(id, name))
|
||||
ipcMain.handle('wines:setDefault', (e, id) => wines.setDefaultWine(id))
|
||||
ipcMain.handle('wines:delete', async (e, id) => {
|
||||
// the build's files back the running prefix (dlls, stub exes) - deleting
|
||||
// it under a running game breaks that game
|
||||
// the build's files back a running prefix; deleting it breaks that game
|
||||
if (library.isWineInUse(id, games.runningInfo())) {
|
||||
const apps = games.runningInfo().filter(r => r.wine === id).map(r => r.name)
|
||||
return { ok: false, error: 'inUse', apps }
|
||||
|
|
@ -94,10 +91,7 @@ function registerIpc({ getWindow, onGamesChanged }) {
|
|||
})
|
||||
|
||||
// prefixes ---------------------------------------------------------------------
|
||||
// A prefix folder must not move or disappear while a game runs in it: wine
|
||||
// keeps the registry and user files open and would write into a folder that
|
||||
// no longer exists (or, for a delete, lose them mid-run). The renderer shows
|
||||
// these as a toast naming the blocking app.
|
||||
// A prefix must not move/disappear while a game runs in it.
|
||||
const prefixInUse = name => {
|
||||
const apps = library.appsUsingPrefix(name, games.runningInfo())
|
||||
return apps.length ? { ok: false, error: 'inUse', apps: apps.map(r => r.name) } : null
|
||||
|
|
@ -107,17 +101,14 @@ function registerIpc({ getWindow, onGamesChanged }) {
|
|||
ipcMain.handle('prefixes:delete', async (e, name) => {
|
||||
const busy = prefixInUse(name)
|
||||
if (busy) return busy
|
||||
// deleting a prefix that still has apps registered in it would orphan
|
||||
// them (they fall back to the default prefix and lose their files)
|
||||
// deleting a prefix with registered apps would orphan them
|
||||
const users = library.gamesUsingPrefix(name).map(g => g.name)
|
||||
if (users.length) return { ok: false, error: 'hasApps', apps: users }
|
||||
return prefixes.deletePrefix(name, data => sendToWindow(getWindow(), 'import:progress', data))
|
||||
})
|
||||
ipcMain.handle('prefixes:rename', (e, oldName, newName) => prefixInUse(oldName) || prefixes.renamePrefix(oldName, newName))
|
||||
ipcMain.handle('prefixes:setDefault', (e, name) => {
|
||||
// apps without a prefix field of their own resolve the default at launch;
|
||||
// switching it now would silently move their next run (a prefix import is
|
||||
// pinned to its own name)
|
||||
// switching the default would silently move apps that follow it
|
||||
const defs = prefixes.listPrefixes()
|
||||
if (name !== defs.default) {
|
||||
const affected = library.gamesFollowingDefault(games.runningInfo())
|
||||
|
|
@ -129,8 +120,7 @@ function registerIpc({ getWindow, onGamesChanged }) {
|
|||
// games: library -----------------------------------------------------------------
|
||||
ipcMain.handle('games:list', () => library.loadGames())
|
||||
ipcMain.handle('games:get', (e, id) => library.getGame(id))
|
||||
// prefix pin is enforced inside library.updateGame (prefix/importSource
|
||||
// fields are ignored for prefix imports), so nothing extra needed here
|
||||
// the prefix pin is enforced inside library.updateGame
|
||||
ipcMain.handle('games:update', (e, id, patch) => library.updateGame(id, patch))
|
||||
ipcMain.handle('games:reorder', (e, ids) => library.reorderGames(ids))
|
||||
ipcMain.handle('games:remove', (e, id) => {
|
||||
|
|
@ -187,8 +177,7 @@ function registerIpc({ getWindow, onGamesChanged }) {
|
|||
if (!game || !game.exePath) return { ok: false, error: 'bad-request' }
|
||||
return extractGameIcon(id, game.exePath)
|
||||
})
|
||||
// exePath comes from the config field, which may hold a path the user just
|
||||
// picked but has not saved yet - the icon has to come from THAT exe
|
||||
// use the exe the field holds (maybe picked but not saved yet)
|
||||
ipcMain.handle('games:autoIcon', (e, id, exePath) => {
|
||||
const game = library.getGame(id)
|
||||
if (!game) return { ok: false, error: 'bad-request' }
|
||||
|
|
@ -198,9 +187,7 @@ function registerIpc({ getWindow, onGamesChanged }) {
|
|||
})
|
||||
|
||||
// "Open with PLWL" ------------------------------------------------------------------
|
||||
// The renderer asks for the file handed in via `--open` (Exec %f), then
|
||||
// launches it with the wine/prefix picked in the popup. Nothing is imported
|
||||
// into the library.
|
||||
// `--open` (Exec %f) hands the file over; nothing is imported.
|
||||
ipcMain.handle('openwith:take', async () => {
|
||||
const p = openwith.getPending()
|
||||
if (!p) return null
|
||||
|
|
@ -246,14 +233,9 @@ function registerIpc({ getWindow, onGamesChanged }) {
|
|||
return errorResult(err)
|
||||
}
|
||||
})
|
||||
// import from an existing wine prefix: pick the prefix first, then the app
|
||||
// folder inside it (drive_c) - paths are stored prefix-relative so the app
|
||||
// shows up for wine as a regular C:\ install
|
||||
// import from an existing prefix: paths are stored prefix-relative
|
||||
ipcMain.handle('games:pickPrefixFolder', async (e, prefix) => {
|
||||
// open the picker straight in the prefix's C: drive (plain wine: top
|
||||
// level, Proton: under pfx/); a prefix used with BOTH kinds has two of
|
||||
// them, so it opens at the prefix folder - the only spot that keeps
|
||||
// drive_c and pfx/drive_c one click away
|
||||
// open the picker in the prefix's C: drive (mixed layouts: prefix folder)
|
||||
const driveRoots = prefixes.prefixDriveRoots(prefix)
|
||||
const start = driveRoots.length === 1 ? driveRoots[0] : prefixes.prefixPath(prefix)
|
||||
const res = await dialog.showOpenDialog(getWindow(), {
|
||||
|
|
@ -277,10 +259,7 @@ function registerIpc({ getWindow, onGamesChanged }) {
|
|||
// dialogs & shell ---------------------------------------------------------------------------
|
||||
ipcMain.handle('dialog:pickFile', async (e, opts) => {
|
||||
const o = { ...(opts || {}) }
|
||||
// Electron resolves a RELATIVE defaultPath against the process cwd (the
|
||||
// install root in packaged mode), which lands the picker somewhere
|
||||
// random like '/'. Renderer paths are FILES-relative by convention, so
|
||||
// anchor them there instead.
|
||||
// anchor FILES-relative paths, or Electron resolves them against cwd
|
||||
if (o.defaultPath && typeof o.defaultPath === 'string' && !path.isAbsolute(o.defaultPath)) {
|
||||
o.defaultPath = path.join(DIRS.FILES, o.defaultPath)
|
||||
}
|
||||
|
|
@ -306,9 +285,7 @@ function registerIpc({ getWindow, onGamesChanged }) {
|
|||
if (pick) file = path.join(iconDir(id), pick)
|
||||
} catch {}
|
||||
if (!file) return new Response('', { status: 404 })
|
||||
// a new icon lands at the SAME url, so the browser would keep its cached
|
||||
// copy and the library card would only catch up after a restart - never
|
||||
// let the icon request be cached
|
||||
// the icon url never changes: send no-cache headers
|
||||
const res = await net.fetch('file://' + file)
|
||||
return new Response(await res.arrayBuffer(), {
|
||||
headers: {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue