This commit is contained in:
Bloxx12 2025-06-24 15:51:34 +02:00
commit 334bca71fe
Signed by: faukah
SSH key fingerprint: SHA256:Uj2AXqvtdCA4hn5Hq0ZonhIAyUqI1q4w2sMG3Z1TH7E
17 changed files with 733 additions and 117 deletions

View file

@ -6,11 +6,9 @@ import Quickshell
import "../../config"
import "components"
Rectangle {
Item {
id: root
color: Config.bar.colors.bar
required property ShellScreen screen
anchors {
@ -48,10 +46,5 @@ Rectangle {
screen: root.screen
}
}
Text {
text: root.screen.name
color: "green"
}
}
}

View file

@ -13,22 +13,23 @@ Rectangle {
required property ShellScreen screen
property var workspaces: Niri.workspaces
property var wsCount: Niri.workspaces.length
property var activeWorkspace: Niri.activeWorkspace
property var activeWorkspaceIndex: Niri.activeWorkspaceIndex
property int wsItemHeight: 15
property bool _: log()
function log() {
console.debug("Screen name: " + screen.name);
console.debug("Found the following workspaces:");
for (let i = 0; i < workspaces.length; i++) {
console.debug("Workspace " + workspaces[i].id + " On screen " + workspaces[i].output + " With name: " + workspaces[i].name);
// console.debug(workspaces[i].output);
}
return true;
signal workspaceAdded(workspace: var)
function onWorkspaceAdded(workspace: var) {
root.workspaces.push(workspace);
}
// property bool _: log()
// function log() {
// console.log(workspaces.values);
// return true;
// }
// Works
height: 300
@ -96,8 +97,13 @@ Rectangle {
border.color: Config.catppuccin.mantle
border.width: 0
color: Config.catppuccin.blue
// visible: wsItem.isCorrectScreen
}
}
}
Component.onCompleted: {
Niri.workspaces.forEach(workspace => {
root.workspaceAdded(workspace);
});
}
}

View file

@ -1,3 +0,0 @@
import QtQuick
import QtQuick.Shapes

View file

@ -0,0 +1,9 @@
import Quickshell
import QtQuick
import QtQuick.Shapes
import "../notifications" as Notifications
Rectangle {
required property Item bar
}

View file

