Enhance multimonitor support.

This commit is contained in:
SimonFair
2025-06-20 22:31:54 +01:00
parent 24c19f265a
commit 2cb0791a2c
2 changed files with 73 additions and 5 deletions

View File

@@ -742,6 +742,7 @@ class Libvirt {
if ($strProtocol == "spice") $virtualaudio = "spice"; else $virtualaudio = "none";
$strEGLHeadless = "";
$strAccel3d ="";
$additionalqxlheads = "";
if ($strModelType == "virtio3d") {
$strModelType = "virtio";
if (!isset($gpu['render'])) $gpu['render'] = "auto";
@@ -756,6 +757,29 @@ class Libvirt {
if ($strModelType == "qxl") {
if (empty($gpu['DisplayOptions'])) $gpu['DisplayOptions'] ="ram='65536' vram='16384' vgamem='16384' heads='1' primary='yes'";
$strDisplayOptions = $gpu['DisplayOptions'];
preg_match_all("/(\w+)='([^']+)'/", $strDisplayOptions, $headmatches, PREG_SET_ORDER);
$headparams = [];
foreach ($headmatches as $headmatch) {
$headparams[$headmatch[1]] = $headmatch[2];
}
// Default heads to 1 if not found
$qxlheads = isset($headparams['heads']) ? (int)$headparams['heads'] : 1;
$additionalqxlheads= '';
if ($os_type == "windows") {
for ($i = 0; $i < $qxlheads - 1; $i++) {
$function = '0x' . dechex($i + 1);
$qxlvideo = <<<XML
<video>
<model type='qxl' ram='{$headparams['ram']}' vram='{$headparams['vram']}' vgamem='{$headparams['vgamem']}' heads='1'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x1e' function='$function'/>
</video>
XML;
$additionalqxlheads .= $qxlvideo;
}
}
}
$vmrc = "<input type='tablet' bus='usb'/>
<input type='mouse' bus='ps2'/>
@@ -771,13 +795,16 @@ class Libvirt {
</model>
<address type='pci' domain='0x0000' bus='0x00' slot='0x1e' function='0x0'/>
</video>
$additionalqxlheads
<audio id='1' type='$virtualaudio'/>";
if ($gpu['copypaste'] == "yes") {
if ($strProtocol == "spice") {
if ($strProtocol == "spice") {
if ($gpu['copypaste'] == "yes" || $qxlheads > 1) {
$channelscopypaste = "<channel type='spicevmc'>
<target type='virtio' name='com.redhat.spice.0'/>
</channel>";
} else {
}
} else {
if ($gpu['copypaste'] == "yes") {
$channelscopypaste = "<channel type='qemu-vdagent'>
<source>
<clipboard copypaste='yes'/>
@@ -786,7 +813,7 @@ class Libvirt {
<target type='virtio' name='com.redhat.spice.0'/>
</channel>";
}
} else $channelcopypaste = "";
}
continue;
}
[$gpu_bus, $gpu_slot, $gpu_function] = my_explode(":", str_replace('.', ':', $gpu['id']), 3);

View File

@@ -353,6 +353,10 @@ if ($snapshots!=null && count($snapshots) && !$boolNew) {
<!--<input type="hidden" name="template[oldstorage]" id="storage_oldname" value="<?=htmlspecialchars($arrConfig['template']['storage'])?>"> -->
<input type="hidden" name="domain[memoryBacking]" id="domain_memorybacking" value="<?=htmlspecialchars($arrConfig['domain']['memoryBacking'])?>">
<script>
const displayOptions = <?= json_encode($arrDisplayOptions, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT) ?>;
</script>
<table>
<tr class="<?=$snaphidden?>">
<td></td>
@@ -1327,7 +1331,10 @@ foreach ($arrConfig['shares'] as $i => $arrShare) {
<span id="vncdspopttext" class="label <?=$vncdspopt?>">_(Display(s) and RAM)_:</span>
<select id="vncdspopt" name="gpu[<?=$i?>][DisplayOptions]" class="second <?=$vncdspopt?>">
<?
foreach ($arrDisplayOptions as $key => $value) echo mk_option($arrGPU['DisplayOptions'], htmlentities($value['qxlxml'],ENT_QUOTES), _($value['text']));
foreach ($arrDisplayOptions as $key => $value) {
if ($arrGPU['protocol'] == 'vnc' && substr($key,0,2) != "H1") continue;
echo mk_option($arrGPU['DisplayOptions'], htmlentities($value['qxlxml'],ENT_QUOTES), _($value['text']));
}
?>
</select>
</td>
@@ -2218,6 +2225,40 @@ function ProtocolChange(protocol) {
$("wsport").addClass('hidden');
$("WSPorttext").addClass('hidden');
}
const select = document.getElementById('vncdspopt');
const currentValue = select.value;
// Clear all options
select.innerHTML = '';
let foundMatch = false;
for (const key in displayOptions) {
const opt = displayOptions[key];
const xml = opt.qxlxml;
const headsMatch = xml.match(/heads='(\d+)'/);
const heads = headsMatch ? parseInt(headsMatch[1]) : 1;
// Only show heads=1 options if protocol is vnc
if (protocol.value === 'vnc' && heads !== 1) continue;
const optionEl = document.createElement('option');
optionEl.value = xml;
optionEl.textContent = opt.text;
if (!foundMatch && xml === currentValue) {
optionEl.selected = true;
foundMatch = true;
}
select.appendChild(optionEl);
}
// If selected value no longer exists, select the first one
if (!foundMatch && select.options.length > 0) {
select.options[0].selected = true;
}
}
function wlan0_info() {