Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion .github/workflows/shared-testing-linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,15 @@ jobs:

eval "$(dbus-launch --sh-syntax)"

export GDK_BACKEND=x11
export NO_AT_BRIDGE=1
export GALLIUM_DRIVER=llvmpipe
export LIBGL_ALWAYS_SOFTWARE=1
export LIBGL_DRI3_DISABLE=1
export MESA_LOADER_DRIVER_OVERRIDE=llvmpipe
export WEBKIT_DISABLE_COMPOSITING_MODE=1
export WEBKIT_DISABLE_DMABUF_RENDERER=1

echo "Launching Xvfb..."
Xvfb :99 \
-screen 0 1920x1080x24 \
Expand Down Expand Up @@ -176,7 +185,19 @@ jobs:
dotnet test --solution InfiniFrame.GitHubActions.Testing.slnf \
--configuration Release \
--no-build \
--no-restore
--no-restore \
-m:1 \
/p:TestTfmsInParallel=false || {
test_exit=$?
echo "=== Test command failed with exit code ${test_exit} ==="
echo "=== Xvfb log ==="
cat xvfb.log || true
echo "=== Mutter log ==="
cat mutter.log || true
echo "=== Process snapshot ==="
ps aux | grep -E '([X]vfb|[m]utter|[d]otnet|[W]ebKit)' || true
exit "${test_exit}"
}

- name: Pack Tool E2E
if: always()
Expand Down
10 changes: 0 additions & 10 deletions .github/workflows/shared-testing-windows-playwright.yml
Original file line number Diff line number Diff line change
Expand Up @@ -126,16 +126,6 @@ jobs:
cache: 'npm'
cache-dependency-path: '**/package-lock.json'

- name: Prepare WebView2 Cache Directory
shell: pwsh
run: New-Item -ItemType Directory -Path ".cache\webview2" -Force | Out-Null

- name: Cache WebView2
uses: actions/cache@v5
with:
path: .cache\webview2
key: webview2-installer-${{ runner.os }}-v1