@ -7,7 +7,7 @@ import "../../config"
Item {
id: root
required property Rectangle bar
required property Item bar
anchors.fill: parent

View file

@ -7,9 +7,11 @@ import QtQuick
import QtQuick.Effects
import "../bar"
import "../volume"
import "../notifications"
// import "../../services"
import "../../services"
import "../../config"
Variants {
model: Quickshell.screens
@ -35,13 +37,22 @@ Variants {
// Clickthrough mask.
// Clickable areas of the window are determined by the provided region.
mask: Region {
// Start at the bottom left; right of the bar and on top of the border
x: bar.implicitWidth
y: 8
width: win.width - bar.implicitWidth
height: win.height - 8
y: Config.border.thickness
// Width is the window width - the bar's width - the border thickness
width: win.width - bar.implicitWidth - Config.border.thickness
// Height is window width - the border thickness x2 top border and bottom border.
height: win.height - Config.border.thickness * 2
// Setting the intersection mode to Xor will invert the mask and make everything in the mask region not clickable and pass through clicks inside it through the window.
intersection: Intersection.Xor
Region {
item: volume
intersection: Intersection.Subtract
}
}
anchors {
@ -60,6 +71,10 @@ Variants {
Border {
bar: bar
}
Backgrounds {
bar: bar
}
}
MultiEffect {
@ -73,45 +88,18 @@ Variants {
id: bar
screen: scope.modelData
}
Item {
id: notifs
readonly property list<Notif> list: []
readonly property list<Notif> popups: list.filter(n => n.popup)
VolumeSlider {
id: volume
isInRightPanel: hover.isInRightPanel
screen: scope.modelData
}
NotificationServer {
id: server
keepOnReload: false
onNotification: notif => {
notif.tracked = true;
console.log("Got notification: " + notif.body);
root.list.push(notifComp.createObject(root, {
popup: true,
notification: notif,
body: notif.body,
appName: notif.appName
}));
}
}
Component {
id: notifComp
Notif {}
}
Hover {
id: hover
screen: scope.modelData
bar: bar
}
}
}
component Notif: QtObject {
property bool popup
readonly property date time: new Date()
required property Notification notification
readonly property string body: notification.body
readonly property string appName: notification.appName
}
}

View file

@ -0,0 +1,319 @@
pragma Singleton
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Io
import Quickshell.Wayland
import Quickshell.Widgets
Singleton {
id: launcher
property bool launcherOpen: false
IpcHandler {
target: "launcher"
function open(): void {
launcher.launcherOpen = true;
}
function close(): void {
launcher.launcherOpen = false;
}
function toggle(): void {
launcher.launcherOpen = !launcher.launcherOpen;
}
}
LazyLoader {
id: loader
activeAsync: launcher.launcherOpen
PanelWindow {
width: 450
height: 7 + searchContainer.implicitHeight + list.topMargin * 2 + list.delegateHeight * 10
color: "transparent"
anchors {
bottom: parent.bottom
}
WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive
WlrLayershell.namespace: "shell:launcher"
Rectangle {
height: 7 + searchContainer.implicitHeight + list.topMargin + list.bottomMargin + Math.min(list.contentHeight, list.delegateHeight * 10)
Behavior on height {
NumberAnimation {
duration: 200
easing.type: Easing.OutCubic
}
}
width: 450
color: "#30c0afaf"
radius: 5
border.color: "black"
border.width: 2
ColumnLayout {
anchors.fill: parent
anchors.margins: 7
anchors.bottomMargin: 0
spacing: 0
Rectangle {
id: searchContainer
Layout.fillWidth: true
implicitHeight: searchbox.implicitHeight + 10
color: "#30c0ffff"
radius: 3
border.color: "#50ffffff"
RowLayout {
id: searchbox
anchors.fill: parent
anchors.margins: 5
IconImage {
implicitSize: parent.height
source: "root:icons/magnifying-glass.svg"
}
TextInput {
id: search
Layout.fillWidth: true
color: "black"
focus: true
Keys.forwardTo: [list]
Keys.onEscapePressed: launcher.launcherOpen = false
Keys.onPressed: event => {
if (event.modifiers & Qt.ControlModifier) {
if (event.key == Qt.Key_J) {
list.currentIndex = list.currentIndex == list.count - 1 ? 0 : list.currentIndex + 1;
event.accepted = true;
} else if (event.key == Qt.Key_K) {
list.currentIndex = list.currentIndex == 0 ? list.count - 1 : list.currentIndex - 1;
event.accepted = true;
}
}
}
onAccepted: {
if (list.currentItem) {
list.currentItem.clicked(null);
}
}
onTextChanged: {
list.currentIndex = 0;
}
}
}
}
ListView {
id: list
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
cacheBuffer: 0 // works around QTBUG-131106
//reuseItems: true
model: ScriptModel {
values: DesktopEntries.applications.values.map(object => {
const stxt = search.text.toLowerCase();
const ntxt = object.name.toLowerCase();
let si = 0;
let ni = 0;
let matches = [];
let startMatch = -1;
for (let si = 0; si != stxt.length; ++si) {
const sc = stxt[si];
while (true) {
// Drop any entries with letters that don't exist in order
if (ni == ntxt.length)
return null;
const nc = ntxt[ni++];
if (nc == sc) {
if (startMatch == -1)
startMatch = ni;
break;
} else {
if (startMatch != -1) {
matches.push({
index: startMatch,
length: ni - startMatch
});
startMatch = -1;
}
}
}
}
if (startMatch != -1) {
matches.push({
index: startMatch,
length: ni - startMatch + 1
});
}
return {
object: object,
matches: matches
};
}).filter(entry => entry !== null).sort((a, b) => {
let ai = 0;
let bi = 0;
let s = 0;
while (ai != a.matches.length && bi != b.matches.length) {
const am = a.matches[ai];
const bm = b.matches[bi];
s = bm.length - am.length;
if (s != 0)
return s;
s = am.index - bm.index;
if (s != 0)
return s;
++ai;
++bi;
}
s = a.matches.length - b.matches.length;
if (s != 0)
return s;
s = a.object.name.length - b.object.name.length;
if (s != 0)
return s;
return a.object.name.localeCompare(b.object.name);
}).map(entry => entry.object)
onValuesChanged: list.currentIndex = 0
}
topMargin: 7
bottomMargin: list.count == 0 ? 0 : 7
add: Transition {
NumberAnimation {
property: "opacity"
from: 0
to: 1
duration: 100
}
}
displaced: Transition {
NumberAnimation {
property: "y"
duration: 200
easing.type: Easing.OutCubic
}
NumberAnimation {
property: "opacity"
to: 1
duration: 100
}
}
move: Transition {
NumberAnimation {
property: "y"
duration: 200
easing.type: Easing.OutCubic
}
NumberAnimation {
property: "opacity"
to: 1
duration: 100
}
}
remove: Transition {
NumberAnimation {
property: "y"
duration: 200
easing.type: Easing.OutCubic
}
NumberAnimation {
property: "opacity"
to: 0
duration: 100
}
}
highlight: Rectangle {
radius: 5
color: "#20e0ffff"
border.color: "#30ffffff"
border.width: 1
}
keyNavigationEnabled: true
keyNavigationWraps: true
highlightMoveVelocity: -1
highlightMoveDuration: 50
preferredHighlightBegin: list.topMargin
preferredHighlightEnd: list.height - list.bottomMargin
highlightRangeMode: ListView.ApplyRange
snapMode: ListView.SnapToItem
readonly property real delegateHeight: 44
delegate: MouseArea {
required property DesktopEntry modelData
implicitHeight: list.delegateHeight
implicitWidth: ListView.view.width
onClicked: {
modelData.execute();
launcher.launcherOpen = false;
}
RowLayout {
id: delegateLayout
anchors {
verticalCenter: parent.verticalCenter
left: parent.left
leftMargin: 5
}
IconImage {
Layout.alignment: Qt.AlignVCenter
asynchronous: true
implicitSize: 30
source: Quickshell.iconPath(modelData.icon)
}
Text {
text: modelData.name
color: "black"
font.family: "ComicShannsMono Nerd Font Mono"
Layout.alignment: Qt.AlignVCenter
}
}
}
}
}
}
}
}
function init() {
}
}

View file

@ -0,0 +1,41 @@
pragma ComponentBehavior: Bound
import Quickshell
import Quickshell.Wayland
import Quickshell.Services.Notifications
import QtQuick
import QtQuick.Effects
Rectangle {
id: root
required property bool isInRightPanel
required property ShellScreen screen
property bool isVisible
color: "transparent"
property bool _: log()
function log() {
console.log(hover.hovered);
return true
}
anchors {
right: parent.right
verticalCenter: parent.verticalCenter
}
implicitWidth: 60
implicitHeight: screen.height / 3
HoverHandler {
id: hover
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
}
Rectangle {
anchors.right: parent.right
color: "green"
implicitWidth: hover.hovered | root.isInRightPanel ? 60 : 10
implicitHeight: root.screen.height / 3
}
}