ScreenRecorder: check for availability

This commit is contained in:
Ly-sec 2025-09-09 13:20:46 +02:00
parent 94d64a91b8
commit 3c9ce6f8b5
5 changed files with 107 additions and 28 deletions

View file

@ -22,7 +22,9 @@ Item {
IpcHandler {
target: "screenRecorder"
function toggle() {
ScreenRecorderService.toggleRecording()
if (ScreenRecorderService.isAvailable) {
ScreenRecorderService.toggleRecording()
}
}
}

View file

@ -735,12 +735,28 @@ Loader {
color: powerButtonArea.containsMouse ? Color.mOnError : Color.mError
}
// Tooltip
NTooltip {
id: tooltipShutdown
target: parent
positionAbove: true
text: "Shut down"
// Tooltip (inline rectangle to avoid separate Window during lock)
Rectangle {
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.top
anchors.bottomMargin: 12 * scaling
radius: Style.radiusM * scaling
color: Color.mSurface
border.color: Color.mOutline
border.width: Math.max(1, Style.borderS * scaling)
visible: powerButtonArea.containsMouse
z: 1
NText {
id: shutdownTooltipText
anchors.margins: Style.marginM * scaling
anchors.fill: parent
text: "Shut down the computer."
font.pointSize: Style.fontSizeM * scaling
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
implicitWidth: shutdownTooltipText.implicitWidth + Style.marginM * 2 * scaling
implicitHeight: shutdownTooltipText.implicitHeight + Style.marginM * 2 * scaling
}
MouseArea {
@ -750,8 +766,6 @@ Loader {
onClicked: {
CompositorService.shutdown()
}
onEntered: tooltipShutdown.show()
onExited: tooltipShutdown.hide()
}
}
@ -773,11 +787,27 @@ Loader {
}
// Tooltip
NTooltip {
id: tooltipRestart
target: parent
positionAbove: true
text: "Restart"
Rectangle {
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.top
anchors.bottomMargin: 12 * scaling
radius: Style.radiusM * scaling
color: Color.mSurface
border.color: Color.mOutline
border.width: Math.max(1, Style.borderS * scaling)
visible: restartButtonArea.containsMouse
z: 1
NText {
id: restartTooltipText
anchors.margins: Style.marginM * scaling
anchors.fill: parent
text: "Restart the computer."
font.pointSize: Style.fontSizeM * scaling
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
implicitWidth: restartTooltipText.implicitWidth + Style.marginM * 2 * scaling
implicitHeight: restartTooltipText.implicitHeight + Style.marginM * 2 * scaling
}
MouseArea {
@ -787,8 +817,7 @@ Loader {
onClicked: {
CompositorService.reboot()
}
onEntered: tooltipRestart.show()
onExited: tooltipRestart.hide()
// Tooltip handled via inline rectangle visibility
}
}
@ -810,11 +839,27 @@ Loader {
}
// Tooltip
NTooltip {
id: tooltipSuspend
target: parent
positionAbove: true
text: "Suspend"
Rectangle {
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.top
anchors.bottomMargin: 12 * scaling
radius: Style.radiusM * scaling
color: Color.mSurface
border.color: Color.mOutline
border.width: Math.max(1, Style.borderS * scaling)
visible: suspendButtonArea.containsMouse
z: 1
NText {
id: suspendTooltipText
anchors.margins: Style.marginM * scaling
anchors.fill: parent
text: "Suspend the system."
font.pointSize: Style.fontSizeM * scaling
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
implicitWidth: suspendTooltipText.implicitWidth + Style.marginM * 2 * scaling
implicitHeight: suspendTooltipText.implicitHeight + Style.marginM * 2 * scaling
}
MouseArea {
@ -824,8 +869,7 @@ Loader {
onClicked: {
CompositorService.suspend()
}
onEntered: tooltipSuspend.show()
onExited: tooltipSuspend.hide()
// Tooltip handled via inline rectangle visibility
}
}
}

View file

@ -26,10 +26,13 @@ NBox {
// Screen Recorder
NIconButton {
icon: "camera-video"
tooltipText: ScreenRecorderService.isRecording ? "Stop screen recording." : "Start screen recording."
enabled: ScreenRecorderService.isAvailable
tooltipText: ScreenRecorderService.isAvailable ? (ScreenRecorderService.isRecording ? "Stop screen recording." : "Start screen recording.") : "Screen recorder not installed."
colorBg: ScreenRecorderService.isRecording ? Color.mPrimary : Color.mSurfaceVariant
colorFg: ScreenRecorderService.isRecording ? Color.mOnPrimary : Color.mPrimary
onClicked: {
if (!ScreenRecorderService.isAvailable)
return
ScreenRecorderService.toggleRecording()
// If we were not recording and we just initiated a start, close the panel
if (!ScreenRecorderService.isRecording) {

View file

@ -13,6 +13,17 @@ Singleton {
property bool isRecording: false
property bool isPending: false
property string outputPath: ""
property bool isAvailable: false
Component.onCompleted: {
checkAvailability()
}
function checkAvailability() {
// Detect native or Flatpak gpu-screen-recorder
availabilityCheckProcess.command = ["sh", "-c", "command -v gpu-screen-recorder >/dev/null 2>&1 || (command -v flatpak >/dev/null 2>&1 && flatpak list --app | grep -q 'com.dec05eba.gpu_screen_recorder')"]
availabilityCheckProcess.running = true
}
// Start or Stop recording
function toggleRecording() {
@ -21,6 +32,9 @@ Singleton {
// Start screen recording using Quickshell.execDetached
function startRecording() {
if (!isAvailable) {
return
}
if (isRecording || isPending) {
return
}
@ -88,6 +102,18 @@ Singleton {
}
}
// Availability check process
Process {
id: availabilityCheckProcess
command: ["sh", "-c", "true"]
onExited: function (exitCode, exitStatus) {
// exitCode 0 means available, non-zero means unavailable
root.isAvailable = (exitCode === 0)
}
stdout: StdioCollector {}
stderr: StdioCollector {}
}
Timer {
id: pendingTimer
interval: 2000 // Wait 2 seconds to see if process stays alive

View file

@ -35,13 +35,13 @@ Rectangle {
opacity: root.enabled ? Style.opacityFull : Style.opacityMedium
color: root.enabled && root.hovering ? colorBgHover : colorBg
radius: width * 0.5
border.color: root.hovering ? colorBorderHover : colorBorder
border.color: root.enabled && root.hovering ? colorBorderHover : colorBorder
border.width: Math.max(1, Style.borderS * scaling)
NIcon {
icon: root.icon
font.pointSize: Style.fontSizeM * scaling
color: root.hovering ? colorFgHover : colorFg
color: root.enabled && root.hovering ? colorFgHover : colorFg
// Center horizontally
x: (root.width - width) / 2
// Center vertically accounting for font metrics
@ -56,13 +56,14 @@ Rectangle {
}
MouseArea {
enabled: root.enabled
// Always enabled to allow hover/tooltip even when the button is disabled
enabled: true
anchors.fill: parent
cursorShape: root.enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
hoverEnabled: true
onEntered: {
hovering = true
hovering = root.enabled ? true : false
if (tooltipText) {
tooltip.show()
}
@ -79,6 +80,9 @@ Rectangle {
if (tooltipText) {
tooltip.hide()
}
if (!root.enabled) {
return
}
if (mouse.button === Qt.LeftButton) {
root.clicked()
} else if (mouse.button === Qt.RightButton) {