Further optimization passes
This commit is contained in:
parent
ff54140d62
commit
68b4916f64
12 changed files with 574 additions and 881 deletions
9
electron/dist/main.js
vendored
9
electron/dist/main.js
vendored
|
|
@ -235,15 +235,22 @@ function debugLog(...args) {
|
||||||
console.log(...args);
|
console.log(...args);
|
||||||
}
|
}
|
||||||
debugLog("[Wo] Electron starting, NODE_VERSION=", process.version);
|
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("ignore-gpu-blocklist");
|
||||||
app.commandLine.appendSwitch("enable-gpu-rasterization");
|
app.commandLine.appendSwitch("enable-gpu-rasterization");
|
||||||
app.commandLine.appendSwitch("enable-zero-copy");
|
app.commandLine.appendSwitch("enable-zero-copy");
|
||||||
app.commandLine.appendSwitch("enable-native-gpu-memory-buffers");
|
app.commandLine.appendSwitch("enable-native-gpu-memory-buffers");
|
||||||
app.commandLine.appendSwitch("disable-software-rasterizer");
|
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("enable-accelerated-video-decode");
|
||||||
app.commandLine.appendSwitch("disable-frame-rate-limit");
|
app.commandLine.appendSwitch("disable-frame-rate-limit");
|
||||||
app.commandLine.appendSwitch("disable-gpu-vsync");
|
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");
|
debugLog("[Wo] GPU acceleration flags applied");
|
||||||
var IPC_SOCKET = process.env.WO_IPC_SOCKET || "/run/user/1000/wo-ipc.sock";
|
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);
|
debugLog("[Wo] WO_WINDOW_CONFIG env =", process.env.WO_WINDOW_CONFIG);
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import { app, BrowserWindow, ipcMain } from 'electron';
|
||||||
import { createConnection, createServer, Socket, Server } from 'net';
|
import { createConnection, createServer, Socket, Server } from 'net';
|
||||||
import { fileURLToPath } from 'url';
|
import { fileURLToPath } from 'url';
|
||||||
import { dirname, resolve as resolvePath, join as joinPath } from 'path';
|
import { dirname, resolve as resolvePath, join as joinPath } from 'path';
|
||||||
|
import { randomUUID } from 'crypto';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import { createRequire } from 'module';
|
import { createRequire } from 'module';
|
||||||
import { MAGIC, stringToBuffer } from './protocol.js';
|
import { MAGIC, stringToBuffer } from './protocol.js';
|
||||||
|
|
@ -44,18 +45,25 @@ function debugLog(...args: any[]) {
|
||||||
debugLog('[Wo] Electron starting, NODE_VERSION=', process.version);
|
debugLog('[Wo] Electron starting, NODE_VERSION=', process.version);
|
||||||
|
|
||||||
// GPU acceleration & rendering performance flags (must be set before app 'ready')
|
// GPU acceleration & rendering performance flags (must be set before app 'ready')
|
||||||
// Note: core flags (--in-process-gpu, --use-gl=egl, --ozone-platform=wayland)
|
// Chromium flags MUST go through appendSwitch — process argv flags are not
|
||||||
// are set on the command line in the Rust spawn(). Flags below augment those.
|
// 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('ignore-gpu-blocklist');
|
||||||
app.commandLine.appendSwitch('enable-gpu-rasterization');
|
app.commandLine.appendSwitch('enable-gpu-rasterization');
|
||||||
app.commandLine.appendSwitch('enable-zero-copy');
|
app.commandLine.appendSwitch('enable-zero-copy');
|
||||||
app.commandLine.appendSwitch('enable-native-gpu-memory-buffers');
|
app.commandLine.appendSwitch('enable-native-gpu-memory-buffers');
|
||||||
app.commandLine.appendSwitch('disable-software-rasterizer');
|
app.commandLine.appendSwitch('disable-software-rasterizer');
|
||||||
app.commandLine.appendSwitch('enable-features',
|
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('enable-accelerated-video-decode');
|
||||||
app.commandLine.appendSwitch('disable-frame-rate-limit');
|
app.commandLine.appendSwitch('disable-frame-rate-limit');
|
||||||
app.commandLine.appendSwitch('disable-gpu-vsync');
|
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');
|
debugLog('[Wo] GPU acceleration flags applied');
|
||||||
|
|
||||||
type ClientWindowInfo = {
|
type ClientWindowInfo = {
|
||||||
|
|
@ -84,8 +92,8 @@ let ipcSocket: Socket | null = null;
|
||||||
let portalUiServer: Server | null = null;
|
let portalUiServer: Server | null = null;
|
||||||
type PendingPortalRequest = {
|
type PendingPortalRequest = {
|
||||||
socket: Socket;
|
socket: Socket;
|
||||||
kind: 'screen_share';
|
requestId: string;
|
||||||
sessionId: string;
|
payload: any;
|
||||||
};
|
};
|
||||||
const portalPendingRequests = new Map<string, PendingPortalRequest>();
|
const portalPendingRequests = new Map<string, PendingPortalRequest>();
|
||||||
const PORTAL_UI_SOCKET = '/tmp/wo-portal-ui.sock';
|
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);
|
surfaceSabCache.set(windowName, entry);
|
||||||
// Tell renderer about the new SAB so it can reference it
|
// Tell renderer about the new SAB so it can reference it
|
||||||
if (mainWindow && !mainWindow.isDestroyed()) {
|
if (mainWindow && !mainWindow.isDestroyed()) {
|
||||||
mainWindow.webContents.postMessage('wo:surface-sab', {
|
mainWindow.webContents.send('wo:surface-sab', {
|
||||||
name: windowName,
|
name: windowName,
|
||||||
sab,
|
sab,
|
||||||
width,
|
width,
|
||||||
|
|
@ -231,7 +239,8 @@ let pointerX = 0;
|
||||||
let pointerY = 0;
|
let pointerY = 0;
|
||||||
|
|
||||||
function respondToPortalRequest(requestId: string, params: {
|
function respondToPortalRequest(requestId: string, params: {
|
||||||
allowed: boolean;
|
response?: unknown;
|
||||||
|
allowed?: boolean;
|
||||||
type?: string;
|
type?: string;
|
||||||
windowName?: unknown;
|
windowName?: unknown;
|
||||||
}): { ok: boolean; error?: string } {
|
}): { ok: boolean; error?: string } {
|
||||||
|
|
@ -240,19 +249,22 @@ function respondToPortalRequest(requestId: string, params: {
|
||||||
return { ok: false, error: `No pending portal request: ${requestId}` };
|
return { ok: false, error: `No pending portal request: ${requestId}` };
|
||||||
}
|
}
|
||||||
|
|
||||||
let response: Record<string, unknown>;
|
const responsePayload =
|
||||||
if (pending.kind === 'screen_share') {
|
params.response !== undefined
|
||||||
response = {
|
? params.response
|
||||||
|
: {
|
||||||
allowed: Boolean(params.allowed),
|
allowed: Boolean(params.allowed),
|
||||||
sourceType: params.type === 'window' ? 'Window' : 'Monitor',
|
sourceType: params.type === 'window' ? 'Window' : 'Monitor',
|
||||||
windowName: typeof params.windowName === 'string' ? params.windowName : null,
|
windowName: typeof params.windowName === 'string' ? params.windowName : null,
|
||||||
};
|
};
|
||||||
} else {
|
|
||||||
response = { allowed: false };
|
if (responsePayload === undefined) {
|
||||||
|
portalPendingRequests.delete(requestId);
|
||||||
|
return { ok: false, error: 'Missing portal response payload' };
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
pending.socket.write(`${JSON.stringify(response)}\n`);
|
pending.socket.write(`${JSON.stringify(responsePayload)}\n`);
|
||||||
pending.socket.end();
|
pending.socket.end();
|
||||||
portalPendingRequests.delete(requestId);
|
portalPendingRequests.delete(requestId);
|
||||||
return { ok: true };
|
return { ok: true };
|
||||||
|
|
@ -276,64 +288,59 @@ function startPortalUiBridge() {
|
||||||
|
|
||||||
socket.on('data', (chunk: Buffer) => {
|
socket.on('data', (chunk: Buffer) => {
|
||||||
received += chunk.toString('utf8');
|
received += chunk.toString('utf8');
|
||||||
const nl = received.indexOf('\n');
|
let nl = received.indexOf('\n');
|
||||||
if (nl < 0) return;
|
while (nl >= 0) {
|
||||||
|
|
||||||
const line = received.slice(0, nl).trim();
|
const line = received.slice(0, nl).trim();
|
||||||
received = received.slice(nl + 1);
|
received = received.slice(nl + 1);
|
||||||
if (!line) return;
|
|
||||||
|
|
||||||
|
if (line.length > 0) {
|
||||||
try {
|
try {
|
||||||
const req = JSON.parse(line) as {
|
const req = JSON.parse(line) as Record<string, unknown>;
|
||||||
type?: string;
|
const requestId = String(
|
||||||
appName?: string;
|
(req?.requestId as string | undefined)
|
||||||
sessionId?: string;
|
?? (req?.sessionId as string | undefined)
|
||||||
};
|
?? (req?.id as string | undefined)
|
||||||
|
?? randomUUID(),
|
||||||
|
);
|
||||||
|
|
||||||
if (req.type !== 'screen_share_request' || !req.sessionId) {
|
portalPendingRequests.set(requestId, { socket, requestId, payload: req });
|
||||||
socket.end('{"allowed":false,"reason":"invalid_request"}\n');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const requestId = req.sessionId;
|
// Auto-timeout if UI does not respond within 90s
|
||||||
|
|
||||||
portalPendingRequests.set(requestId, {
|
|
||||||
socket,
|
|
||||||
kind: 'screen_share',
|
|
||||||
sessionId: req.sessionId,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Auto-deny if UI does not respond within 90s
|
|
||||||
socket.setTimeout(90_000, () => {
|
socket.setTimeout(90_000, () => {
|
||||||
const pending = portalPendingRequests.get(requestId);
|
const pending = portalPendingRequests.get(requestId);
|
||||||
if (pending) {
|
if (pending) {
|
||||||
portalPendingRequests.delete(requestId);
|
portalPendingRequests.delete(requestId);
|
||||||
pending.socket.end('{"allowed":false,"reason":"timeout"}\n');
|
pending.socket.end(JSON.stringify({ error: 'timeout', requestId }) + '\n');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (mainWindow && !mainWindow.isDestroyed()) {
|
if (mainWindow && !mainWindow.isDestroyed()) {
|
||||||
const payload = {
|
mainWindow.webContents.send('wo:portal-request', {
|
||||||
requestId,
|
requestId,
|
||||||
kind: 'screen_share',
|
payload: req,
|
||||||
appName: req.appName || 'Application',
|
kind: typeof req?.type === 'string'
|
||||||
sessionId: req.sessionId,
|
? (req.type as string)
|
||||||
};
|
: typeof req?.kind === 'string'
|
||||||
|
? (req.kind as string)
|
||||||
mainWindow.webContents.send('wo:portal-request', payload);
|
: undefined,
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
portalPendingRequests.delete(requestId);
|
portalPendingRequests.delete(requestId);
|
||||||
socket.end('{"allowed":false,"reason":"no_ui"}\n');
|
socket.end(JSON.stringify({ error: 'no_ui', requestId }) + '\n');
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
socket.end('{"allowed":false,"reason":"invalid_json"}\n');
|
socket.end('{"error":"invalid_json"}\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nl = received.indexOf('\n');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('close', () => {
|
socket.on('close', () => {
|
||||||
for (const [sessionId, pending] of portalPendingRequests.entries()) {
|
for (const [requestId, pending] of portalPendingRequests.entries()) {
|
||||||
if (pending.socket === socket) {
|
if (pending.socket === socket) {
|
||||||
portalPendingRequests.delete(sessionId);
|
portalPendingRequests.delete(requestId);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -356,7 +363,7 @@ function startPortalUiBridge() {
|
||||||
function stopPortalUiBridge() {
|
function stopPortalUiBridge() {
|
||||||
for (const pending of portalPendingRequests.values()) {
|
for (const pending of portalPendingRequests.values()) {
|
||||||
try {
|
try {
|
||||||
pending.socket.end('{"allowed":false,"reason":"shutdown"}\n');
|
pending.socket.end(JSON.stringify({ error: 'shutdown', requestId: pending.requestId }) + '\n');
|
||||||
} catch {
|
} catch {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
|
|
@ -402,321 +409,22 @@ let clientWindows: ClientWindowInfo[] = parseClientWindows();
|
||||||
// Live window list received from the compositor via WOWM metadata messages.
|
// Live window list received from the compositor via WOWM metadata messages.
|
||||||
let compositorWindows: Record<string, unknown>[] = [];
|
let compositorWindows: Record<string, unknown>[] = [];
|
||||||
|
|
||||||
type StatusNotifierTrayItem = {
|
type DbBus = 'user' | 'system';
|
||||||
id: string;
|
function runBusctl(bus: DbBus, args: string[]): { ok: boolean; stdout: string; stderr: string; exitCode: number } {
|
||||||
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 {
|
|
||||||
try {
|
try {
|
||||||
const { execFileSync } = require('child_process') as typeof import('child_process');
|
const { spawnSync } = require('child_process') as typeof import('child_process');
|
||||||
return execFileSync('busctl', ['--user', ...args], {
|
const res = spawnSync('busctl', [bus === 'system' ? '--system' : '--user', ...args], {
|
||||||
encoding: 'utf8',
|
encoding: 'utf8',
|
||||||
stdio: ['ignore', 'pipe', 'ignore'],
|
stdio: ['ignore', 'pipe', 'pipe'],
|
||||||
}).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'),
|
|
||||||
});
|
});
|
||||||
}
|
return {
|
||||||
|
ok: res.status === 0,
|
||||||
return results;
|
stdout: (res.stdout as string | undefined)?.trim?.() || '',
|
||||||
}
|
stderr: (res.stderr as string | undefined)?.trim?.() || '',
|
||||||
|
exitCode: res.status ?? -1,
|
||||||
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'),
|
|
||||||
};
|
};
|
||||||
|
} catch (error: any) {
|
||||||
if (newDepth === 0) {
|
return { ok: false, stdout: '', stderr: String(error), exitCode: -1 };
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1263,17 +971,56 @@ function connectToCompositor(): Promise<void> {
|
||||||
const dmabufFormat = compositorRxBuffer.readUInt32LE(off); off += 4;
|
const dmabufFormat = compositorRxBuffer.readUInt32LE(off); off += 4;
|
||||||
const numPlanes = 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;
|
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 {
|
try {
|
||||||
if (nativeDmabuf && ipcSocket) {
|
if (nativeDmabuf && ipcSocket) {
|
||||||
const socketFd = (ipcSocket as any)?._handle?.fd;
|
const socketFd = (ipcSocket as any)?._handle?.fd;
|
||||||
if (typeof socketFd === 'number' && socketFd >= 0) {
|
if (typeof socketFd === 'number' && socketFd >= 0) {
|
||||||
const dmabufFd = nativeDmabuf.recvFd(socketFd);
|
const planeFds: number[] = [];
|
||||||
if (dmabufFd >= 0) {
|
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 {
|
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()) {
|
if (mainWindow && !mainWindow.isDestroyed()) {
|
||||||
mainWindow.webContents.send('wo:dmabuf-frame', {
|
mainWindow.webContents.send('wo:dmabuf-frame', {
|
||||||
name: dmabufName,
|
name: dmabufName,
|
||||||
|
|
@ -1283,7 +1030,9 @@ function connectToCompositor(): Promise<void> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
fs.closeSync(dmabufFd);
|
for (const fd of planeFds) {
|
||||||
|
try { fs.closeSync(fd); } catch { /* ignore */ }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1704,74 +1453,71 @@ function setupIpcHandlers() {
|
||||||
return { ok: true };
|
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' };
|
|
||||||
}
|
|
||||||
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': {
|
case 'portal_respond': {
|
||||||
const requestId = String(params.requestId || '');
|
const requestId = String(params.requestId || '');
|
||||||
if (!requestId) {
|
if (!requestId) {
|
||||||
return { ok: false, error: 'Missing portal requestId' };
|
return { ok: false, error: 'Missing portal requestId' };
|
||||||
}
|
}
|
||||||
return respondToPortalRequest(requestId, {
|
return respondToPortalRequest(requestId, {
|
||||||
allowed: Boolean(params.allowed),
|
response: params.response,
|
||||||
|
allowed: params.allowed,
|
||||||
type: typeof params.type === 'string' ? params.type : undefined,
|
type: typeof params.type === 'string' ? params.type : undefined,
|
||||||
windowName: params.windowName,
|
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:
|
default:
|
||||||
return { ok: false, error: `Unknown syscall: ${type}` };
|
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
|
// In offscreen mode, we need actual content to trigger paint events
|
||||||
// Load the configured URL or fallback to minimal page
|
// Load the configured URL/file or fallback to minimal page
|
||||||
debugLog('[Wo] Loading content URL: ' + (url || 'minimal fallback'));
|
debugLog('[Wo] Loading content URL: ' + (url || html || 'minimal fallback'));
|
||||||
try {
|
try {
|
||||||
const pageUrl = url || 'data:text/html,<!DOCTYPE html><html><head><style>body{background:white;margin:0;}</style></head><body></body></html>';
|
const pageUrl = url
|
||||||
const loadPromise = mainWindow!.loadURL(pageUrl);
|
|| (html ? `file://${html}` : null)
|
||||||
|
|| 'data:text/html,<!DOCTYPE html><html><head><style>body{background:white;margin:0;}</style></head><body></body></html>';
|
||||||
|
const loadPromise = pageUrl.startsWith('file://')
|
||||||
|
? mainWindow!.loadURL(pageUrl)
|
||||||
|
: mainWindow!.loadURL(pageUrl);
|
||||||
// Give it time to load but don't wait forever
|
// Give it time to load but don't wait forever
|
||||||
await Promise.race([
|
await Promise.race([
|
||||||
loadPromise,
|
loadPromise,
|
||||||
|
|
|
||||||
|
|
@ -120,15 +120,13 @@ const compositorAPI: CompositorAPI = {
|
||||||
// Generic portal request event for client-provided popup/approval handlers
|
// Generic portal request event for client-provided popup/approval handlers
|
||||||
onPortalRequest: (callback: (data: {
|
onPortalRequest: (callback: (data: {
|
||||||
requestId: string;
|
requestId: string;
|
||||||
kind: string;
|
payload: any;
|
||||||
appName?: string;
|
kind?: string;
|
||||||
sessionId?: string;
|
|
||||||
}) => void) => {
|
}) => void) => {
|
||||||
const handler = (_event: Electron.IpcRendererEvent, data: {
|
const handler = (_event: Electron.IpcRendererEvent, data: {
|
||||||
requestId: string;
|
requestId: string;
|
||||||
kind: string;
|
payload: any;
|
||||||
appName?: string;
|
kind?: string;
|
||||||
sessionId?: string;
|
|
||||||
}) => callback(data);
|
}) => callback(data);
|
||||||
ipcRenderer.on('wo:portal-request', handler);
|
ipcRenderer.on('wo:portal-request', handler);
|
||||||
return () => ipcRenderer.removeListener('wo:portal-request', handler);
|
return () => ipcRenderer.removeListener('wo:portal-request', handler);
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"name": "@wl-wo/wo-types",
|
"name": "@wl-wo/wo-types",
|
||||||
"module": "index.ts",
|
"module": "index.ts",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "1.0.0",
|
"version": "1.0.1",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/bun": "latest"
|
"@types/bun": "latest"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
16
electron/types/types.d.ts
vendored
16
electron/types/types.d.ts
vendored
|
|
@ -88,7 +88,10 @@ export interface SyscallLogoutParams { [key: string]: any; }
|
||||||
export interface SyscallLockParams { [key: string]: any; }
|
export interface SyscallLockParams { [key: string]: any; }
|
||||||
export interface SyscallSleepParams { [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 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 SyscallLaunchResult { ok: boolean; pid?: number; error?: string; }
|
||||||
export interface SyscallExecResult { 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 SyscallSleepResult { ok: boolean; error?: string; }
|
||||||
export interface SyscallNotifyResult { ok: boolean; error?: string; }
|
export interface SyscallNotifyResult { ok: boolean; error?: string; }
|
||||||
export interface SyscallPortalRespondResult { 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 {
|
export interface PortalRequestEvent {
|
||||||
requestId: string;
|
requestId: string;
|
||||||
kind: string;
|
payload: any;
|
||||||
appName?: string;
|
kind?: string;
|
||||||
sessionId?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ScreencopyEvent {
|
export interface ScreencopyEvent {
|
||||||
|
|
@ -217,6 +222,9 @@ export interface Compositor {
|
||||||
syscall(type: 'sleep', params?: SyscallSleepParams): Promise<SyscallSleepResult>;
|
syscall(type: 'sleep', params?: SyscallSleepParams): Promise<SyscallSleepResult>;
|
||||||
syscall(type: 'notify', params: SyscallNotifyParams): Promise<SyscallNotifyResult>;
|
syscall(type: 'notify', params: SyscallNotifyParams): Promise<SyscallNotifyResult>;
|
||||||
syscall(type: 'portal_respond', params: SyscallPortalRespondParams): Promise<SyscallPortalRespondResult>;
|
syscall(type: 'portal_respond', params: SyscallPortalRespondParams): Promise<SyscallPortalRespondResult>;
|
||||||
|
syscall(type: 'dbus_call', params: SyscallDbusCallParams): Promise<SyscallDbusCallResult>;
|
||||||
|
syscall(type: 'dbus_get_property', params: SyscallDbusGetPropertyParams): Promise<SyscallDbusGetPropertyResult>;
|
||||||
|
syscall(type: 'load_local_file', params: SyscallLoadLocalFileParams): Promise<SyscallLoadLocalFileResult>;
|
||||||
syscall(type: string, params?: any): Promise<any>;
|
syscall(type: string, params?: any): Promise<any>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
48
electron/whatever.txt
Normal file
48
electron/whatever.txt
Normal file
|
|
@ -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 <FK23>
|
||||||
|
> The XKEYBOARD keymap compiler (xkbcomp) reports:
|
||||||
|
> Warning: Multiple symbols for level 1/group 1 on key <FK23>
|
||||||
|
> Using F23, ignoring XF86TouchpadOff
|
||||||
|
> Warning: Symbol map for key <FK23> redefined
|
||||||
|
> Using last definition for conflicting fields
|
||||||
|
> Warning: Symbol map for key <FK24> redefined
|
||||||
|
> Using last definition for conflicting fields
|
||||||
|
Using F23, ignoring XF86TouchpadOff
|
||||||
|
> Warning: Symbol map for key <FK23> redefined
|
||||||
|
> Using last definition for conflicting fields
|
||||||
|
> Warning: Symbol map for key <FK24> 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
|
||||||
|
|
@ -296,6 +296,8 @@ impl ElectronClientConnection {
|
||||||
|
|
||||||
// Get buffer properties
|
// Get buffer properties
|
||||||
let num_planes = dmabuf.num_planes();
|
let num_planes = dmabuf.num_planes();
|
||||||
|
let offsets: Vec<u32> = dmabuf.offsets().collect();
|
||||||
|
let strides: Vec<u32> = dmabuf.strides().collect();
|
||||||
let (w, h) = {
|
let (w, h) = {
|
||||||
let size = dmabuf.size();
|
let size = dmabuf.size();
|
||||||
(size.w as u32, size.h as u32)
|
(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)
|
// For each plane: fd(4) + offset(8) + stride(4) + modifier(8)
|
||||||
// Note: We'll collect actual plane data from dmabuf handles iterator
|
// Note: We'll collect actual plane data from dmabuf handles iterator
|
||||||
for _handle in dmabuf.handles() {
|
for plane_idx in 0..num_planes {
|
||||||
// fd: will be sent via ancillary data, so we put 0 as placeholder
|
// fd placeholder — actual fds are sent via SCM_RIGHTS ancillary data
|
||||||
buf[off..off + 4].copy_from_slice(&0u32.to_le_bytes());
|
buf[off..off + 4].copy_from_slice(&0u32.to_le_bytes());
|
||||||
off += 4;
|
off += 4;
|
||||||
// offset: 0 for now (can be extended later)
|
let offset = offsets.get(plane_idx).copied().unwrap_or(0);
|
||||||
buf[off..off + 8].copy_from_slice(&0u64.to_le_bytes());
|
buf[off..off + 8].copy_from_slice(&(offset as u64).to_le_bytes());
|
||||||
off += 8;
|
off += 8;
|
||||||
// stride: will depend on format (approximate)
|
let stride = strides.get(plane_idx).copied().unwrap_or(w * 4);
|
||||||
let stride = (w * 4) as u32; // ARGB8888 = 4 bytes/pixel, adjust as needed
|
|
||||||
buf[off..off + 4].copy_from_slice(&stride.to_le_bytes());
|
buf[off..off + 4].copy_from_slice(&stride.to_le_bytes());
|
||||||
off += 4;
|
off += 4;
|
||||||
// modifier (8 bytes) - DrmModifier converts to u64
|
// modifier (8 bytes) - DrmModifier converts to u64
|
||||||
|
|
@ -595,43 +596,30 @@ impl ElectronProcess {
|
||||||
let main_js = app_dir.join("dist/main.js");
|
let main_js = app_dir.join("dist/main.js");
|
||||||
|
|
||||||
let child = Command::new(electron_bin)
|
let child = Command::new(electron_bin)
|
||||||
.arg(&main_js)
|
|
||||||
.env("WO_IPC_SOCKET", ipc_socket)
|
.env("WO_IPC_SOCKET", ipc_socket)
|
||||||
.env("WO_WINDOW_CONFIG", &serialized)
|
.env("WO_WINDOW_CONFIG", &serialized)
|
||||||
.env("WO_DRM_RENDER_NODE", render_node)
|
.env("WO_DRM_RENDER_NODE", render_node)
|
||||||
// Wayland Ozone platform: Electron connects to our own Wayland
|
// ── Chromium flags ──────────────────────────────────────
|
||||||
// compositor (WAYLAND_DISPLAY is already set in the env) for
|
// These MUST appear before the app script on the command
|
||||||
// GPU/EGL initialisation. This gives Chromium a proper
|
// line. Electron treats everything after the script path
|
||||||
// wayland-egl display so hardware-accelerated rasterisation
|
// as application arguments (process.argv), NOT Chromium
|
||||||
// works. The BrowserWindow still uses `offscreen: true`, so
|
// switches. Flags here also reach the GPU subprocess
|
||||||
// no Wayland surfaces are mapped — the connection is used
|
// (critical for --in-process-gpu and --use-gl).
|
||||||
// solely for the EGL context.
|
|
||||||
//
|
//
|
||||||
// The previous `--ozone-platform=headless` approach failed
|
// Wayland Ozone platform: Electron connects to our own
|
||||||
// because headless Ozone has no EGL display, causing the GPU
|
// Wayland compositor (WAYLAND_DISPLAY is already set in
|
||||||
// subprocess to crash with "gl=none,angle=none not found" and
|
// the env) for GPU/EGL initialisation.
|
||||||
// silently falling back to ~1 FPS software rasterisation.
|
|
||||||
.arg("--ozone-platform=wayland")
|
.arg("--ozone-platform=wayland")
|
||||||
.arg("--no-sandbox")
|
.arg("--no-sandbox")
|
||||||
.arg("--disable-gpu-sandbox")
|
.arg("--disable-gpu-sandbox")
|
||||||
// Run GPU code in the main Electron process to avoid the
|
.arg("--use-gl=angle")
|
||||||
// separate GPU subprocess which adds IPC overhead and can
|
.arg("--use-angle=vulkan")
|
||||||
// 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("--disable-gpu-vsync")
|
.arg("--disable-gpu-vsync")
|
||||||
// Enable GPU-accelerated rasterization and zero-copy features
|
.arg("--enable-features=CanvasOopRasterization,Vulkan,VaapiVideoDecoder,RawDraw,SharedArrayBuffer,DefaultANGLEVulkan,VulkanFromANGLE")
|
||||||
// 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("--num-raster-threads=4")
|
.arg("--num-raster-threads=4")
|
||||||
// Don't throttle renderers that lose focus.
|
|
||||||
.arg("--disable-renderer-backgrounding")
|
.arg("--disable-renderer-backgrounding")
|
||||||
|
// ── App entry point (must come after Chromium flags) ────
|
||||||
|
.arg(&main_js)
|
||||||
.stdin(Stdio::null())
|
.stdin(Stdio::null())
|
||||||
.stdout(Stdio::inherit())
|
.stdout(Stdio::inherit())
|
||||||
.stderr(Stdio::inherit())
|
.stderr(Stdio::inherit())
|
||||||
|
|
|
||||||
|
|
@ -165,7 +165,7 @@ impl WoState {
|
||||||
self.pointer_location = new_pos;
|
self.pointer_location = new_pos;
|
||||||
|
|
||||||
// Process active grab (interactive move/resize) before normal dispatch
|
// 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 {
|
match grab {
|
||||||
GrabState::Move {
|
GrabState::Move {
|
||||||
window,
|
window,
|
||||||
|
|
@ -178,7 +178,18 @@ impl WoState {
|
||||||
initial_window_location.x + dx as i32,
|
initial_window_location.x + dx as i32,
|
||||||
initial_window_location.y + dy 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.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 {
|
GrabState::Resize {
|
||||||
surface,
|
surface,
|
||||||
|
|
@ -192,11 +203,11 @@ impl WoState {
|
||||||
let dx = (self.pointer_location.x - initial_pointer.x) as i32;
|
let dx = (self.pointer_location.x - initial_pointer.x) as i32;
|
||||||
let dy = (self.pointer_location.y - initial_pointer.y) 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) =
|
let (mut new_x, mut new_y) =
|
||||||
(initial_window_location.x, initial_window_location.y);
|
(initial_window_location.x, initial_window_location.y);
|
||||||
|
|
||||||
match *edges {
|
match edges {
|
||||||
ResizeEdge::Right | ResizeEdge::TopRight | ResizeEdge::BottomRight => {
|
ResizeEdge::Right | ResizeEdge::TopRight | ResizeEdge::BottomRight => {
|
||||||
new_w = (new_w + dx).max(1);
|
new_w = (new_w + dx).max(1);
|
||||||
}
|
}
|
||||||
|
|
@ -206,7 +217,7 @@ impl WoState {
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
match *edges {
|
match edges {
|
||||||
ResizeEdge::Bottom | ResizeEdge::BottomLeft | ResizeEdge::BottomRight => {
|
ResizeEdge::Bottom | ResizeEdge::BottomLeft | ResizeEdge::BottomRight => {
|
||||||
new_h = (new_h + dy).max(1);
|
new_h = (new_h + dy).max(1);
|
||||||
}
|
}
|
||||||
|
|
@ -218,14 +229,24 @@ impl WoState {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Respect client min/max size constraints.
|
// 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| {
|
surface.with_pending_state(|s| {
|
||||||
s.size = Some((clamped_w, clamped_h).into());
|
s.size = Some((clamped_w, clamped_h).into());
|
||||||
});
|
});
|
||||||
surface.send_configure();
|
surface.send_configure();
|
||||||
|
let prev_loc = self
|
||||||
|
.space
|
||||||
|
.element_location(&window)
|
||||||
|
.unwrap_or(initial_window_location);
|
||||||
self.space
|
self.space
|
||||||
.map_element(window.clone(), (new_x, new_y), false);
|
.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;
|
return;
|
||||||
|
|
@ -243,7 +264,7 @@ impl WoState {
|
||||||
self.pointer_location = new_pos;
|
self.pointer_location = new_pos;
|
||||||
|
|
||||||
// Process active grab (interactive move/resize) before normal dispatch
|
// 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 {
|
match grab {
|
||||||
GrabState::Move {
|
GrabState::Move {
|
||||||
window,
|
window,
|
||||||
|
|
@ -256,7 +277,17 @@ impl WoState {
|
||||||
initial_window_location.x + dx as i32,
|
initial_window_location.x + dx as i32,
|
||||||
initial_window_location.y + dy 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.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 {
|
GrabState::Resize {
|
||||||
surface,
|
surface,
|
||||||
|
|
@ -270,11 +301,11 @@ impl WoState {
|
||||||
let dx = (self.pointer_location.x - initial_pointer.x) as i32;
|
let dx = (self.pointer_location.x - initial_pointer.x) as i32;
|
||||||
let dy = (self.pointer_location.y - initial_pointer.y) 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) =
|
let (mut new_x, mut new_y) =
|
||||||
(initial_window_location.x, initial_window_location.y);
|
(initial_window_location.x, initial_window_location.y);
|
||||||
|
|
||||||
match *edges {
|
match edges {
|
||||||
ResizeEdge::Right | ResizeEdge::TopRight | ResizeEdge::BottomRight => {
|
ResizeEdge::Right | ResizeEdge::TopRight | ResizeEdge::BottomRight => {
|
||||||
new_w = (new_w + dx).max(1);
|
new_w = (new_w + dx).max(1);
|
||||||
}
|
}
|
||||||
|
|
@ -284,7 +315,7 @@ impl WoState {
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
match *edges {
|
match edges {
|
||||||
ResizeEdge::Bottom | ResizeEdge::BottomLeft | ResizeEdge::BottomRight => {
|
ResizeEdge::Bottom | ResizeEdge::BottomLeft | ResizeEdge::BottomRight => {
|
||||||
new_h = (new_h + dy).max(1);
|
new_h = (new_h + dy).max(1);
|
||||||
}
|
}
|
||||||
|
|
@ -296,14 +327,24 @@ impl WoState {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Respect client min/max size constraints.
|
// 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| {
|
surface.with_pending_state(|s| {
|
||||||
s.size = Some((clamped_w, clamped_h).into());
|
s.size = Some((clamped_w, clamped_h).into());
|
||||||
});
|
});
|
||||||
surface.send_configure();
|
surface.send_configure();
|
||||||
|
let prev_loc = self
|
||||||
|
.space
|
||||||
|
.element_location(&window)
|
||||||
|
.unwrap_or(initial_window_location);
|
||||||
self.space
|
self.space
|
||||||
.map_element(window.clone(), (new_x, new_y), false);
|
.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;
|
return;
|
||||||
|
|
|
||||||
21
src/main.rs
21
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);
|
std::env::set_var("WAYLAND_DISPLAY", &config.compositor.socket_name);
|
||||||
// Propagate now; DISPLAY will be re-propagated once XWayland is ready.
|
// Propagate now; DISPLAY will be re-propagated once XWayland is ready.
|
||||||
crate::state::propagate_environment(&["WAYLAND_DISPLAY"]);
|
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 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
|
// Register the Wayland display fd with calloop so that client messages
|
||||||
// (surface commits, etc.) wake the event loop. Without this, the loop
|
// (surface commits, etc.) wake the event loop. Without this, the loop
|
||||||
// only wakes on DRM VBlank / libinput / session events and rendering
|
// 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(|p| p.get("y"))
|
||||||
.and_then(|v| v.as_i64())
|
.and_then(|v| v.as_i64())
|
||||||
.unwrap_or(0) as i32;
|
.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" => {
|
"resize" => {
|
||||||
let new_w = payload_json.as_ref()
|
let new_w = payload_json.as_ref()
|
||||||
|
|
|
||||||
|
|
@ -1310,7 +1310,14 @@ fn process_electron_message(
|
||||||
.unwrap_or(0) as i32;
|
.unwrap_or(0) as i32;
|
||||||
// comraw reports the MacWindow origin (title bar top);
|
// comraw reports the MacWindow origin (title bar top);
|
||||||
// the Wayland surface sits th pixels below that.
|
// 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" => {
|
"resize" => {
|
||||||
let new_w = payload_json
|
let new_w = payload_json
|
||||||
|
|
|
||||||
61
src/state.rs
61
src/state.rs
|
|
@ -19,7 +19,7 @@ use smithay::{
|
||||||
relative_pointer::RelativePointerManagerState,
|
relative_pointer::RelativePointerManagerState,
|
||||||
pointer_constraints::{self, PointerConstraintsHandler, PointerConstraintsState},
|
pointer_constraints::{self, PointerConstraintsHandler, PointerConstraintsState},
|
||||||
keyboard_shortcuts_inhibit::{KeyboardShortcutsInhibitHandler, KeyboardShortcutsInhibitState, KeyboardShortcutsInhibitor},
|
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},
|
xwayland::{XWayland, xwm::X11Wm},
|
||||||
};
|
};
|
||||||
|
|
@ -558,6 +558,65 @@ impl WoState {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the stable parent name (Wayland or X11) for a window, if any.
|
||||||
|
pub fn parent_name_for_window(&self, window: &Window) -> Option<String> {
|
||||||
|
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::<XdgToplevelSurfaceData>()
|
||||||
|
.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).
|
/// Find a Wayland or X11 Window element by its stable name (even if minimized).
|
||||||
pub fn find_wayland_window(&self, name: &str) -> Option<Window> {
|
pub fn find_wayland_window(&self, name: &str) -> Option<Window> {
|
||||||
self.all_windows.iter().find(|w| {
|
self.all_windows.iter().find(|w| {
|
||||||
|
|
|
||||||
524
whatever.txt
524
whatever.txt
|
|
@ -1,337 +1,7 @@
|
||||||
warning: unused import: `Buffer as BufferCoord`
|
Compiling wo v0.1.0 (/home/hellings/Documents/wo)
|
||||||
--> src/cursor.rs:10:22
|
Compiling wo v0.1.0 (/home/hellings/Documents/wo)
|
||||||
|
|
Finished `release` profile [optimized] target(s) in 2m 21s
|
||||||
10 | use smithay::utils::{Buffer as BufferCoord, Size};
|
Finished `release` profile [optimized] target(s) in 2m 21s
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
|
||||||
= 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::<N, Kind>::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::<N, Kind>::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::<N, Kind>::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::<N, Kind>::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<B>,
|
|
||||||
| ^^^^^ 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<B>,
|
|
||||||
| ^^^^^ 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<i32, Physical>) -> Self {
|
|
||||||
| ^^^
|
|
||||||
|
|
||||||
| impl Frame {
|
|
||||||
| ---------- associated function in this implementation
|
|
||||||
45 | pub fn new(output_rect: Rectangle<i32, Physical>) -> 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
|
|
||||||
Running `target/release/wo`
|
Running `target/release/wo`
|
||||||
Running `target/release/wo`
|
Running `target/release/wo`
|
||||||
Xwayland glamor: GBM Wayland interfaces not available
|
Xwayland glamor: GBM Wayland interfaces not available
|
||||||
|
|
@ -374,73 +44,179 @@ The XKEYBOARD keymap compiler (xkbcomp) reports:
|
||||||
> Using 0, ignoring 0
|
> Using 0, ignoring 0
|
||||||
Errors from xkbcomp are not fatal to the X server
|
Errors from xkbcomp are not fatal to the X server
|
||||||
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)].
|
Authorization required, but no authorization protocol specified
|
||||||
[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
|
Authorization required, but no authorization protocol specified
|
||||||
[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)].
|
Authorization required, but no authorization protocol specified
|
||||||
[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
|
Authorization required, but no authorization protocol specified
|
||||||
[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)].
|
Gtk-Message: 13:58:16.908: Failed to load module "appmenu-gtk-module"
|
||||||
[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)].
|
Gtk-Message: 13:58:16.908: Failed to load module "appmenu-gtk-module"
|
||||||
[75966:0310/190621.261808:ERROR:components/viz/service/main/viz_main_impl.cc:189] Exiting GPU process due to errors during initialization
|
Authorization required, but no authorization protocol specified
|
||||||
[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.
|
Authorization required, but no authorization protocol specified
|
||||||
(Use `electron --trace-deprecation ...` to show where the warning was created)
|
|
||||||
(node:75859) DeprecationWarning: getBitmap() is deprecated, use toBitmap() instead.
|
[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
|
||||||
(Use `electron --trace-deprecation ...` to show where the warning was created)
|
[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
|
||||||
Error sending from webFrameMain: Error: Failed to serialize arguments
|
[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 s.send (node:electron/js2c/browser_init:2:100266)
|
||||||
at b.send (node:electron/js2c/browser_init:2:84687)
|
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.<anonymous> (file:///home/hellings/Documents/wo/electron/dist/main.js:1213:36)
|
||||||
at Socket.<anonymous> (file:///home/hellings/Documents/wo/electron/dist/main.js:1251:30)
|
|
||||||
at Socket.emit (node:events:519:28)
|
at Socket.emit (node:events:519:28)
|
||||||
at addChunk (node:internal/streams/readable:561:12)
|
at addChunk (node:internal/streams/readable:561:12)
|
||||||
at readableAddChunkPushByteMode (node:internal/streams/readable:512:3)
|
at readableAddChunkPushByteMode (node:internal/streams/readable:512:3)
|
||||||
at Readable.push (node:internal/streams/readable:392:5)
|
at Readable.push (node:internal/streams/readable:392:5)
|
||||||
at Pipe.onStreamRead (node:internal/stream_base_commons:189:23)
|
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 s.send (node:electron/js2c/browser_init:2:100266)
|
||||||
at b.send (node:electron/js2c/browser_init:2:84687)
|
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.<anonymous> (file:///home/hellings/Documents/wo/electron/dist/main.js:1213:36)
|
||||||
at Socket.<anonymous> (file:///home/hellings/Documents/wo/electron/dist/main.js:1251:30)
|
|
||||||
at Socket.emit (node:events:519:28)
|
at Socket.emit (node:events:519:28)
|
||||||
at addChunk (node:internal/streams/readable:561:12)
|
at addChunk (node:internal/streams/readable:561:12)
|
||||||
at readableAddChunkPushByteMode (node:internal/streams/readable:512:3)
|
at readableAddChunkPushByteMode (node:internal/streams/readable:512:3)
|
||||||
at Readable.push (node:internal/streams/readable:392:5)
|
at Readable.push (node:internal/streams/readable:392:5)
|
||||||
at Pipe.onStreamRead (node:internal/stream_base_commons:189:23)
|
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 s.send (node:electron/js2c/browser_init:2:100266)
|
||||||
at b.send (node:electron/js2c/browser_init:2:84687)
|
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.<anonymous> (file:///home/hellings/Documents/wo/electron/dist/main.js:1235:40)
|
||||||
at Socket.<anonymous> (file:///home/hellings/Documents/wo/electron/dist/main.js:1251:30)
|
|
||||||
at Socket.emit (node:events:519:28)
|
at Socket.emit (node:events:519:28)
|
||||||
at addChunk (node:internal/streams/readable:561:12)
|
at addChunk (node:internal/streams/readable:561:12)
|
||||||
at readableAddChunkPushByteMode (node:internal/streams/readable:512:3)
|
at readableAddChunkPushByteMode (node:internal/streams/readable:512:3)
|
||||||
at Readable.push (node:internal/streams/readable:392:5)
|
at Readable.push (node:internal/streams/readable:392:5)
|
||||||
at Pipe.onStreamRead (node:internal/stream_base_commons:189:23)
|
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 s.send (node:electron/js2c/browser_init:2:100266)
|
||||||
at b.send (node:electron/js2c/browser_init:2:84687)
|
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.<anonymous> (file:///home/hellings/Documents/wo/electron/dist/main.js:1235:40)
|
||||||
at Socket.<anonymous> (file:///home/hellings/Documents/wo/electron/dist/main.js:1251:30)
|
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.<anonymous> (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.<anonymous> (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.<anonymous> (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.<anonymous> (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.<anonymous> (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.<anonymous> (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.<anonymous> (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.<anonymous> (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.<anonymous> (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.<anonymous> (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.<anonymous> (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.<anonymous> (file:///home/hellings/Documents/wo/electron/dist/main.js:1235:40)
|
||||||
at Socket.emit (node:events:519:28)
|
at Socket.emit (node:events:519:28)
|
||||||
at addChunk (node:internal/streams/readable:561:12)
|
at addChunk (node:internal/streams/readable:561:12)
|
||||||
at readableAddChunkPushByteMode (node:internal/streams/readable:512:3)
|
at readableAddChunkPushByteMode (node:internal/streams/readable:512:3)
|
||||||
at Readable.push (node:internal/streams/readable:392:5)
|
at Readable.push (node:internal/streams/readable:392:5)
|
||||||
at Pipe.onStreamRead (node:internal/stream_base_commons:189:23)
|
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
|
||||||
(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
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue