Fix QML scope error that disabled all camera movement, and close the lint gap that hid it #3
@@ -43,6 +43,22 @@ else
|
||||
die "neither kpackagetool6 nor kpackagetool5 found; is this a KDE Plasma session?"
|
||||
fi
|
||||
|
||||
# Qt caches compiled QML and JS on disk. Replacing the applet's files does not
|
||||
# invalidate that cache reliably, and a stale compiled logic.js missing a
|
||||
# newer helper function is enough to break bindings that reference it. Clearing
|
||||
# it costs only a slower first load.
|
||||
clear_qml_cache() {
|
||||
local cleared=0 d
|
||||
for d in "${XDG_CACHE_HOME:-$HOME/.cache}"/plasmashell/qmlcache \
|
||||
"${XDG_CACHE_HOME:-$HOME/.cache}"/org.kde.plasmashell/qmlcache \
|
||||
"${XDG_CACHE_HOME:-$HOME/.cache}"/qmlcache; do
|
||||
if [[ -d $d ]]; then
|
||||
rm -rf -- "$d" && echo " cleared $d" && cleared=1
|
||||
fi
|
||||
done
|
||||
(( cleared )) || echo " no QML cache to clear"
|
||||
}
|
||||
|
||||
restart_shell() {
|
||||
(( RESTART )) || return 0
|
||||
echo "Restarting plasmashell:"
|
||||
@@ -73,6 +89,8 @@ install)
|
||||
echo "Installing:"
|
||||
"$KPT" --type Plasma/Applet --install "$PKG"
|
||||
fi
|
||||
echo "Clearing the compiled QML cache:"
|
||||
clear_qml_cache
|
||||
restart_shell
|
||||
echo
|
||||
echo "Done. Right-click a panel or the desktop, Add Widgets, search 'Insta360'."
|
||||
|
||||
@@ -30,11 +30,16 @@ PlasmoidItem {
|
||||
// `sh -c` with plasmashell's environment, which does not include whatever
|
||||
// a login shell adds to PATH, so a bare name often cannot be run here
|
||||
// even when it works in a terminal.
|
||||
property string resolvedBin: ""
|
||||
// Starts as the configured name so commands always have something to
|
||||
// run. The probe only upgrades this to an absolute path; it can never
|
||||
// leave the widget unable to act.
|
||||
property string resolvedBin: Plasmoid.configuration.linkctlPath || "linkctl"
|
||||
property bool resolving: false
|
||||
// Incremented per command so no two command strings are ever identical.
|
||||
property int seq: 0
|
||||
readonly property bool ready: root.resolvedBin !== ""
|
||||
property string lastCmd: ""
|
||||
property int lastExit: -1
|
||||
readonly property int stepMax: Plasmoid.configuration.maxStep
|
||||
readonly property int tickMs: Plasmoid.configuration.tickInterval
|
||||
readonly property bool invertPan: Plasmoid.configuration.invertPan
|
||||
@@ -54,16 +59,28 @@ PlasmoidItem {
|
||||
property bool keyUp: false
|
||||
property bool keyDown: false
|
||||
|
||||
readonly property var keyVec: Logic.vectorFromKeys({
|
||||
left: root.keyLeft, right: root.keyRight,
|
||||
up: root.keyUp, down: root.keyDown
|
||||
})
|
||||
readonly property bool keyEngaged: root.keyVec.nx !== 0 || root.keyVec.ny !== 0
|
||||
// Keyboard vector. Computed defensively on purpose: the pointer path
|
||||
// reads inNx/inEngaged too, so anything that throws in here would
|
||||
// disable dragging as well. Qt caches compiled QML and JS on disk, and a
|
||||
// stale cached logic.js lacking a newer helper is enough to do it.
|
||||
readonly property bool keyboardAvailable: typeof Logic !== "undefined"
|
||||
&& typeof Logic.vectorFromKeys === "function"
|
||||
readonly property var keyVec: root.keyboardAvailable
|
||||
? Logic.vectorFromKeys({
|
||||
left: root.keyLeft, right: root.keyRight,
|
||||
up: root.keyUp, down: root.keyDown
|
||||
})
|
||||
: { nx: 0, ny: 0 }
|
||||
readonly property real keyNx: (root.keyVec && typeof root.keyVec.nx === "number")
|
||||
? root.keyVec.nx : 0
|
||||
readonly property real keyNy: (root.keyVec && typeof root.keyVec.ny === "number")
|
||||
? root.keyVec.ny : 0
|
||||
readonly property bool keyEngaged: root.keyNx !== 0 || root.keyNy !== 0
|
||||
|
||||
// The pointer wins while it is down, so a drag is never fought over by a
|
||||
// key left held down underneath it.
|
||||
readonly property real inNx: stick.held ? stick.nx : root.keyVec.nx
|
||||
readonly property real inNy: stick.held ? stick.ny : root.keyVec.ny
|
||||
readonly property real inNx: stick.held ? stick.nx : root.keyNx
|
||||
readonly property real inNy: stick.held ? stick.ny : root.keyNy
|
||||
readonly property bool inEngaged: stick.engaged || root.keyEngaged
|
||||
|
||||
// WASD and the arrow keys. Returns "" for anything that is not a
|
||||
@@ -114,6 +131,11 @@ PlasmoidItem {
|
||||
root.refreshTracking();
|
||||
return;
|
||||
}
|
||||
if (typeof Logic.resolveCommand !== "function") {
|
||||
// Stale cached logic.js: keep the configured name and carry on.
|
||||
root.refresh();
|
||||
return;
|
||||
}
|
||||
root.statusText = "Looking for linkctl...";
|
||||
root.resolving = true;
|
||||
sh.exec(Logic.resolveCommand(root.configuredBin));
|
||||
@@ -149,6 +171,9 @@ PlasmoidItem {
|
||||
const err = (data.stderr || "").trim();
|
||||
disconnectSource(source);
|
||||
root.busy = false;
|
||||
root.lastExit = code;
|
||||
console.log("[insta360] exit", code, "out:", String(out).trim(),
|
||||
"err:", err);
|
||||
|
||||
if (root.resolving) {
|
||||
root.resolving = false;
|
||||
@@ -158,8 +183,11 @@ PlasmoidItem {
|
||||
root.refresh();
|
||||
root.refreshTracking();
|
||||
} else {
|
||||
root.statusText = "linkctl not found. Set its full path "
|
||||
+ "in this widget's settings.";
|
||||
// Keep the configured name as the fallback rather than
|
||||
// blocking: on a packaged install it is on PATH anyway.
|
||||
root.statusText = "Could not locate linkctl; using '"
|
||||
+ root.configuredBin + "'.";
|
||||
root.refresh();
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -176,7 +204,12 @@ PlasmoidItem {
|
||||
root.seq += 1;
|
||||
// Never reuse a command string: the engine would serve the
|
||||
// previous run's cached output and not run anything.
|
||||
connectSource(Logic.uniqueify(cmd, root.seq));
|
||||
const unique = (typeof Logic.uniqueify === "function")
|
||||
? Logic.uniqueify(cmd, root.seq)
|
||||
: cmd + " # " + root.seq;
|
||||
root.lastCmd = unique;
|
||||
console.log("[insta360] run:", unique);
|
||||
connectSource(unique);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,24 +227,14 @@ PlasmoidItem {
|
||||
}
|
||||
|
||||
function refresh() {
|
||||
if (!root.ready) {
|
||||
return;
|
||||
}
|
||||
sh.exec(root.baseCmd() + " status");
|
||||
}
|
||||
|
||||
function refreshTracking() {
|
||||
if (!root.ready) {
|
||||
return;
|
||||
}
|
||||
sh.exec(root.baseCmd() + " tracking status");
|
||||
}
|
||||
|
||||
function action(args) {
|
||||
if (!root.ready) {
|
||||
root.resolveBinary();
|
||||
return;
|
||||
}
|
||||
sh.exec(root.baseCmd() + " " + args);
|
||||
}
|
||||
|
||||
@@ -219,7 +242,7 @@ PlasmoidItem {
|
||||
|
||||
// Re-resolve if the configured path is edited.
|
||||
onConfiguredBinChanged: {
|
||||
root.resolvedBin = "";
|
||||
root.resolvedBin = root.configuredBin;
|
||||
root.resolveBinary();
|
||||
}
|
||||
|
||||
@@ -311,11 +334,12 @@ PlasmoidItem {
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: moveTimer
|
||||
// Drives both input methods. Only runs while something is asking
|
||||
// for movement, so an idle popup costs nothing.
|
||||
interval: root.tickMs
|
||||
repeat: true
|
||||
running: root.inEngaged && root.ready
|
||||
running: root.inEngaged
|
||||
triggeredOnStart: true
|
||||
onTriggered: {
|
||||
if (root.busy) {
|
||||
@@ -425,6 +449,56 @@ PlasmoidItem {
|
||||
}
|
||||
}
|
||||
|
||||
PlasmaComponents.Button {
|
||||
id: diagToggle
|
||||
Layout.fillWidth: true
|
||||
focusPolicy: Qt.NoFocus
|
||||
checkable: true
|
||||
icon.name: "help-about"
|
||||
text: "Diagnostics"
|
||||
}
|
||||
|
||||
// Live internal state. Exists because every failure so far has
|
||||
// presented as "nothing happens", which is the one symptom that
|
||||
// carries no information.
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
visible: diagToggle.checked
|
||||
spacing: 0
|
||||
|
||||
Repeater {
|
||||
model: [
|
||||
"binary: " + root.resolvedBin,
|
||||
"configured: " + root.configuredBin,
|
||||
"device: " + (root.device === "" ? "(auto)" : root.device),
|
||||
"helpers: vectorFromKeys=" + root.keyboardAvailable
|
||||
+ " uniqueify="
|
||||
+ (typeof Logic.uniqueify === "function")
|
||||
+ " resolveCommand="
|
||||
+ (typeof Logic.resolveCommand === "function"),
|
||||
"stick: held=" + stick.held
|
||||
+ " nx=" + stick.nx.toFixed(2)
|
||||
+ " ny=" + stick.ny.toFixed(2)
|
||||
+ " engaged=" + stick.engaged,
|
||||
"keys: nx=" + root.keyNx.toFixed(2)
|
||||
+ " ny=" + root.keyNy.toFixed(2)
|
||||
+ " focus=" + panel.activeFocus,
|
||||
"input: engaged=" + root.inEngaged
|
||||
+ " timer=" + moveTimer.running,
|
||||
"busy: " + root.busy + " seq: " + root.seq
|
||||
+ " lastExit: " + root.lastExit,
|
||||
"lastCmd: " + root.lastCmd
|
||||
]
|
||||
PlasmaComponents.Label {
|
||||
Layout.fillWidth: true
|
||||
text: modelData
|
||||
font: Kirigami.Theme.smallFont
|
||||
opacity: 0.8
|
||||
wrapMode: Text.WrapAnywhere
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user