diff --git a/electron/dist/main.js b/electron/dist/main.js index e1084f2..e2acad5 100644 --- a/electron/dist/main.js +++ b/electron/dist/main.js @@ -235,15 +235,22 @@ function debugLog(...args) { console.log(...args); } debugLog("[Wo] Electron starting, NODE_VERSION=", process.version); +app.commandLine.appendSwitch("use-gl", "angle"); +app.commandLine.appendSwitch("use-angle", "vulkan"); +app.commandLine.appendSwitch("ozone-platform", "wayland"); +app.commandLine.appendSwitch("no-sandbox"); +app.commandLine.appendSwitch("disable-gpu-sandbox"); app.commandLine.appendSwitch("ignore-gpu-blocklist"); app.commandLine.appendSwitch("enable-gpu-rasterization"); app.commandLine.appendSwitch("enable-zero-copy"); app.commandLine.appendSwitch("enable-native-gpu-memory-buffers"); app.commandLine.appendSwitch("disable-software-rasterizer"); -app.commandLine.appendSwitch("enable-features", "CanvasOopRasterization,Vulkan,VaapiVideoDecoder,VaapiVideoEncoder,SharedArrayBuffer,RawDraw"); +app.commandLine.appendSwitch("enable-features", "CanvasOopRasterization,Vulkan,VaapiVideoDecoder,VaapiVideoEncoder,SharedArrayBuffer,RawDraw,DefaultANGLEVulkan,VulkanFromANGLE"); app.commandLine.appendSwitch("enable-accelerated-video-decode"); app.commandLine.appendSwitch("disable-frame-rate-limit"); app.commandLine.appendSwitch("disable-gpu-vsync"); +app.commandLine.appendSwitch("num-raster-threads", "4"); +app.commandLine.appendSwitch("disable-renderer-backgrounding"); debugLog("[Wo] GPU acceleration flags applied"); var IPC_SOCKET = process.env.WO_IPC_SOCKET || "/run/user/1000/wo-ipc.sock"; debugLog("[Wo] WO_WINDOW_CONFIG env =", process.env.WO_WINDOW_CONFIG); diff --git a/electron/src/main.ts b/electron/src/main.ts index e751555..e693ac4 100644 --- a/electron/src/main.ts +++ b/electron/src/main.ts @@ -2,6 +2,7 @@ import { app, BrowserWindow, ipcMain } from 'electron'; import { createConnection, createServer, Socket, Server } from 'net'; import { fileURLToPath } from 'url'; import { dirname, resolve as resolvePath, join as joinPath } from 'path'; +import { randomUUID } from 'crypto'; import fs from 'fs'; import { createRequire } from 'module'; import { MAGIC, stringToBuffer } from './protocol.js'; @@ -44,18 +45,25 @@ function debugLog(...args: any[]) { debugLog('[Wo] Electron starting, NODE_VERSION=', process.version); // GPU acceleration & rendering performance flags (must be set before app 'ready') -// Note: core flags (--in-process-gpu, --use-gl=egl, --ozone-platform=wayland) -// are set on the command line in the Rust spawn(). Flags below augment those. +// Chromium flags MUST go through appendSwitch — process argv flags are not +// reliably forwarded by Electron to Chromium's command-line parser. +app.commandLine.appendSwitch('use-gl', 'angle'); +app.commandLine.appendSwitch('use-angle', 'vulkan'); +app.commandLine.appendSwitch('ozone-platform', 'wayland'); +app.commandLine.appendSwitch('no-sandbox'); +app.commandLine.appendSwitch('disable-gpu-sandbox'); app.commandLine.appendSwitch('ignore-gpu-blocklist'); app.commandLine.appendSwitch('enable-gpu-rasterization'); app.commandLine.appendSwitch('enable-zero-copy'); app.commandLine.appendSwitch('enable-native-gpu-memory-buffers'); app.commandLine.appendSwitch('disable-software-rasterizer'); app.commandLine.appendSwitch('enable-features', - 'CanvasOopRasterization,Vulkan,VaapiVideoDecoder,VaapiVideoEncoder,SharedArrayBuffer,RawDraw'); + 'CanvasOopRasterization,Vulkan,VaapiVideoDecoder,VaapiVideoEncoder,SharedArrayBuffer,RawDraw,DefaultANGLEVulkan,VulkanFromANGLE'); app.commandLine.appendSwitch('enable-accelerated-video-decode'); app.commandLine.appendSwitch('disable-frame-rate-limit'); app.commandLine.appendSwitch('disable-gpu-vsync'); +app.commandLine.appendSwitch('num-raster-threads', '4'); +app.commandLine.appendSwitch('disable-renderer-backgrounding'); debugLog('[Wo] GPU acceleration flags applied'); type ClientWindowInfo = { @@ -84,8 +92,8 @@ let ipcSocket: Socket | null = null; let portalUiServer: Server | null = null; type PendingPortalRequest = { socket: Socket; - kind: 'screen_share'; - sessionId: string; + requestId: string; + payload: any; }; const portalPendingRequests = new Map(); const PORTAL_UI_SOCKET = '/tmp/wo-portal-ui.sock'; @@ -202,7 +210,7 @@ function getOrCreateSab(windowName: string, width: number, height: number, strid surfaceSabCache.set(windowName, entry); // Tell renderer about the new SAB so it can reference it if (mainWindow && !mainWindow.isDestroyed()) { - mainWindow.webContents.postMessage('wo:surface-sab', { + mainWindow.webContents.send('wo:surface-sab', { name: windowName, sab, width, @@ -231,7 +239,8 @@ let pointerX = 0; let pointerY = 0; function respondToPortalRequest(requestId: string, params: { - allowed: boolean; + response?: unknown; + allowed?: boolean; type?: string; windowName?: unknown; }): { ok: boolean; error?: string } { @@ -240,19 +249,22 @@ function respondToPortalRequest(requestId: string, params: { return { ok: false, error: `No pending portal request: ${requestId}` }; } - let response: Record; - if (pending.kind === 'screen_share') { - response = { - allowed: Boolean(params.allowed), - sourceType: params.type === 'window' ? 'Window' : 'Monitor', - windowName: typeof params.windowName === 'string' ? params.windowName : null, - }; - } else { - response = { allowed: false }; + const responsePayload = + params.response !== undefined + ? params.response + : { + allowed: Boolean(params.allowed), + sourceType: params.type === 'window' ? 'Window' : 'Monitor', + windowName: typeof params.windowName === 'string' ? params.windowName : null, + }; + + if (responsePayload === undefined) { + portalPendingRequests.delete(requestId); + return { ok: false, error: 'Missing portal response payload' }; } try { - pending.socket.write(`${JSON.stringify(response)}\n`); + pending.socket.write(`${JSON.stringify(responsePayload)}\n`); pending.socket.end(); portalPendingRequests.delete(requestId); return { ok: true }; @@ -276,64 +288,59 @@ function startPortalUiBridge() { socket.on('data', (chunk: Buffer) => { received += chunk.toString('utf8'); - const nl = received.indexOf('\n'); - if (nl < 0) return; + let nl = received.indexOf('\n'); + while (nl >= 0) { + const line = received.slice(0, nl).trim(); + received = received.slice(nl + 1); - const line = received.slice(0, nl).trim(); - received = received.slice(nl + 1); - if (!line) return; + if (line.length > 0) { + try { + const req = JSON.parse(line) as Record; + const requestId = String( + (req?.requestId as string | undefined) + ?? (req?.sessionId as string | undefined) + ?? (req?.id as string | undefined) + ?? randomUUID(), + ); - try { - const req = JSON.parse(line) as { - type?: string; - appName?: string; - sessionId?: string; - }; + portalPendingRequests.set(requestId, { socket, requestId, payload: req }); - if (req.type !== 'screen_share_request' || !req.sessionId) { - socket.end('{"allowed":false,"reason":"invalid_request"}\n'); - return; - } + // Auto-timeout if UI does not respond within 90s + socket.setTimeout(90_000, () => { + const pending = portalPendingRequests.get(requestId); + if (pending) { + portalPendingRequests.delete(requestId); + pending.socket.end(JSON.stringify({ error: 'timeout', requestId }) + '\n'); + } + }); - const requestId = req.sessionId; - - portalPendingRequests.set(requestId, { - socket, - kind: 'screen_share', - sessionId: req.sessionId, - }); - - // Auto-deny if UI does not respond within 90s - socket.setTimeout(90_000, () => { - const pending = portalPendingRequests.get(requestId); - if (pending) { - portalPendingRequests.delete(requestId); - pending.socket.end('{"allowed":false,"reason":"timeout"}\n'); + if (mainWindow && !mainWindow.isDestroyed()) { + mainWindow.webContents.send('wo:portal-request', { + requestId, + payload: req, + kind: typeof req?.type === 'string' + ? (req.type as string) + : typeof req?.kind === 'string' + ? (req.kind as string) + : undefined, + }); + } else { + portalPendingRequests.delete(requestId); + socket.end(JSON.stringify({ error: 'no_ui', requestId }) + '\n'); + } + } catch { + socket.end('{"error":"invalid_json"}\n'); } - }); - - if (mainWindow && !mainWindow.isDestroyed()) { - const payload = { - requestId, - kind: 'screen_share', - appName: req.appName || 'Application', - sessionId: req.sessionId, - }; - - mainWindow.webContents.send('wo:portal-request', payload); - } else { - portalPendingRequests.delete(requestId); - socket.end('{"allowed":false,"reason":"no_ui"}\n'); } - } catch { - socket.end('{"allowed":false,"reason":"invalid_json"}\n'); + + nl = received.indexOf('\n'); } }); socket.on('close', () => { - for (const [sessionId, pending] of portalPendingRequests.entries()) { + for (const [requestId, pending] of portalPendingRequests.entries()) { if (pending.socket === socket) { - portalPendingRequests.delete(sessionId); + portalPendingRequests.delete(requestId); break; } } @@ -356,7 +363,7 @@ function startPortalUiBridge() { function stopPortalUiBridge() { for (const pending of portalPendingRequests.values()) { try { - pending.socket.end('{"allowed":false,"reason":"shutdown"}\n'); + pending.socket.end(JSON.stringify({ error: 'shutdown', requestId: pending.requestId }) + '\n'); } catch { // ignore } @@ -402,321 +409,22 @@ let clientWindows: ClientWindowInfo[] = parseClientWindows(); // Live window list received from the compositor via WOWM metadata messages. let compositorWindows: Record[] = []; -type StatusNotifierTrayItem = { - id: string; - title: string; - status: 'active' | 'passive' | 'attention'; - icon: string; - iconDataUrl?: string; - service: string; - objectPath: string; - menuPath?: string; - hasMenu: boolean; -}; - -function parseQuotedStrings(output: string): string[] { - const matches = output.matchAll(/"((?:[^"\\]|\\.)*)"/g); - const values: string[] = []; - for (const match of matches) { - const raw = match[1]; - values.push(raw.replace(/\\"/g, '"').replace(/\\\\/g, '\\')); - } - return values; -} - -function runBusctlUser(args: string[]): string { +type DbBus = 'user' | 'system'; +function runBusctl(bus: DbBus, args: string[]): { ok: boolean; stdout: string; stderr: string; exitCode: number } { try { - const { execFileSync } = require('child_process') as typeof import('child_process'); - return execFileSync('busctl', ['--user', ...args], { + const { spawnSync } = require('child_process') as typeof import('child_process'); + const res = spawnSync('busctl', [bus === 'system' ? '--system' : '--user', ...args], { encoding: 'utf8', - stdio: ['ignore', 'pipe', 'ignore'], - }).trim(); - } catch { - return ''; - } -} - -function parseServiceAndPath(itemRef: string): { service: string; objectPath: string } | null { - const slashIdx = itemRef.indexOf('/'); - if (slashIdx > 0) { - return { - service: itemRef.slice(0, slashIdx), - objectPath: itemRef.slice(slashIdx), - }; - } - - if (!itemRef) { - return null; - } - - return { - service: itemRef, - objectPath: '/StatusNotifierItem', - }; -} - -function parseBusctlStringValue(output: string): string { - const quoted = parseQuotedStrings(output); - if (quoted.length > 0) { - return quoted[0]; - } - const parts = output.split(/\s+/); - return parts.length >= 2 ? parts.slice(1).join(' ').trim() : ''; -} - -function getBusProperty(service: string, objectPath: string, iface: string, prop: string): string { - const out = runBusctlUser(['get-property', service, objectPath, iface, prop]); - return out ? parseBusctlStringValue(out) : ''; -} - -function mapTrayIcon(iconName: string, title: string): string { - const n = iconName.toLowerCase(); - const t = title.toLowerCase(); - if (n.includes('network') || t.includes('network') || t.includes('wifi')) return 'mdi:wifi'; - if (n.includes('audio') || n.includes('volume') || t.includes('volume')) return 'mdi:volume-high'; - if (n.includes('battery') || t.includes('battery')) return 'mdi:battery'; - if (n.includes('bluetooth') || t.includes('bluetooth')) return 'mdi:bluetooth'; - if (n.includes('telegram') || t.includes('telegram')) return 'mdi:telegram'; - if (n.includes('discord') || t.includes('discord')) return 'mdi:discord'; - if (n.includes('steam') || t.includes('steam')) return 'mdi:steam'; - if (n.includes('dropbox') || t.includes('dropbox')) return 'mdi:dropbox'; - if (n.includes('mail') || t.includes('mail')) return 'mdi:email-outline'; - if (n.includes('kde') || t.includes('kde')) return 'mdi:kde'; - return 'mdi:circle-medium'; -} - -function iconPathCandidates(iconName: string): string[] { - const direct = iconName.startsWith('/') ? [iconName] : []; - if (iconName.startsWith('/')) { - return direct; - } - - const exts = ['png', 'svg']; - const bases = [ - '/usr/share/pixmaps', - '/usr/share/icons/hicolor/16x16/apps', - '/usr/share/icons/hicolor/22x22/apps', - '/usr/share/icons/hicolor/24x24/apps', - '/usr/share/icons/hicolor/32x32/apps', - '/usr/share/icons/hicolor/48x48/apps', - '/usr/share/icons/hicolor/scalable/apps', - '/usr/share/icons/breeze/apps/22', - '/usr/share/icons/breeze/apps/24', - '/usr/share/icons/breeze/apps/32', - ]; - - const results: string[] = []; - for (const base of bases) { - for (const ext of exts) { - results.push(`${base}/${iconName}.${ext}`); - } - } - return results; -} - -function toDataUrlForIconFile(iconPath: string): string | undefined { - try { - if (!fs.existsSync(iconPath)) { - return undefined; - } - const lower = iconPath.toLowerCase(); - const mime = lower.endsWith('.svg') ? 'image/svg+xml' : lower.endsWith('.png') ? 'image/png' : ''; - if (!mime) { - return undefined; - } - const base64 = fs.readFileSync(iconPath).toString('base64'); - return `data:${mime};base64,${base64}`; - } catch { - return undefined; - } -} - -function resolveTrayIconDataUrl(iconName: string): string | undefined { - for (const candidate of iconPathCandidates(iconName)) { - const dataUrl = toDataUrlForIconFile(candidate); - if (dataUrl) { - return dataUrl; - } - } - return undefined; -} - -function getStatusNotifierTrayItems(): StatusNotifierTrayItem[] { - const watcherCall = runBusctlUser([ - 'call', - 'org.kde.StatusNotifierWatcher', - '/StatusNotifierWatcher', - 'org.kde.StatusNotifierWatcher', - 'RegisteredStatusNotifierItems', - ]); - - if (!watcherCall) { - return []; - } - - const refs = parseQuotedStrings(watcherCall); - const results: StatusNotifierTrayItem[] = []; - - for (const itemRef of refs) { - const parsed = parseServiceAndPath(itemRef); - if (!parsed) { - continue; - } - - const statusRaw = getBusProperty(parsed.service, parsed.objectPath, 'org.kde.StatusNotifierItem', 'Status'); - const title = - getBusProperty(parsed.service, parsed.objectPath, 'org.kde.StatusNotifierItem', 'Title') - || getBusProperty(parsed.service, parsed.objectPath, 'org.kde.StatusNotifierItem', 'Id') - || parsed.service; - const iconName = - getBusProperty(parsed.service, parsed.objectPath, 'org.kde.StatusNotifierItem', 'AttentionIconName') - || getBusProperty(parsed.service, parsed.objectPath, 'org.kde.StatusNotifierItem', 'IconName'); - const menuPath = getBusProperty(parsed.service, parsed.objectPath, 'org.kde.StatusNotifierItem', 'Menu'); - const iconDataUrl = iconName ? resolveTrayIconDataUrl(iconName) : undefined; - - let status: StatusNotifierTrayItem['status'] = 'active'; - const s = statusRaw.toLowerCase(); - if (s.includes('passive')) { - status = 'passive'; - } else if (s.includes('attention') || s.includes('needsattention')) { - status = 'attention'; - } - - results.push({ - id: `${parsed.service}${parsed.objectPath}`, - title, - status, - icon: mapTrayIcon(iconName || title, title), - iconDataUrl, - service: parsed.service, - objectPath: parsed.objectPath, - menuPath: menuPath || undefined, - hasMenu: Boolean(menuPath && menuPath !== '/NO_DBUSMENU'), + stdio: ['ignore', 'pipe', 'pipe'], }); - } - - return results; -} - -function activateStatusNotifierItem(service: string, objectPath: string): boolean { - const out = runBusctlUser([ - 'call', - service, - objectPath, - 'org.kde.StatusNotifierItem', - 'Activate', - 'ii', - '0', - '0', - ]); - return out.length > 0; -} - -function secondaryActivateStatusNotifierItem(service: string, objectPath: string): boolean { - const out = runBusctlUser([ - 'call', - service, - objectPath, - 'org.kde.StatusNotifierItem', - 'SecondaryActivate', - 'ii', - '0', - '0', - ]); - return out.length > 0; -} - -function openStatusNotifierContextMenu(service: string, objectPath: string, x: number, y: number): boolean { - const out = runBusctlUser([ - 'call', - service, - objectPath, - 'org.kde.StatusNotifierItem', - 'ContextMenu', - 'ii', - String(Math.trunc(x)), - String(Math.trunc(y)), - ]); - return out.length > 0; -} - -type DBusMenuItem = { - id: string; - label: string; - enabled: boolean; - children?: DBusMenuItem[]; -}; - -function getDBusMenuLayout(service: string, menuPath: string): DBusMenuItem[] { - try { - const out = runBusctlUser([ - 'call', - service, - menuPath.startsWith('/') ? menuPath : '/com/canonical/dbusmenu', - 'com.canonical.dbusmenu', - 'GetLayout', - 'u', - '0', - ]); - - if (!out) { - return []; - } - - const lines = out.split('\n').filter(l => l.trim().length > 0); - const items: DBusMenuItem[] = []; - let depth = 0; - - for (const line of lines) { - const trimmed = line.trim(); - const newDepth = (line.match(/^\s*/)?.[0]?.length ?? 0) / 2; - - if (trimmed.startsWith('(') && trimmed.includes('"')) { - const quoted = parseQuotedStrings(trimmed); - if (quoted.length > 0) { - const label = quoted[0]; - const item: DBusMenuItem = { - id: label, - label, - enabled: !line.toLowerCase().includes('disabled'), - }; - - if (newDepth === 0) { - items.push(item); - } else if (items.length > 0 && newDepth > depth) { - const parent = items[items.length - 1]; - if (!parent.children) { - parent.children = []; - } - parent.children.push(item); - } - } - depth = newDepth; - } - } - - return items; - } catch { - return []; - } -} - -function triggerDBusMenuEvent(service: string, menuPath: string, menuId: string): boolean { - try { - const out = runBusctlUser([ - 'call', - service, - menuPath.startsWith('/') ? menuPath : '/com/canonical/dbusmenu', - 'com.canonical.dbusmenu', - 'Event', - 'sis', - menuId, - 'clicked', - '', - ]); - return out.length > 0; - } catch { - return false; + return { + ok: res.status === 0, + stdout: (res.stdout as string | undefined)?.trim?.() || '', + stderr: (res.stderr as string | undefined)?.trim?.() || '', + exitCode: res.status ?? -1, + }; + } catch (error: any) { + return { ok: false, stdout: '', stderr: String(error), exitCode: -1 }; } } @@ -1263,17 +971,56 @@ function connectToCompositor(): Promise { const dmabufFormat = compositorRxBuffer.readUInt32LE(off); off += 4; const numPlanes = compositorRxBuffer.readUInt32LE(off); off += 4; - const totalSize = (off - rxReadOffset) + (numPlanes * 24); + const planeSectionSize = numPlanes * 24; + const totalSize = (off - rxReadOffset) + planeSectionSize; if (rxAvailable() < totalSize) break; + const planes: Array<{ offset: bigint; stride: number; modifier: bigint }> = []; + let planeOff = off; + for (let i = 0; i < numPlanes; i++) { + planeOff += 4; // fd placeholder + const planeOffset = compositorRxBuffer.readBigUInt64LE(planeOff); planeOff += 8; + const planeStride = compositorRxBuffer.readUInt32LE(planeOff); planeOff += 4; + const modifier = compositorRxBuffer.readBigUInt64LE(planeOff); planeOff += 8; + planes.push({ offset: planeOffset, stride: planeStride, modifier }); + } + try { if (nativeDmabuf && ipcSocket) { const socketFd = (ipcSocket as any)?._handle?.fd; if (typeof socketFd === 'number' && socketFd >= 0) { - const dmabufFd = nativeDmabuf.recvFd(socketFd); - if (dmabufFd >= 0) { + const planeFds: number[] = []; + for (let i = 0; i < numPlanes; i++) { + const fd = nativeDmabuf.recvFd(socketFd); + if (fd >= 0) planeFds.push(fd); + } + + const primaryFd = planeFds.find((fd) => fd >= 0); + const primaryPlane = planes[0]; + const stride = primaryPlane?.stride || dmabufW * 4; + const offset = primaryPlane ? Number(primaryPlane.offset) : 0; + + if (primaryFd !== undefined) { try { - const textureInfo = nativeDmabuf.importDmabufTexture(dmabufName, dmabufFd, dmabufW, dmabufH, dmabufFormat); + // Map DMABUF into SAB so renderer can reuse existing surface path + const sabEntry = getOrCreateSab(dmabufName, dmabufW, dmabufH, stride); + const copySize = offset + stride * dmabufH; + nativeDmabuf.copyMmapToSab(primaryFd, sabEntry.sab, copySize, offset); + + surfaceUpdatePending.set(dmabufName, { + name: dmabufName, + width: dmabufW, + height: dmabufH, + stride, + generation: ++surfaceUpdateGeneration, + }); + if (!surfaceUpdateFlushScheduled) { + surfaceUpdateFlushScheduled = true; + setImmediate(flushSurfaceUpdates); + } + + // Preserve existing DMABUF texture notification for any consumers + const textureInfo = nativeDmabuf.importDmabufTexture(dmabufName, primaryFd, dmabufW, dmabufH, dmabufFormat); if (mainWindow && !mainWindow.isDestroyed()) { mainWindow.webContents.send('wo:dmabuf-frame', { name: dmabufName, @@ -1283,7 +1030,9 @@ function connectToCompositor(): Promise { }); } } finally { - fs.closeSync(dmabufFd); + for (const fd of planeFds) { + try { fs.closeSync(fd); } catch { /* ignore */ } + } } } } @@ -1701,64 +1450,8 @@ function setupIpcHandlers() { timestamp: Date.now(), }); } - return { ok: true }; - } - - case 'tray_list': { - return getStatusNotifierTrayItems(); - } - - case 'tray_activate': { - const service = String(params.service || ''); - const objectPath = String(params.objectPath || ''); - if (!service || !objectPath) { - return { ok: false, error: 'Missing service or objectPath' }; + return { ok: true }; } - const ok = activateStatusNotifierItem(service, objectPath); - return ok ? { ok: true } : { ok: false, error: 'Activation failed' }; - } - - case 'tray_secondary_activate': { - const service = String(params.service || ''); - const objectPath = String(params.objectPath || ''); - if (!service || !objectPath) { - return { ok: false, error: 'Missing service or objectPath' }; - } - const ok = secondaryActivateStatusNotifierItem(service, objectPath); - return ok ? { ok: true } : { ok: false, error: 'Secondary activation failed' }; - } - - case 'tray_context_menu': { - const service = String(params.service || ''); - const objectPath = String(params.objectPath || ''); - const x = Number(params.x ?? 0); - const y = Number(params.y ?? 0); - if (!service || !objectPath) { - return { ok: false, error: 'Missing service or objectPath' }; - } - const ok = openStatusNotifierContextMenu(service, objectPath, x, y); - return ok ? { ok: true } : { ok: false, error: 'Context menu failed' }; - } - - case 'tray_menu_items': { - const service = String(params.service || ''); - const menuPath = String(params.menuPath || ''); - if (!service || !menuPath) { - return []; - } - return getDBusMenuLayout(service, menuPath); - } - - case 'tray_menu_event': { - const service = String(params.service || ''); - const menuPath = String(params.menuPath || ''); - const menuId = String(params.menuId || ''); - if (!service || !menuPath || !menuId) { - return { ok: false, error: 'Missing parameters' }; - } - const ok = triggerDBusMenuEvent(service, menuPath, menuId); - return ok ? { ok: true } : { ok: false, error: 'Menu event failed' }; - } case 'portal_respond': { const requestId = String(params.requestId || ''); @@ -1766,12 +1459,65 @@ function setupIpcHandlers() { return { ok: false, error: 'Missing portal requestId' }; } return respondToPortalRequest(requestId, { - allowed: Boolean(params.allowed), + response: params.response, + allowed: params.allowed, type: typeof params.type === 'string' ? params.type : undefined, windowName: params.windowName, }); } + case 'dbus_call': { + const bus: DbBus = params.bus === 'system' ? 'system' : 'user'; + const service = String(params.service || ''); + const objectPath = String(params.objectPath || ''); + const iface = String(params.interface || params.iface || ''); + const method = String(params.method || ''); + const signature = typeof params.signature === 'string' ? params.signature : ''; + const argList: any[] = Array.isArray(params.args) ? params.args : []; + if (!service || !objectPath || !iface || !method) { + return { ok: false, error: 'Missing dbus parameters' }; + } + const args = ['call', service, objectPath, iface, method, signature || '']; + if (signature) { + args.push(...argList.map((v) => String(v))); + } + const result = runBusctl(bus, args); + return result; + } + + case 'dbus_get_property': { + const bus: DbBus = params.bus === 'system' ? 'system' : 'user'; + const service = String(params.service || ''); + const objectPath = String(params.objectPath || ''); + const iface = String(params.interface || params.iface || ''); + const prop = String(params.property || params.prop || ''); + if (!service || !objectPath || !iface || !prop) { + return { ok: false, error: 'Missing dbus parameters' }; + } + const result = runBusctl(bus, ['get-property', service, objectPath, iface, prop]); + return result; + } + + case 'load_local_file': { + const filePath = String(params.path || ''); + if (!filePath) { + return { ok: false, error: 'Missing path' }; + } + if (!fs.existsSync(filePath)) { + return { ok: false, error: `Path does not exist: ${filePath}` }; + } + if (!mainWindow || mainWindow.isDestroyed()) { + return { ok: false, error: 'Main window unavailable' }; + } + try { + debugLog('[Wo] Loading local file:', filePath); + await mainWindow.loadFile(filePath); + return { ok: true }; + } catch (error) { + return { ok: false, error: String(error) }; + } + } + default: return { ok: false, error: `Unknown syscall: ${type}` }; } @@ -1830,11 +1576,15 @@ async function createWindow() { } // In offscreen mode, we need actual content to trigger paint events - // Load the configured URL or fallback to minimal page - debugLog('[Wo] Loading content URL: ' + (url || 'minimal fallback')); + // Load the configured URL/file or fallback to minimal page + debugLog('[Wo] Loading content URL: ' + (url || html || 'minimal fallback')); try { - const pageUrl = url || 'data:text/html,'; - const loadPromise = mainWindow!.loadURL(pageUrl); + const pageUrl = url + || (html ? `file://${html}` : null) + || 'data:text/html,'; + const loadPromise = pageUrl.startsWith('file://') + ? mainWindow!.loadURL(pageUrl) + : mainWindow!.loadURL(pageUrl); // Give it time to load but don't wait forever await Promise.race([ loadPromise, diff --git a/electron/src/preload.ts b/electron/src/preload.ts index d348bde..b8d3b33 100644 --- a/electron/src/preload.ts +++ b/electron/src/preload.ts @@ -120,15 +120,13 @@ const compositorAPI: CompositorAPI = { // Generic portal request event for client-provided popup/approval handlers onPortalRequest: (callback: (data: { requestId: string; - kind: string; - appName?: string; - sessionId?: string; + payload: any; + kind?: string; }) => void) => { const handler = (_event: Electron.IpcRendererEvent, data: { requestId: string; - kind: string; - appName?: string; - sessionId?: string; + payload: any; + kind?: string; }) => callback(data); ipcRenderer.on('wo:portal-request', handler); return () => ipcRenderer.removeListener('wo:portal-request', handler); diff --git a/electron/types/package.json b/electron/types/package.json index 660d5b0..e7314b6 100644 --- a/electron/types/package.json +++ b/electron/types/package.json @@ -2,7 +2,7 @@ "name": "@wl-wo/wo-types", "module": "index.ts", "type": "module", - "version": "1.0.0", + "version": "1.0.1", "devDependencies": { "@types/bun": "latest" }, diff --git a/electron/types/types.d.ts b/electron/types/types.d.ts index 7b9f371..590e11d 100644 --- a/electron/types/types.d.ts +++ b/electron/types/types.d.ts @@ -88,7 +88,10 @@ export interface SyscallLogoutParams { [key: string]: any; } export interface SyscallLockParams { [key: string]: any; } export interface SyscallSleepParams { [key: string]: any; } export interface SyscallNotifyParams { id?: string; title: string; body?: string; icon?: string; timeout?: number; [key: string]: any; } -export interface SyscallPortalRespondParams { requestId: string; allowed: boolean; type?: string; windowName?: string | null; [key: string]: any; } +export interface SyscallPortalRespondParams { requestId: string; response?: any; allowed?: boolean; type?: string; windowName?: string | null; [key: string]: any; } +export interface SyscallDbusCallParams { service: string; objectPath: string; interface: string; method: string; signature?: string; args?: any[]; bus?: 'user' | 'system'; [key: string]: any; } +export interface SyscallDbusGetPropertyParams { service: string; objectPath: string; interface: string; property: string; bus?: 'user' | 'system'; [key: string]: any; } +export interface SyscallLoadLocalFileParams { path: string; [key: string]: any; } export interface SyscallLaunchResult { ok: boolean; pid?: number; error?: string; } export interface SyscallExecResult { ok: boolean; pid?: number; error?: string; } @@ -102,12 +105,14 @@ export interface SyscallLockResult { ok: boolean; error?: string; } export interface SyscallSleepResult { ok: boolean; error?: string; } export interface SyscallNotifyResult { ok: boolean; error?: string; } export interface SyscallPortalRespondResult { ok: boolean; error?: string; } +export interface SyscallDbusCallResult { ok: boolean; stdout?: string; stderr?: string; exitCode?: number; error?: string; } +export interface SyscallDbusGetPropertyResult { ok: boolean; stdout?: string; stderr?: string; exitCode?: number; error?: string; } +export interface SyscallLoadLocalFileResult { ok: boolean; error?: string; } export interface PortalRequestEvent { requestId: string; - kind: string; - appName?: string; - sessionId?: string; + payload: any; + kind?: string; } export interface ScreencopyEvent { @@ -217,6 +222,9 @@ export interface Compositor { syscall(type: 'sleep', params?: SyscallSleepParams): Promise; syscall(type: 'notify', params: SyscallNotifyParams): Promise; syscall(type: 'portal_respond', params: SyscallPortalRespondParams): Promise; + syscall(type: 'dbus_call', params: SyscallDbusCallParams): Promise; + syscall(type: 'dbus_get_property', params: SyscallDbusGetPropertyParams): Promise; + syscall(type: 'load_local_file', params: SyscallLoadLocalFileParams): Promise; syscall(type: string, params?: any): Promise; /** @@ -453,4 +461,4 @@ export interface DamageFramePayload { fullFrame?: Uint8Array; fullStride?: number; patches?: DamagePatch[]; -} \ No newline at end of file +} diff --git a/electron/whatever.txt b/electron/whatever.txt new file mode 100644 index 0000000..52e1fbe --- /dev/null +++ b/electron/whatever.txt @@ -0,0 +1,48 @@ + Finished `release` profile [optimized] target(s) in 0.12s + Finished `release` profile [optimized] target(s) in 0.12s + Running `/home/hellings/Documents/wo/target/release/wo` + Running `/home/hellings/Documents/wo/target/release/wo` +Xwayland glamor: GBM Wayland interfaces not available +Failed to initialize glamor, falling back to sw +Xwayland glamor: GBM Wayland interfaces not available +Failed to initialize glamor, falling back to sw +(II) IGLX: Loaded and initialized swrast +(II) GLX: Initialized DRISWRAST GL provider for screen 0 +(II) IGLX: Loaded and initialized swrast +(II) GLX: Initialized DRISWRAST GL provider for screen 0 +The XKEYBOARD keymap compiler (xkbcomp) reports: +> Warning: Multiple symbols for level 1/group 1 on key +> The XKEYBOARD keymap compiler (xkbcomp) reports: +> Warning: Multiple symbols for level 1/group 1 on key +> Using F23, ignoring XF86TouchpadOff +> Warning: Symbol map for key redefined +> Using last definition for conflicting fields +> Warning: Symbol map for key redefined +> Using last definition for conflicting fields +Using F23, ignoring XF86TouchpadOff +> Warning: Symbol map for key redefined +> Using last definition for conflicting fields +> Warning: Symbol map for key redefined +> Using last definition for conflicting fields +Errors from xkbcomp are not fatal to the X server +Errors from xkbcomp are not fatal to the X server +The XKEYBOARD keymap compiler (xkbcomp) reports: +> Warning: Unsupported maximum keycode 709, clipping. +> X11 cannot support keycodes above 255. +The XKEYBOARD keymap compiler (xkbcomp) reports: +> Warning: Unsupported maximum keycode 709, clipping. +> X11 cannot support keycodes above 255. +> Warning: Virtual modifier Hyper multiply defined +> Using 0, ignoring 0 +> Warning: > Warning: Virtual modifier Hyper multiply defined +> Using 0, ignoring 0 +> Warning: Virtual modifier ScrollLock multiply defined +> Using 0, ignoring 0 +Virtual modifier ScrollLock multiply defined +> Using 0, ignoring 0 +Errors from xkbcomp are not fatal to the X server +Errors from xkbcomp are not fatal to the X server +[4120:0311/124914.666158:ERROR:gpu/ipc/service/gpu_init.cc:209] Vulkan not supported with in process gpu +[4120:0311/124914.666158:ERROR:gpu/ipc/service/gpu_init.cc:209] Vulkan not supported with in process gpu +(EE) failed to read Wayland events: Broken pipe +(EE) failed to read Wayland events: Broken pipe diff --git a/src/electron.rs b/src/electron.rs index 75b7c1b..b53ea62 100644 --- a/src/electron.rs +++ b/src/electron.rs @@ -296,6 +296,8 @@ impl ElectronClientConnection { // Get buffer properties let num_planes = dmabuf.num_planes(); + let offsets: Vec = dmabuf.offsets().collect(); + let strides: Vec = dmabuf.strides().collect(); let (w, h) = { let size = dmabuf.size(); (size.w as u32, size.h as u32) @@ -330,15 +332,14 @@ impl ElectronClientConnection { // For each plane: fd(4) + offset(8) + stride(4) + modifier(8) // Note: We'll collect actual plane data from dmabuf handles iterator - for _handle in dmabuf.handles() { - // fd: will be sent via ancillary data, so we put 0 as placeholder + for plane_idx in 0..num_planes { + // fd placeholder — actual fds are sent via SCM_RIGHTS ancillary data buf[off..off + 4].copy_from_slice(&0u32.to_le_bytes()); off += 4; - // offset: 0 for now (can be extended later) - buf[off..off + 8].copy_from_slice(&0u64.to_le_bytes()); + let offset = offsets.get(plane_idx).copied().unwrap_or(0); + buf[off..off + 8].copy_from_slice(&(offset as u64).to_le_bytes()); off += 8; - // stride: will depend on format (approximate) - let stride = (w * 4) as u32; // ARGB8888 = 4 bytes/pixel, adjust as needed + let stride = strides.get(plane_idx).copied().unwrap_or(w * 4); buf[off..off + 4].copy_from_slice(&stride.to_le_bytes()); off += 4; // modifier (8 bytes) - DrmModifier converts to u64 @@ -595,43 +596,30 @@ impl ElectronProcess { let main_js = app_dir.join("dist/main.js"); let child = Command::new(electron_bin) - .arg(&main_js) .env("WO_IPC_SOCKET", ipc_socket) .env("WO_WINDOW_CONFIG", &serialized) .env("WO_DRM_RENDER_NODE", render_node) - // Wayland Ozone platform: Electron connects to our own Wayland - // compositor (WAYLAND_DISPLAY is already set in the env) for - // GPU/EGL initialisation. This gives Chromium a proper - // wayland-egl display so hardware-accelerated rasterisation - // works. The BrowserWindow still uses `offscreen: true`, so - // no Wayland surfaces are mapped — the connection is used - // solely for the EGL context. + // ── Chromium flags ────────────────────────────────────── + // These MUST appear before the app script on the command + // line. Electron treats everything after the script path + // as application arguments (process.argv), NOT Chromium + // switches. Flags here also reach the GPU subprocess + // (critical for --in-process-gpu and --use-gl). // - // The previous `--ozone-platform=headless` approach failed - // because headless Ozone has no EGL display, causing the GPU - // subprocess to crash with "gl=none,angle=none not found" and - // silently falling back to ~1 FPS software rasterisation. + // Wayland Ozone platform: Electron connects to our own + // Wayland compositor (WAYLAND_DISPLAY is already set in + // the env) for GPU/EGL initialisation. .arg("--ozone-platform=wayland") .arg("--no-sandbox") .arg("--disable-gpu-sandbox") - // Run GPU code in the main Electron process to avoid the - // separate GPU subprocess which adds IPC overhead and can - // fail to initialise independently. - .arg("--in-process-gpu") - // Use native EGL (provided by wayland-egl through the Ozone - // Wayland platform) for Chromium's compositor. - .arg("--use-gl=egl") - // Disable GPU vsync — we are rendering offscreen, there is - // no physical display to synchronise with. + .arg("--use-gl=angle") + .arg("--use-angle=vulkan") .arg("--disable-gpu-vsync") - // Enable GPU-accelerated rasterization and zero-copy features - // so OSR paint callbacks deliver GPU-backed bitmaps instead - // of slow CPU readbacks. - .arg("--enable-features=CanvasOopRasterization,Vulkan,VaapiVideoDecoder,RawDraw,SharedArrayBuffer") - // Use multiple raster threads for parallelised tile painting. + .arg("--enable-features=CanvasOopRasterization,Vulkan,VaapiVideoDecoder,RawDraw,SharedArrayBuffer,DefaultANGLEVulkan,VulkanFromANGLE") .arg("--num-raster-threads=4") - // Don't throttle renderers that lose focus. .arg("--disable-renderer-backgrounding") + // ── App entry point (must come after Chromium flags) ──── + .arg(&main_js) .stdin(Stdio::null()) .stdout(Stdio::inherit()) .stderr(Stdio::inherit()) diff --git a/src/handlers/input.rs b/src/handlers/input.rs index 1471306..664b822 100644 --- a/src/handlers/input.rs +++ b/src/handlers/input.rs @@ -165,7 +165,7 @@ impl WoState { self.pointer_location = new_pos; // Process active grab (interactive move/resize) before normal dispatch - if let Some(ref grab) = self.grab_state.clone() { + if let Some(grab) = self.grab_state.clone() { match grab { GrabState::Move { window, @@ -178,7 +178,18 @@ impl WoState { initial_window_location.x + dx as i32, initial_window_location.y + dy as i32, ); + + let prev_loc = self + .space + .element_location(&window) + .unwrap_or(initial_window_location); self.space.map_element(window.clone(), new_loc, false); + self.translate_dialog_children( + &window, + new_loc.0 - prev_loc.x, + new_loc.1 - prev_loc.y, + ); + self.metadata_dirty = true; } GrabState::Resize { surface, @@ -192,11 +203,11 @@ impl WoState { let dx = (self.pointer_location.x - initial_pointer.x) as i32; let dy = (self.pointer_location.y - initial_pointer.y) as i32; - let (mut new_w, mut new_h) = *initial_window_size; + let (mut new_w, mut new_h) = initial_window_size; let (mut new_x, mut new_y) = (initial_window_location.x, initial_window_location.y); - match *edges { + match edges { ResizeEdge::Right | ResizeEdge::TopRight | ResizeEdge::BottomRight => { new_w = (new_w + dx).max(1); } @@ -206,7 +217,7 @@ impl WoState { } _ => {} } - match *edges { + match edges { ResizeEdge::Bottom | ResizeEdge::BottomLeft | ResizeEdge::BottomRight => { new_h = (new_h + dy).max(1); } @@ -218,14 +229,24 @@ impl WoState { } // Respect client min/max size constraints. - let (clamped_w, clamped_h) = self.clamp_to_size_hints(window, new_w, new_h); + let (clamped_w, clamped_h) = self.clamp_to_size_hints(&window, new_w, new_h); surface.with_pending_state(|s| { s.size = Some((clamped_w, clamped_h).into()); }); surface.send_configure(); + let prev_loc = self + .space + .element_location(&window) + .unwrap_or(initial_window_location); self.space .map_element(window.clone(), (new_x, new_y), false); + self.translate_dialog_children( + &window, + new_x - prev_loc.x, + new_y - prev_loc.y, + ); + self.metadata_dirty = true; } } return; @@ -243,7 +264,7 @@ impl WoState { self.pointer_location = new_pos; // Process active grab (interactive move/resize) before normal dispatch - if let Some(ref grab) = self.grab_state.clone() { + if let Some(grab) = self.grab_state.clone() { match grab { GrabState::Move { window, @@ -256,7 +277,17 @@ impl WoState { initial_window_location.x + dx as i32, initial_window_location.y + dy as i32, ); + let prev_loc = self + .space + .element_location(&window) + .unwrap_or(initial_window_location); self.space.map_element(window.clone(), new_loc, false); + self.translate_dialog_children( + &window, + new_loc.0 - prev_loc.x, + new_loc.1 - prev_loc.y, + ); + self.metadata_dirty = true; } GrabState::Resize { surface, @@ -270,11 +301,11 @@ impl WoState { let dx = (self.pointer_location.x - initial_pointer.x) as i32; let dy = (self.pointer_location.y - initial_pointer.y) as i32; - let (mut new_w, mut new_h) = *initial_window_size; + let (mut new_w, mut new_h) = initial_window_size; let (mut new_x, mut new_y) = (initial_window_location.x, initial_window_location.y); - match *edges { + match edges { ResizeEdge::Right | ResizeEdge::TopRight | ResizeEdge::BottomRight => { new_w = (new_w + dx).max(1); } @@ -284,7 +315,7 @@ impl WoState { } _ => {} } - match *edges { + match edges { ResizeEdge::Bottom | ResizeEdge::BottomLeft | ResizeEdge::BottomRight => { new_h = (new_h + dy).max(1); } @@ -296,14 +327,24 @@ impl WoState { } // Respect client min/max size constraints. - let (clamped_w, clamped_h) = self.clamp_to_size_hints(window, new_w, new_h); + let (clamped_w, clamped_h) = self.clamp_to_size_hints(&window, new_w, new_h); surface.with_pending_state(|s| { s.size = Some((clamped_w, clamped_h).into()); }); surface.send_configure(); + let prev_loc = self + .space + .element_location(&window) + .unwrap_or(initial_window_location); self.space .map_element(window.clone(), (new_x, new_y), false); + self.translate_dialog_children( + &window, + new_x - prev_loc.x, + new_y - prev_loc.y, + ); + self.metadata_dirty = true; } } return; diff --git a/src/main.rs b/src/main.rs index e38b99a..6a8cd9b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1708,6 +1708,14 @@ fn run_drm(mut config: Config) -> Result<(), anyhow::Error> { } } + // Bind the Wayland listening socket BEFORE spawning Electron so that + // Chromium's Ozone/Wayland backend can connect immediately. Without + // this, `--ozone-platform=wayland` fails with "Connection refused" + // because the socket is not yet accepting connections. + let wayland_socket = + ListeningSocket::bind(&config.compositor.socket_name).context("binding Wayland socket")?; + info!(socket = %config.compositor.socket_name, "Wayland socket bound"); + std::env::set_var("WAYLAND_DISPLAY", &config.compositor.socket_name); // Propagate now; DISPLAY will be re-propagated once XWayland is ready. crate::state::propagate_environment(&["WAYLAND_DISPLAY"]); @@ -1805,10 +1813,6 @@ fn run_drm(mut config: Config) -> Result<(), anyhow::Error> { }; let last_render = std::time::Instant::now(); - let wayland_socket = - ListeningSocket::bind(&config.compositor.socket_name).context("binding Wayland socket")?; - info!(socket = %config.compositor.socket_name, "Wayland socket bound"); - // Register the Wayland display fd with calloop so that client messages // (surface commits, etc.) wake the event loop. Without this, the loop // only wakes on DRM VBlank / libinput / session events and rendering @@ -2167,7 +2171,14 @@ fn run_drm(mut config: Config) -> Result<(), anyhow::Error> { .and_then(|p| p.get("y")) .and_then(|v| v.as_i64()) .unwrap_or(0) as i32; - data.state.space.map_element(window, (x, y + th), false); + let prev_loc = data.state.space.element_location(&window).unwrap_or_default(); + data.state.space.map_element(window.clone(), (x, y + th), false); + data.state.translate_dialog_children( + &window, + x - prev_loc.x, + y + th - prev_loc.y, + ); + data.state.metadata_dirty = true; } "resize" => { let new_w = payload_json.as_ref() diff --git a/src/nested.rs b/src/nested.rs index 6c489ff..23ab05c 100644 --- a/src/nested.rs +++ b/src/nested.rs @@ -1310,7 +1310,14 @@ fn process_electron_message( .unwrap_or(0) as i32; // comraw reports the MacWindow origin (title bar top); // the Wayland surface sits th pixels below that. - state.space.map_element(window, (x, y + th), false); + let prev_loc = state.space.element_location(&window).unwrap_or_default(); + state.space.map_element(window.clone(), (x, y + th), false); + state.translate_dialog_children( + &window, + x - prev_loc.x, + y + th - prev_loc.y, + ); + state.metadata_dirty = true; } "resize" => { let new_w = payload_json diff --git a/src/state.rs b/src/state.rs index 366e0f9..b42993f 100644 --- a/src/state.rs +++ b/src/state.rs @@ -19,7 +19,7 @@ use smithay::{ relative_pointer::RelativePointerManagerState, pointer_constraints::{self, PointerConstraintsHandler, PointerConstraintsState}, keyboard_shortcuts_inhibit::{KeyboardShortcutsInhibitHandler, KeyboardShortcutsInhibitState, KeyboardShortcutsInhibitor}, - shell::xdg::{XdgShellState, decoration::XdgDecorationState}, shm::ShmState, single_pixel_buffer::SinglePixelBufferState, tablet_manager::TabletSeatHandler, viewporter::ViewporterState, xdg_activation::{XdgActivationHandler, XdgActivationState, XdgActivationToken, XdgActivationTokenData}, xwayland_shell::XWaylandShellState + shell::xdg::{XdgShellState, XdgToplevelSurfaceData, decoration::XdgDecorationState}, shm::ShmState, single_pixel_buffer::SinglePixelBufferState, tablet_manager::TabletSeatHandler, viewporter::ViewporterState, xdg_activation::{XdgActivationHandler, XdgActivationState, XdgActivationToken, XdgActivationTokenData}, xwayland_shell::XWaylandShellState }, xwayland::{XWayland, xwm::X11Wm}, }; @@ -558,6 +558,65 @@ impl WoState { None } + /// Return the stable parent name (Wayland or X11) for a window, if any. + pub fn parent_name_for_window(&self, window: &Window) -> Option { + if let Some(x11) = window.x11_surface() { + if let Some(parent_id) = x11.is_transient_for() { + return self.x11_window_names.get(&parent_id).cloned(); + } + } + + let parent_surface = window.toplevel().and_then(|t| { + with_states(t.wl_surface(), |states| { + states + .data_map + .get::() + .and_then(|d| d.lock().ok().and_then(|data| data.parent.clone())) + }) + }); + + if let Some(parent_wl) = parent_surface { + use smithay::reexports::wayland_server::Resource; + return self.wayland_window_names.get(&parent_wl.id()).cloned(); + } + + None + } + + /// Translate all dialog/transient children of `parent` by (dx, dy) to keep them anchored. + pub fn translate_dialog_children(&mut self, parent: &Window, dx: i32, dy: i32) { + if dx == 0 && dy == 0 { + return; + } + + let parent_name = match self.wayland_window_name(parent) { + Some(name) => name.clone(), + None => return, + }; + + let children: Vec<_> = self + .all_windows + .iter() + .cloned() + .filter(|win| { + if let Some(child_parent) = self.parent_name_for_window(win) { + child_parent == parent_name + } else { + false + } + }) + .collect(); + + for child in children { + if let Some(loc) = self.space.element_location(&child) { + self.space + .map_element(child.clone(), (loc.x + dx, loc.y + dy), false); + } + } + + self.metadata_dirty = true; + } + /// Find a Wayland or X11 Window element by its stable name (even if minimized). pub fn find_wayland_window(&self, name: &str) -> Option { self.all_windows.iter().find(|w| { diff --git a/whatever.txt b/whatever.txt index 62aee9e..5602b99 100644 --- a/whatever.txt +++ b/whatever.txt @@ -1,337 +1,7 @@ -warning: unused import: `Buffer as BufferCoord` - --> src/cursor.rs:10:22 - | -10 | use smithay::utils::{Buffer as BufferCoord, Size}; - | ^^^^^^^^^^^^^^^^^^^^^ - | - = note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default - -warning: unused import: `std::os::unix::io::AsRawFd` - --> src/dmabuf.rs:51:13 - | -51 |warning: unused import: `Buffer as BufferCoord` - --> src/cursor.rs:10:22 - | -10 | use smithay::utils::{Buffer as BufferCoord, Size}; - | ^^^^^^^^^^^^^^^^^^^^^ - | - = note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default - -warning: unused import: `std::os::unix::io::AsRawFd` - --> src/dmabuf.rs:51:13 - | -51 | use std::os::unix::io::AsRawFd; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: unused import: `smithay::utils::Rectangle` - --> src/dmabuf.rs:280:9 - | -280 | use smithay::utils::Rectangle; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: unused import: `std::collections::HashMap` - --> src/handlers/screencopy.rs:6:5 - | -6 | use std::collections::HashMap; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: unused import: `wl_output::WlOutput` - --> src/handlers/screencopy.rs:15:37 - | -15 | protocol::{wl_buffer::WlBuffer, wl_output::WlOutput, wl_shm}, - | ^^^^^^^^^^^^^^^^^^^ - - use std::os::unix::io::AsRawFd; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: unused import: `smithay::utils::Rectangle` - --> src/dmabuf.rs:280:9 - | -280 | use smithay::utils::Rectangle; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: unused import: `std::collections::HashMap` - --> src/handlers/screencopy.rs:6:5 - | -6 | use std::collections::HashMap; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: unused import: `wl_output::WlOutput` - --> src/handlers/screencopy.rs:15:37 - | -15 | protocol::{wl_buffer::WlBuffer, wl_output::WlOutput, wl_shm}, - | ^^^^^^^^^^^^^^^^^^^ - -warning: use of deprecated associated function `smithay::desktop::Window::new` - --> src/handlers/xdg_shell.rs:53:30 - | -53 | let window = Window::new(surface); - | ^^^ - | - = notewarning: use of deprecated associated function `smithay::desktop::Window::new` - --> src/handlers/xdg_shell.rs:53:30 - | -53 | let window = Window::new(surface); - | ^^^ - | - = note: `#[warn(deprecated)]` on by default - -: `#[warn(deprecated)]` on by default - -warning: use of deprecated associated function `smithay::utils::Rectangle::::from_loc_and_size`: use new or from_size - --> src/handlers/xwayland.rs:258:58 - | -258 |warning: use of deprecated associated function `smithay::utils::Rectangle::::from_loc_and_size`: use new or from_size - --> src/handlers/xwayland.rs:258:58 - | -258 | if let Err(e) = window.configure(Some(Rectangle::from_loc_and_size((0, y_offset), (ow, content_h)))) { - | ^^^^^^^^^^^^^^^^^ - - if let Err(e) = window.configure(Some(Rectangle::from_loc_and_size((0, y_offset), (ow, content_h)))) { - | ^^^^^^^^^^^^^^^^^ - -warning: use of deprecated associated function `smithay::utils::Rectangle::::from_loc_and_size`: use new or from_size - --> src/handlers/xwayland.rs:303:58 - | -303 | if let Err(e) = window.configure(Some(Rectangle::from_loc_and_size((0, 0), (suggest_w, suggest_h)))) { - | ^^^^^^^^^^^^^^^^^ - -warning: variable `plane_idx` is assigned to, but never used - --> src/electron.rs:332:13 - | -332 | let mut plane_idx = 0; - | ^^^^^^^^^^^^^ - | - warning: use of deprecated associated function `smithay::utils::Rectangle::::from_loc_and_size`: use new or from_size - --> src/handlers/xwayland.rs:303:58 - | -303 | if let Err(e) = window.configure(Some(Rectangle::from_loc_and_size((0, 0), (suggest_w, suggest_h)))) { - | ^^^^^^^^^^^^^^^^^ - -warning: variable `plane_idx` is assigned to, but never used - --> src/electron.rs:332:13 - | -332 | let mut plane_idx = 0; - | ^^^^^^^^^^^^^ - | - = note: consider using `_plane_idx` instead - = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default - -= note: consider using `_plane_idx` instead - = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default - -warning: value assigned to `plane_idx` is never read - --> src/electron.rs:348:13 - | -348 | plane_idx += 1; - | ^^^^^^^^^^^^^^ - | - = help: maybe it is overwritten before being read? - = notewarning: value assigned to `plane_idx` is never read - --> src/electron.rs:348:13 - | -348 | plane_idx += 1; - | ^^^^^^^^^^^^^^ - | - = help: maybe it is overwritten before being read? - = note: `#[warn(unused_assignments)]` (part of `#[warn(unused)]`) on by default - -: `#[warn(unused_assignments)]` (part of `#[warn(unused)]`) on by default - -warning: unreachable pattern - --> src/electron.rs:1259:46 - | -1259 | Err(nix::errno::Errno::EAGAIN) | Err(nix::errno::Errno::EWOULDBLOCK) => Ok(()), - | ------------------------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no value can reach this - | warning: unreachable pattern - --> src/electron.rs:1259:46 - | -1259 | Err(nix::errno::Errno::EAGAIN) | Err(nix::errno::Errno::EWOULDBLOCK) => Ok(()), - | ------------------------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no value can reach this - | | - | matches all the relevant values - | - = note: `#[warn(unreachable_patterns)]` (part of `#[warn(unused)]`) on by default - -| - | matches all the relevant values - | - = note: `#[warn(unreachable_patterns)]` (part of `#[warn(unused)]`) on by default - -warning: unreachable pattern - --> src/electron.rs:1286:42 - | -1286 | Err(nix::errno::Errno::EAGAIN) | Err(nix::errno::Errno::EWOULDBLOCK) => Ok(()), - | ------------------------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unreachable pattern - --> src/electron.rs:1286:42 - | -1286 | Err(nix::errno::Errno::EAGAIN) | Err(nix::errno::Errno::EWOULDBLOCK) => Ok(()), - | ------------------------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no value can reach this - | | - | matches all the relevant values - -no value can reach this - | | - | matches all the relevant values - -warning: unused variable: `surface_loc` - --> src/handlers/input.rs:439:42 - | -439 | if let Some((window, surface_loc)) = under_surface { - | ^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_surface_loc`warning: unused variable: `surface_loc` - --> src/handlers/input.rs:439:42 - | -439 | if let Some((window, surface_loc)) = under_surface { - | ^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_surface_loc` - - - -warning: unused variable: `window` - --> src/handlers/xdg_shell.rs:249:21 - | -249 | if let Some(window) = window { - | ^^^^^^ help: if this is intentional, prefix it with an underscore: `_window` - -warning: unused variable: `window` - --> src/handlers/xdg_shell.rs:249:21 - | -249 | if let Some(window) = window { - | ^^^^^^ help: if this is intentional, prefix it with an underscore: `_window` - -warning: unused variable: `event` - --> src/state.rs:615:9 - | -615 | event: &smithay::backend::input::InputEvent, - | ^^^^^ help: if this is intentional, prefix it with an underscore: `_event` - -warning: unused variable: `event` - --> src/state.rs:615:9 - | -615 | event: &smithay::backend::input::InputEvent, - | ^^^^^ help: if this is intentional, prefix it with an underscore: `_event` - -warning: `wo` (lib) generated 15 warnings (run `cargo fix --lib -p wo` to apply 8 suggestions) -warning: `wo` (lib) generated 15 warnings (run `cargo fix --lib -p wo` to apply 8 suggestions) -warning: unused import: `nix::sys::memfd::MFdFlags` - --> src/nested.rs:8:5 - | -8warning: unused import: `nix::sys::memfd::MFdFlags` - --> src/nested.rs:8:5 - | -8 | use nix::sys::memfd::MFdFlags; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - - | use nix::sys::memfd::MFdFlags; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: unused import: `std::os::unix::io::AsRawFd` - --> src/main.rs:773:17 - | -773 warning: unused import: `std::os::unix::io::AsRawFd` - --> src/main.rs:773:17 - | -773 | use std::os::unix::io::AsRawFd; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -| use std::os::unix::io::AsRawFd; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: unused import: `nix::sys::memfd::MFdFlags` - --> src/main.rs:774:17 - | -774 warning: unused import: `nix::sys::memfd::MFdFlags` - --> src/main.rs:774:17 - | -774 | use nix::sys::memfd::MFdFlags; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -| use nix::sys::memfd::MFdFlags; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: unused import: `RenderElement` - --> src/main.rs:18:52 - | -18warning: unused import: `RenderElement` - --> src/main.rs:18:52 - | -18 | use smithay::backend::renderer::element::{Element, RenderElement}; - | ^^^^^^^^^^^^^ - - | use smithay::backend::renderer::element::{Element, RenderElement}; - | ^^^^^^^^^^^^^ - -warning: trait `RenderBackend` is never used - --> src/backend.rs:11:11 - | -11warning: trait `RenderBackend` is never used - --> src/backend.rs:11:11 - | -11 | pub trait RenderBackend { - | ^^^^^^^^^^^^^ - | - = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default - - | pub trait RenderBackend { - | ^^^^^^^^^^^^^ - | - = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default - -warning: struct `Frame` is never constructed - --> src/backend.rs:39:12 - | -39warning: struct `Frame` is never constructed - --> src/backend.rs:39:12 - | -39 | pub struct Frame { - | ^^^^^ - - | pub struct Frame { - | ^^^^^ - -warning: associated function `new` is never used - --> src/backend.rs:45:12 - | -44 warning: associated function `new` is never used - --> src/backend.rs:45:12 - | -44 | impl Frame { - | ---------- associated function in this implementation -45 | pub fn new(output_rect: Rectangle) -> Self { - | ^^^ - -| impl Frame { - | ---------- associated function in this implementation -45 | pub fn new(output_rect: Rectangle) -> Self { - | ^^^ - -warning: function `reimport_cached_frame` is never used - --> src/dmabuf.rs:212:8 - | -212 warning: function `reimport_cached_frame` is never used - --> src/dmabuf.rs:212:8 - | -212 | pub fn reimport_cached_frame( - | ^^^^^^^^^^^^^^^^^^^^^ - -| pub fn reimport_cached_frame( - | ^^^^^^^^^^^^^^^^^^^^^ - -warning: struct `PlaneInfoWire` is never constructed - --> src/electron.rs:57:12 - | -warning: struct `PlaneInfoWire` is never constructed - --> src/electron.rs:57:12 - | -57 | pub struct PlaneInfoWire { - | ^^^^^^^^^^^^^ - -57 | pub struct PlaneInfoWire { - | ^^^^^^^^^^^^^ - -warning: `wo` (bin "wo") generated 24 warnings (15 duplicates) (run `cargo fix --bin "wo" -p wo` to apply 3 suggestions) -warning: `wo` (bin "wo") generated 24 warnings (15 duplicates) (run `cargo fix --bin "wo" -p wo` to apply 3 suggestions) - Finished `release` profile [optimized] target(s) in 0.20s - Finished `release` profile [optimized] target(s) in 0.20s + Compiling wo v0.1.0 (/home/hellings/Documents/wo) + Compiling wo v0.1.0 (/home/hellings/Documents/wo) + Finished `release` profile [optimized] target(s) in 2m 21s + Finished `release` profile [optimized] target(s) in 2m 21s Running `target/release/wo` Running `target/release/wo` Xwayland glamor: GBM Wayland interfaces not available @@ -374,73 +44,179 @@ The XKEYBOARD keymap compiler (xkbcomp) reports: > Using 0, ignoring 0 Errors from xkbcomp are not fatal to the X server Errors from xkbcomp are not fatal to the X server -[75913:0310/190621.144695:ERROR:ui/gl/init/gl_factory.cc:102] Requested GL implementation (gl=none,angle=none) not found in allowed implementations: [(gl=egl-angle,angle=default)]. -[75913:0310/190621.144695:ERROR:ui/gl/init/gl_factory.cc:102] Requested GL implementation (gl=none,angle=none) not found in allowed implementations: [(gl=egl-angle,angle=default)]. -[75913:0310/190621.145938:ERROR:components/viz/service/main/viz_main_impl.cc:189] Exiting GPU process due to errors during initialization -[75913:0310/190621.145938:ERROR:components/viz/service/main/viz_main_impl.cc:189] Exiting GPU process due to errors during initialization -[75933:0310/190621.205869:ERROR:ui/gl/init/gl_factory.cc:102] Requested GL implementation (gl=none,angle=none) not found in allowed implementations: [(gl=egl-angle,angle=default)]. -[75933:0310/190621.205869:ERROR:ui/gl/init/gl_factory.cc:102] Requested GL implementation (gl=none,angle=none) not found in allowed implementations: [(gl=egl-angle,angle=default)]. -[75933:0310/190621.207105:ERROR:components/viz/service/main/viz_main_impl.cc:189] Exiting GPU process due to errors during initialization -[75933:0310/190621.207105:ERROR:components/viz/service/main/viz_main_impl.cc:189] Exiting GPU process due to errors during initialization -[75966:0310/190621.260351:ERROR:ui/gl/init/gl_factory.cc:102] Requested GL implementation (gl=none,angle=none) not found in allowed implementations: [(gl=egl-angle,angle=default)]. -[75966:0310/190621.260351:ERROR:ui/gl/init/gl_factory.cc:102] Requested GL implementation (gl=none,angle=none) not found in allowed implementations: [(gl=egl-angle,angle=default)]. -[75966:0310/190621.261808:ERROR:components/viz/service/main/viz_main_impl.cc:189] Exiting GPU process due to errors during initialization -[75966:0310/190621.261808:ERROR:components/viz/service/main/viz_main_impl.cc:189] Exiting GPU process due to errors during initialization -(node:75859) DeprecationWarning: getBitmap() is deprecated, use toBitmap() instead. -(Use `electron --trace-deprecation ...` to show where the warning was created) -(node:75859) DeprecationWarning: getBitmap() is deprecated, use toBitmap() instead. -(Use `electron --trace-deprecation ...` to show where the warning was created) -Error sending from webFrameMain: Error: Failed to serialize arguments +Authorization required, but no authorization protocol specified + +Authorization required, but no authorization protocol specified + +Authorization required, but no authorization protocol specified + +Authorization required, but no authorization protocol specified + +Gtk-Message: 13:58:16.908: Failed to load module "appmenu-gtk-module" +Gtk-Message: 13:58:16.908: Failed to load module "appmenu-gtk-module" +Authorization required, but no authorization protocol specified + +Authorization required, but no authorization protocol specified + +[24415:0311/135817.250839:ERROR:ui/ozone/platform/wayland/gpu/wayland_surface_factory.cc:250] '--ozone-platform=wayland' is not compatible with Vulkan. Consider switching to '--ozone-platform=x11' or disabling Vulkan +[24415:0311/135817.250839:ERROR:ui/ozone/platform/wayland/gpu/wayland_surface_factory.cc:250] '--ozone-platform=wayland' is not compatible with Vulkan. Consider switching to '--ozone-platform=x11' or disabling Vulkan +[24415:0311/135817.264878:ERROR:components/viz/service/display_embedder/skia_output_device_vulkan.cc:301] Failed to create vulkan surface. +[24415:0311/135817.264878:ERROR:components/viz/service/display_embedder/skia_output_device_vulkan.cc:301] Failed to create vulkan surface. +[24330:0311/135939.036070:ERROR:content/browser/network_service_instance_impl.cc:613] Network service crashed, restarting service. +[24330:0311/135939.036070:ERROR:content/browser/network_service_instance_impl.cc:613] Network service crashed, restarting service. +[24330:0311/135939.185963:ERROR:content/browser/gpu/gpu_process_host.cc:999] GPU process exited unexpectedly: exit_code=15 +[24330:0311/135939.185963:ERROR:content/browser/gpu/gpu_process_host.cc:999] GPU process exited unexpectedly: exit_code=15 +Error sending from webFrameMain: Error: Render frame was disposed before WebFrameMain could be accessed at s.send (node:electron/js2c/browser_init:2:100266) at b.send (node:electron/js2c/browser_init:2:84687) - at getOrCreateSab (file:///home/hellings/Documents/wo/electron/dist/main.js:318:28) - at Socket. (file:///home/hellings/Documents/wo/electron/dist/main.js:1251:30) + at Socket. (file:///home/hellings/Documents/wo/electron/dist/main.js:1213:36) at Socket.emit (node:events:519:28) at addChunk (node:internal/streams/readable:561:12) at readableAddChunkPushByteMode (node:internal/streams/readable:512:3) at Readable.push (node:internal/streams/readable:392:5) at Pipe.onStreamRead (node:internal/stream_base_commons:189:23) -Error sending from webFrameMain: Error: Failed to serialize arguments +Error sending from webFrameMain: Error: Render frame was disposed before WebFrameMain could be accessed at s.send (node:electron/js2c/browser_init:2:100266) at b.send (node:electron/js2c/browser_init:2:84687) - at getOrCreateSab (file:///home/hellings/Documents/wo/electron/dist/main.js:318:28) - at Socket. (file:///home/hellings/Documents/wo/electron/dist/main.js:1251:30) + at Socket. (file:///home/hellings/Documents/wo/electron/dist/main.js:1213:36) at Socket.emit (node:events:519:28) at addChunk (node:internal/streams/readable:561:12) at readableAddChunkPushByteMode (node:internal/streams/readable:512:3) at Readable.push (node:internal/streams/readable:392:5) at Pipe.onStreamRead (node:internal/stream_base_commons:189:23) -Error sending from webFrameMain: Error: Failed to serialize arguments +Error sending from webFrameMain: Error: Render frame was disposed before WebFrameMain could be accessed at s.send (node:electron/js2c/browser_init:2:100266) at b.send (node:electron/js2c/browser_init:2:84687) - at getOrCreateSab (file:///home/hellings/Documents/wo/electron/dist/main.js:318:28) - at Socket. (file:///home/hellings/Documents/wo/electron/dist/main.js:1251:30) + at Socket. (file:///home/hellings/Documents/wo/electron/dist/main.js:1235:40) at Socket.emit (node:events:519:28) at addChunk (node:internal/streams/readable:561:12) at readableAddChunkPushByteMode (node:internal/streams/readable:512:3) at Readable.push (node:internal/streams/readable:392:5) at Pipe.onStreamRead (node:internal/stream_base_commons:189:23) -Error sending from webFrameMain: Error: Failed to serialize arguments +Error sending from webFrameMain: Error: Render frame was disposed before WebFrameMain could be accessed at s.send (node:electron/js2c/browser_init:2:100266) at b.send (node:electron/js2c/browser_init:2:84687) - at getOrCreateSab (file:///home/hellings/Documents/wo/electron/dist/main.js:318:28) - at Socket. (file:///home/hellings/Documents/wo/electron/dist/main.js:1251:30) + at Socket. (file:///home/hellings/Documents/wo/electron/dist/main.js:1235:40) + at Socket.emit (node:events:519:28) + at addChunk (node:internal/streams/readable:561:12) + at readableAddChunkPushByteMode (node:internal/streams/readable:512:3) + at Readable.push (node:internal/streams/readable:392:5) + at Pipe.onStreamRead (node:internal/stream_base_commons:189:23) +Authorization required, but no authorization protocol specified + +Authorization required, but no authorization protocol specified + +Error sending from webFrameMain: Error: Render frame was disposed before WebFrameMain could be accessed + at s.send (node:electron/js2c/browser_init:2:100266) + at b.send (node:electron/js2c/browser_init:2:84687) + at Socket. (file:///home/hellings/Documents/wo/electron/dist/main.js:1213:36) + at Socket.emit (node:events:519:28) + at addChunk (node:internal/streams/readable:561:12) + at readableAddChunkPushByteMode (node:internal/streams/readable:512:3) + at Readable.push (node:internal/streams/readable:392:5) + at Pipe.onStreamRead (node:internal/stream_base_commons:189:23) +Error sending from webFrameMain: Error: Render frame was disposed before WebFrameMain could be accessed + at s.send (node:electron/js2c/browser_init:2:100266) + at b.send (node:electron/js2c/browser_init:2:84687) + at Socket. (file:///home/hellings/Documents/wo/electron/dist/main.js:1213:36) + at Socket.emit (node:events:519:28) + at addChunk (node:internal/streams/readable:561:12) + at readableAddChunkPushByteMode (node:internal/streams/readable:512:3) + at Readable.push (node:internal/streams/readable:392:5) + at Pipe.onStreamRead (node:internal/stream_base_commons:189:23) +Error sending from webFrameMain: Error: Render frame was disposed before WebFrameMain could be accessed + at s.send (node:electron/js2c/browser_init:2:100266) + at b.send (node:electron/js2c/browser_init:2:84687) + at Socket. (file:///home/hellings/Documents/wo/electron/dist/main.js:1235:40) + at Socket.emit (node:events:519:28) + at addChunk (node:internal/streams/readable:561:12) + at readableAddChunkPushByteMode (node:internal/streams/readable:512:3) + at Readable.push (node:internal/streams/readable:392:5) + at Pipe.onStreamRead (node:internal/stream_base_commons:189:23) +Error sending from webFrameMain: Error: Render frame was disposed before WebFrameMain could be accessed + at s.send (node:electron/js2c/browser_init:2:100266) + at b.send (node:electron/js2c/browser_init:2:84687) + at Socket. (file:///home/hellings/Documents/wo/electron/dist/main.js:1235:40) + at Socket.emit (node:events:519:28) + at addChunk (node:internal/streams/readable:561:12) + at readableAddChunkPushByteMode (node:internal/streams/readable:512:3) + at Readable.push (node:internal/streams/readable:392:5) + at Pipe.onStreamRead (node:internal/stream_base_commons:189:23) +Authorization required, but no authorization protocol specified + +Authorization required, but no authorization protocol specified + +Error sending from webFrameMain: Error: Render frame was disposed before WebFrameMain could be accessed + at s.send (node:electron/js2c/browser_init:2:100266) + at b.send (node:electron/js2c/browser_init:2:84687) + at Socket. (file:///home/hellings/Documents/wo/electron/dist/main.js:1213:36) + at Socket.emit (node:events:519:28) + at addChunk (node:internal/streams/readable:561:12) + at readableAddChunkPushByteMode (node:internal/streams/readable:512:3) + at Readable.push (node:internal/streams/readable:392:5) + at Pipe.onStreamRead (node:internal/stream_base_commons:189:23) +Error sending from webFrameMain: Error: Render frame was disposed before WebFrameMain could be accessed + at s.send (node:electron/js2c/browser_init:2:100266) + at b.send (node:electron/js2c/browser_init:2:84687) + at Socket. (file:///home/hellings/Documents/wo/electron/dist/main.js:1213:36) + at Socket.emit (node:events:519:28) + at addChunk (node:internal/streams/readable:561:12) + at readableAddChunkPushByteMode (node:internal/streams/readable:512:3) + at Readable.push (node:internal/streams/readable:392:5) + at Pipe.onStreamRead (node:internal/stream_base_commons:189:23) +Error sending from webFrameMain: Error: Render frame was disposed before WebFrameMain could be accessed + at s.send (node:electron/js2c/browser_init:2:100266) + at b.send (node:electron/js2c/browser_init:2:84687) + at Socket. (file:///home/hellings/Documents/wo/electron/dist/main.js:1235:40) + at Socket.emit (node:events:519:28) + at addChunk (node:internal/streams/readable:561:12) + at readableAddChunkPushByteMode (node:internal/streams/readable:512:3) + at Readable.push (node:internal/streams/readable:392:5) + at Pipe.onStreamRead (node:internal/stream_base_commons:189:23) +Error sending from webFrameMain: Error: Render frame was disposed before WebFrameMain could be accessed + at s.send (node:electron/js2c/browser_init:2:100266) + at b.send (node:electron/js2c/browser_init:2:84687) + at Socket. (file:///home/hellings/Documents/wo/electron/dist/main.js:1235:40) + at Socket.emit (node:events:519:28) + at addChunk (node:internal/streams/readable:561:12) + at readableAddChunkPushByteMode (node:internal/streams/readable:512:3) + at Readable.push (node:internal/streams/readable:392:5) + at Pipe.onStreamRead (node:internal/stream_base_commons:189:23) +Error sending from webFrameMain: Error: Render frame was disposed before WebFrameMain could be accessed + at s.send (node:electron/js2c/browser_init:2:100266) + at b.send (node:electron/js2c/browser_init:2:84687) + at Socket. (file:///home/hellings/Documents/wo/electron/dist/main.js:1213:36) + at Socket.emit (node:events:519:28) + at addChunk (node:internal/streams/readable:561:12) + at readableAddChunkPushByteMode (node:internal/streams/readable:512:3) + at Readable.push (node:internal/streams/readable:392:5) + at Pipe.onStreamRead (node:internal/stream_base_commons:189:23) +Error sending from webFrameMain: Error: Render frame was disposed before WebFrameMain could be accessed + at s.send (node:electron/js2c/browser_init:2:100266) + at b.send (node:electron/js2c/browser_init:2:84687) + at Socket. (file:///home/hellings/Documents/wo/electron/dist/main.js:1213:36) + at Socket.emit (node:events:519:28) + at addChunk (node:internal/streams/readable:561:12) + at readableAddChunkPushByteMode (node:internal/streams/readable:512:3) + at Readable.push (node:internal/streams/readable:392:5) + at Pipe.onStreamRead (node:internal/stream_base_commons:189:23) +Error sending from webFrameMain: Error: Render frame was disposed before WebFrameMain could be accessed + at s.send (node:electron/js2c/browser_init:2:100266) + at b.send (node:electron/js2c/browser_init:2:84687) + at Socket. (file:///home/hellings/Documents/wo/electron/dist/main.js:1235:40) + at Socket.emit (node:events:519:28) + at addChunk (node:internal/streams/readable:561:12) + at readableAddChunkPushByteMode (node:internal/streams/readable:512:3) + at Readable.push (node:internal/streams/readable:392:5) + at Pipe.onStreamRead (node:internal/stream_base_commons:189:23) +Error sending from webFrameMain: Error: Render frame was disposed before WebFrameMain could be accessed + at s.send (node:electron/js2c/browser_init:2:100266) + at b.send (node:electron/js2c/browser_init:2:84687) + at Socket. (file:///home/hellings/Documents/wo/electron/dist/main.js:1235:40) at Socket.emit (node:events:519:28) at addChunk (node:internal/streams/readable:561:12) at readableAddChunkPushByteMode (node:internal/streams/readable:512:3) at Readable.push (node:internal/streams/readable:392:5) at Pipe.onStreamRead (node:internal/stream_base_commons:189:23) -Key repeat discarded, Wayland compositor doesn't seem to be processing events fast enough! -Key repeat discarded, Wayland compositor doesn't seem to be processing events fast enough! (EE) failed to read Wayland events: Broken pipe (EE) failed to read Wayland events: Broken pipe -[75859:0310/190654.025906:ERROR:mojo/public/cpp/bindings/lib/interface_endpoint_client.cc:732] Message 0 rejected by interface blink.mojom.WidgetHost -[75859:0310/190654.025906:ERROR:mojo/public/cpp/bindings/lib/interface_endpoint_client.cc:732] Message 0 rejected by interface blink.mojom.WidgetHost -[75859:0310/190654.035184:ERROR:mojo/public/cpp/bindings/lib/interface_endpoint_client.cc:732] Message 4 rejected by interface blink.mojom.WidgetHost -[75859:0310/190654.035184:ERROR:mojo/public/cpp/bindings/lib/interface_endpoint_client.cc:732] Message 4 rejected by interface blink.mojom.WidgetHost -[75859:0310/190654.058269:ERROR:mojo/public/cpp/bindings/lib/interface_endpoint_client.cc:732] Message 5 rejected by interface blink.mojom.WidgetHost -[75859:0310/190654.058269:ERROR:mojo/public/cpp/bindings/lib/interface_endpoint_client.cc:732] Message 5 rejected by interface blink.mojom.WidgetHost -[75859:0310/190654.068805:ERROR:content/browser/network_service_instance_impl.cc:613] Network service crashed, restarting service. -[75859:0310/190654.068805:ERROR:content/browser/network_service_instance_impl.cc:613] Network service crashed, restarting service. -[75859:0310/190654.077683:ERROR:content/browser/gpu/gpu_process_host.cc:999] GPU process exited unexpectedly: exit_code=15 -[75859:0310/190654.077683:ERROR:content/browser/gpu/gpu_process_host.cc:999] GPU process exited unexpectedly: exit_code=15