Merge branch 'end-4:main' into main

This commit is contained in:
jwihardi
2025-11-30 15:32:19 -05:00
committed by GitHub
43 changed files with 861 additions and 158 deletions
+16 -16
View File
@@ -4,27 +4,27 @@
#! #!
##! Shell ##! Shell
# These absolutely need to be on top, or they won't work consistently # These absolutely need to be on top, or they won't work consistently
bindid = Super, Super_L, Toggle overview, global, quickshell:overviewToggleRelease # Toggle overview/launcher bindid = Super, Super_L, Toggle search, global, quickshell:searchToggleRelease # Toggle search
bindid = Super, Super_R, Toggle overview, global, quickshell:overviewToggleRelease # [hidden] Toggle overview/launcher bindid = Super, Super_R, Toggle search, global, quickshell:searchToggleRelease # [hidden] Toggle search
bind = Super, Super_L, exec, qs -c $qsConfig ipc call TEST_ALIVE || pkill fuzzel || fuzzel # [hidden] Launcher (fallback) bind = Super, Super_L, exec, qs -c $qsConfig ipc call TEST_ALIVE || pkill fuzzel || fuzzel # [hidden] Launcher (fallback)
bind = Super, Super_R, exec, qs -c $qsConfig ipc call TEST_ALIVE || pkill fuzzel || fuzzel # [hidden] Launcher (fallback) bind = Super, Super_R, exec, qs -c $qsConfig ipc call TEST_ALIVE || pkill fuzzel || fuzzel # [hidden] Launcher (fallback)
binditn = Super, catchall, global, quickshell:overviewToggleReleaseInterrupt # [hidden] binditn = Super, catchall, global, quickshell:searchToggleReleaseInterrupt # [hidden]
bind = Ctrl, Super_L, global, quickshell:overviewToggleReleaseInterrupt # [hidden] bind = Ctrl, Super_L, global, quickshell:searchToggleReleaseInterrupt # [hidden]
bind = Ctrl, Super_R, global, quickshell:overviewToggleReleaseInterrupt # [hidden] bind = Ctrl, Super_R, global, quickshell:searchToggleReleaseInterrupt # [hidden]
bind = Super, mouse:272, global, quickshell:overviewToggleReleaseInterrupt # [hidden] bind = Super, mouse:272, global, quickshell:searchToggleReleaseInterrupt # [hidden]
bind = Super, mouse:273, global, quickshell:overviewToggleReleaseInterrupt # [hidden] bind = Super, mouse:273, global, quickshell:searchToggleReleaseInterrupt # [hidden]
bind = Super, mouse:274, global, quickshell:overviewToggleReleaseInterrupt # [hidden] bind = Super, mouse:274, global, quickshell:searchToggleReleaseInterrupt # [hidden]
bind = Super, mouse:275, global, quickshell:overviewToggleReleaseInterrupt # [hidden] bind = Super, mouse:275, global, quickshell:searchToggleReleaseInterrupt # [hidden]
bind = Super, mouse:276, global, quickshell:overviewToggleReleaseInterrupt # [hidden] bind = Super, mouse:276, global, quickshell:searchToggleReleaseInterrupt # [hidden]
bind = Super, mouse:277, global, quickshell:overviewToggleReleaseInterrupt # [hidden] bind = Super, mouse:277, global, quickshell:searchToggleReleaseInterrupt # [hidden]
bind = Super, mouse_up, global, quickshell:overviewToggleReleaseInterrupt # [hidden] bind = Super, mouse_up, global, quickshell:searchToggleReleaseInterrupt # [hidden]
bind = Super, mouse_down,global, quickshell:overviewToggleReleaseInterrupt # [hidden] bind = Super, mouse_down,global, quickshell:searchToggleReleaseInterrupt # [hidden]
bindit = ,Super_L, global, quickshell:workspaceNumber # [hidden] bindit = ,Super_L, global, quickshell:workspaceNumber # [hidden]
bindit = ,Super_R, global, quickshell:workspaceNumber # [hidden] bindit = ,Super_R, global, quickshell:workspaceNumber # [hidden]
bind = Super, Tab, global, quickshell:overviewWorkspacesToggle # Toggle overview
bindd = Super, V, Clipboard history >> clipboard, global, quickshell:overviewClipboardToggle # Clipboard history >> clipboard bindd = Super, V, Clipboard history >> clipboard, global, quickshell:overviewClipboardToggle # Clipboard history >> clipboard
bindd = Super, Period, Emoji >> clipboard, global, quickshell:overviewEmojiToggle # Emoji >> clipboard bindd = Super, Period, Emoji >> clipboard, global, quickshell:overviewEmojiToggle # Emoji >> clipboard
bind = Super, Tab, global, quickshell:overviewWorkspacesToggle # [hidden] Toggle overview/launcher (alt)
bind = Super, A, global, quickshell:sidebarLeftToggle # Toggle left sidebar bind = Super, A, global, quickshell:sidebarLeftToggle # Toggle left sidebar
bind = Super+Alt, A, global, quickshell:sidebarLeftToggleDetach # [hidden] bind = Super+Alt, A, global, quickshell:sidebarLeftToggleDetach # [hidden]
bind = Super, B, global, quickshell:sidebarLeftToggle # [hidden] bind = Super, B, global, quickshell:sidebarLeftToggle # [hidden]
@@ -218,8 +218,8 @@ submap = global
#! #!
# Testing # Testing
bind = Super+Alt, f11, exec, bash -c 'RANDOM_IMAGE=$(find ~/Pictures -type f | grep -v -i "nipple" | grep -v -i "pussy" | shuf -n 1); ACTION=$(notify-send "Test notification with body image" "This notification should contain your user account <b>image</b> and <a href=\"https://discord.com/app\">Discord</a> <b>icon</b>. Oh and here is a random image in your Pictures folder: <img src=\"$RANDOM_IMAGE\" alt=\"Testing image\"/>" -a "Hyprland keybind" -p -h "string:image-path:/var/lib/AccountsService/icons/$USER" -t 6000 -i "discord" -A "openImage=Open profile image" -A "action2=Open the random image" -A "action3=Useless button"); [[ $ACTION == *openImage ]] && xdg-open "/var/lib/AccountsService/icons/$USER"; [[ $ACTION == *action2 ]] && xdg-open \"$RANDOM_IMAGE\"' # [hidden] bind = Super+Alt, f11, exec, bash -c 'RANDOM_IMAGE=$(find ~/Pictures -type f | grep -v -i "nipple" | grep -v -i "pussy" | shuf -n 1); ACTION=$(notify-send "Test notification with body image" "This notification should contain your user account <b>image</b> and <a href=\"https://discord.com/app\">Discord</a> <b>icon</b>. Oh and here is a random image in your Pictures folder: <img src=\"$RANDOM_IMAGE\" alt=\"Testing image\"/>" -a "Hyprland keybind" -p -h "string:image-path:/var/lib/AccountsService/icons/$USER" -t 6000 -i "discord" -A "openImage=Profile image" -A "action2=Open the random image" -A "action3=Useless button"); [[ $ACTION == *openImage ]] && xdg-open "/var/lib/AccountsService/icons/$USER"; [[ $ACTION == *action2 ]] && xdg-open \"$RANDOM_IMAGE\"' # [hidden]
bind = Super+Alt, f12, exec, bash -c 'RANDOM_IMAGE=$(find ~/Pictures -type f | grep -v -i "nipple" | grep -v -i "pussy" | shuf -n 1); ACTION=$(notify-send "Test notification" "This notification should contain a random image in your <b>Pictures</b> folder and <a href=\"https://discord.com/app\">Discord</a> <b>icon</b>.\n<i>Flick right to dismiss!</i>" -a "Discord (fake)" -p -h "string:image-path:$RANDOM_IMAGE" -t 6000 -i "discord" -A "openImage=Open profile image" -A "action2=Useless button" -A "action3=Cry more"); [[ $ACTION == *openImage ]] && xdg-open "/var/lib/AccountsService/icons/$USER"' # [hidden] bind = Super+Alt, f12, exec, bash -c 'RANDOM_IMAGE=$(find ~/Pictures -type f | grep -v -i "nipple" | grep -v -i "pussy" | shuf -n 1); ACTION=$(notify-send "Test notification" "This notification should contain a random image in your <b>Pictures</b> folder and <a href=\"https://discord.com/app\">Discord</a> <b>icon</b>.\n<i>Flick right to dismiss!</i>" -a "Discord (fake)" -p -h "string:image-path:$RANDOM_IMAGE" -t 6000 -i "discord" -A "openImage=Profile image" -A "action2=Useless button"); [[ $ACTION == *openImage ]] && xdg-open "/var/lib/AccountsService/icons/$USER"' # [hidden]
bind = Super+Alt, Equal, exec, notify-send "Urgent notification" "Ah hell no" -u critical -a 'Hyprland keybind' # [hidden] bind = Super+Alt, Equal, exec, notify-send "Urgent notification" "Ah hell no" -u critical -a 'Hyprland keybind' # [hidden]
##! Session ##! Session
@@ -20,6 +20,7 @@ Singleton {
property bool overlayOpen: false property bool overlayOpen: false
property bool overviewOpen: false property bool overviewOpen: false
property bool regionSelectorOpen: false property bool regionSelectorOpen: false
property bool searchOpen: false
property bool screenLocked: false property bool screenLocked: false
property bool screenLockContainsCharacters: false property bool screenLockContainsCharacters: false
property bool screenUnlockFailed: false property bool screenUnlockFailed: false
@@ -0,0 +1,4 @@
<?xml version="1.0" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#000000">
<path d="M8.20514 4.84312C8.70586 4.61008 9.30068 4.82707 9.53372 5.32778C9.76676 5.82849 9.54977 6.42331 9.04906 6.65635C6.59946 7.79644 5 10.2547 5 13.003C5 16.8671 8.13391 19.9997 12 19.9997C15.8661 19.9997 19 16.8671 19 13.003C19 10.2604 17.4072 7.80631 14.9653 6.66304C14.4651 6.42887 14.2495 5.83355 14.4836 5.33337C14.7178 4.83319 15.3131 4.61756 15.8133 4.85173C18.9517 6.32109 21 9.47689 21 13.003C21 17.9719 16.9705 21.9997 12 21.9997C7.02953 21.9997 3 17.9719 3 13.003C3 9.46957 5.05682 6.30841 8.20514 4.84312ZM12 1.99902C12.5128 1.99902 12.9355 2.38506 12.9933 2.8824L13 2.99902V10.0004C13 10.5527 12.5523 11.0004 12 11.0004C11.4872 11.0004 11.0645 10.6144 11.0067 10.1171L11 10.0004V2.99902C11 2.44674 11.4477 1.99902 12 1.99902Z" fill="#000000"/>
</svg>

After

Width:  |  Height:  |  Size: 906 B

@@ -0,0 +1,4 @@
<?xml version="1.0" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#000000">
<path d="M8.2042 4.82046C8.57962 4.64545 9.02584 4.80792 9.20085 5.18334C9.37586 5.55876 9.2134 6.00498 8.83797 6.18C6.21382 7.4033 4.5 10.0416 4.5 12.9914C4.5 17.1386 7.85759 20.5002 11.9989 20.5002C16.1403 20.5002 19.4979 17.1386 19.4979 12.9914C19.4979 10.0477 17.7912 7.41389 15.1753 6.18718C14.8002 6.01131 14.6388 5.56472 14.8147 5.1897C14.9905 4.81467 15.4371 4.65322 15.8121 4.82909C18.9502 6.30065 20.9979 9.46066 20.9979 12.9914C20.9979 17.9666 16.9691 22.0002 11.9989 22.0002C7.02876 22.0002 3 17.9666 3 12.9914C3 9.45334 5.05623 6.28796 8.2042 4.82046ZM11.9989 2.49609C12.3786 2.49609 12.6924 2.77825 12.7421 3.14432L12.7489 3.24609V10.746C12.7489 11.1602 12.4132 11.496 11.9989 11.496C11.6192 11.496 11.3055 11.2139 11.2558 10.8478L11.2489 10.746V3.24609C11.2489 2.83188 11.5847 2.49609 11.9989 2.49609Z" fill="#000000"/>
</svg>

After

Width:  |  Height:  |  Size: 979 B

@@ -26,8 +26,8 @@
inkscape:zoom="4.65625" inkscape:zoom="4.65625"
inkscape:cx="32" inkscape:cx="32"
inkscape:cy="32" inkscape:cy="32"
inkscape:window-width="1197" inkscape:window-width="1595"
inkscape:window-height="1020" inkscape:window-height="664"
inkscape:window-x="0" inkscape:window-x="0"
inkscape:window-y="0" inkscape:window-y="0"
inkscape:window-maximized="1" inkscape:window-maximized="1"
@@ -48,10 +48,10 @@
</linearGradient> </linearGradient>
<linearGradient <linearGradient
id="linearGradient919" id="linearGradient919"
x1="4.3106" x1="4.4818125"
x2="14.36" x2="14.188787"
y1="8.4665" y1="7.1660123"
y2="8.4665" y2="9.7669888"
gradientTransform="matrix(1.226575,0,0,1.226575,-0.82407803,-6.4497629)" gradientTransform="matrix(1.226575,0,0,1.226575,-0.82407803,-6.4497629)"
gradientUnits="userSpaceOnUse"> gradientUnits="userSpaceOnUse">
<stop <stop
@@ -61,7 +61,7 @@
style="stop-color:#5fe277;stop-opacity:1;" /> style="stop-color:#5fe277;stop-opacity:1;" />
<stop <stop
stop-color="#55b4ff" stop-color="#55b4ff"
offset="1" offset="0.40375727"
id="stop2" id="stop2"
style="stop-color:#0078d3;stop-opacity:1;" /> style="stop-color:#0078d3;stop-opacity:1;" />
</linearGradient> </linearGradient>

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

@@ -23,10 +23,10 @@
inkscape:pagecheckerboard="0" inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1" inkscape:deskcolor="#d1d1d1"
inkscape:zoom="6.5849319" inkscape:zoom="6.5849319"
inkscape:cx="26.95548" inkscape:cx="27.031411"
inkscape:cy="26.423963" inkscape:cy="26.423963"
inkscape:window-width="1257" inkscape:window-width="1621"
inkscape:window-height="1020" inkscape:window-height="820"
inkscape:window-x="0" inkscape:window-x="0"
inkscape:window-y="0" inkscape:window-y="0"
inkscape:window-maximized="1" inkscape:window-maximized="1"
@@ -35,10 +35,10 @@
id="defs2"> id="defs2">
<linearGradient <linearGradient
id="linearGradient919" id="linearGradient919"
x1="4.3106" x1="4.4818139"
x2="14.36" x2="14.188786"
y1="8.4665" y1="7.1660118"
y2="8.4665" y2="9.7669868"
gradientTransform="matrix(1.226575,0,0,1.226575,-0.82407803,-6.4497629)" gradientTransform="matrix(1.226575,0,0,1.226575,-0.82407803,-6.4497629)"
gradientUnits="userSpaceOnUse"> gradientUnits="userSpaceOnUse">
<stop <stop
@@ -48,7 +48,7 @@
style="stop-color:#5fe277;stop-opacity:1;" /> style="stop-color:#5fe277;stop-opacity:1;" />
<stop <stop
stop-color="#55b4ff" stop-color="#55b4ff"
offset="1" offset="0.40380999"
id="stop2" id="stop2"
style="stop-color:#0078d3;stop-opacity:1;" /> style="stop-color:#0078d3;stop-opacity:1;" />
</linearGradient> </linearGradient>

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

@@ -1,6 +1,7 @@
pragma Singleton pragma Singleton
pragma ComponentBehavior: Bound pragma ComponentBehavior: Bound
import qs.services
import qs.modules.common.functions import qs.modules.common.functions
import QtCore import QtCore
import QtQuick import QtQuick
@@ -46,6 +47,9 @@ Singleton {
property string aiChats: FileUtils.trimFileProtocol(`${Directories.state}/user/ai/chats`) property string aiChats: FileUtils.trimFileProtocol(`${Directories.state}/user/ai/chats`)
property string aiTranslationScriptPath: FileUtils.trimFileProtocol(`${Directories.scriptPath}/ai/gemini-translate.sh`) property string aiTranslationScriptPath: FileUtils.trimFileProtocol(`${Directories.scriptPath}/ai/gemini-translate.sh`)
property string recordScriptPath: FileUtils.trimFileProtocol(`${Directories.scriptPath}/videos/record.sh`) property string recordScriptPath: FileUtils.trimFileProtocol(`${Directories.scriptPath}/videos/record.sh`)
property string userAvatarPathAccountsService: FileUtils.trimFileProtocol(`/var/lib/AccountsService/icons/${SystemInfo.username}`)
property string userAvatarPathRicersAndWeirdSystems: FileUtils.trimFileProtocol(`${Directories.home}.face`)
property string userAvatarPathRicersAndWeirdSystems2: FileUtils.trimFileProtocol(`${Directories.home}.face.icon`)
// Cleanup on init // Cleanup on init
Component.onCompleted: { Component.onCompleted: {
Quickshell.execDetached(["mkdir", "-p", `${shellConfig}`]) Quickshell.execDetached(["mkdir", "-p", `${shellConfig}`])
@@ -84,4 +84,28 @@ Singleton {
// Older dates // Older dates
return Qt.formatDateTime(messageTime, "MMMM dd"); return Qt.formatDateTime(messageTime, "MMMM dd");
} }
function processNotificationBody(body, appName) {
let processedBody = body
// Clean Chromium-based browsers notifications - remove first line
if (appName) {
const lowerApp = appName.toLowerCase()
const chromiumBrowsers = [
"brave", "chrome", "chromium", "vivaldi", "opera", "microsoft edge"
]
if (chromiumBrowsers.some(name => lowerApp.includes(name))) {
const lines = body.split('\n\n')
if (lines.length > 1 && lines[0].startsWith('<a')) {
processedBody = lines.slice(1).join('\n\n')
}
}
}
processedBody = processedBody.replace(/<img/gi, '\n\n<img');
return processedBody
}
} }
@@ -31,28 +31,6 @@ Item { // Notification item area
implicitHeight: background.implicitHeight implicitHeight: background.implicitHeight
function processNotificationBody(body, appName) {
let processedBody = body
// Clean Chromium-based browsers notifications - remove first line
if (appName) {
const lowerApp = appName.toLowerCase()
const chromiumBrowsers = [
"brave", "chrome", "chromium", "vivaldi", "opera", "microsoft edge"
]
if (chromiumBrowsers.some(name => lowerApp.includes(name))) {
const lines = body.split('\n\n')
if (lines.length > 1 && lines[0].startsWith('<a')) {
processedBody = lines.slice(1).join('\n\n')
}
}
}
return processedBody
}
function destroyWithAnimation(left = false) { function destroyWithAnimation(left = false) {
root.qmlParent.resetDrag() root.qmlParent.resetDrag()
background.anchors.leftMargin = background.anchors.leftMargin; // Break binding background.anchors.leftMargin = background.anchors.leftMargin; // Break binding
@@ -196,12 +174,13 @@ Item { // Notification item area
maximumLineCount: 1 maximumLineCount: 1
textFormat: Text.StyledText textFormat: Text.StyledText
text: { text: {
return processNotificationBody(notificationObject.body, notificationObject.appName || notificationObject.summary).replace(/\n/g, "<br/>") return NotificationUtils.processNotificationBody(notificationObject.body, notificationObject.appName || notificationObject.summary).replace(/\n/g, "<br/>")
} }
} }
} }
ColumnLayout { // Expanded content ColumnLayout { // Expanded content
id: expandedContentColumn
Layout.fillWidth: true Layout.fillWidth: true
opacity: root.expanded ? 1 : 0 opacity: root.expanded ? 1 : 0
visible: opacity > 0 visible: opacity > 0
@@ -218,8 +197,8 @@ Item { // Notification item area
elide: Text.ElideRight elide: Text.ElideRight
textFormat: Text.RichText textFormat: Text.RichText
text: { text: {
return `<style>img{max-width:${300 /* binding to notificationBodyText.width would cause a binding loop */}px;}</style>` + return `<style>img{max-width:${expandedContentColumn.width}px;}</style>` +
`${processNotificationBody(notificationObject.body, notificationObject.appName || notificationObject.summary).replace(/\n/g, "<br/>")}` `${NotificationUtils.processNotificationBody(notificationObject.body, notificationObject.appName || notificationObject.summary).replace(/\n/g, "<br/>")}`
} }
onLinkActivated: (link) => { onLinkActivated: (link) => {
@@ -293,6 +272,8 @@ Item { // Notification item area
id: actionRepeater id: actionRepeater
model: notificationObject.actions model: notificationObject.actions
NotificationActionButton { NotificationActionButton {
id: notifAction
required property var modelData
Layout.fillWidth: true Layout.fillWidth: true
buttonText: modelData.text buttonText: modelData.text
urgency: notificationObject.urgency urgency: notificationObject.urgency
@@ -12,4 +12,14 @@ Image {
Behavior on opacity { Behavior on opacity {
animation: Appearance.animation.elementMoveEnter.numberAnimation.createObject(this) animation: Appearance.animation.elementMoveEnter.numberAnimation.createObject(this)
} }
property list<string> fallbacks: []
property int currentFallbackIndex: 0
onStatusChanged: {
if (status === Image.Error && currentFallbackIndex < fallbacks.length) {
source = fallbacks[currentFallbackIndex];
currentFallbackIndex += 1;
}
}
} }
@@ -20,6 +20,7 @@ ToolTip {
hintingPreference: Font.PreferNoHinting // Prevent shaky text hintingPreference: Font.PreferNoHinting // Prevent shaky text
} }
delay: 0
visible: internalVisibleCondition visible: internalVisibleCondition
contentItem: StyledToolTipContent { contentItem: StyledToolTipContent {
@@ -162,7 +162,7 @@ Scope {
} }
IpcHandler { IpcHandler {
target: "overview" target: "search"
function toggle() { function toggle() {
GlobalStates.overviewOpen = !GlobalStates.overviewOpen; GlobalStates.overviewOpen = !GlobalStates.overviewOpen;
@@ -185,8 +185,8 @@ Scope {
} }
GlobalShortcut { GlobalShortcut {
name: "overviewToggle" name: "searchToggle"
description: "Toggles overview on press" description: "Toggles search on press"
onPressed: { onPressed: {
GlobalStates.overviewOpen = !GlobalStates.overviewOpen; GlobalStates.overviewOpen = !GlobalStates.overviewOpen;
@@ -201,16 +201,8 @@ Scope {
} }
} }
GlobalShortcut { GlobalShortcut {
name: "overviewClose" name: "searchToggleRelease"
description: "Closes overview" description: "Toggles search on release"
onPressed: {
GlobalStates.overviewOpen = false;
}
}
GlobalShortcut {
name: "overviewToggleRelease"
description: "Toggles overview on release"
onPressed: { onPressed: {
GlobalStates.superReleaseMightTrigger = true; GlobalStates.superReleaseMightTrigger = true;
@@ -225,8 +217,8 @@ Scope {
} }
} }
GlobalShortcut { GlobalShortcut {
name: "overviewToggleReleaseInterrupt" name: "searchToggleReleaseInterrupt"
description: "Interrupts possibility of overview being toggled on release. " + "This is necessary because GlobalShortcut.onReleased in quickshell triggers whether or not you press something else while holding the key. " + "To make sure this works consistently, use binditn = MODKEYS, catchall in an automatically triggered submap that includes everything." description: "Interrupts possibility of search being toggled on release. " + "This is necessary because GlobalShortcut.onReleased in quickshell triggers whether or not you press something else while holding the key. " + "To make sure this works consistently, use binditn = MODKEYS, catchall in an automatically triggered submap that includes everything."
onPressed: { onPressed: {
GlobalStates.superReleaseMightTrigger = false; GlobalStates.superReleaseMightTrigger = false;
@@ -66,7 +66,7 @@ BarButton {
} }
} }
AppIcon { WAppIcon {
id: iconWidget id: iconWidget
anchors.centerIn: parent anchors.centerIn: parent
iconName: root.iconName iconName: root.iconName
@@ -5,17 +5,12 @@ import qs.modules.common
import qs.modules.common.functions import qs.modules.common.functions
import qs.modules.waffle.looks import qs.modules.waffle.looks
WButton { AcrylicButton {
id: root id: root
property var altAction: () => {} property var altAction: () => {}
property var middleClickAction: () => {} property var middleClickAction: () => {}
colBackground: ColorUtils.transparentize(Looks.colors.bg1)
colBackgroundHover: Looks.colors.bg1Hover
colBackgroundActive: Looks.colors.bg1Active
property color colBackgroundBorder
property color color
Layout.fillHeight: true Layout.fillHeight: true
topInset: 4 topInset: 4
bottomInset: 4 bottomInset: 4
@@ -23,16 +18,7 @@ WButton {
rightInset: 0 rightInset: 0
horizontalPadding: 8 horizontalPadding: 8
colBackgroundBorder: ColorUtils.transparentize(Looks.colors.bg1Border, (root.checked || root.hovered) ? Looks.backgroundTransparency : 1) colBackground: ColorUtils.transparentize(Looks.colors.bg1)
color: {
if (root.down) {
return root.colBackgroundActive
} else if ((root.hovered && !root.down) || root.checked) {
return root.colBackgroundHover
} else {
return root.colBackground
}
}
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
@@ -50,15 +36,4 @@ WButton {
} }
} }
background: AcrylicRectangle {
shiny: ((root.hovered && !root.down) || root.checked)
color: root.color
radius: Looks.radius.medium
border.width: 1
border.color: root.colBackgroundBorder
Behavior on border.color {
animation: Looks.transition.color.createObject(this)
}
}
} }
@@ -7,14 +7,16 @@ import qs.services
import qs.modules.common import qs.modules.common
import qs.modules.waffle.looks import qs.modules.waffle.looks
// TODO: Replace the icon with QMLized svg (with /usr/lib/qt6/bin/svgtoqml) for proper micro-animation
AppButton { AppButton {
id: root id: root
leftInset: Config.options.waffles.bar.leftAlignApps ? 12 : 0 leftInset: Config.options.waffles.bar.leftAlignApps ? 12 : 0
iconName: down ? "start-here-pressed" : "start-here" iconName: down ? "start-here-pressed" : "start-here"
checked: GlobalStates.searchOpen
onClicked: { onClicked: {
GlobalStates.overviewOpen = !GlobalStates.overviewOpen; // For now... GlobalStates.searchOpen = !GlobalStates.searchOpen;
} }
BarToolTip { BarToolTip {
@@ -42,7 +42,7 @@ AppButton {
} }
spacing: 6 spacing: 6
AppIcon { WAppIcon {
id: iconWidget id: iconWidget
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
iconName: root.iconName iconName: root.iconName
@@ -43,7 +43,7 @@ Button {
Layout.fillHeight: false Layout.fillHeight: false
spacing: 8 spacing: 8
AppIcon { WAppIcon {
id: appIcon id: appIcon
Layout.leftMargin: Looks.radius.large - root.padding + 2 Layout.leftMargin: Looks.radius.large - root.padding + 2
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
@@ -0,0 +1,42 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import qs.modules.common
import qs.modules.common.functions
import qs.modules.waffle.looks
WButton {
id: root
colBackground: Looks.colors.bg1
colBackgroundHover: Looks.colors.bg1Hover
colBackgroundActive: Looks.colors.bg1Active
property color colBackgroundBorder
property color color
property alias border: background.border
property alias shinyColor: background.borderColor
colBackgroundBorder: ColorUtils.transparentize(color, (root.checked || root.hovered) ? Looks.backgroundTransparency : 0)
color: {
if (root.down) {
return root.colBackgroundActive
} else if ((root.hovered && !root.down) || root.checked) {
return root.colBackgroundHover
} else {
return root.colBackground
}
}
background: AcrylicRectangle {
id: background
shiny: ((root.hovered && !root.down) || root.checked)
color: root.color
radius: Looks.radius.medium
border.width: 1
border.color: root.colBackgroundBorder
Behavior on border.color {
animation: Looks.transition.color.createObject(this)
}
}
}
@@ -9,16 +9,17 @@ Rectangle {
id: root id: root
property bool shiny: true // Top border property bool shiny: true // Top border
property color borderColor: ColorUtils.transparentize(Looks.colors.bg2Border, shiny ? 0.5 : 1) property color borderColor: ColorUtils.transparentize(Looks.colors.bg1Hover, 0.7)
property color internalBorderColor: ColorUtils.transparentize(borderColor, shiny ? 0.0 : 1)
color: Looks.colors.bg1Hover color: Looks.colors.bg1Hover
radius: Looks.radius.medium radius: Looks.radius.medium
Behavior on color { Behavior on color {
animation: Looks.transition.color.createObject(this) animation: Looks.transition.color.createObject(this)
} }
Behavior on borderColor { Behavior on internalBorderColor {
animation: Looks.transition.color.createObject(this) animation: Looks.transition.color.createObject(this)
} }
onBorderColorChanged: { onInternalBorderColorChanged: {
borderCanvas.requestPaint(); borderCanvas.requestPaint();
} }
@@ -32,7 +33,7 @@ Rectangle {
var ctx = getContext("2d"); var ctx = getContext("2d");
ctx.clearRect(0, 0, width, height); ctx.clearRect(0, 0, width, height);
var borderColor = root.borderColor; var borderColor = root.internalBorderColor;
var r = root.radius; var r = root.radius;
var fadeLength = Math.max(1, r); var fadeLength = Math.max(1, r);
@@ -53,6 +53,8 @@ Singleton {
property color controlBgHover: '#57575B' property color controlBgHover: '#57575B'
property color controlFg: "#FFFFFF" property color controlFg: "#FFFFFF"
property color accentUnfocused: "#848484" property color accentUnfocused: "#848484"
property color link: "#235CCF"
property color inputBg: ColorUtils.transparentize(bg0, 0.4)
} }
darkColors: QtObject { darkColors: QtObject {
id: darkColors id: darkColors
@@ -70,7 +72,7 @@ Singleton {
property color bg2: '#8a8a8a' property color bg2: '#8a8a8a'
property color bg2Hover: '#b1b1b1' property color bg2Hover: '#b1b1b1'
property color bg2Active: '#919191' property color bg2Active: '#919191'
property color bg2Border: '#c4c4c4' property color bg2Border: '#bdbdbd'
property color subfg: "#CED1D7" property color subfg: "#CED1D7"
property color fg: "#FFFFFF" property color fg: "#FFFFFF"
property color fg1: "#D1D1D1" property color fg1: "#D1D1D1"
@@ -80,6 +82,8 @@ Singleton {
property color controlBgHover: "#CFCED1" property color controlBgHover: "#CFCED1"
property color controlFg: "#454545" property color controlFg: "#454545"
property color accentUnfocused: "#989898" property color accentUnfocused: "#989898"
property color link: "#A7C9FC"
property color inputBg: ColorUtils.transparentize(darkColors.bg0, 0.5)
} }
colors: QtObject { colors: QtObject {
id: colors id: colors
@@ -110,6 +114,8 @@ Singleton {
property color controlBg: root.dark ? root.darkColors.controlBg : root.lightColors.controlBg property color controlBg: root.dark ? root.darkColors.controlBg : root.lightColors.controlBg
property color controlBgHover: root.dark ? root.darkColors.controlBgHover : root.lightColors.controlBgHover property color controlBgHover: root.dark ? root.darkColors.controlBgHover : root.lightColors.controlBgHover
property color controlFg: root.dark ? root.darkColors.controlFg : root.lightColors.controlFg property color controlFg: root.dark ? root.darkColors.controlFg : root.lightColors.controlFg
property color inputBg: root.dark ? root.darkColors.inputBg : root.lightColors.inputBg
property color link: root.dark ? root.darkColors.link : root.lightColors.link
property color danger: "#C42B1C" property color danger: "#C42B1C"
property color dangerActive: "#B62D1F" property color dangerActive: "#B62D1F"
property color warning: "#FF9900" property color warning: "#FF9900"
@@ -118,6 +124,7 @@ Singleton {
property color accentActive: Appearance.colors.colPrimaryActive property color accentActive: Appearance.colors.colPrimaryActive
property color accentUnfocused: root.dark ? root.darkColors.accentUnfocused : root.lightColors.accentUnfocused property color accentUnfocused: root.dark ? root.darkColors.accentUnfocused : root.lightColors.accentUnfocused
property color accentFg: ColorUtils.isDark(accent) ? "#FFFFFF" : "#000000" property color accentFg: ColorUtils.isDark(accent) ? "#FFFFFF" : "#000000"
property color selection: Appearance.colors.colPrimaryContainer
} }
radius: QtObject { radius: QtObject {
@@ -2,7 +2,6 @@ import QtQuick
import org.kde.kirigami as Kirigami import org.kde.kirigami as Kirigami
import qs.services import qs.services
import qs.modules.common import qs.modules.common
import qs.modules.waffle.looks
Kirigami.Icon { Kirigami.Icon {
id: root id: root
@@ -53,10 +53,11 @@ Button {
// Hover stuff // Hover stuff
signal hoverTimedOut signal hoverTimedOut
property bool shouldShowTooltip: false property bool shouldShowTooltip: false
ToolTip.delay: 400
property Timer hoverTimer: Timer { property Timer hoverTimer: Timer {
id: hoverTimer id: hoverTimer
running: root.hovered running: root.hovered
interval: 400 interval: root.ToolTip.delay
onTriggered: { onTriggered: {
root.hoverTimedOut(); root.hoverTimedOut();
} }
@@ -8,8 +8,11 @@ Text {
color: Looks.colors.fg color: Looks.colors.fg
font { font {
hintingPreference: Font.PreferFullHinting
family: Looks.font.family.ui family: Looks.font.family.ui
pixelSize: Looks.font.pixelSize.normal pixelSize: Looks.font.pixelSize.normal
weight: Looks.font.weight.regular weight: Looks.font.weight.regular
} }
linkColor: Looks.colors.link
} }
@@ -0,0 +1,18 @@
import QtQuick
import QtQuick.Controls
TextInput {
id: root
renderType: Text.NativeRendering
verticalAlignment: Text.AlignVCenter
color: Looks.colors.fg
font {
hintingPreference: Font.PreferFullHinting
family: Looks.font.family.ui
pixelSize: Looks.font.pixelSize.large
weight: Looks.font.weight.regular
}
selectionColor: Looks.colors.selection
}
@@ -20,6 +20,7 @@ WBarAttachedPanelContent {
property bool collapsed: false property bool collapsed: false
contentItem: ColumnLayout { contentItem: ColumnLayout {
id: contentLayout
anchors { anchors {
horizontalCenter: parent.horizontalCenter horizontalCenter: parent.horizontalCenter
top: parent.top top: parent.top
@@ -41,9 +42,24 @@ WBarAttachedPanelContent {
} }
contentItem: NotificationPaneContent { contentItem: NotificationPaneContent {
implicitWidth: calendarColumnLayout.implicitWidth implicitWidth: calendarColumnLayout.implicitWidth
implicitHeight: Notifications.list.length > 0 ? (notificationArea.height - notificationPane.borderWidth * 2) : 230 implicitHeight: {
if (Notifications.list.length > 0) {
return ((contentLayout.height - calendarPane.height - contentLayout.spacing) - notificationPane.borderWidth * 2)
}
return 230;
}
Timer {
id: enableTimer
interval: Config.options.hacks.arbitraryRaceConditionDelay
onTriggered: heightBehavior.enabled = true;
}
Behavior on implicitHeight { Behavior on implicitHeight {
id: heightBehavior
enabled: false
Component.onCompleted: {
enableTimer.restart();
}
animation: Looks.transition.enter.createObject(this) animation: Looks.transition.enter.createObject(this)
} }
} }
@@ -51,9 +67,9 @@ WBarAttachedPanelContent {
} }
WPane { WPane {
contentItem: ColumnLayout { id: calendarPane
contentItem: WPanelPageColumn {
id: calendarColumnLayout id: calendarColumnLayout
spacing: 0
DateHeader { DateHeader {
Layout.fillWidth: true Layout.fillWidth: true
Synchronizer on collapsed { Synchronizer on collapsed {
@@ -8,18 +8,24 @@ import qs.modules.common.functions
import qs.modules.waffle.looks import qs.modules.waffle.looks
WBorderlessButton { WBorderlessButton {
id: headerButton id: root
Layout.fillWidth: false Layout.fillWidth: false
implicitWidth: 16 property real implicitSize: 16
implicitHeight: 16 implicitWidth: implicitSize
implicitHeight: implicitSize
color: "transparent" color: "transparent"
colForeground: root.hovered && !root.pressed ? Looks.colors.fg : Looks.colors.fg1
Behavior on colForeground {
animation: Looks.transition.color.createObject(this)
}
contentItem: Item { contentItem: Item {
FluentIcon { FluentIcon {
anchors.centerIn: parent anchors.centerIn: parent
implicitSize: 16 implicitSize: root.implicitSize
icon: headerButton.icon.name icon: root.icon.name
color: headerButton.hovered && !headerButton.pressed ? Looks.colors.fg : Looks.colors.fg1 color: root.colForeground
} }
} }
} }
@@ -2,18 +2,27 @@ import QtQuick
import qs import qs
import qs.services import qs.services
import qs.modules.common import qs.modules.common
import qs.modules.common.functions
import qs.modules.waffle.looks import qs.modules.waffle.looks
SmallBorderedIconButton { AcrylicButton {
id: root id: root
property bool iconVisible: true property bool iconVisible: true
property string iconName: "" property string iconName: ""
property bool iconFilled: true property bool iconFilled: true
colBackground: Looks.colors.bg2
colBackgroundHover: Looks.colors.bg2Hover
colBackgroundActive: Looks.colors.bg2Active
property color colBorder: Looks.colors.bg2Border
property color colBorderToggled: Looks.colors.accent
border.color: checked ? colBorderToggled : colBorder
leftPadding: 12 leftPadding: 12
rightPadding: 12 rightPadding: 12
implicitWidth: focusButtonContent.implicitWidth + leftPadding + rightPadding implicitWidth: focusButtonContent.implicitWidth + leftPadding + rightPadding
implicitHeight: 24
contentItem: Row { contentItem: Row {
id: focusButtonContent id: focusButtonContent
@@ -12,6 +12,7 @@ MouseArea {
required property var notificationGroup required property var notificationGroup
readonly property var notifications: notificationGroup?.notifications ?? [] readonly property var notifications: notificationGroup?.notifications ?? []
property bool expanded: false
implicitWidth: contentLayout.implicitWidth implicitWidth: contentLayout.implicitWidth
implicitHeight: contentLayout.implicitHeight implicitHeight: contentLayout.implicitHeight
@@ -34,12 +35,23 @@ MouseArea {
interactive: false interactive: false
spacing: 4 spacing: 4
model: ScriptModel { model: ScriptModel {
values: root.notifications.slice().reverse() values: root.expanded ? root.notifications.slice().reverse() : root.notifications.slice(-1)
objectProp: "notificationId"
} }
delegate: WSingleNotification { delegate: WSingleNotification {
required property int index
required property var modelData required property var modelData
width: ListView.view.width width: ListView.view.width
notification: modelData notification: modelData
groupExpandControlMessage: {
if (root.notifications.length <= 1) return "";
if (!root.expanded) return Translation.tr("+%1 notifications").arg(root.notifications.length - 1);
if (index === root.notifications.length - 1) return Translation.tr("See fewer");
return "";
}
onGroupExpandToggle: {
root.expanded = !root.expanded;
}
} }
} }
} }
@@ -1,3 +1,4 @@
pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import Quickshell import Quickshell
@@ -12,11 +13,18 @@ MouseArea {
id: root id: root
required property var notification required property var notification
property bool expanded: false property bool expanded: notification.actions.length > 0
property string groupExpandControlMessage: ""
signal groupExpandToggle
hoverEnabled: true
implicitHeight: contentItem.implicitHeight implicitHeight: contentItem.implicitHeight
implicitWidth: contentItem.implicitWidth implicitWidth: contentItem.implicitWidth
Behavior on implicitHeight {
animation: Looks.transition.enter.createObject(this)
}
Rectangle { Rectangle {
id: contentItem id: contentItem
anchors.fill: parent anchors.fill: parent
@@ -26,34 +34,205 @@ MouseArea {
implicitHeight: notificationContent.implicitHeight + padding * 2 implicitHeight: notificationContent.implicitHeight + padding * 2
implicitWidth: notificationContent.implicitWidth + padding * 2 implicitWidth: notificationContent.implicitWidth + padding * 2
border.width: 1 border.width: 1
border.color: Looks.applyContentTransparency(Looks.colors.ambientShadow) border.color: ColorUtils.applyAlpha(Looks.colors.ambientShadow, 0.1)
ColumnLayout { ColumnLayout {
id: notificationContent id: notificationContent
anchors.fill: parent anchors.fill: parent
anchors.margins: contentItem.padding anchors.margins: contentItem.padding
spacing: 19
RowLayout { // Header
SingleNotificationHeader {
Layout.fillWidth: true Layout.fillWidth: true
WText { }
text: NotificationUtils.getFriendlyNotifTimeString(root.notification?.time)
// Content
Item {
id: actualContent
Layout.fillWidth: true
Layout.fillHeight: true
property real spacing: 16
implicitHeight: Math.max(contentColumn.implicitHeight, imageLoader.height)
implicitWidth: contentColumn.implicitWidth
Loader {
id: imageLoader
anchors {
top: parent.top
left: parent.left
}
active: root.notification.image != ""
sourceComponent: StyledImage {
readonly property int size: 48
width: size
height: size
sourceSize.width: size
sourceSize.height: size
source: root.notification.image
fillMode: Image.PreserveAspectFit
}
}
ColumnLayout {
id: contentColumn
anchors {
top: parent.top
left: parent.left
right: parent.right
}
spacing: 3
SummaryText {
id: summaryText
Layout.leftMargin: imageLoader.active ? imageLoader.width + actualContent.spacing : 0
}
BodyText {
Layout.leftMargin: imageLoader.active ? imageLoader.width + actualContent.spacing : 0
// onLineLaidOut: (line) => {
// if (!imageLoader.active) return;
// const dodgeDistance = imageLoader.width + actualContent.spacing;
// // print(line.y, dodgeDistance)
// if (summaryText.height + line.y > dodgeDistance) {
// line.x -= dodgeDistance;
// line.width += dodgeDistance;
// }
// }
}
} }
} }
ColumnLayout { // Actions
ActionsRow {
Layout.fillWidth: true Layout.fillWidth: true
WText { }
Layout.fillWidth: true
elide: Text.ElideRight // "+1 notifications" button
text: root.notification.summary GroupExpandButton {
} Layout.bottomMargin: 2
WText { }
Layout.fillWidth: true }
elide: Text.ElideRight }
component SingleNotificationHeader: RowLayout {
ExpandButton {
Layout.topMargin: -2
}
Item {
Layout.fillWidth: true
}
NotificationHeaderButton {
Layout.rightMargin: 4
opacity: root.containsMouse ? 1 : 0
icon.name: "dismiss"
implicitSize: 12
onClicked: {
Qt.callLater(() => {
Notifications.discardNotification(root.notification?.notificationId);
});
}
}
}
component ActionsRow: RowLayout {
visible: root.expanded && root.notification.actions.length > 0
uniformCellSizes: true
Repeater {
id: actionRepeater
model: root.notification.actions
delegate: WBorderedButton {
id: actionButton
Layout.fillHeight: true
required property var modelData
Layout.fillWidth: true
verticalPadding: 16
horizontalPadding: 12
text: modelData.text
implicitHeight: actionButtonText.implicitHeight + verticalPadding * 2
contentItem: WText {
id: actionButtonText
text: actionButton.text
font.pixelSize: Looks.font.pixelSize.large
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.Wrap wrapMode: Text.Wrap
maximumLineCount: root.expanded ? 100 : 1
} }
} }
} }
} }
component SummaryText: WText {
Layout.fillWidth: true
elide: Text.ElideRight
text: root.notification?.summary
font.pixelSize: Looks.font.pixelSize.large
}
component BodyText: WText {
Layout.fillWidth: true
Layout.fillHeight: true
elide: Text.ElideRight
verticalAlignment: Text.AlignTop
wrapMode: Text.Wrap
maximumLineCount: root.expanded ? 100 : 1
text: {
if (root.expanded)
return `<style>img{max-width:${summaryText.width}px; align: right}</style>` + `${NotificationUtils.processNotificationBody(root.notification.body, root.notification.appName || root.notification.summary).replace(/\n/g, "<br/>")}`;
return NotificationUtils.processNotificationBody(root.notification.body, root.notification.appName || root.notification.summary).replace(/\n/g, "<br/>");
}
color: Looks.colors.subfg
textFormat: root.expanded ? Text.RichText : Text.StyledText
onLinkActivated: link => {
Qt.openUrlExternally(link);
GlobalStates.sidebarRightOpen = false;
}
}
component ExpandButton: NotificationHeaderButton {
id: expandButton
implicitWidth: expandButtonContent.implicitWidth
onClicked: root.expanded = !root.expanded
contentItem: Item {
id: expandButtonContent
implicitWidth: expandButtonRow.implicitWidth
implicitHeight: expandButtonRow.implicitHeight
RowLayout {
id: expandButtonRow
anchors.centerIn: parent
spacing: 8
WText {
color: expandButton.colForeground
text: NotificationUtils.getFriendlyNotifTimeString(root.notification?.time)
}
FluentIcon {
Layout.rightMargin: 12
icon: "chevron-down"
implicitSize: 18
rotation: root.expanded ? -180 : 0
color: expandButton.colForeground
Behavior on rotation {
animation: Looks.transition.rotate.createObject(this)
}
}
}
}
}
component GroupExpandButton: AcrylicButton {
id: groupExpandButton
visible: root.groupExpandControlMessage !== ""
horizontalPadding: 10
implicitHeight: 24
implicitWidth: expandButtonText.implicitWidth + horizontalPadding * 2
onClicked: root.groupExpandToggle()
contentItem: Item {
WText {
id: expandButtonText
anchors.centerIn: parent
text: root.groupExpandControlMessage
}
}
}
} }
@@ -0,0 +1,84 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import qs
import qs.services
import qs.modules.common
import qs.modules.common.functions
import qs.modules.waffle.looks
FooterRectangle {
id: root
property bool searching: text.length > 0
property alias text: searchInput.text
Component.onCompleted: searchInput.forceActiveFocus()
focus: true
color: searching ? Looks.colors.bgPanelBody : Looks.colors.bgPanelFooter
implicitWidth: 832 // TODO: Make sizes naturally inferred
implicitHeight: 63
Rectangle {
id: outline
anchors {
fill: parent
leftMargin: 32
rightMargin: 32
topMargin: 16
bottomMargin: 15
}
color: "transparent"
radius: height / 2
border.width: 1
border.color: Looks.colors.bg2Border
}
Rectangle {
id: searchInputBg
anchors.fill: outline
anchors.margins: 1
radius: height / 2
color: Looks.colors.inputBg
RowLayout {
anchors.fill: parent
spacing: 11
WAppIcon {
Layout.leftMargin: 14
iconName: "system-search-checked"
separateLightDark: true
implicitSize: 18
}
WTextInput {
id: searchInput
focus: true
Layout.fillWidth: true
WText {
anchors {
left: parent.left
verticalCenter: parent.verticalCenter
}
color: Looks.colors.accentUnfocused
text: Translation.tr("Search for apps") // should also have "", settings, and documents" but we don't have those
visible: searchInput.text.length === 0
font.pixelSize: Looks.font.pixelSize.large
}
}
}
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.IBeamCursor
acceptedButtons: Qt.NoButton
}
}
@@ -0,0 +1,16 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import qs
import qs.services
import qs.modules.common
import qs.modules.common.functions
import qs.modules.waffle.looks
BodyRectangle {
id: root
}
@@ -0,0 +1,39 @@
pragma ComponentBehavior: Bound
import Qt.labs.synchronizer
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import qs
import qs.services
import qs.modules.common
import qs.modules.common.functions
import qs.modules.waffle.looks
WBarAttachedPanelContent {
id: root
property bool searching: false
property string searchText: ""
contentItem: WPane {
contentItem: WPanelPageColumn {
SearchBar {
focus: true
Layout.fillWidth: true
Synchronizer on searching {
property alias target: root.searching
}
Synchronizer on text {
property alias source: root.searchText
}
}
Loader {
id: pageContentLoader
Layout.fillWidth: true
source: root.searching ? "SearchPageContent.qml" : "StartPageContent.qml"
}
}
}
}
@@ -0,0 +1,98 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import Quickshell
import org.kde.kirigami as Kirigami
import qs
import qs.services
import qs.modules.common
import qs.modules.common.functions
import qs.modules.common.widgets
import qs.modules.waffle.looks
WPanelPageColumn {
id: root
WPanelSeparator {}
BodyRectangle {
implicitHeight: 736 // TODO: Make sizes naturally inferred
}
WPanelSeparator {}
StartFooter {
Layout.fillWidth: true
}
component StartFooter: FooterRectangle {
implicitHeight: 63
UserButton {
anchors {
left: parent.left
leftMargin: 52
bottom: parent.bottom
bottomMargin: 12
}
}
PowerButton {
anchors {
right: parent.right
rightMargin: 52
bottom: parent.bottom
bottomMargin: 12
}
}
}
component UserButton: WBorderlessButton {
id: userButton
implicitWidth: userButtonRow.implicitWidth + 12 * 2
implicitHeight: 40
contentItem: Item {
RowLayout {
id: userButtonRow
anchors.centerIn: parent
spacing: 12
StyledImage {
id: avatar
// Use this for free fallback because I'm lazy
Layout.alignment: Qt.AlignTop
sourceSize: Qt.size(32, 32)
source: Directories.userAvatarPathAccountsService
fallbacks: [Directories.userAvatarPathRicersAndWeirdSystems, Directories.userAvatarPathRicersAndWeirdSystems2]
layer.enabled: true
layer.effect: OpacityMask {
maskSource: Circle {
diameter: avatar.height
}
}
}
WText {
Layout.alignment: Qt.AlignVCenter
text: SystemInfo.username
}
}
}
}
component PowerButton: WBorderlessButton {
implicitWidth: 40
implicitHeight: 40
contentItem: Item {
FluentIcon {
anchors.centerIn: parent
icon: "power"
implicitSize: 20
}
}
}
}
@@ -0,0 +1,119 @@
import QtQuick
import Quickshell
import Quickshell.Io
import Quickshell.Wayland
import Quickshell.Hyprland
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
Scope {
id: root
Connections {
target: GlobalStates
function onSearchOpenChanged() {
if (GlobalStates.searchOpen)
panelLoader.active = true;
}
}
Loader {
id: panelLoader
active: GlobalStates.searchOpen
sourceComponent: PanelWindow {
id: panelWindow
exclusiveZone: 0
WlrLayershell.namespace: "quickshell:wStartMenu"
WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand
color: "transparent"
anchors {
bottom: Config.options.waffles.bar.bottom
top: !Config.options.waffles.bar.bottom
left: Config.options.waffles.bar.leftAlignApps
}
implicitWidth: content.implicitWidth
implicitHeight: content.implicitHeight
HyprlandFocusGrab {
id: focusGrab
active: true
windows: [panelWindow]
onCleared: content.close()
}
Connections {
target: GlobalStates
function onSearchOpenChanged() {
if (!GlobalStates.searchOpen)
content.close();
}
}
StartMenuContent {
id: content
anchors.fill: parent
focus: true
onClosed: {
GlobalStates.searchOpen = false;
panelLoader.active = false;
}
}
}
}
IpcHandler {
target: "search"
function toggle() {
GlobalStates.searchOpen = !GlobalStates.searchOpen;
}
function close() {
GlobalStates.searchOpen = false;
}
function open() {
GlobalStates.searchOpen = true;
}
function toggleReleaseInterrupt() {
GlobalStates.superReleaseMightTrigger = false;
}
}
GlobalShortcut {
name: "searchToggle"
description: "Toggles search on press"
onPressed: {
GlobalStates.searchOpen = !GlobalStates.searchOpen;
}
}
GlobalShortcut {
name: "searchToggleRelease"
description: "Toggles search on release"
onPressed: {
GlobalStates.superReleaseMightTrigger = true;
}
onReleased: {
if (!GlobalStates.superReleaseMightTrigger) {
GlobalStates.superReleaseMightTrigger = true;
return;
}
GlobalStates.searchOpen = !GlobalStates.searchOpen;
}
}
GlobalShortcut {
name: "searchToggleReleaseInterrupt"
description: "Interrupts possibility of search being toggled on release. " + "This is necessary because GlobalShortcut.onReleased in quickshell triggers whether or not you press something else while holding the key. " + "To make sure this works consistently, use binditn = MODKEYS, catchall in an automatically triggered submap that includes everything."
onPressed: {
GlobalStates.superReleaseMightTrigger = false;
}
}
}
+4 -1
View File
@@ -33,6 +33,7 @@ import qs.modules.waffle.background
import qs.modules.waffle.bar import qs.modules.waffle.bar
import qs.modules.waffle.notificationCenter import qs.modules.waffle.notificationCenter
import qs.modules.waffle.onScreenDisplay import qs.modules.waffle.onScreenDisplay
import qs.modules.waffle.startMenu
import QtQuick import QtQuick
import QtQuick.Window import QtQuick.Window
@@ -77,11 +78,13 @@ ShellRoot {
PanelLoader { identifier: "iiSidebarRight"; component: SidebarRight {} } PanelLoader { identifier: "iiSidebarRight"; component: SidebarRight {} }
PanelLoader { identifier: "iiVerticalBar"; extraCondition: Config.options.bar.vertical; component: VerticalBar {} } PanelLoader { identifier: "iiVerticalBar"; extraCondition: Config.options.bar.vertical; component: VerticalBar {} }
PanelLoader { identifier: "iiWallpaperSelector"; component: WallpaperSelector {} } PanelLoader { identifier: "iiWallpaperSelector"; component: WallpaperSelector {} }
PanelLoader { identifier: "wActionCenter"; component: WaffleActionCenter {} } PanelLoader { identifier: "wActionCenter"; component: WaffleActionCenter {} }
PanelLoader { identifier: "wBar"; component: WaffleBar {} } PanelLoader { identifier: "wBar"; component: WaffleBar {} }
PanelLoader { identifier: "wBackground"; component: WaffleBackground {} } PanelLoader { identifier: "wBackground"; component: WaffleBackground {} }
PanelLoader { identifier: "wNotificationCenter"; component: WaffleNotificationCenter {} } PanelLoader { identifier: "wNotificationCenter"; component: WaffleNotificationCenter {} }
PanelLoader { identifier: "wOnScreenDisplay"; component: WaffleOSD {} } PanelLoader { identifier: "wOnScreenDisplay"; component: WaffleOSD {} }
PanelLoader { identifier: "wStartMenu"; component: WaffleStartMenu {} }
ReloadPopup {} ReloadPopup {}
component PanelLoader: LazyLoader { component PanelLoader: LazyLoader {
@@ -94,7 +97,7 @@ ShellRoot {
property list<string> families: ["ii", "waffle"] property list<string> families: ["ii", "waffle"]
property var panelFamilies: ({ property var panelFamilies: ({
"ii": ["iiBar", "iiBackground", "iiCheatsheet", "iiDock", "iiLock", "iiMediaControls", "iiNotificationPopup", "iiOnScreenDisplay", "iiOnScreenKeyboard", "iiOverlay", "iiOverview", "iiPolkit", "iiRegionSelector", "iiScreenCorners", "iiSessionScreen", "iiSidebarLeft", "iiSidebarRight", "iiVerticalBar", "iiWallpaperSelector"], "ii": ["iiBar", "iiBackground", "iiCheatsheet", "iiDock", "iiLock", "iiMediaControls", "iiNotificationPopup", "iiOnScreenDisplay", "iiOnScreenKeyboard", "iiOverlay", "iiOverview", "iiPolkit", "iiRegionSelector", "iiScreenCorners", "iiSessionScreen", "iiSidebarLeft", "iiSidebarRight", "iiVerticalBar", "iiWallpaperSelector"],
"waffle": ["wActionCenter", "wBar", "wBackground", "wNotificationCenter", "wOnScreenDisplay", "iiCheatsheet", "iiLock", "iiNotificationPopup", "iiOnScreenKeyboard", "iiOverlay", "iiOverview", "iiPolkit", "iiRegionSelector", "iiSessionScreen", "iiWallpaperSelector"], "waffle": ["wActionCenter", "wBar", "wBackground", "wNotificationCenter", "wOnScreenDisplay", "wStartMenu", "iiCheatsheet", "iiLock", "iiNotificationPopup", "iiOnScreenKeyboard", "iiOverlay", "iiPolkit", "iiRegionSelector", "iiSessionScreen", "iiWallpaperSelector"],
}) })
function cyclePanelFamily() { function cyclePanelFamily() {
const currentIndex = families.indexOf(Config.options.panelFamily) const currentIndex = families.indexOf(Config.options.panelFamily)
+3
View File
@@ -191,6 +191,9 @@ Tips:
- Used in Quickshell config. - Used in Quickshell config.
- `wlogout` - `wlogout`
- Used in Hyprland config. - Used in Hyprland config.
- `libqalculate`
- Used in Quickshell config, providing math ability in searchbar.
- Note that `qalc` is the needed executable. In Arch Linux [libqalculate](https://archlinux.org/packages/extra/x86_64/libqalculate) provides it, but in Fedora [qalculate](https://packages.fedoraproject.org/pkgs/libqalculate/qalculate/fedora-43.html#files) does and [libqalculate](https://packages.fedoraproject.org/pkgs/libqalculate/libqalculate/fedora-43.html#files) does not.
# Actual packages # Actual packages
@@ -1,6 +1,6 @@
pkgname=illogical-impulse-widgets pkgname=illogical-impulse-widgets
pkgver=1.0 pkgver=1.0
pkgrel=5 pkgrel=6
pkgdesc='Illogical Impulse Widget Dependencies' pkgdesc='Illogical Impulse Widget Dependencies'
arch=(any) arch=(any)
license=(None) license=(None)
@@ -14,4 +14,5 @@ depends=(
songrec songrec
translate-shell translate-shell
wlogout wlogout
libqalculate
) )
+3 -1
View File
@@ -181,6 +181,7 @@ packages = [
"hyprpicker", "hyprpicker",
"songrec", "songrec",
"translate-shell", "translate-shell",
"qalculate",
"wlogout" "wlogout"
] ]
@@ -191,4 +192,5 @@ packages = [
"plasma-systemmonitor", "plasma-systemmonitor",
"unzip" "unzip"
] ]
install_opts = ["--setopt=install_weak_deps=False"] install_opts = ["--setopt=install_weak_deps=False"]
+32 -2
View File
@@ -37,8 +37,38 @@ As [commented](https://github.com/end-4/dots-hyprland/issues/1061#issuecomment-3
See also [caelestia-dots/shell#668](https://github.com/caelestia-dots/shell/issues/668). See also [caelestia-dots/shell#668](https://github.com/caelestia-dots/shell/issues/668).
### NixGL ### GPU
On non-NixOS distros, packages installed via home-manager have problem accessing GPU, especially Hyprland because it requires GPU acceleration to launch. `nixGL` should be used to address the problem. On non-NixOS distros, packages installed via home-manager have problem accessing GPU, especially Hyprland because it requires GPU acceleration to launch.
~~`nixGL` should be used to address the problem.~~
Since home-manager 25.11, for non-NixOS just set the following:
```nix
targets.genericLinux.enable = true;
```
Then during building, home-manager will show a message to tell you running a command manually to configure GPU, like:
```bash
sudo /nix/store/<HASH>-non-nixos-gpu/bin/non-nixos-gpu-setup
```
It runs a bash script with following content:
```
#!/nix/store/<HASH>-bash-<VERSION>/bin/bash
set -e
# Install the systemd service file and ensure that the store path won't be
# garbage-collected as long as it's installed.
unit_path=/etc/systemd/system/non-nixos-gpu.service
ln -sf /nix/store/<HASH>-non-nixos-gpu/resources/non-nixos-gpu.service "$unit_path"
ln -sf "$unit_path" "/nix/var/nix"/gcroots/non-nixos-gpu.service
systemctl daemon-reload
systemctl enable non-nixos-gpu.service
systemctl restart non-nixos-gpu.service
```
_Note: it uses `systemctl`, maybe won't work for OpenRC..._
See [gpu-non-nixos](https://nix-community.github.io/home-manager/index.xhtml#sec-usage-gpu-non-nixos).
# Handling dot files # Handling dot files
## Status ## Status
+11 -8
View File
@@ -3,23 +3,24 @@
description = "illogical-impulse"; description = "illogical-impulse";
inputs = { inputs = {
# Qt 6.10 is not yet available from released version of nixpkgs. nixpkgs.url = "nixpkgs/nixos-25.11";
#nixpkgs.url = "nixpkgs/nixos-25.05"; #nixpkgs.url = "nixpkgs/nixos-unstable";
nixpkgs.url = "nixpkgs/nixos-unstable";
home-manager = { home-manager = {
#url = "github:nix-community/home-manager/release-25.05"; url = "github:nix-community/home-manager/release-25.11";
url = "github:nix-community/home-manager/master"; #url = "github:nix-community/home-manager/master";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
nixgl.url = "github:nix-community/nixGL"; #nixgl.url = "github:nix-community/nixGL";
quickshell = { quickshell = {
url = "github:quickshell-mirror/quickshell/db1777c20b936a86528c1095cbcb1ebd92801402"; url = "github:quickshell-mirror/quickshell/db1777c20b936a86528c1095cbcb1ebd92801402";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
}; };
outputs = { nixpkgs, home-manager, nixgl, quickshell, ... }: outputs = { nixpkgs, home-manager,
#nixgl,
quickshell, ... }:
let let
home_attrs = rec { home_attrs = rec {
username = import ./username.nix; username = import ./username.nix;
@@ -36,7 +37,9 @@
homeConfigurations = { homeConfigurations = {
illogical_impulse = home-manager.lib.homeManagerConfiguration { illogical_impulse = home-manager.lib.homeManagerConfiguration {
inherit pkgs; inherit pkgs;
extraSpecialArgs = { inherit home_attrs nixgl quickshell; }; extraSpecialArgs = { inherit home_attrs
#nixgl
quickshell; };
modules = [ modules = [
./home.nix ./home.nix
]; ];
+14 -5
View File
@@ -1,8 +1,13 @@
{ config, lib, pkgs, nixgl, quickshell, home_attrs, ... }: { config, lib, pkgs,
#nixgl,
quickshell, home_attrs, ... }:
{ {
programs.home-manager.enable = true; programs.home-manager.enable = true;
nixGL.packages = nixgl.packages;
nixGL.defaultWrapper = "mesa"; # Necessary for non-NixOS to handle GPU (since home-manager version 25.11)
targets.genericLinux.enable = true;
#nixGL.packages = nixgl.packages;
#nixGL.defaultWrapper = "mesa";
xdg.portal = { xdg.portal = {
enable = true; enable = true;
@@ -27,7 +32,8 @@
systemd.enable = false; plugins = []; settings = {}; extraConfig = ""; systemd.enable = false; plugins = []; settings = {}; extraConfig = "";
enable = true; enable = true;
## Use NixGL ## Use NixGL
package = config.lib.nixGL.wrap pkgs.hyprland; #package = config.lib.nixGL.wrap pkgs.hyprland;
package = pkgs.hyprland;
}; };
home = { home = {
@@ -167,6 +173,7 @@
songrec #songrec songrec #songrec
translate-shell #translate-shell translate-shell #translate-shell
wlogout #wlogout wlogout #wlogout
libqalculate #libqalculate
] ]
++ [ ++ [
@@ -174,7 +181,9 @@
### illogical-impulse-quickshell-git ### illogical-impulse-quickshell-git
#(config.lib.nixGL.wrap quickshell.packages.x86_64-linux.default) #(config.lib.nixGL.wrap quickshell.packages.x86_64-linux.default)
(import ./quickshell.nix { inherit pkgs quickshell; nixGLWrap = config.lib.nixGL.wrap; }) (import ./quickshell.nix { inherit pkgs quickshell;
#nixGLWrap = config.lib.nixGL.wrap;
})
]; ];
}//home_attrs; }//home_attrs;
} }
+7 -3
View File
@@ -1,10 +1,14 @@
{ pkgs, quickshell, nixGLWrap, ... }: { pkgs, quickshell,
#nixGLWrap,
... }:
let let
qs = nixGLWrap quickshell.packages.x86_64-linux.default; #qs = nixGLWrap quickshell.packages.x86_64-linux.default;
qs = quickshell.packages.x86_64-linux.default;
in pkgs.stdenv.mkDerivation { in pkgs.stdenv.mkDerivation {
name = "illogical-impulse-quickshell-wrapper"; name = "illogical-impulse-quickshell-wrapper";
meta = with pkgs.lib; { meta = with pkgs.lib; {
description = "Quickshell wrapped with NixGL + bundled Qt deps for home-manager usage"; #description = "Quickshell wrapped with NixGL + bundled Qt deps for home-manager usage";
description = "Quickshell bundled Qt deps for home-manager usage";
license = licenses.gpl3Only; license = licenses.gpl3Only;
}; };
+3 -2
View File
@@ -32,8 +32,8 @@ function install_home-manager(){
try source $HOME/.nix-profile/etc/profile.d/hm-session-vars.sh try source $HOME/.nix-profile/etc/profile.d/hm-session-vars.sh
command -v $cmd && return command -v $cmd && return
x nix-channel --add https://nixos.org/channels/nixos-25.05 nixpkgs-home x nix-channel --add https://nixos.org/channels/nixos-25.11 nixpkgs-home
x nix-channel --add https://github.com/nix-community/home-manager/archive/release-25.05.tar.gz home-manager x nix-channel --add https://github.com/nix-community/home-manager/archive/release-25.11.tar.gz home-manager
x nix-channel --update x nix-channel --update
x env NIX_PATH="nixpkgs=$HOME/.nix-defexpr/channels/nixpkgs-home" nix-shell '<home-manager>' -A install x env NIX_PATH="nixpkgs=$HOME/.nix-defexpr/channels/nixpkgs-home" nix-shell '<home-manager>' -A install
@@ -56,6 +56,7 @@ function hm_deps(){
x home-manager switch --flake .#illogical_impulse \ x home-manager switch --flake .#illogical_impulse \
--extra-experimental-features nix-command \ --extra-experimental-features nix-command \
--extra-experimental-features flakes --extra-experimental-features flakes
x sudo /nix/store/*-non-nixos-gpu/bin/non-nixos-gpu-setup
cd $REPO_ROOT cd $REPO_ROOT
x git rm -f "${SETUP_USERNAME_NIXFILE}" x git rm -f "${SETUP_USERNAME_NIXFILE}"
} }