summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--accounts/gkleen@sif/default.nix2
-rw-r--r--accounts/gkleen@sif/shell/default.nix69
-rw-r--r--accounts/gkleen@sif/shell/quickshell-plugins/CMakeLists.txt1
-rw-r--r--accounts/gkleen@sif/shell/quickshell-plugins/Chrono.cpp12
-rw-r--r--accounts/gkleen@sif/shell/quickshell-plugins/Chrono.hpp14
-rw-r--r--accounts/gkleen@sif/shell/quickshell-plugins/FileSelector.cpp99
-rw-r--r--accounts/gkleen@sif/shell/quickshell-plugins/FileSelector.hpp52
-rw-r--r--accounts/gkleen@sif/shell/quickshell/Clock.qml39
-rw-r--r--accounts/gkleen@sif/shell/quickshell/Services/NiriService.qml6
-rw-r--r--accounts/gkleen@sif/shell/quickshell/Services/WallpaperSelector.qml8
-rw-r--r--accounts/gkleen@sif/shell/quickshell/WallpaperBackground.qml85
-rw-r--r--accounts/gkleen@sif/shell/quickshell/WorkspaceSwitcher.qml117
-rw-r--r--accounts/gkleen@sif/shell/quickshell/shell.qml23
13 files changed, 487 insertions, 40 deletions
diff --git a/accounts/gkleen@sif/default.nix b/accounts/gkleen@sif/default.nix
index f2978b6e..190a5016 100644
--- a/accounts/gkleen@sif/default.nix
+++ b/accounts/gkleen@sif/default.nix
@@ -374,7 +374,7 @@ in {
374 374
375 services = { 375 services = {
376 wpaperd = { 376 wpaperd = {
377 enable = true; 377 enable = false;
378 settings.default = { 378 settings.default = {
379 path = "~/.wallpapers"; 379 path = "~/.wallpapers";
380 duration = "15m"; 380 duration = "15m";
diff --git a/accounts/gkleen@sif/shell/default.nix b/accounts/gkleen@sif/shell/default.nix
index 26c8bd98..84140072 100644
--- a/accounts/gkleen@sif/shell/default.nix
+++ b/accounts/gkleen@sif/shell/default.nix
@@ -7,8 +7,75 @@
7 config = { 7 config = {
8 src = ./quickshell; 8 src = ./quickshell;
9 replacements = { 9 replacements = {
10 coreutils = toString pkgs.coreutils;
11 ignore_workspaces = builtins.toJSON (map ({ name, ... }: name) config.programs.niri.scratchspaces); 10 ignore_workspaces = builtins.toJSON (map ({ name, ... }: name) config.programs.niri.scratchspaces);
11 wallpapers = builtins.toJSON (pkgs.stdenvNoCC.mkDerivation {
12 name = "wallpapers";
13 srcs = [
14 (pkgs.fetchurl {
15 url = "https://esawebb.org/media/archives/images/publicationtiff10k/carinanebula3.tif";
16 hash = "sha256-YxZEweDKJfvfrdxb/QFmgJhcZDEJYxotoHrG+RRn1tw=";
17 })
18 (pkgs.fetchurl {
19 url = "https://esawebb.org/media/archives/images/original/pillarsofcreation_composite.tif";
20 hash = "sha256-qRiODxR0lZWdxgYXna0fNRFFDErpBJDwOJuQl6sNjRc=";
21 })
22 (pkgs.fetchurl {
23 url = "https://esawebb.org/media/archives/images/publicationtiff10k/weic2212a.tif";
24 hash = "sha256-l2fqE/z//C1a0xkvZwsnwPbTSb+WuA11h+SUl3E1dhw=";
25 })
26 (pkgs.fetchurl {
27 url = "https://esawebb.org/media/archives/images/publicationtiff10k/weic2415a.tif";
28 hash = "sha256-onBy7cPoUpDuzQStbY2E+qmlGgSLXPwFCLX53ukAb4c=";
29 })
30 (pkgs.fetchurl {
31 url = "https://esawebb.org/media/archives/images/publicationtiff10k/weic2330a.tif";
32 hash = "sha256-nn0ZtjZIrPcpj3YcLTsrL7XiXvyh3QYgCSmdDMD+3OM=";
33 })
34 (pkgs.fetchurl {
35 url = "https://esawebb.org/media/archives/images/original/weic2426a.tif";
36 hash = "sha256-EDnfPn3GE9jt6XPqiGInP7E2F3Az7d25NqATSWltDv0=";
37 })
38 (pkgs.fetchurl {
39 url = "https://esawebb.org/media/archives/images/original/weic2503a.tif";
40 hash = "sha256-3/RX6RQp8naELcgReHPd5/zhJkoCjnA10w5BEnNo+qI=";
41 })
42 (pkgs.fetchurl {
43 url = "https://esawebb.org/media/archives/images/original/weic2506a.tif";
44 hash = "sha256-aDld0aoY1owRxDVf7Jcyw71TH42M1foYotxn2thyFYw=";
45 })
46 (pkgs.fetchurl {
47 url = "https://esawebb.org/media/archives/images/original/weic2514a.tif";
48 hash = "sha256-jTi1G1Ofo5xsF6ggrbtYJHxqLaCQ7edM5B3uORiVQtg=";
49 })
50 (pkgs.fetchurl {
51 url = "https://esawebb.org/media/archives/images/original/weic2425c.tif";
52 hash = "sha256-oaEOexSJHEGj090dJF3ct5HAoR+Y5gRiPrUlxdvnTRo=";
53 })
54 ];
55
56 dontUnpack = true;
57
58 buildInputs = [ pkgs.imagemagick ];
59 buildPhase = ''
60 runHook preBuild
61
62 typeset sources=($srcs)
63
64 mkdir -p $out
65 magick ''${sources[0]} -crop 10000x5625+0+79 +repage -define jpeg:extent=10MB $out/carinanebula3.jpeg
66 magick ''${sources[1]} -crop 6716x3778+329+80 +repage -define jpeg:extent=10MB $out/pillarsofcreation_composite.jpeg
67 magick ''${sources[2]} -crop 10000x5625+0+79 +repage -define jpeg:extent=10MB $out/weic2212a.jpeg
68 magick ''${sources[3]} -crop 7650x4302+1166+389 +repage -define jpeg:extent=10MB $out/weic2415a.jpeg
69 magick ''${sources[4]} -crop 8732x4912+0+434 +repage -define jpeg:extent=10MB $out/weic2330a.jpeg
70 magick ''${sources[5]} -crop 5302x2982+636+0 +repage -define jpeg:extent=10MB $out/weic2426a.jpeg
71 magick ''${sources[6]} -crop 4328x2434+0+906 +repage -define jpeg:extent=10MB $out/weic2503a.jpeg
72 magick ''${sources[7]} -crop 4152x2335+0+666 +repage -define jpeg:extent=10MB $out/weic2506a.jpeg
73 magick ''${sources[8]} -crop 4320x2430+0+0 +repage -define jpeg:extent=10MB $out/weic2514a.jpeg
74 magick ''${sources[9]} -crop 5863x3298+0+477 +repage -define jpeg:extent=10MB $out/weic2425c.jpeg
75
76 runHook postBuild
77 '';
78 });
12 }; 79 };
13 }; 80 };
14 }; 81 };
diff --git a/accounts/gkleen@sif/shell/quickshell-plugins/CMakeLists.txt b/accounts/gkleen@sif/shell/quickshell-plugins/CMakeLists.txt
index aa363c4c..2123ed35 100644
--- a/accounts/gkleen@sif/shell/quickshell-plugins/CMakeLists.txt
+++ b/accounts/gkleen@sif/shell/quickshell-plugins/CMakeLists.txt
@@ -104,6 +104,7 @@ qt6_add_qml_module(customplugin
104 104
105target_sources(customplugin PRIVATE 105target_sources(customplugin PRIVATE
106 Chrono.cpp Chrono.hpp 106 Chrono.cpp Chrono.hpp
107 FileSelector.cpp FileSelector.hpp
107) 108)
108 109
109target_compile_features(customplugin PUBLIC cxx_std_26) 110target_compile_features(customplugin PUBLIC cxx_std_26)
diff --git a/accounts/gkleen@sif/shell/quickshell-plugins/Chrono.cpp b/accounts/gkleen@sif/shell/quickshell-plugins/Chrono.cpp
index 929b7be6..df0c5781 100644
--- a/accounts/gkleen@sif/shell/quickshell-plugins/Chrono.cpp
+++ b/accounts/gkleen@sif/shell/quickshell-plugins/Chrono.cpp
@@ -75,14 +75,10 @@ void Chrono::schedule(const std::chrono::time_point<std::chrono::system_clock>&
75 this->timer.start(delay); 75 this->timer.start(delay);
76} 76}
77 77
78QString Chrono::format() const { return this->mFormat; } 78QString Chrono::format(const QString& fmt) const {
79void Chrono::setFormat(QString format) { 79 return QString::fromStdString(std::format(std::runtime_format(fmt.toStdString()), std::chrono::zoned_time(std::chrono::current_zone(), std::chrono::time_point_cast<std::chrono::seconds>(this->currentTime))));
80 if (format == this->mFormat) return;
81 this->mFormat = format;
82 emit this->formatChanged();
83 this->update();
84} 80}
85 81
86QString Chrono::date() const { 82QDateTime Chrono::date() const {
87 return QString::fromStdString(std::format(std::runtime_format(this->mFormat.toStdString()), std::chrono::zoned_time(std::chrono::current_zone(), std::chrono::time_point_cast<std::chrono::seconds>(this->currentTime)))); 83 return QDateTime::fromStdTimePoint(std::chrono::time_point_cast<std::chrono::milliseconds>(this->currentTime));
88} 84}
diff --git a/accounts/gkleen@sif/shell/quickshell-plugins/Chrono.hpp b/accounts/gkleen@sif/shell/quickshell-plugins/Chrono.hpp
index 788fa88e..04080187 100644
--- a/accounts/gkleen@sif/shell/quickshell-plugins/Chrono.hpp
+++ b/accounts/gkleen@sif/shell/quickshell-plugins/Chrono.hpp
@@ -1,17 +1,18 @@
1#pragma once 1#pragma once
2 2
3#include <chrono>
4
5#include <QDateTime>
3#include <QObject> 6#include <QObject>
4#include <QTimer> 7#include <QTimer>
5 8
6#include <qqmlintegration.h> 9#include <qqmlintegration.h>
7#include <chrono>
8 10
9class Chrono : public QObject { 11class Chrono : public QObject {
10 Q_OBJECT; 12 Q_OBJECT;
11 Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged); 13 Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged);
12 Q_PROPERTY(Chrono::Precision precision READ precision WRITE setPrecision NOTIFY precisionChanged); 14 Q_PROPERTY(Chrono::Precision precision READ precision WRITE setPrecision NOTIFY precisionChanged);
13 Q_PROPERTY(QString format READ format WRITE setFormat NOTIFY formatChanged); 15 Q_PROPERTY(QDateTime date READ date NOTIFY dateChanged)
14 Q_PROPERTY(QString date READ date NOTIFY dateChanged);
15 QML_ELEMENT; 16 QML_ELEMENT;
16 17
17public: 18public:
@@ -30,15 +31,13 @@ public:
30 Chrono::Precision precision() const; 31 Chrono::Precision precision() const;
31 void setPrecision(Chrono::Precision precision); 32 void setPrecision(Chrono::Precision precision);
32 33
33 QString format() const; 34 Q_INVOKABLE QString format(const QString& fmt) const;
34 void setFormat (QString format);
35 35
36 QString date() const; 36 QDateTime date() const;
37 37
38signals: 38signals:
39 void enabledChanged(); 39 void enabledChanged();
40 void precisionChanged(); 40 void precisionChanged();
41 void formatChanged();
42 void dateChanged(); 41 void dateChanged();
43 42
44private slots: 43private slots:
@@ -47,7 +46,6 @@ private slots:
47private: 46private:
48 bool mEnabled = true; 47 bool mEnabled = true;
49 Chrono::Precision mPrecision = Chrono::Seconds; 48 Chrono::Precision mPrecision = Chrono::Seconds;
50 QString mFormat = "{:%c}";
51 QTimer timer; 49 QTimer timer;
52 std::chrono::time_point<std::chrono::system_clock> currentTime, targetTime; 50 std::chrono::time_point<std::chrono::system_clock> currentTime, targetTime;
53 51
diff --git a/accounts/gkleen@sif/shell/quickshell-plugins/FileSelector.cpp b/accounts/gkleen@sif/shell/quickshell-plugins/FileSelector.cpp
new file mode 100644
index 00000000..3a0537b6
--- /dev/null
+++ b/accounts/gkleen@sif/shell/quickshell-plugins/FileSelector.cpp
@@ -0,0 +1,99 @@
1#include "FileSelector.hpp"
2
3#include <sstream>
4#include <vector>
5#include <random>
6#include <algorithm>
7
8#include <iostream>
9#include <format>
10
11namespace fs = std::filesystem;
12
13FileSelector::FileSelector(QObject* parent): QObject(parent) {
14 QObject::connect(&this->timer, &QTimer::timeout, this, &FileSelector::onTimeout);
15}
16
17QString FileSelector::directory() const {
18 return QString::fromStdString(this->mDirectory->string());
19}
20void FileSelector::setDirectory(QString directory) {
21 this->mDirectory = directory.toStdString();
22 if (this->mDirectory && this->mEpoch)
23 this->update();
24 emit this->directoryChanged();
25}
26
27unsigned int FileSelector::epoch() const {
28 return std::chrono::duration_cast<std::chrono::milliseconds>(*this->mEpoch).count();
29}
30void FileSelector::setEpoch(unsigned int epoch) {
31 this->mEpoch = std::chrono::milliseconds{epoch};
32 if (this->mDirectory && this->mEpoch)
33 this->update();
34 emit this->epochChanged();
35}
36
37QString FileSelector::seed() const {
38 return this->mSeed;
39}
40void FileSelector::setSeed(QString seed) {
41 this->mSeed = seed;
42 emit this->seedChanged();
43}
44
45QString FileSelector::selected() const {
46 if (!this->mDirectory || !this->mEpoch)
47 return QString();
48
49 std::vector<fs::path> shuffled(this->mFiles.begin(), this->mFiles.end());
50 std::sort(shuffled.begin(), shuffled.end());
51
52 auto currentTime = std::chrono::system_clock::now();
53 uint64_t currentEpoch = currentTime.time_since_epoch() / *this->mEpoch;
54 std::chrono::milliseconds timeInEpoch = std::chrono::duration_cast<std::chrono::milliseconds>(currentTime.time_since_epoch()) % *this->mEpoch;
55
56 std::ostringstream seed;
57 seed << this->mSeed.size() << ";" << this->mSeed.toStdString() << ";";
58 seed << *this->mEpoch << ";";
59 seed << currentEpoch << ";";
60 seed << this->mDirectory->string().size() << ";" << *this->mDirectory << ";";
61 seed << this->mFiles.size() << ";";
62 for (const fs::path& p: this->mFiles)
63 seed << p.string().size() << ";" << p << ";";
64
65 std::vector<std::seed_seq::result_type> v;
66 v.reserve(seed.str().size());
67 for (const char& c: seed.str())
68 v.push_back(c);
69
70 std::seed_seq engine_seed(v.begin(), v.end());
71 std::mt19937 g(engine_seed);
72 std::shuffle(shuffled.begin(), shuffled.end(), g);
73
74 std::vector<fs::path>::size_type ix = shuffled.size() * timeInEpoch / *this->mEpoch;
75 return QString::fromStdString((*this->mDirectory / shuffled[ix]).string());
76}
77
78void FileSelector::onTimeout() {
79 if (!this->mFiles.size())
80 return;
81
82 auto currentTime = std::chrono::system_clock::now();
83 uint64_t currentMinorEpoch = currentTime.time_since_epoch() / (*this->mEpoch / this->mFiles.size());
84 auto nextTime = std::chrono::time_point<std::chrono::system_clock>((2 * currentMinorEpoch + 3) * (*this->mEpoch / (this->mFiles.size() * 2)));
85 this->timer.start(std::chrono::duration_cast<std::chrono::milliseconds>(nextTime - currentTime).count());
86
87 emit this->selectedChanged();
88}
89
90void FileSelector::update() {
91 this->mFiles = std::set<fs::path>{};
92 for (const fs::directory_entry& entry:
93 fs::recursive_directory_iterator(*this->mDirectory, fs::directory_options::follow_directory_symlink))
94 {
95 this->mFiles.insert(fs::relative(entry, *this->mDirectory));
96 }
97
98 this->onTimeout();
99}
diff --git a/accounts/gkleen@sif/shell/quickshell-plugins/FileSelector.hpp b/accounts/gkleen@sif/shell/quickshell-plugins/FileSelector.hpp
new file mode 100644
index 00000000..72c4f2a7
--- /dev/null
+++ b/accounts/gkleen@sif/shell/quickshell-plugins/FileSelector.hpp
@@ -0,0 +1,52 @@
1#pragma once
2
3#include <filesystem>
4#include <chrono>
5#include <set>
6#include <optional>
7
8#include <QObject>
9#include <QTimer>
10
11#include <qqmlintegration.h>
12
13class FileSelector : public QObject {
14 Q_OBJECT;
15 Q_PROPERTY(QString directory READ directory WRITE setDirectory NOTIFY directoryChanged REQUIRED);
16 Q_PROPERTY(unsigned int epoch READ epoch WRITE setEpoch NOTIFY epochChanged REQUIRED);
17 Q_PROPERTY(QString seed READ seed WRITE setSeed NOTIFY seedChanged);
18 Q_PROPERTY(QString selected READ selected NOTIFY selectedChanged);
19 QML_ELEMENT;
20
21public:
22 explicit FileSelector(QObject* parent = nullptr);
23
24 QString directory() const;
25 void setDirectory(QString directory);
26
27 unsigned int epoch() const;
28 void setEpoch(unsigned int epoch);
29
30 QString seed() const;
31 void setSeed(QString seed);
32
33 QString selected() const;
34
35signals:
36 void directoryChanged();
37 void epochChanged();
38 void seedChanged();
39 void selectedChanged();
40
41private slots:
42 void onTimeout();
43
44private:
45 std::optional<std::filesystem::path> mDirectory;
46 std::optional<std::chrono::milliseconds> mEpoch;
47 std::set<std::filesystem::path> mFiles;
48 QString mSeed;
49 QTimer timer;
50
51 void update();
52};
diff --git a/accounts/gkleen@sif/shell/quickshell/Clock.qml b/accounts/gkleen@sif/shell/quickshell/Clock.qml
index 744b187f..edce57e3 100644
--- a/accounts/gkleen@sif/shell/quickshell/Clock.qml
+++ b/accounts/gkleen@sif/shell/quickshell/Clock.qml
@@ -43,10 +43,9 @@ Item {
43 43
44 Custom.Chrono { 44 Custom.Chrono {
45 id: chrono 45 id: chrono
46 format: "W{0:%V-%u} {0:%F} {0:%H:%M:%S%Ez}"
47 }
48 46
49 text: chrono.date 47 onDateChanged: clock.text = format("W{0:%V-%u} {0:%F} {0:%H:%M:%S%Ez}")
48 }
50 49
51 font.pointSize: 10 50 font.pointSize: 10
52 font.family: "Fira Sans" 51 font.family: "Fira Sans"
@@ -79,7 +78,7 @@ Item {
79 color: "black" 78 color: "black"
80 79
81 onVisibleChanged: { 80 onVisibleChanged: {
82 yearCalendar.year = systemClock.date.getFullYear(); 81 yearCalendar.year = chrono.date.getFullYear();
83 clockMouseArea.angleRem = 0; 82 clockMouseArea.angleRem = 0;
84 } 83 }
85 84
@@ -117,7 +116,7 @@ Item {
117 } 116 }
118 117
119 GridLayout { 118 GridLayout {
120 property int year: systemClock.date.getFullYear() 119 property int year: chrono.date.getFullYear()
121 120
122 id: yearCalendar 121 id: yearCalendar
123 122
@@ -128,12 +127,6 @@ Item {
128 Layout.alignment: Qt.AlignHCenter 127 Layout.alignment: Qt.AlignHCenter
129 Layout.fillWidth: false 128 Layout.fillWidth: false
130 129
131 SystemClock {
132 id: systemClock
133
134 precision: SystemClock.Minutes
135 }
136
137 Repeater { 130 Repeater {
138 model: 12 131 model: 12
139 132
@@ -169,17 +162,25 @@ Item {
169 Layout.column: 1 162 Layout.column: 1
170 Layout.fillWidth: true 163 Layout.fillWidth: true
171 164
172 delegate: Text { 165 delegate: WrapperItem {
173 required property string shortName 166 required property string shortName
174 167
175 font.pointSize: 10 168 width: dowLabel.contentWidth + 6
176 font.family: "Fira Mono"
177 169
178 text: shortName 170 Text {
179 color: "#ffcc66" 171 id: dowLabel
180 172
181 horizontalAlignment: Text.AlignRight 173 anchors.fill: parent
182 verticalAlignment: Text.AlignVCenter 174
175 font.pointSize: 10
176 font.family: "Fira Sans"
177
178 text: parent.shortName
179 color: "#ffcc66"
180
181 horizontalAlignment: Text.AlignHCenter
182 verticalAlignment: Text.AlignVCenter
183 }
183 } 184 }
184 } 185 }
185 186
@@ -244,7 +245,7 @@ Item {
244 font.family: "Fira Sans" 245 font.family: "Fira Sans"
245 font.features: { "tnum": 1 } 246 font.features: { "tnum": 1 }
246 247
247 property bool today: systemClock.date.getFullYear() == model.year && systemClock.date.getMonth() == model.month && systemClock.date.getDate() == model.day 248 property bool today: chrono.date.getFullYear() == model.year && chrono.date.getMonth() == model.month && chrono.date.getDate() == model.day
248 249
249 text: model.day 250 text: model.day
250 color: today ? "#ff6699" : "white" 251 color: today ? "#ff6699" : "white"
diff --git a/accounts/gkleen@sif/shell/quickshell/Services/NiriService.qml b/accounts/gkleen@sif/shell/quickshell/Services/NiriService.qml
index 179b55e0..af522ec4 100644
--- a/accounts/gkleen@sif/shell/quickshell/Services/NiriService.qml
+++ b/accounts/gkleen@sif/shell/quickshell/Services/NiriService.qml
@@ -160,7 +160,11 @@ Singleton {
160 }); 160 });
161 } 161 }
162 function eventWindowOpenedOrChanged(data) { 162 function eventWindowOpenedOrChanged(data) {
163 root.windows = Array.from(root.windows).filter(win => win.id !== data.window.id).concat([data.window]); 163 root.windows = Array.from(root.windows).map(win => {
164 if (data.window.is_focused)
165 win.is_focused = false;
166 return win;
167 }).filter(win => win.id !== data.window.id).concat([data.window]);
164 } 168 }
165 function eventWindowClosed(data) { 169 function eventWindowClosed(data) {
166 root.windows = Array.from(root.windows).filter(win => win.id !== data.id); 170 root.windows = Array.from(root.windows).filter(win => win.id !== data.id);
diff --git a/accounts/gkleen@sif/shell/quickshell/Services/WallpaperSelector.qml b/accounts/gkleen@sif/shell/quickshell/Services/WallpaperSelector.qml
new file mode 100644
index 00000000..3c524955
--- /dev/null
+++ b/accounts/gkleen@sif/shell/quickshell/Services/WallpaperSelector.qml
@@ -0,0 +1,8 @@
1import Custom as Custom
2
3Custom.FileSelector {
4 id: root
5
6 directory: @wallpapers@
7 epoch: 72000000
8}
diff --git a/accounts/gkleen@sif/shell/quickshell/WallpaperBackground.qml b/accounts/gkleen@sif/shell/quickshell/WallpaperBackground.qml
new file mode 100644
index 00000000..de31915f
--- /dev/null
+++ b/accounts/gkleen@sif/shell/quickshell/WallpaperBackground.qml
@@ -0,0 +1,85 @@
1import QtQuick
2import Quickshell
3import qs.Services
4
5Item {
6 id: root
7
8 anchors.fill: parent
9
10 required property string screen
11
12 property Img current: one
13 property string source: selector.selected
14
15 WallpaperSelector {
16 id: selector
17 seed: screen
18 }
19
20 onSourceChanged: {
21 if (!source)
22 current = null;
23 else if (current === one)
24 two.update()
25 else
26 one.update()
27 }
28
29 Img { id: one }
30 Img { id: two }
31
32 component Img: Image {
33 id: img
34
35 function update() {
36 source = root.source || ""
37 }
38
39 anchors.fill: parent
40 fillMode: Image.PreserveAspectCrop
41 smooth: true
42 asynchronous: true
43 cache: false
44
45 opacity: 0
46
47 onStatusChanged: {
48 if (status === Image.Ready) {
49 root.current = this
50 }
51 }
52
53 states: State {
54 name: "visible"
55 when: root.current === img
56
57 PropertyChanges {
58 img.opacity: 1
59 }
60 StateChangeScript {
61 name: "unloadOther"
62 script: {
63 if (img === one)
64 two.source = ""
65 if (img === two)
66 one.source = ""
67 }
68 }
69 }
70
71 transitions: Transition {
72 SequentialAnimation {
73 NumberAnimation {
74 target: img
75 properties: "opacity"
76 duration: 5000
77 easing.type: Easing.OutCubic
78 }
79 ScriptAction {
80 scriptName: "unloadOther"
81 }
82 }
83 }
84 }
85}
diff --git a/accounts/gkleen@sif/shell/quickshell/WorkspaceSwitcher.qml b/accounts/gkleen@sif/shell/quickshell/WorkspaceSwitcher.qml
index 9546abb4..c8c017c3 100644
--- a/accounts/gkleen@sif/shell/quickshell/WorkspaceSwitcher.qml
+++ b/accounts/gkleen@sif/shell/quickshell/WorkspaceSwitcher.qml
@@ -2,6 +2,7 @@ import Quickshell
2import QtQuick 2import QtQuick
3import qs.Services 3import qs.Services
4import Quickshell.Widgets 4import Quickshell.Widgets
5import QtQuick.Layouts
5 6
6Row { 7Row {
7 id: workspaces 8 id: workspaces
@@ -79,6 +80,122 @@ Row {
79 } 80 }
80 } 81 }
81 } 82 }
83
84 PopupWindow {
85 id: tooltip
86
87 property bool nextVisible: (mouseArea.containsMouse || tooltipMouseArea.containsMouse) && [...windowsModel.values].length > 0
88
89 anchor {
90 item: mouseArea
91 edges: Edges.Bottom | Edges.Left
92 }
93 visible: false
94
95 onNextVisibleChanged: hangTimer.restart()
96
97 Timer {
98 id: hangTimer
99 interval: 100
100 onTriggered: tooltip.visible = tooltip.nextVisible
101 }
102
103 implicitWidth: tooltipContent.implicitWidth
104 implicitHeight: tooltipContent.implicitHeight
105 color: "black"
106
107 WrapperMouseArea {
108 id: tooltipMouseArea
109
110 hoverEnabled: true
111 enabled: true
112
113 anchors.fill: parent
114
115 WrapperItem {
116 id: tooltipContent
117
118 margin: 0
119
120 ColumnLayout {
121 spacing: 0
122
123 Repeater {
124 model: ScriptModel {
125 id: windowsModel
126
127 values: {
128 let currWindows = Array.from(NiriService.windows).filter(win => win.workspace_id == wsItem.workspaceData.id);
129 currWindows.sort((a, b) => {
130 if (a.is_floating !== b.is_floating)
131 return b.is_floating - a.is_floating;
132 if (a.layout.tile_pos_in_workspace_view?.[0] !== b.layout.tile_pos_in_workspace_view?.[0])
133 return a.layout.tile_pos_in_workspace_view?.[0] - b.layout.tile_pos_in_workspace_view?.[0]
134 if (a.layout.tile_pos_in_workspace_view?.[1] !== b.layout.tile_pos_in_workspace_view?.[1])
135 return a.layout.tile_pos_in_workspace_view?.[1] - b.layout.tile_pos_in_workspace_view?.[1]
136 if (a.layout.pos_in_scrolling_layout?.[0] !== b.layout.pos_in_scrolling_layout?.[0])
137 return a.layout.pos_in_scrolling_layout?.[0] - b.layout.pos_in_scrolling_layout?.[0]
138 if (a.layout.pos_in_scrolling_layout?.[1] !== b.layout.pos_in_scrolling_layout?.[1])
139 return a.layout.pos_in_scrolling_layout?.[1] - b.layout.pos_in_scrolling_layout?.[1]
140 if (a.app_id !== b.app_id)
141 return a.app_id.localeCompare(b.app_id);
142
143 return a.title.localeCompare(b.title);
144 });
145 return currWindows;
146 }
147 }
148
149 WrapperMouseArea {
150 id: windowMouseArea
151
152 property var windowData: modelData
153
154 hoverEnabled: true
155 cursorShape: Qt.PointingHandCursor
156 enabled: true
157
158 Layout.fillWidth: true
159
160 onClicked: {
161 NiriService.sendCommand({ "Action": { "FocusWindow": { "id": windowData.id } } }, _ => {})
162 }
163
164 WrapperRectangle {
165 color: windowMouseArea.containsMouse ? "#33808080" : "transparent";
166
167 anchors.fill: parent
168
169 WrapperItem {
170 anchors.fill: parent
171
172 margin: 4
173
174 Text {
175 id: windowLabel
176
177 font.pointSize: 10
178 font.family: "Fira Sans"
179 color: {
180 if (windowData.is_focused)
181 return "#23fd00";
182 if (NiriService.workspaces.find(ws => ws.id == windowData.workspace_id)?.active_window_id == windowData.id)
183 return "white";
184 return "#555";
185 }
186
187 text: windowData.title
188
189 horizontalAlignment: Text.AlignLeft
190 }
191 }
192 }
193 }
194 }
195 }
196 }
197 }
198 }
82 } 199 }
83 } 200 }
84} 201}
diff --git a/accounts/gkleen@sif/shell/quickshell/shell.qml b/accounts/gkleen@sif/shell/quickshell/shell.qml
index 4934cd4d..2ddecad9 100644
--- a/accounts/gkleen@sif/shell/quickshell/shell.qml
+++ b/accounts/gkleen@sif/shell/quickshell/shell.qml
@@ -1,6 +1,7 @@
1//@ pragma UseQApplication 1//@ pragma UseQApplication
2 2
3import Quickshell 3import Quickshell
4import Quickshell.Wayland
4 5
5ShellRoot { 6ShellRoot {
6 settings.watchFiles: false 7 settings.watchFiles: false
@@ -13,9 +14,27 @@ ShellRoot {
13 14
14 required property var modelData 15 required property var modelData
15 16
16 Bar { 17 PanelWindow {
17 id: bar 18 id: bgWindow
19
20 screen: screenScope.modelData
21
22 WlrLayershell.layer: WlrLayer.Background
23 WlrLayershell.exclusionMode: ExclusionMode.Ignore
24
25 anchors.top: true
26 anchors.bottom: true
27 anchors.left: true
28 anchors.right: true
18 29
30 color: "black"
31
32 WallpaperBackground {
33 screen: bgWindow.screen.name
34 }
35 }
36
37 Bar {
19 screen: screenScope.modelData 38 screen: screenScope.modelData
20 } 39 }
21 } 40 }