sdl3/examples/multi_process_windows.php
2025-10-25 22:04:24 +02:00

161 lines
4.1 KiB
PHP

<?php
/**
* Multi-Process Window Example
*
* Each window runs in a separate process (not thread!)
* This works because each process has its own main thread for OpenGL
*/
require_once __DIR__ . '/../vendor/autoload.php';
use PHPNative\Framework\Application;
use PHPNative\Ui\Widget\Button;
use PHPNative\Ui\Widget\Container;
use PHPNative\Ui\Widget\Label;
// Check if we're the main process or a child
$windowId = $argv[1] ?? null;
if ($windowId === null) {
// MAIN PROCESS - Launch child processes
echo "Main Process: Launching 2 window processes...\n\n";
$pids = [];
// Launch Window 1 process
$pid1 = pcntl_fork();
if ($pid1 == -1) {
die("Could not fork for Window 1\n");
} elseif ($pid1 == 0) {
// Child process 1
runWindow('1', 'Window 1 - Blue', 100, 100, 'blue');
exit(0);
} else {
$pids[] = $pid1;
echo "Main Process: Window 1 started with PID $pid1\n";
}
// Small delay to avoid race conditions
usleep(100000);
// Launch Window 2 process
$pid2 = pcntl_fork();
if ($pid2 == -1) {
die("Could not fork for Window 2\n");
} elseif ($pid2 == 0) {
// Child process 2
runWindow('2', 'Window 2 - Green', 550, 100, 'green');
exit(0);
} else {
$pids[] = $pid2;
echo "Main Process: Window 2 started with PID $pid2\n";
}
echo "\nMain Process: Both windows launched!\n";
echo "Main Process: Waiting for child processes to exit...\n\n";
// Wait for all child processes
foreach ($pids as $pid) {
$status = 0;
pcntl_waitpid($pid, $status);
echo "Main Process: Child process $pid exited\n";
}
echo "\nMain Process: All windows closed. Exiting.\n";
} else {
// This shouldn't happen in fork mode
die("Error: Unexpected command line argument\n");
}
/**
* Run a single window in this process
*/
function runWindow(string $id, string $title, int $x, int $y, string $bgColor): void
{
echo "Process $id: Creating window '$title'\n";
// Create application
$app = new Application();
// Create window
$window = $app->createWindow($title, 400, 350, $x, $y);
// Create UI
$container = new Container("flex flex-col p-6 gap-4 bg-$bgColor-100");
$titleLabel = new Label(
text: $title,
style: "text-2xl text-$bgColor-900"
);
$processLabel = new Label(
text: 'Process ID: ' . getmypid(),
style: "text-sm text-$bgColor-700"
);
$frameLabel = new Label(
text: 'Frame: 0',
style: "text-base text-$bgColor-600"
);
$button = new Button(
text: 'Click Me!',
style: "bg-$bgColor-500 hover:bg-$bgColor-700 text-white p-4 rounded-lg"
);
$clickCount = 0;
$button->setOnClick(function() use (&$clickCount, $button, $title) {
$clickCount++;
$button->setText("Clicked $clickCount times");
echo "$title - Button clicked! Count: $clickCount\n";
});
$closeButton = new Button(
text: 'Close Window',
style: "bg-red-500 hover:bg-red-700 text-white p-3 rounded"
);
$closeButton->setOnClick(function() use ($window) {
echo "Close button clicked!\n";
$window->close();
});
$container->addComponent($titleLabel);
$container->addComponent($processLabel);
$container->addComponent($frameLabel);
$container->addComponent($button);
$container->addComponent($closeButton);
$window->setRoot($container);
echo "Process $id: Starting event loop\n";
// Run the window
$frameCount = 0;
while (!$window->shouldClose()) {
$frameCount++;
$frameLabel->setText("Frame: $frameCount");
$window->layout();
// Poll events
rgfw_pollEvents();
$window->handleEvents();
// Update
\PHPNative\Async\TaskManager::getInstance()->update();
$window->update();
// Render
$window->render();
// ~60 FPS
usleep(16666);
}
// Cleanup
echo "Process $id: Window closed after $frameCount frames\n";
$window->cleanup();
}