Merge branch 'caelestia-dots:main' into betteractions

This commit is contained in:
Tim Hämisch 2025-06-13 17:49:49 +02:00 committed by GitHub
commit 5fb727a4c8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 173 additions and 94 deletions

21
.github/CONTRIBUTING.md vendored Normal file
View file

@ -0,0 +1,21 @@
# Contributing
There are only a few rules:
- Follow the commit convention as follows:
- The name of the commit should be `module: change`
- Try to be consistent with the module names; you can look at existing commits for the module names I use
- If there is more than one change, the change in the commit name should be the most impactful change
- Put other changes in the description
- Format your code
- I use the vscode qml extension with default arguments to format the code, however you do not have to use it
- Just try to follow the code style of the rest of the code and ensure that there is:
- no trailing whitespace on any lines
- a single space between operators
- No AI slop allowed
- AI readme/docs slop = instant block
- PLEASE TEST YOUR PRS
- I can't believe I have to put this here, but please test your PRs before submitting them
- Your PR must not break anything currently existing, or specify in the description if it does
- PR descriptions should be descriptive
- Please explain what the PR does and how to use it in your PR description
- Also include any breaking changes and/or side effects of the PR

View file

@ -8,6 +8,15 @@ Scope {
property bool launcherInterrupted
CustomShortcut {
name: "showall"
description: "Toggle launcher, dashboard and osd"
onPressed: {
const v = Visibilities.getForActive();
v.launcher = v.dashboard = v.osd = !(v.launcher || v.dashboard || v.osd);
}
}
CustomShortcut {
name: "session"
description: "Toggle session menu"

View file

@ -8,7 +8,7 @@ import QtQuick
Item {
id: root
property url source: Wallpapers.current ? `file://${Wallpapers.current}` : ""
property string source: Wallpapers.current
property Image current: one
anchors.fill: parent
@ -32,20 +32,14 @@ Item {
id: img
function update(): void {
const srcPath = `${root.source}`.slice(7);
if (thumbnail.originalPath === srcPath) {
if (path === root.source)
root.current = this;
} else
path = srcPath;
else
path = root.source;
}
anchors.fill: parent
loadOriginal: true
asynchronous: true
cache: false
fillMode: Image.PreserveAspectCrop
opacity: 0
scale: Wallpapers.showPreview ? 1 : 0.8

View file

@ -10,13 +10,13 @@ Row {
id: root
padding: Appearance.padding.large
spacing: Appearance.spacing.large
spacing: Appearance.spacing.normal
StyledClippingRect {
implicitWidth: info.implicitHeight
implicitHeight: info.implicitHeight
radius: Appearance.rounding.full
radius: Appearance.rounding.large
color: Colours.palette.m3surfaceContainerHigh
MaterialIcon {

View file

@ -16,6 +16,8 @@ MouseArea {
property bool osdHovered
property point dragStart
property bool dashboardShortcutActive
property bool osdShortcutActive
function withinPanelHeight(panel: Item, x: real, y: real): bool {
const panelY = BorderConfig.thickness + panel.y;
@ -37,9 +39,14 @@ MouseArea {
onPressed: event => dragStart = Qt.point(event.x, event.y)
onContainsMouseChanged: {
if (!containsMouse) {
visibilities.osd = false;
osdHovered = false;
visibilities.dashboard = false;
// Only hide if not activated by shortcut
if (!osdShortcutActive) {
visibilities.osd = false;
osdHovered = false;
}
if (!dashboardShortcutActive) {
visibilities.dashboard = false;
}
popouts.hasCurrent = false;
}
}
@ -47,8 +54,16 @@ MouseArea {
onPositionChanged: ({x, y}) => {
// Show osd on hover
const showOsd = inRightPanel(panels.osd, x, y);
visibilities.osd = showOsd;
osdHovered = showOsd;
// Always update visibility based on hover if not in shortcut mode
if (!osdShortcutActive) {
visibilities.osd = showOsd;
osdHovered = showOsd;
} else if (showOsd) {
// If hovering over OSD area while in shortcut mode, transition to hover control
osdShortcutActive = false;
osdHovered = true;
}
// Show/hide session on drag
if (pressed && withinPanelHeight(panels.session, x, y)) {
@ -60,7 +75,15 @@ MouseArea {
}
// Show dashboard on hover
visibilities.dashboard = inTopPanel(panels.dashboard, x, y);
const showDashboard = inTopPanel(panels.dashboard, x, y);
// Always update visibility based on hover if not in shortcut mode
if (!dashboardShortcutActive) {
visibilities.dashboard = showDashboard;
} else if (showDashboard) {
// If hovering over dashboard area while in shortcut mode, transition to hover control
dashboardShortcutActive = false;
}
// Show popouts on hover
const popout = panels.popouts;
@ -75,6 +98,57 @@ MouseArea {
popouts.hasCurrent = false;
}
// Monitor individual visibility changes
Connections {
target: root.visibilities
function onLauncherChanged() {
// If launcher is hidden, clear shortcut flags for dashboard and OSD
if (!root.visibilities.launcher) {
root.dashboardShortcutActive = false;
root.osdShortcutActive = false;
// Also hide dashboard and OSD if they're not being hovered
const inDashboardArea = root.inTopPanel(root.panels.dashboard, root.mouseX, root.mouseY);
const inOsdArea = root.inRightPanel(root.panels.osd, root.mouseX, root.mouseY);
if (!inDashboardArea) {
root.visibilities.dashboard = false;
}
if (!inOsdArea) {
root.visibilities.osd = false;
root.osdHovered = false;
}
}
}
function onDashboardChanged() {
if (root.visibilities.dashboard) {
// Dashboard became visible, immediately check if this should be shortcut mode
const inDashboardArea = root.inTopPanel(root.panels.dashboard, root.mouseX, root.mouseY);
if (!inDashboardArea) {
root.dashboardShortcutActive = true;
}
} else {
// Dashboard hidden, clear shortcut flag
root.dashboardShortcutActive = false;
}
}
function onOsdChanged() {
if (root.visibilities.osd) {
// OSD became visible, immediately check if this should be shortcut mode
const inOsdArea = root.inRightPanel(root.panels.osd, root.mouseX, root.mouseY);
if (!inOsdArea) {
root.osdShortcutActive = true;
}
} else {
// OSD hidden, clear shortcut flag
root.osdShortcutActive = false;
}
}
}
Osd.Interactions {
screen: root.screen
visibilities: root.visibilities

View file

@ -4,5 +4,6 @@ set -l dbus 'quickshell.dbus.properties.warning = false;quickshell.dbus.dbusmenu
set -l notifs 'quickshell.service.notifications.warning = false' # Notification server warnings on reload
set -l sni 'quickshell.service.sni.host.warning = false' # StatusNotifierItem warnings on reload
set -l process 'QProcess: Destroyed while process' # Long running processes on reload
set -l cache "Cannot open: file://$XDG_CACHE_HOME/caelestia/imagecache/"
qs -p (dirname (status filename)) --log-rules "$dbus;$notifs;$sni" | grep -vE -e $process
qs -p (dirname (status filename)) --log-rules "$dbus;$notifs;$sni" | grep -vF -e $process -e $cache

View file

@ -1,72 +0,0 @@
pragma Singleton
pragma ComponentBehavior: Bound
import "root:/utils"
import Quickshell
import Quickshell.Io
import QtQuick
Singleton {
id: root
readonly property string thumbDir: `${Paths.cache}/thumbnails`.slice(7)
function go(obj: var): var {
return thumbComp.createObject(obj, {
originalPath: obj.path,
width: obj.width,
height: obj.height,
loadOriginal: obj.loadOriginal
});
}
component Thumbnail: QtObject {
id: obj
required property string originalPath
required property int width
required property int height
required property bool loadOriginal
property string path
readonly property Process proc: Process {
running: true
command: ["fish", "-c", `
set -l path "${root.thumbDir}/$(sha1sum ${obj.originalPath} | cut -d ' ' -f 1)@${obj.width}x${obj.height}-exact.png"
if test -f $path
echo $path
else
echo 'start'
set -l size (identify -ping -format '%w\n%h' ${obj.originalPath})
if test $size[1] -gt ${obj.width} -o $size[2] -gt ${obj.height}
magick ${obj.originalPath} -${obj.width > 1024 || obj.height > 1024 ? "resize" : "thumbnail"} ${obj.width}x${obj.height}^ -background none -gravity center -extent ${obj.width}x${obj.height} -unsharp 0x.5 $path
else
cp ${obj.originalPath} $path
end
echo $path
end`]
stdout: SplitParser {
onRead: data => {
if (data === "start") {
if (obj.loadOriginal)
obj.path = obj.originalPath;
} else {
obj.path = data;
}
}
}
}
function reload(): void {
proc.signal(9);
proc.running = true;
}
}
Component {
id: thumbComp
Thumbnail {}
}
}

View file

@ -1,6 +1,7 @@
pragma Singleton
import Quickshell
import Quickshell.Io
import Qt.labs.platform
Singleton {
@ -12,4 +13,19 @@ Singleton {
readonly property url data: `${StandardPaths.standardLocations(StandardPaths.GenericDataLocation)[0]}/caelestia`
readonly property url state: `${StandardPaths.standardLocations(StandardPaths.GenericStateLocation)[0]}/caelestia`
readonly property url cache: `${StandardPaths.standardLocations(StandardPaths.GenericCacheLocation)[0]}/caelestia`
readonly property url imagecache: `${cache}/imagecache`
function mkdir(path: url): void {
mkdirProc.path = path.toString().replace("file://", "");
mkdirProc.startDetached();
}
Process {
id: mkdirProc
property string path
command: ["mkdir", "-p", path]
}
}

View file

@ -1,14 +1,50 @@
import "root:/services"
import "root:/utils"
import Quickshell.Io
import QtQuick
Image {
id: root
property string path
property bool loadOriginal
readonly property Thumbnailer.Thumbnail thumbnail: Thumbnailer.go(this)
property string hash
readonly property string cachePath: `${Paths.imagecache}/${hash}@${width}x${height}.png`.slice(7)
source: thumbnail.path ? `file://${thumbnail.path}` : ""
asynchronous: true
cache: false
fillMode: Image.PreserveAspectCrop
sourceSize.width: width
sourceSize.height: height
onPathChanged: {
shaProc.signal(9);
shaProc.path = path.replace("file://", "");
shaProc.running = true;
}
onCachePathChanged: {
if (hash)
source = cachePath;
}
onStatusChanged: {
if (source == cachePath && status === Image.Error)
source = path;
else if (source == path && status === Image.Ready) {
Paths.mkdir(Paths.imagecache);
const grabPath = cachePath;
grabToImage(res => res.saveToFile(grabPath));
}
}
Process {
id: shaProc
property string path
command: ["sha256sum", path]
stdout: SplitParser {
onRead: data => root.hash = data.split(" ")[0]
}
}
}