Add quickshell screenshot
This commit is contained in:
parent
36ff76a601
commit
5a70b9493c
|
@ -384,11 +384,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1711618169,
|
"lastModified": 1711716099,
|
||||||
"narHash": "sha256-K5j+SlsGfyrJeBzcZVH02O8P4T+ep4UEFryVVBWFdAw=",
|
"narHash": "sha256-j9j3O4iR0ovVZTgjUb2nyvyZ1fPNMrR0fm65E4kZcgo=",
|
||||||
"ref": "refs/heads/master",
|
"ref": "refs/heads/master",
|
||||||
"rev": "439788fce09efff383768ac2403526f9e0fe5ddd",
|
"rev": "83afce7f68f8ffc74f53642d2bac9e604bd64dfc",
|
||||||
"revCount": 136,
|
"revCount": 137,
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://git.outfoxxed.me/outfoxxed/quickshell"
|
"url": "https://git.outfoxxed.me/outfoxxed/quickshell"
|
||||||
},
|
},
|
||||||
|
|
|
@ -109,6 +109,8 @@ layerrule = animation fade, shell:background
|
||||||
layerrule = blur, shell:bar
|
layerrule = blur, shell:bar
|
||||||
layerrule = ignorezero, shell:bar
|
layerrule = ignorezero, shell:bar
|
||||||
|
|
||||||
|
layerrule = noanim, shell:screenshot
|
||||||
|
|
||||||
layerrule = blur, walker
|
layerrule = blur, walker
|
||||||
layerrule = ignorezero, walker
|
layerrule = ignorezero, walker
|
||||||
layerrule = animation popin 90%, 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, grave, exec, $launcher
|
||||||
bind = $mod+SHIFT, q, hy3:killactive
|
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
|
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
|
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, f, fullscreen, 1
|
||||||
bind = $mod+SHIFT, f, fullscreen, 0
|
bind = $mod+SHIFT, f, fullscreen, 0
|
||||||
|
@ -163,10 +167,6 @@ bind = ,XF86AudioStop, exec, playerctl -a stop
|
||||||
bind = ,XF86AudioNext, exec, playerctl next
|
bind = ,XF86AudioNext, exec, playerctl next
|
||||||
bind = ,XF86AudioPrev, exec, playerctl previous
|
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, h, hy3:movefocus, l
|
||||||
bind = $mod, j, hy3:movefocus, d
|
bind = $mod, j, hy3:movefocus, d
|
||||||
bind = $mod, k, hy3:movefocus, u
|
bind = $mod, k, hy3:movefocus, u
|
||||||
|
|
|
@ -5,6 +5,7 @@ in {
|
||||||
qt6.qtimageformats # amog
|
qt6.qtimageformats # amog
|
||||||
quickshell.packages.${system}.default
|
quickshell.packages.${system}.default
|
||||||
pamtester # lockscreen
|
pamtester # lockscreen
|
||||||
|
grim imagemagick # screenshot
|
||||||
];
|
];
|
||||||
|
|
||||||
xdg.configFile."quickshell/manifest.conf".text = lib.generators.toKeyValue {} {
|
xdg.configFile."quickshell/manifest.conf".text = lib.generators.toKeyValue {} {
|
||||||
|
|
|
@ -40,7 +40,6 @@ Item {
|
||||||
yCurve.interpolate(p, collapsedLayerRect.y, expandedLayerRect.y),
|
yCurve.interpolate(p, collapsedLayerRect.y, expandedLayerRect.y),
|
||||||
xCurve.interpolate(p, collapsedLayerRect.width, expandedLayerRect.width),
|
xCurve.interpolate(p, collapsedLayerRect.width, expandedLayerRect.width),
|
||||||
yCurve.interpolate(p, collapsedLayerRect.height, expandedLayerRect.height),
|
yCurve.interpolate(p, collapsedLayerRect.height, expandedLayerRect.height),
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,8 @@ import QtQuick
|
||||||
import Quickshell
|
import Quickshell
|
||||||
|
|
||||||
Singleton {
|
Singleton {
|
||||||
|
readonly property string rtpath: "/run/user/1000/quickshell"
|
||||||
|
|
||||||
readonly property var colors: QtObject {
|
readonly property var colors: QtObject {
|
||||||
readonly property var bar: "#30c0ffff";
|
readonly property var bar: "#30c0ffff";
|
||||||
readonly property var barOutline: "#50ffffff";
|
readonly property var barOutline: "#50ffffff";
|
||||||
|
|
|
@ -5,6 +5,7 @@ import Quickshell.Io
|
||||||
|
|
||||||
Singleton {
|
Singleton {
|
||||||
property bool termSelect: false;
|
property bool termSelect: false;
|
||||||
|
signal screenshot();
|
||||||
|
|
||||||
SocketServer {
|
SocketServer {
|
||||||
active: true
|
active: true
|
||||||
|
@ -15,6 +16,9 @@ Singleton {
|
||||||
onRead: message => {
|
onRead: message => {
|
||||||
console.log(message)
|
console.log(message)
|
||||||
switch (message) {
|
switch (message) {
|
||||||
|
case "screenshot":
|
||||||
|
screenshot();
|
||||||
|
break;
|
||||||
case "termselect:start":
|
case "termselect:start":
|
||||||
termSelect = true;
|
termSelect = true;
|
||||||
break;
|
break;
|
||||||
|
|
206
modules/user/modules/quickshell/shell/screenshot/Controller.qml
Normal file
206
modules/user/modules/quickshell/shell/screenshot/Controller.qml
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,8 +4,30 @@ import Quickshell.Wayland
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import ".."
|
import ".."
|
||||||
|
import "screenshot" as Screenshot
|
||||||
|
|
||||||
ShellRoot {
|
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 {
|
Variants {
|
||||||
model: Quickshell.screens
|
model: Quickshell.screens
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue