Add quickshell screenshot

This commit is contained in:
outfoxxed 2024-03-29 06:22:26 -07:00
parent 36ff76a601
commit 5a70b9493c
Signed by: outfoxxed
GPG key ID: 4C88A185FB89301E
9 changed files with 310 additions and 9 deletions

View file

@ -384,11 +384,11 @@
]
},
"locked": {
"lastModified": 1711618169,
"narHash": "sha256-K5j+SlsGfyrJeBzcZVH02O8P4T+ep4UEFryVVBWFdAw=",
"lastModified": 1711716099,
"narHash": "sha256-j9j3O4iR0ovVZTgjUb2nyvyZ1fPNMrR0fm65E4kZcgo=",
"ref": "refs/heads/master",
"rev": "439788fce09efff383768ac2403526f9e0fe5ddd",
"revCount": 136,
"rev": "83afce7f68f8ffc74f53642d2bac9e604bd64dfc",
"revCount": 137,
"type": "git",
"url": "https://git.outfoxxed.me/outfoxxed/quickshell"
},

View file

@ -109,6 +109,8 @@ layerrule = animation fade, shell:background
layerrule = blur, shell:bar
layerrule = ignorezero, shell:bar
layerrule = noanim, shell:screenshot
layerrule = blur, walker
layerrule = ignorezero, walker
layerrule = animation popin 90%, walker
@ -136,8 +138,10 @@ bind = $mod+SHIFT, return, exec, alacritty --class AlacrittyFloating
bind = $mod, grave, exec, $launcher
bind = $mod+SHIFT, q, hy3:killactive
bind = $mod+SHIFT, s, exec, echo "screenshot" | nc -w 0 -U /run/user/1000/quickshell.sock
bind = $mod, c, exec, echo "termselect:start" | nc -w 0 -U /run/user/1000/quickshell.sock
bindr = $mod, c, exec, echo "termselect:stop" | nc -w 0 -U /run/user/1000/quickshell.sock
bind = $mod, PERIOD, exec, quickshell -c lockscreen
bind = $mod, f, fullscreen, 1
bind = $mod+SHIFT, f, fullscreen, 0
@ -163,10 +167,6 @@ bind = ,XF86AudioStop, exec, playerctl -a stop
bind = ,XF86AudioNext, exec, playerctl next
bind = ,XF86AudioPrev, exec, playerctl previous
bind = $mod+SHIFT, s, exec, grim -g "$(slurp)" - | wl-copy
bind = $mod, PERIOD, exec, quickshell -c lockscreen
bind = $mod, h, hy3:movefocus, l
bind = $mod, j, hy3:movefocus, d
bind = $mod, k, hy3:movefocus, u

View file

@ -5,6 +5,7 @@ in {
qt6.qtimageformats # amog
quickshell.packages.${system}.default
pamtester # lockscreen
grim imagemagick # screenshot
];
xdg.configFile."quickshell/manifest.conf".text = lib.generators.toKeyValue {} {

View file

@ -40,7 +40,6 @@ Item {
yCurve.interpolate(p, collapsedLayerRect.y, expandedLayerRect.y),
xCurve.interpolate(p, collapsedLayerRect.width, expandedLayerRect.width),
yCurve.interpolate(p, collapsedLayerRect.height, expandedLayerRect.height),
);
}

View file

