feat: basic quickshell setup
This commit is contained in:
@@ -20,3 +20,7 @@ output_path = '~/.config/gtk-3.0/gtk.css'
|
|||||||
[templates.gtk4]
|
[templates.gtk4]
|
||||||
input_path = '~/.config/matugen/templates/gtk-4.0/gtk.css'
|
input_path = '~/.config/matugen/templates/gtk-4.0/gtk.css'
|
||||||
output_path = '~/.config/gtk-4.0/gtk.css'
|
output_path = '~/.config/gtk-4.0/gtk.css'
|
||||||
|
|
||||||
|
[templates.wlogout]
|
||||||
|
input_path = '~/.config/matugen/templates/wlogout/style.css'
|
||||||
|
output_path = '~/.config/wlogout/style.css'
|
||||||
|
|||||||
@@ -1 +1,4 @@
|
|||||||
# Quickshell Status bar
|
# Quickshell Status bar
|
||||||
|
Many of the components were taken and adapted from the [End-4 configs](https://github.com/end-4/dots-hyprland).
|
||||||
|
|
||||||
|
All of the files in `utils/` are taken from the End-4 configs
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import "./widgets/"
|
||||||
|
import "../config"
|
||||||
|
|
||||||
|
Scope {
|
||||||
|
Variants {
|
||||||
|
model: Quickshell.screens
|
||||||
|
|
||||||
|
PanelWindow {
|
||||||
|
id: barRoot
|
||||||
|
property var modelData
|
||||||
|
screen: modelData
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
top: true
|
||||||
|
left: true
|
||||||
|
right: true
|
||||||
|
}
|
||||||
|
|
||||||
|
color: Appearance.colors.m3background
|
||||||
|
|
||||||
|
implicitHeight: 40
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
Clock {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import "../config/"
|
||||||
|
|
||||||
|
// Mostly from here: https://github.com/ChrisTitusTech/quickshell/blob/main/bar/BarBlock.qml
|
||||||
|
Rectangle {
|
||||||
|
id: root
|
||||||
|
radius: Appearance.rounding.barItems
|
||||||
|
|
||||||
|
Layout.preferredWidth: contentContainer.implicitWidth + 20
|
||||||
|
Layout.preferredHeight: 30
|
||||||
|
|
||||||
|
property Item content: Text {
|
||||||
|
text: "No content"
|
||||||
|
}
|
||||||
|
property bool hoverEnabled: false
|
||||||
|
property Item mouseArea: mouseArea
|
||||||
|
|
||||||
|
property bool dim: false
|
||||||
|
property var onClicked: function () {}
|
||||||
|
property int leftPadding
|
||||||
|
property int rightPadding
|
||||||
|
|
||||||
|
// Background color
|
||||||
|
color: {
|
||||||
|
if (mouseArea.containsMouse)
|
||||||
|
return Appearance.colors.m3primary;
|
||||||
|
return Appearance.colors.m3background;
|
||||||
|
}
|
||||||
|
|
||||||
|
states: [
|
||||||
|
State {
|
||||||
|
when: mouseArea.containsMouse
|
||||||
|
PropertyChanges {
|
||||||
|
target: root
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: 200
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
// Contents of the bar block
|
||||||
|
id: contentContainer
|
||||||
|
implicitWidth: content.implicitWidth
|
||||||
|
implicitHeight: content.implicitHeight
|
||||||
|
anchors.centerIn: parent
|
||||||
|
children: content
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
enabled: root.hoverEnabled
|
||||||
|
id: mouseArea
|
||||||
|
anchors.fill: root
|
||||||
|
hoverEnabled: true
|
||||||
|
acceptedButtons: Qt.LeftButton
|
||||||
|
onClicked: root.onClicked()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
Bar 1.0 Bar.qml
|
||||||
|
WidgetWrapper 1.0 WidgetWrapper.qml
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
|
||||||
|
Scope {}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import "."
|
||||||
|
import "../../config"
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: `${ClockHandler.date}, ${ClockHandler.time}`
|
||||||
|
color: Appearance.colors.m3onBackground
|
||||||
|
Layout.leftMargin: 10
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
pragma Singleton
|
||||||
|
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
property string time
|
||||||
|
property string date
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: dateProc
|
||||||
|
command: ["date", "+%a %e %b|%T"]
|
||||||
|
running: true
|
||||||
|
|
||||||
|
stdout: SplitParser {
|
||||||
|
onRead: data => {
|
||||||
|
date = data.split("|")[0];
|
||||||
|
time = data.split("|")[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
interval: 1000
|
||||||
|
running: true
|
||||||
|
repeat: true
|
||||||
|
onTriggered: dateProc.running = true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
Scope {
|
||||||
|
id: root
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
Clock 1.0 Clock.qml
|
||||||
|
singleton ClockHandler 1.0 ClockHandler.qml
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
pragma Singleton
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
property QtObject colors
|
||||||
|
property QtObject fonts
|
||||||
|
property QtObject fontsizes
|
||||||
|
property QtObject rounding
|
||||||
|
|
||||||
|
// From end-4 configs
|
||||||
|
colors: QtObject {
|
||||||
|
property color m3background: "#141313"
|
||||||
|
property color m3onBackground: "#e6e1e1"
|
||||||
|
property color m3surface: "#141313"
|
||||||
|
property color m3surfaceDim: "#141313"
|
||||||
|
property color m3surfaceBright: "#3a3939"
|
||||||
|
property color m3surfaceContainerLowest: "#0f0e0e"
|
||||||
|
property color m3surfaceContainerLow: "#1c1b1c"
|
||||||
|
property color m3surfaceContainer: "#201f20"
|
||||||
|
property color m3surfaceContainerHigh: "#2b2a2a"
|
||||||
|
property color m3surfaceContainerHighest: "#363435"
|
||||||
|
property color m3onSurface: "#e6e1e1"
|
||||||
|
property color m3surfaceVariant: "#49464a"
|
||||||
|
property color m3onSurfaceVariant: "#cbc5ca"
|
||||||
|
property color m3inverseSurface: "#e6e1e1"
|
||||||
|
property color m3inverseOnSurface: "#313030"
|
||||||
|
property color m3outline: "#948f94"
|
||||||
|
property color m3outlineVariant: "#49464a"
|
||||||
|
property color m3shadow: "#000000"
|
||||||
|
property color m3scrim: "#000000"
|
||||||
|
property color m3surfaceTint: "#cbc4cb"
|
||||||
|
property color m3primary: "#cbc4cb"
|
||||||
|
property color m3onPrimary: "#322f34"
|
||||||
|
property color m3primaryContainer: "#2d2a2f"
|
||||||
|
property color m3onPrimaryContainer: "#bcb6bc"
|
||||||
|
property color m3inversePrimary: "#615d63"
|
||||||
|
property color m3secondary: "#cac5c8"
|
||||||
|
property color m3onSecondary: "#323032"
|
||||||
|
property color m3secondaryContainer: "#4d4b4d"
|
||||||
|
property color m3onSecondaryContainer: "#ece6e9"
|
||||||
|
property color m3tertiary: "#d1c3c6"
|
||||||
|
property color m3onTertiary: "#372e30"
|
||||||
|
property color m3tertiaryContainer: "#31292b"
|
||||||
|
property color m3onTertiaryContainer: "#c1b4b7"
|
||||||
|
property color m3error: "#ffb4ab"
|
||||||
|
property color m3onError: "#690005"
|
||||||
|
property color m3errorContainer: "#93000a"
|
||||||
|
property color m3onErrorContainer: "#ffdad6"
|
||||||
|
property color m3primaryFixed: "#e7e0e7"
|
||||||
|
property color m3primaryFixedDim: "#cbc4cb"
|
||||||
|
property color m3onPrimaryFixed: "#1d1b1f"
|
||||||
|
property color m3onPrimaryFixedVariant: "#49454b"
|
||||||
|
property color m3secondaryFixed: "#e6e1e4"
|
||||||
|
property color m3secondaryFixedDim: "#cac5c8"
|
||||||
|
property color m3onSecondaryFixed: "#1d1b1d"
|
||||||
|
property color m3onSecondaryFixedVariant: "#484648"
|
||||||
|
property color m3tertiaryFixed: "#eddfe1"
|
||||||
|
property color m3tertiaryFixedDim: "#d1c3c6"
|
||||||
|
property color m3onTertiaryFixed: "#211a1c"
|
||||||
|
property color m3onTertiaryFixedVariant: "#4e4447"
|
||||||
|
property color m3success: "#B5CCBA"
|
||||||
|
property color m3onSuccess: "#213528"
|
||||||
|
property color m3successContainer: "#374B3E"
|
||||||
|
property color m3onSuccessContainer: "#D1E9D6"
|
||||||
|
}
|
||||||
|
|
||||||
|
rounding: QtObject {
|
||||||
|
property int barItems: 10
|
||||||
|
}
|
||||||
|
|
||||||
|
function reapplyTheme() {
|
||||||
|
themeFileView.reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyTheme(fileContent) {
|
||||||
|
const json = JSON.parse(fileContent);
|
||||||
|
for (const key in json) {
|
||||||
|
if (json.hasOwnProperty(key)) {
|
||||||
|
// Convert snake_case to CamelCase
|
||||||
|
const camelCaseKey = key.replace(/_([a-z])/g, g => g[1].toUpperCase());
|
||||||
|
const m3Key = `${camelCaseKey}`;
|
||||||
|
root.colors[m3Key] = json[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: delayedFileRead
|
||||||
|
interval: 1000
|
||||||
|
repeat: false
|
||||||
|
running: false
|
||||||
|
onTriggered: {
|
||||||
|
root.applyTheme(themeFileView.text());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FileView {
|
||||||
|
id: themeFileView
|
||||||
|
path: Qt.resolvedUrl(Paths.materialColorsPath)
|
||||||
|
watchChanges: true
|
||||||
|
onFileChanged: {
|
||||||
|
this.reload();
|
||||||
|
delayedFileRead.start();
|
||||||
|
}
|
||||||
|
onLoadedChanged: {
|
||||||
|
const fileContent = themeFileView.text();
|
||||||
|
root.applyTheme(fileContent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
pragma Singleton
|
||||||
|
|
||||||
|
import Quickshell
|
||||||
|
import QtCore
|
||||||
|
import "../utils/"
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
readonly property string home: StandardPaths.standardLocations(StandardPaths.HomeLocation)[0]
|
||||||
|
readonly property string config: StandardPaths.standardLocations(StandardPaths.ConfigLocation)[0]
|
||||||
|
readonly property string state: StandardPaths.standardLocations(StandardPaths.StateLocation)[0]
|
||||||
|
readonly property string cache: StandardPaths.standardLocations(StandardPaths.CacheLocation)[0]
|
||||||
|
|
||||||
|
property string materialColorsPath: FileUtils.trimFileProtocol(`${Paths.state}/user/generated/colors.json`)
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
singleton Appearance 1.0 Appearance.qml
|
||||||
|
singleton Paths 1.0 Paths.qml
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
// From https://github.com/quickshell-mirror/quickshell-examples/blob/master/volume-osd/shell.qml
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Services.Pipewire
|
||||||
|
import Quickshell.Widgets
|
||||||
|
import "../config/"
|
||||||
|
|
||||||
|
Scope {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
// Bind the pipewire node so its volume will be tracked
|
||||||
|
PwObjectTracker {
|
||||||
|
objects: [Pipewire.defaultAudioSink]
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: Pipewire.defaultAudioSink?.audio
|
||||||
|
|
||||||
|
function onVolumeChanged() {
|
||||||
|
root.shouldShowOsd = true;
|
||||||
|
hideTimer.restart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
property bool shouldShowOsd: false
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: hideTimer
|
||||||
|
interval: 1000
|
||||||
|
onTriggered: root.shouldShowOsd = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// The OSD window will be created and destroyed based on shouldShowOsd.
|
||||||
|
// PanelWindow.visible could be set instead of using a loader, but using
|
||||||
|
// a loader will reduce the memory overhead when the window isn't open.
|
||||||
|
LazyLoader {
|
||||||
|
active: root.shouldShowOsd
|
||||||
|
|
||||||
|
PanelWindow {
|
||||||
|
// Since the panel's screen is unset, it will be picked by the compositor
|
||||||
|
// when the window is created. Most compositors pick the current active monitor.
|
||||||
|
|
||||||
|
anchors.bottom: true
|
||||||
|
margins.bottom: screen.height / 5
|
||||||
|
exclusiveZone: 0
|
||||||
|
|
||||||
|
implicitWidth: 300
|
||||||
|
implicitHeight: 50
|
||||||
|
color: "transparent"
|
||||||
|
|
||||||
|
// An empty click mask prevents the window from blocking mouse events.
|
||||||
|
mask: Region {}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: height / 2
|
||||||
|
color: Appearance.colors.m3background
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors {
|
||||||
|
fill: parent
|
||||||
|
leftMargin: 10
|
||||||
|
rightMargin: 15
|
||||||
|
}
|
||||||
|
|
||||||
|
IconImage {
|
||||||
|
implicitSize: 30
|
||||||
|
source: Quickshell.iconPath("audio-volume-high-symbolic")
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
// Stretches to fill all left-over space
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
implicitHeight: 10
|
||||||
|
radius: 20
|
||||||
|
color: "#50ffffff"
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors {
|
||||||
|
left: parent.left
|
||||||
|
top: parent.top
|
||||||
|
bottom: parent.bottom
|
||||||
|
}
|
||||||
|
|
||||||
|
implicitWidth: parent.width * (Pipewire.defaultAudioSink?.audio.volume ?? 0)
|
||||||
|
radius: parent.radius
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Volume 1.0 Volume.qml
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
import "config"
|
||||||
|
import "bar"
|
||||||
|
import "osd"
|
||||||
|
|
||||||
|
ShellRoot {
|
||||||
|
Component.onCompleted: {
|
||||||
|
// Load themes
|
||||||
|
Appearance.reapplyTheme();
|
||||||
|
}
|
||||||
|
|
||||||
|
Bar {}
|
||||||
|
Volume {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
pragma Singleton
|
||||||
|
|
||||||
|
import Quickshell
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trims the File protocol off the input string
|
||||||
|
* @param {string} str
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function trimFileProtocol(str) {
|
||||||
|
let s = str;
|
||||||
|
if (typeof s !== "string") s = str.toString(); // Convert to string if it's an url or whatever
|
||||||
|
return s.startsWith("file://") ? s.slice(7) : s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the file name from a file path
|
||||||
|
* @param {string} str
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function fileNameForPath(str) {
|
||||||
|
if (typeof str !== "string") return "";
|
||||||
|
const trimmed = trimFileProtocol(str);
|
||||||
|
return trimmed.split(/[\\/]/).pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the folder name from a directory path
|
||||||
|
* @param {string} str
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function folderNameForPath(str) {
|
||||||
|
if (typeof str !== "string") return "";
|
||||||
|
const trimmed = trimFileProtocol(str);
|
||||||
|
// Remove trailing slash if present
|
||||||
|
const noTrailing = trimmed.endsWith("/") ? trimmed.slice(0, -1) : trimmed;
|
||||||
|
if (!noTrailing) return "";
|
||||||
|
return noTrailing.split(/[\\/]/).pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the file extension from a file path or name
|
||||||
|
* @param {string} str
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function trimFileExt(str) {
|
||||||
|
if (typeof str !== "string") return "";
|
||||||
|
const trimmed = trimFileProtocol(str);
|
||||||
|
const lastDot = trimmed.lastIndexOf(".");
|
||||||
|
if (lastDot > -1 && lastDot > trimmed.lastIndexOf("/")) {
|
||||||
|
return trimmed.slice(0, lastDot);
|
||||||
|
}
|
||||||
|
return trimmed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the parent directory of a given file path
|
||||||
|
* @param {string} str
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function parentDirectory(str) {
|
||||||
|
if (typeof str !== "string") return "";
|
||||||
|
const trimmed = trimFileProtocol(str);
|
||||||
|
const parts = trimmed.split(/[\\/]/);
|
||||||
|
if (parts.length <= 1) return "";
|
||||||
|
parts.pop();
|
||||||
|
return parts.join("/");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
singleton FileUtils 1.0 FileUtils.qml
|
||||||
Executable
+4
@@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
mkdir ~/.config/quickshell | true
|
||||||
|
cp -r ./config/quickshell/* ~/.config/quickshell/
|
||||||
Reference in New Issue
Block a user