- name: Install WebView2 Runtime
shell: pwsh
run: |
Expand Down
1 change: 1 addition & 0 deletions InfiniFrame.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
<File Path=".github/workflows/shared-testing.yml" />
</Folder>
<Folder Name="/.dev-tools/scripts/">
<File Path="scripts/BuildFrontend.mjs" />
<File Path="scripts/clion-linux-environment.sh" />
<File Path="scripts/docker-linux-compose.sh" />
<File Path="scripts/docker-linux-run-blazorwebview.sh" />
Expand Down
7 changes: 7 additions & 0 deletions docker/infiniframe-linux/common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,14 @@ start_virtual_display() {
setup_display_mode() {
local xvfb_log="${1:-/tmp/xvfb.log}"
local mutter_log="${2:-/tmp/mutter.log}"
export GDK_BACKEND="${GDK_BACKEND:-x11}"
export NO_AT_BRIDGE="${NO_AT_BRIDGE:-1}"
export GALLIUM_DRIVER="${GALLIUM_DRIVER:-llvmpipe}"
export LIBGL_ALWAYS_SOFTWARE="${LIBGL_ALWAYS_SOFTWARE:-1}"
export LIBGL_DRI3_DISABLE="${LIBGL_DRI3_DISABLE:-1}"
export MESA_LOADER_DRIVER_OVERRIDE="${MESA_LOADER_DRIVER_OVERRIDE:-llvmpipe}"
export WEBKIT_DISABLE_COMPOSITING_MODE="${WEBKIT_DISABLE_COMPOSITING_MODE:-1}"
export WEBKIT_DISABLE_DMABUF_RENDERER="${WEBKIT_DISABLE_DMABUF_RENDERER:-1}"
start_dbus_session

if [[ "${USE_HOST_DISPLAY}" == "1" ]]; then
Expand Down
13 changes: 12 additions & 1 deletion docker/infiniframe-linux/tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,15 @@ dotnet test --solution "${SOLUTION_FILTER}" \
--no-build \
--no-restore \
/p:UseAppHost=false \
"${COMMON_DOTNET_PROPS[@]}"
/p:TestTfmsInParallel=false \
"${COMMON_DOTNET_PROPS[@]}" || {
test_exit=$?
echo "=== Test command failed with exit code ${test_exit} ==="
echo "=== Xvfb log ==="
cat /tmp/xvfb.log || true
echo "=== Mutter log ==="
cat /tmp/mutter.log || true
echo "=== Process snapshot ==="
ps aux | grep -E '([X]vfb|[m]utter|[d]otnet|[W]ebKit)' || true
exit "${test_exit}"
}
83 changes: 42 additions & 41 deletions docs/docs/migration/photino-backlog.md

Large diffs are not rendered by default.

150 changes: 150 additions & 0 deletions scripts/BuildFrontend.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import {spawnSync} from 'node:child_process';
import {
existsSync,
mkdirSync,
readdirSync,
readFileSync,
rmSync,
statSync,
writeFileSync,
} from 'node:fs';
import path from 'node:path';

const [, , appDirectoryArg, stampFileArg, outputFileArg] = process.argv;

if (!appDirectoryArg || !stampFileArg || !outputFileArg) {
console.error('Usage: node BuildFrontend.mjs <app-directory> <stamp-file> <output-file>');
process.exit(1);
}

const appDirectory = path.resolve(appDirectoryArg);
const stampFile = path.resolve(stampFileArg);
const outputFile = path.resolve(outputFileArg);
const lockDirectory = `${stampFile}.lock`;
const sourceExclusions = new Set(['node_modules', '.git']);

function sleep(milliseconds) {
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, milliseconds);
}

function isProcessRunning(processId) {
if (!Number.isInteger(processId) || processId <= 0) {
return false;
}

try {
process.kill(processId, 0);
return true;
} catch {
return false;
}
}

function shouldRemoveExistingLock() {
const ownerFile = path.join(lockDirectory, 'owner.txt');

if (existsSync(ownerFile)) {
const ownerProcessId = Number.parseInt(readFileSync(ownerFile, 'utf8'), 10);
if (!isProcessRunning(ownerProcessId)) {
return true;
}
}

const lockAgeMilliseconds = Date.now() - statSync(lockDirectory).mtimeMs;
return lockAgeMilliseconds > 60 * 1000;
}

function acquireLock() {
mkdirSync(path.dirname(stampFile), {recursive: true});

const startedAt = Date.now();
while (true) {
try {
mkdirSync(lockDirectory);
writeFileSync(path.join(lockDirectory, 'owner.txt'), `${process.pid}\n`, 'utf8');
return;
} catch (error) {
if (error?.code !== 'EEXIST') {
throw error;
}

if (shouldRemoveExistingLock()) {
rmSync(lockDirectory, {recursive: true, force: true});
continue;
}

if (Date.now() - startedAt > 2 * 60 * 1000) {
throw new Error(`Timed out waiting for frontend build lock: ${lockDirectory}`);
}

sleep(250);
}
}
}

function getLatestSourceWriteTime(directory) {
let latest = statSync(directory).mtimeMs;

for (const entry of readdirSync(directory, {withFileTypes: true})) {
if (sourceExclusions.has(entry.name)) {
continue;
}

const entryPath = path.join(directory, entry.name);
const entryStats = statSync(entryPath);
latest = Math.max(latest, entryStats.mtimeMs);

if (entry.isDirectory()) {
latest = Math.max(latest, getLatestSourceWriteTime(entryPath));
}
}

return latest;
}

function isBuildCurrent() {
if (!existsSync(stampFile) || !existsSync(outputFile)) {
return false;
}

return statSync(stampFile).mtimeMs >= getLatestSourceWriteTime(appDirectory);
}

function runNpm(args) {
const npmCommand = process.platform === 'win32' ? 'cmd.exe' : 'npm';
const npmArgs = process.platform === 'win32'
? ['/d', '/s', '/c', 'npm', ...args]
: args;

const result = spawnSync(npmCommand, npmArgs, {
cwd: appDirectory,
stdio: 'inherit',
});

if (result.error) {
console.error(result.error.message);
process.exit(1);
}

if (result.status !== 0) {
process.exit(result.status ?? 1);
}
}

acquireLock();

try {
if (isBuildCurrent()) {
console.log('Frontend build output is current.');
process.exit(0);
}

if (process.env.CI === 'true') {
runNpm(['ci']);
}

runNpm(['run', 'build']);
writeFileSync(stampFile, `${new Date().toISOString()}\n`, 'utf8');
} finally {
rmSync(lockDirectory, {recursive: true, force: true});
}
2 changes: 1 addition & 1 deletion scripts/clion-linux-environment.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/bash
#!/bin/bash
set -e

echo "Updating package lists..."
Expand Down
2 changes: 1 addition & 1 deletion scripts/docker-linux-compose.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env bash
#!/usr/bin/env bash
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
Expand Down
5 changes: 5 additions & 0 deletions src/InfiniFrame.Native/Core/InfiniFrameWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ class InfiniFrameWindow {
/** @brief Close the window and terminate the message loop */
void Close();

#ifdef __linux__
/** @brief Request close from a GTK delete-event handler */
[[nodiscard]] bool RequestClose();
#endif

// -----------------------------------------------------------------------------------------------------------------
// Get Properties
// -----------------------------------------------------------------------------------------------------------------
Expand Down
Loading
Loading