@ -4,6 +4,8 @@ import QtQuick
import Quickshell
Singleton {
readonly property string rtpath: "/run/user/1000/quickshell"
readonly property var colors: QtObject {
readonly property var bar: "#30c0ffff";
readonly property var barOutline: "#50ffffff";

View file

@ -5,6 +5,7 @@ import Quickshell.Io
Singleton {
property bool termSelect: false;
signal screenshot();
SocketServer {
active: true
@ -15,6 +16,9 @@ Singleton {
onRead: message => {
console.log(message)
switch (message) {
case "screenshot":
screenshot();
break;
case "termselect:start":
termSelect = true;
break;

View file

@ -0,0 +1,206 @@
// very bad code DO NOT COPY
import QtQuick
import Quickshell
import Quickshell.Io
import Quickshell.Wayland
import ".."
Scope {
id: root
property bool shooting: false;
property bool shootingComplete: false;
property bool visible: false;
readonly property string path: `${ShellGlobals.rtpath}/screenshot.png`;
onShootingChanged: {
if (shooting) {
grimProc.running = true
} else {
visible = false
shootingComplete = false
cleanupProc.running = true
}
}
Process {
id: grimProc
command: ["grim", "-l", "0", path]
onExited: code => {
if (code == 0) {
root.visible = true
} else {
console.log("screenshot failed")
cleanupProc.running = true
}
}
}
Process {
id: magickProc
command: [
"magick",
path,
"-crop",
`${selection.w}x${selection.h}+${selection.x}+${selection.y}`,
"-quality",
"70",
path,
]
onExited: wlCopy.running = true;
}
Process {
id: wlCopy
command: ["sh", "-c", `wl-copy < '${path}'`]
onExited: shootingComplete = true;
}
Process {
id: cleanupProc
command: ["rm", path]
}
QtObject {
id: selection
property real x1;
property real y1;
property real x2;
property real y2;
readonly property real x: Math.min(x1, x2)
readonly property real y: Math.min(y1, y2)
readonly property real w: Math.max(x1, x2) - x
readonly property real h: Math.max(y1, y2) - y
}
LazyLoader {
loading: root.shooting
active: root.visible
onLoadingChanged: console.log(`loading set to ${loading} at ${new Date()}`)
onActiveChanged: console.log(`active set to ${active} at ${new Date()}`)
Variants {
model: Quickshell.screens
property bool selectionComplete: false
Component.onCompleted: {
selection.x1 = 0
selection.y1 = 0
selection.x2 = 0
selection.y2 = 0
}
PanelWindow {
required property var modelData;
screen: modelData
visible: root.visible
exclusionMode: ExclusionMode.Ignore
WlrLayershell.namespace: "shell:screenshot"
WlrLayershell.layer: WlrLayer.Overlay
anchors {
top: true
left: true
right: true
bottom: true
}
MouseArea {
id: area
anchors.fill: parent
cursorShape: selectionComplete ? Qt.WaitCursor : Qt.CrossCursor
enabled: !selectionComplete
onPressed: {
selection.x1 = mouseX + screen.x;
selection.x2 = selection.x1;
selection.y1 = mouseY + screen.y;
selection.y2 = selection.y1;
}
onPositionChanged: {
selection.x2 = mouseX + screen.x;
selection.y2 = mouseY + screen.y;
}
onReleased: {
console.log(`area: ${selection.x} ${selection.y} ${selection.w} ${selection.h}`)
if (selection.w > 0 && selection.h > 0) {
magickProc.running = true
selectionComplete = true
} else {
root.shooting = false
}
}
Image {
parent: area
anchors.fill: parent
source: root.visible ? root.path : ""
sourceClipRect: Qt.rect(screen.x, screen.y, screen.width, screen.height)
}
CutoutRect {
id: cutoutRect
anchors.fill: parent
innerX: selection.x - screen.x
innerY: selection.y - screen.y
innerW: selection.w
innerH: selection.h
NumberAnimation {
id: rectFlashIn
target: cutoutRect
property: "opacity"
duration: 200
easing.type: Easing.OutExpo
from: 0.0
to: 1.0
}
PropertyAnimation {
running: selectionComplete
target: cutoutRect
property: "innerBorderColor"
duration: 200
to: "#00ff20"
}
NumberAnimation {
running: selectionComplete
target: cutoutRect
property: "backgroundOpacity"
duration: 200
to: 0.0
}
NumberAnimation {
running: shootingComplete
target: cutoutRect
property: "opacity"
easing.type: Easing.OutCubic
duration: 150
to: 0.0
onStopped: root.shooting = false
}
}
Connections {
target: root
function onVisibleChanged() {
if (root.visible) {
rectFlashIn.start();
}
}
}
}
}
}
}
}

View file

@ -0,0 +1,67 @@
import QtQuick
Item {
id: root
property color backgroundColor: "#20ffffff"
property real backgroundOpacity: 1.0
property alias innerBorderColor: center.border.color
property alias innerX: center.x
property alias innerY: center.y
property alias innerW: center.width
property alias innerH: center.height
Rectangle {
id: center
border.color: "white"
border.width: 2
color: "transparent"
}
Rectangle {
color: root.backgroundColor
opacity: backgroundOpacity
anchors {
top: parent.top
left: parent.left
right: parent.right
bottom: center.top
}
}
Rectangle {
color: root.backgroundColor
opacity: backgroundOpacity
anchors {
top: center.bottom
left: parent.left
right: parent.right
bottom: parent.bottom
}
}
Rectangle {
color: root.backgroundColor
opacity: backgroundOpacity
anchors {
top: center.top
left: parent.left
right: center.left
bottom: center.bottom
}
}
Rectangle {
color: root.backgroundColor
opacity: backgroundOpacity
anchors {
top: center.top
left: center.right
right: parent.right
bottom: center.bottom
}
}
}

View file

@ -4,8 +4,30 @@ import Quickshell.Wayland
import QtQuick
import QtQuick.Layouts
import ".."
import "screenshot" as Screenshot
ShellRoot {
Process {
command: ["mkdir", "-p", ShellGlobals.rtpath]
running: true
}
LazyLoader {
id: screenshot
loading: true
Screenshot.Controller {
}
}
Connections {
target: ShellIpc
function onScreenshot() {
screenshot.item.shooting = true;
}
}
Variants {
model: Quickshell.screens