diff --git a/virtscreen/assets/AppWindow.qml b/virtscreen/assets/AppWindow.qml
index 2bf9e6a..f013b64 100644
--- a/virtscreen/assets/AppWindow.qml
+++ b/virtscreen/assets/AppWindow.qml
@@ -277,6 +277,17 @@ ApplicationWindow {
}
}
+ Loader {
+ id: displayOptionsLoader
+ active: false
+ source: "DisplayOptionsDialog.qml"
+ onLoaded: {
+ item.onClosed.connect(function() {
+ displayOptionsLoader.active = false;
+ });
+ }
+ }
+
Loader {
id: vncOptionsLoader
active: false
diff --git a/virtscreen/assets/DisplayOptionsDialog.qml b/virtscreen/assets/DisplayOptionsDialog.qml
new file mode 100644
index 0000000..e242ee4
--- /dev/null
+++ b/virtscreen/assets/DisplayOptionsDialog.qml
@@ -0,0 +1,70 @@
+import QtQuick 2.10
+import QtQuick.Controls 2.3
+import QtQuick.Controls.Material 2.3
+import QtQuick.Layouts 1.3
+
+Dialog {
+ title: "Display Options"
+ focus: true
+ modal: true
+ visible: true
+ standardButtons: Dialog.Ok
+ x: (window.width - width) / 2
+ y: (window.width - height) / 2
+ width: popupWidth
+ height: 250
+
+ ColumnLayout {
+ anchors.fill: parent
+
+ RowLayout {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ Label { id: deviceLabel; text: "Device"; }
+ ComboBox {
+ id: deviceComboBox
+ anchors.left: deviceLabel.right
+ anchors.right: parent.right
+ anchors.leftMargin: 100
+ textRole: "name"
+ model: backend.screens
+ currentIndex: {
+ if (settings.virt.device) {
+ for (var i = 0; i < model.length; i++) {
+ if (model[i].name == settings.virt.device) {
+ return i;
+ }
+ }
+ }
+ settings.virt.device = '';
+ return -1;
+ }
+ onActivated: function(index) {
+ settings.virt.device = model[index].name;
+ }
+ delegate: ItemDelegate {
+ width: deviceComboBox.width
+ text: modelData.name
+ font.weight: deviceComboBox.currentIndex === index ? Font.Bold : Font.Normal
+ enabled: modelData.connected ? false : true
+ }
+ }
+ }
+
+ Text {
+ font { pointSize: 10 }
+ wrapMode: Text.WordWrap
+ text: "Warning: Edit only if 'VIRTUAL1' is not available
" +
+ "If so, please note that the virtual screen may be
" +
+ "unstable/unavailable depending on a graphic
" +
+ "card and its driver."
+ }
+
+ RowLayout {
+ // Empty layout
+ Layout.fillHeight: true
+ }
+ }
+ onAccepted: {}
+ onRejected: {}
+}
diff --git a/virtscreen/assets/DisplayPage.qml b/virtscreen/assets/DisplayPage.qml
index b71ac0b..393a00e 100644
--- a/virtscreen/assets/DisplayPage.qml
+++ b/virtscreen/assets/DisplayPage.qml
@@ -59,26 +59,14 @@ ColumnLayout {
}
}
RowLayout {
- anchors.left: parent.left
- anchors.right: parent.right
- Label { id: deviceLabel; text: "Device"; }
- ComboBox {
- id: deviceComboBox
- anchors.left: deviceLabel.right
- anchors.right: parent.right
- anchors.leftMargin: 100
- textRole: "name"
- model: backend.screens
- currentIndex: backend.virtScreenIndex
- onActivated: function(index) {
- backend.virtScreenIndex = index
- }
- delegate: ItemDelegate {
- width: deviceComboBox.width
- text: modelData.name
- font.weight: deviceComboBox.currentIndex === index ? Font.Bold : Font.Normal
- enabled: modelData.connected ? false : true
- }
+ Layout.alignment: Qt.AlignRight
+ Button {
+ text: "Advanced"
+ font.capitalization: Font.MixedCase
+ onClicked: displayOptionsLoader.active = true;
+ background.opacity : 0
+ onHoveredChanged: hovered ? background.opacity = 0.4
+ :background.opacity = 0;
}
}
}
diff --git a/virtscreen/assets/VncOptionsDialog.qml b/virtscreen/assets/VncOptionsDialog.qml
index da1a036..e047a36 100644
--- a/virtscreen/assets/VncOptionsDialog.qml
+++ b/virtscreen/assets/VncOptionsDialog.qml
@@ -4,7 +4,6 @@ import QtQuick.Controls.Material 2.3
import QtQuick.Layouts 1.3
Dialog {
- id: preferenceDialog
title: "VNC Options"
focus: true
modal: true
diff --git a/virtscreen/assets/VncPage.qml b/virtscreen/assets/VncPage.qml
index 0d4b627..167f510 100644
--- a/virtscreen/assets/VncPage.qml
+++ b/virtscreen/assets/VncPage.qml
@@ -84,7 +84,7 @@ ColumnLayout {
GroupBox {
title: "Available IP addresses"
Layout.fillWidth: true
- implicitHeight: 150
+ implicitHeight: 145
ColumnLayout {
anchors.fill: parent
ListView {
diff --git a/virtscreen/assets/main.qml b/virtscreen/assets/main.qml
index 039966d..077f315 100644
--- a/virtscreen/assets/main.qml
+++ b/virtscreen/assets/main.qml
@@ -10,6 +10,12 @@ Item {
property var settings: JSON.parse(backend.settings)
property bool autostart: settings.vnc.autostart
+ function createVirtScreen () {
+ backend.createVirtScreen(settings.virt.device, settings.virt.width,
+ settings.virt.height, settings.virt.portrait,
+ settings.virt.hidpi);
+ }
+
function startVNC () {
var options = '';
var data = settings.x11vncOptions;
@@ -185,8 +191,7 @@ Item {
// Give a very short delay to show busyDialog.
timer.setTimeout (function() {
if (!backend.virtScreenCreated) {
- backend.createVirtScreen(settings.virt.width, settings.virt.height,
- settings.virt.portrait, settings.virt.hidpi);
+ createVirtScreen();
} else {
// If auto start enabled, stop VNC first then
if (autostart && (backend.vncState != Backend.OFF)) {
diff --git a/virtscreen/virtscreen.py b/virtscreen/virtscreen.py
index 7c21242..c6457c0 100755
--- a/virtscreen/virtscreen.py
+++ b/virtscreen/virtscreen.py
@@ -257,7 +257,6 @@ class DisplayProperty(QObject):
# Screen adjustment class
# -------------------------------------------------------------------------------
class XRandR(SubprocessWrapper):
- DEFAULT_VIRT_SCREEN = "VIRTUAL1"
VIRT_SCREEN_SUFFIX = "_virt"
def __init__(self):
@@ -266,6 +265,7 @@ class XRandR(SubprocessWrapper):
self.screens: List[Display] = []
self.virt: Display() = None
self.primary: Display() = None
+ self.virt_name: str = ''
self.virt_idx: int = None
self.primary_idx: int = None
# Primary display
@@ -276,13 +276,14 @@ class XRandR(SubprocessWrapper):
self.primary = None
self.virt = None
self.screens = []
+ self.virt_idx = None
self.primary_idx = None
pattern = re.compile(r"^(\S*)\s+(connected|disconnected)\s+((primary)\s+)?"
r"((\d+)x(\d+)\+(\d+)\+(\d+)\s+)?.*$", re.M)
for idx, match in enumerate(pattern.finditer(output)):
screen = Display()
screen.name = match.group(1)
- if (self.virt_idx is None) and (screen.name == self.DEFAULT_VIRT_SCREEN):
+ if self.virt_name and screen.name == self.virt_name:
self.virt_idx = idx
screen.primary = True if match.group(4) else False
if screen.primary:
@@ -299,19 +300,23 @@ class XRandR(SubprocessWrapper):
print("Display information:")
for s in self.screens:
print("\t", s)
+ if self.primary_idx is None:
+ raise RuntimeError("There is no primary screen detected.\n"
+ "Go to display settings and set\n"
+ "a primary screen\n")
if self.virt_idx == self.primary_idx:
raise RuntimeError("Virtual screen must be selected other than the primary screen")
- if self.virt_idx is None:
- for idx, screen in enumerate(self.screens):
- if not screen.connected and not screen.active:
- self.virt_idx = idx
- break
- if self.virt_idx is None:
- raise RuntimeError("There is no available devices for virtual screen")
- self.virt = self.screens[self.virt_idx]
+ if self.virt_idx is not None:
+ self.virt = self.screens[self.virt_idx]
+ elif self.virt_name and self.virt_idx is None:
+ raise RuntimeError("No virtual screen name found")
self.primary = self.screens[self.primary_idx]
def _add_screen_mode(self, width, height, portrait, hidpi) -> None:
+ if not self.virt or not self.virt_name:
+ raise RuntimeError("No virtual screen selected.\n"
+ "Go to Display->Virtual Display->Advaced\n"
+ "To select a device.")
# Set virtual screen property first
self.virt.width = width
self.virt.height = height
@@ -353,6 +358,7 @@ class XRandR(SubprocessWrapper):
def create_virtual_screen(self, width, height, portrait=False, hidpi=False) -> None:
print("creating: ", self.virt)
+ self._update_screens()
self._add_screen_mode(width, height, portrait, hidpi)
self.check_output(f"xrandr --output {self.virt.name} --mode {self.mode_name}")
self.check_output("sleep 5")
@@ -360,6 +366,7 @@ class XRandR(SubprocessWrapper):
self._update_screens()
def delete_virtual_screen(self) -> None:
+ self._update_screens()
try:
self.virt.name
self.mode_name
@@ -400,7 +407,6 @@ class Backend(QObject):
# Virtual screen properties
self.xrandr: XRandR = XRandR()
self._virtScreenCreated: bool = False
- self._virtScreenIndex: int = self.xrandr.virt_idx
# VNC server properties
self._vncUsePassword: bool = False
self._vncState: self.VNCState = self.VNCState.OFF
@@ -473,18 +479,11 @@ class Backend(QObject):
@pyqtProperty(QQmlListProperty, constant=True)
def screens(self):
- return QQmlListProperty(DisplayProperty, self, [DisplayProperty(x) for x in self.xrandr.screens])
-
- @pyqtProperty(int, notify=onVirtScreenIndexChanged)
- def virtScreenIndex(self):
- return self._virtScreenIndex
-
- @virtScreenIndex.setter
- def virtScreenIndex(self, virtScreenIndex):
- print("Changing virt to ", virtScreenIndex)
- self.xrandr.virt_idx = virtScreenIndex
- self.xrandr.virt = self.xrandr.screens[self.xrandr.virt_idx]
- self._virtScreenIndex = virtScreenIndex
+ try:
+ return QQmlListProperty(DisplayProperty, self, [DisplayProperty(x) for x in self.xrandr.screens])
+ except RuntimeError as e:
+ self.onError.emit(str(e))
+ return QQmlListProperty(DisplayProperty, self, [])
@pyqtProperty(bool, notify=onVncUsePasswordChanged)
def vncUsePassword(self):
@@ -523,7 +522,11 @@ class Backend(QObject):
@pyqtProperty(DisplayProperty)
def primary(self):
- self._primaryProp = DisplayProperty(self.xrandr.get_primary_screen())
+ try:
+ self._primaryProp = DisplayProperty(self.xrandr.get_primary_screen())
+ except RuntimeError as e:
+ self.onError.emit(str(e))
+ return
return self._primaryProp
@pyqtProperty(int)
@@ -537,14 +540,18 @@ class Backend(QObject):
return cursor.y()
# Qt Slots
- @pyqtSlot(int, int, bool, bool)
- def createVirtScreen(self, width, height, portrait, hidpi):
+ @pyqtSlot(str, int, int, bool, bool)
+ def createVirtScreen(self, device, width, height, portrait, hidpi):
+ self.xrandr.virt_name = device
print("Creating a Virtual Screen...")
try:
self.xrandr.create_virtual_screen(width, height, portrait, hidpi)
except subprocess.CalledProcessError as e:
self.onError.emit(str(e.cmd) + '\n' + e.stdout.decode('utf-8'))
return
+ except RuntimeError as e:
+ self.onError.emit(str(e))
+ return
self.virtScreenCreated = True
@pyqtSlot()
@@ -554,7 +561,11 @@ class Backend(QObject):
self.onError.emit("Turn off the VNC server first")
self.virtScreenCreated = True
return
- self.xrandr.delete_virtual_screen()
+ try:
+ self.xrandr.delete_virtual_screen()
+ except RuntimeError as e:
+ self.onError.emit(str(e))
+ return
self.virtScreenCreated = False
@pyqtSlot(str)
@@ -619,7 +630,11 @@ class Backend(QObject):
logfile = open(X11VNC_LOG_PATH, "wb")
self.vncServer = ProcessProtocol(_onConnected, _onReceived, _onReceived, _onEnded, logfile)
- virt = self.xrandr.get_virtual_screen()
+ try:
+ virt = self.xrandr.get_virtual_screen()
+ except RuntimeError as e:
+ self.onError.emit(str(e))
+ return
clip = f"{virt.width}x{virt.height}+{virt.x_offset}+{virt.y_offset}"
arg = f"x11vnc -rfbport {port} -clip {clip} {options}"
if self.vncUsePassword:
@@ -717,7 +732,11 @@ def main():
QMessageBox.critical(None, "VirtScreen",
"x11vnc is not installed.")
sys.exit(1)
-
+ try:
+ test = XRandR()
+ except RuntimeError as e:
+ QMessageBox.critical(None, "VirtScreen", str(e))
+ sys.exit(1)
# Replace Twisted reactor with qt5reactor
import qt5reactor # pylint: disable=E0401
qt5reactor.install()