mirror of
https://github.com/end-4/dots-hyprland.git
synced 2026-06-05 14:59:27 -05:00
Merge branch 'end-4:main' into parallax
This commit is contained in:
@@ -53,7 +53,7 @@ bindd = Ctrl+Super, T, Toggle wallpaper selector, global, quickshell:wallpaperSe
|
||||
bindd = Ctrl+Super+Alt, T, Select random wallpaper, global, quickshell:wallpaperSelectorRandom # Random wallpaper
|
||||
bindd = Ctrl+Super, T, Change wallpaper, exec, qs -c $qsConfig ipc call TEST_ALIVE || ~/.config/quickshell/$qsConfig/scripts/colors/switchwall.sh # [hidden] Change wallpaper (fallback)
|
||||
bind = Ctrl+Super, R, exec, killall ags agsv1 gjs ydotool qs quickshell; qs -c $qsConfig & # Restart widgets
|
||||
bind = Super+Alt, W, global, quickshell:panelFamilyCycle # Cycle panel family
|
||||
bind = Ctrl+Super, P, global, quickshell:panelFamilyCycle # Cycle panel family
|
||||
|
||||
##! Utilities
|
||||
# Screenshot, Record, OCR, Color picker, Clipboard history
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
sodipodi:docname=".svg"
|
||||
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs1" />
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="7.75"
|
||||
inkscape:cx="12"
|
||||
inkscape:cy="12"
|
||||
inkscape:window-width="1173"
|
||||
inkscape:window-height="790"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1007 B |
@@ -0,0 +1 @@
|
||||
<svg width="24" height="24" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m8.5 16.586-3.793-3.793a1 1 0 0 0-1.414 1.414l4.5 4.5a1 1 0 0 0 1.414 0l11-11a1 1 0 0 0-1.414-1.414L8.5 16.586Z" fill="#212121"/></svg>
|
||||
|
After Width: | Height: | Size: 239 B |
@@ -0,0 +1 @@
|
||||
<svg width="24" height="24" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M4.53 12.97a.75.75 0 0 0-1.06 1.06l4.5 4.5a.75.75 0 0 0 1.06 0l11-11a.75.75 0 0 0-1.06-1.06L8.5 16.94l-3.97-3.97Z" fill="#212121"/></svg>
|
||||
|
After Width: | Height: | Size: 241 B |
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
sodipodi:docname=".svg"
|
||||
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs1" />
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="7.75"
|
||||
inkscape:cx="12"
|
||||
inkscape:cy="12"
|
||||
inkscape:window-width="1173"
|
||||
inkscape:window-height="790"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1007 B |
@@ -418,6 +418,8 @@ Singleton {
|
||||
property real scale: 0.18 // Relative to screen size
|
||||
property real rows: 2
|
||||
property real columns: 5
|
||||
property bool orderRightLeft: false
|
||||
property bool orderBottomUp: false
|
||||
property bool centerIcons: true
|
||||
}
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ Singleton {
|
||||
property string wallpaperSwitchScriptPath: FileUtils.trimFileProtocol(`${Directories.scriptPath}/colors/switchwall.sh`)
|
||||
property string defaultAiPrompts: Quickshell.shellPath("defaults/ai/prompts")
|
||||
property string userAiPrompts: FileUtils.trimFileProtocol(`${Directories.shellConfig}/ai/prompts`)
|
||||
property string userActions: FileUtils.trimFileProtocol(`${Directories.shellConfig}/actions`)
|
||||
property string aiChats: FileUtils.trimFileProtocol(`${Directories.state}/user/ai/chats`)
|
||||
property string aiTranslationScriptPath: FileUtils.trimFileProtocol(`${Directories.scriptPath}/ai/gemini-translate.sh`)
|
||||
property string recordScriptPath: FileUtils.trimFileProtocol(`${Directories.scriptPath}/videos/record.sh`)
|
||||
@@ -59,6 +60,7 @@ Singleton {
|
||||
Quickshell.execDetached(["bash", "-c", `rm -rf '${latexOutput}'; mkdir -p '${latexOutput}'`])
|
||||
Quickshell.execDetached(["bash", "-c", `rm -rf '${cliphistDecode}'; mkdir -p '${cliphistDecode}'`])
|
||||
Quickshell.execDetached(["mkdir", "-p", `${aiChats}`])
|
||||
Quickshell.execDetached(["mkdir", "-p", `${userActions}`])
|
||||
Quickshell.execDetached(["rm", "-rf", `${tempImages}`])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +63,10 @@ Singleton {
|
||||
property real temperature: 0.5
|
||||
}
|
||||
|
||||
property JsonObject cheatsheet: JsonObject {
|
||||
property int tabIndex: 0
|
||||
}
|
||||
|
||||
property JsonObject sidebar: JsonObject {
|
||||
property JsonObject bottomGroup: JsonObject {
|
||||
property bool collapsed: false
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import Quickshell
|
||||
|
||||
ScriptModel {
|
||||
required property int count
|
||||
values: Array(count).map((_, i) => i)
|
||||
}
|
||||
@@ -72,7 +72,7 @@ Scope {
|
||||
}
|
||||
|
||||
function stopFingerPam() {
|
||||
if (fingerPam.running) {
|
||||
if (fingerPam.active) {
|
||||
fingerPam.abort();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +92,6 @@ Scope {
|
||||
WlSessionLock {
|
||||
id: lock
|
||||
locked: GlobalStates.screenLocked
|
||||
|
||||
surface: root.sessionLockSurface
|
||||
}
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ ListView {
|
||||
to: 1,
|
||||
}),
|
||||
] : []
|
||||
}
|
||||
}
|
||||
|
||||
move: Transition {
|
||||
animations: root.animateMovement ? [
|
||||
|
||||
@@ -4,6 +4,7 @@ import qs.modules.common.widgets
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Qt.labs.synchronizer
|
||||
import Qt5Compat.GraphicalEffects
|
||||
import Quickshell.Io
|
||||
import Quickshell
|
||||
@@ -135,7 +136,10 @@ Scope { // Scope
|
||||
ToolbarTabBar {
|
||||
id: tabBar
|
||||
tabButtonList: root.tabButtonList
|
||||
currentIndex: swipeView.currentIndex
|
||||
|
||||
Synchronizer on currentIndex {
|
||||
property alias source: swipeView.currentIndex
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,8 +148,11 @@ Scope { // Scope
|
||||
Layout.topMargin: 5
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
currentIndex: tabBar.currentIndex
|
||||
spacing: 10
|
||||
currentIndex: Persistent.states.cheatsheet.tabIndex
|
||||
onCurrentIndexChanged: {
|
||||
Persistent.states.cheatsheet.tabIndex = currentIndex;
|
||||
}
|
||||
|
||||
implicitWidth: Math.max.apply(null, contentChildren.map(child => child.implicitWidth || 0))
|
||||
implicitHeight: Math.max.apply(null, contentChildren.map(child => child.implicitHeight || 0))
|
||||
|
||||
@@ -50,6 +50,21 @@ Item {
|
||||
|
||||
property Component windowComponent: OverviewWindow {}
|
||||
property list<OverviewWindow> windowWidgets: []
|
||||
|
||||
function getWsRow(ws) {
|
||||
// 1-indexed workspace, 0-indexed row
|
||||
var normalRow = Math.floor((ws - 1) / Config.options.overview.columns) % Config.options.overview.rows;
|
||||
return (Config.options.overview.orderBottomUp ? Config.options.overview.rows - normalRow - 1 : normalRow);
|
||||
}
|
||||
function getWsColumn(ws) {
|
||||
// 1-indexed workspace, 0-indexed column
|
||||
var normalCol = (ws - 1) % Config.options.overview.columns;
|
||||
return (Config.options.overview.orderRightLeft ? Config.options.overview.columns - normalCol - 1 : normalCol);
|
||||
}
|
||||
function getWsInCell(ri, ci) {
|
||||
// 1-indexed workspace, 0-indexed row and column index
|
||||
return (Config.options.overview.orderBottomUp ? Config.options.overview.rows - ri - 1 : ri) * Config.options.overview.columns + (Config.options.overview.orderRightLeft ? Config.options.overview.columns - ci - 1 : ci) + 1
|
||||
}
|
||||
|
||||
StyledRectangularShadow {
|
||||
target: overviewBackground
|
||||
@@ -85,7 +100,7 @@ Item {
|
||||
id: workspace
|
||||
required property int index
|
||||
property int colIndex: index
|
||||
property int workspaceValue: root.workspaceGroup * root.workspacesShown + row.index * Config.options.overview.columns + colIndex + 1
|
||||
property int workspaceValue: root.workspaceGroup * root.workspacesShown + getWsInCell(row.index, colIndex)
|
||||
property color defaultWorkspaceColor: ColorUtils.mix(Appearance.colors.colBackgroundSurfaceContainer, Appearance.colors.colSurfaceContainerHigh, 0.8)
|
||||
property color hoveredWorkspaceColor: ColorUtils.mix(defaultWorkspaceColor, Appearance.colors.colLayer1Hover, 0.1)
|
||||
property color hoveredBorderColor: Appearance.colors.colLayer2Hover
|
||||
@@ -182,8 +197,8 @@ Item {
|
||||
property bool atInitPosition: (initX == x && initY == y)
|
||||
|
||||
// Offset on the canvas
|
||||
property int workspaceColIndex: (windowData?.workspace.id - 1) % Config.options.overview.columns
|
||||
property int workspaceRowIndex: Math.floor((windowData?.workspace.id - 1) % root.workspacesShown / Config.options.overview.columns)
|
||||
property int workspaceColIndex: getWsColumn(windowData?.workspace.id)
|
||||
property int workspaceRowIndex: getWsRow(windowData?.workspace.id)
|
||||
xOffset: (root.workspaceImplicitWidth + workspaceSpacing) * workspaceColIndex
|
||||
yOffset: (root.workspaceImplicitHeight + workspaceSpacing) * workspaceRowIndex
|
||||
property real xWithinWorkspaceWidget: Math.max((windowData?.at[0] - (monitor?.x ?? 0) - monitorData?.reserved[0]) * root.scale, 0)
|
||||
@@ -286,9 +301,8 @@ Item {
|
||||
|
||||
Rectangle { // Focused workspace indicator
|
||||
id: focusedWorkspaceIndicator
|
||||
property int activeWorkspaceInGroup: monitor.activeWorkspace?.id - (root.workspaceGroup * root.workspacesShown)
|
||||
property int rowIndex: Math.floor((activeWorkspaceInGroup - 1) / Config.options.overview.columns)
|
||||
property int colIndex: (activeWorkspaceInGroup - 1) % Config.options.overview.columns
|
||||
property int rowIndex: getWsRow(monitor.activeWorkspace?.id)
|
||||
property int colIndex: getWsColumn(monitor.activeWorkspace?.id)
|
||||
x: (root.workspaceImplicitWidth + workspaceSpacing) * colIndex
|
||||
y: (root.workspaceImplicitHeight + workspaceSpacing) * rowIndex
|
||||
z: root.windowZ
|
||||
|
||||
@@ -739,6 +739,45 @@ ContentPage {
|
||||
}
|
||||
}
|
||||
}
|
||||
ConfigRow {
|
||||
uniform: true
|
||||
ConfigSelectionArray {
|
||||
currentValue: Config.options.overview.orderRightLeft
|
||||
onSelected: newValue => {
|
||||
Config.options.overview.orderRightLeft = newValue
|
||||
}
|
||||
options: [
|
||||
{
|
||||
displayName: Translation.tr("Left to right"),
|
||||
icon: "arrow_forward",
|
||||
value: 0
|
||||
},
|
||||
{
|
||||
displayName: Translation.tr("Right to left"),
|
||||
icon: "arrow_back",
|
||||
value: 1
|
||||
}
|
||||
]
|
||||
}
|
||||
ConfigSelectionArray {
|
||||
currentValue: Config.options.overview.orderBottomUp
|
||||
onSelected: newValue => {
|
||||
Config.options.overview.orderBottomUp = newValue
|
||||
}
|
||||
options: [
|
||||
{
|
||||
displayName: Translation.tr("Top-down"),
|
||||
icon: "arrow_downward",
|
||||
value: 0
|
||||
},
|
||||
{
|
||||
displayName: Translation.tr("Bottom-up"),
|
||||
icon: "arrow_upward",
|
||||
value: 1
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ContentSection {
|
||||
|
||||
@@ -9,8 +9,8 @@ MouseArea {
|
||||
id: root
|
||||
|
||||
Layout.fillHeight: true
|
||||
implicitHeight: row.implicitHeight
|
||||
implicitWidth: row.implicitWidth
|
||||
implicitHeight: appRow.implicitHeight
|
||||
implicitWidth: appRow.implicitWidth
|
||||
hoverEnabled: true
|
||||
|
||||
function showPreviewPopup(appEntry, button) {
|
||||
@@ -21,31 +21,31 @@ MouseArea {
|
||||
animation: Looks.transition.move.createObject(this)
|
||||
}
|
||||
|
||||
// Apps row
|
||||
RowLayout {
|
||||
id: row
|
||||
WListView {
|
||||
id: appRow
|
||||
anchors {
|
||||
top: parent.top
|
||||
bottom: parent.bottom
|
||||
}
|
||||
orientation: Qt.Horizontal
|
||||
spacing: 0
|
||||
implicitWidth: contentWidth
|
||||
clip: true
|
||||
interactive: false
|
||||
// TODO: Include only apps (and windows) in current workspace only | wait, does that even make sense in a Hyprland workflow?
|
||||
model: ScriptModel {
|
||||
objectProp: "appId"
|
||||
values: TaskbarApps.apps.filter(app => app.appId !== "SEPARATOR")
|
||||
}
|
||||
delegate: TaskAppButton {
|
||||
required property var modelData
|
||||
appEntry: modelData
|
||||
|
||||
Repeater {
|
||||
// TODO: Include only apps (and windows) in current workspace only | wait, does that even make sense in a Hyprland workflow?
|
||||
model: ScriptModel {
|
||||
objectProp: "appId"
|
||||
values: TaskbarApps.apps.filter(app => app.appId !== "SEPARATOR")
|
||||
onHoverPreviewRequested: {
|
||||
root.showPreviewPopup(appEntry, this);
|
||||
}
|
||||
delegate: TaskAppButton {
|
||||
required property var modelData
|
||||
appEntry: modelData
|
||||
|
||||
onHoverPreviewRequested: {
|
||||
root.showPreviewPopup(appEntry, this)
|
||||
}
|
||||
onHoverPreviewDismissed: {
|
||||
previewPopup.close()
|
||||
}
|
||||
onHoverPreviewDismissed: {
|
||||
previewPopup.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,5 +56,4 @@ MouseArea {
|
||||
tasksHovered: root.containsMouse
|
||||
anchor.window: root.QsWindow.window
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,15 +36,34 @@ LockScreen {
|
||||
Image {
|
||||
id: bg
|
||||
z: 0
|
||||
anchors.fill: parent
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
onStatusChanged: {
|
||||
if (status === Image.Ready) {
|
||||
print("Lock wallpaper loaded");
|
||||
print(lockSurfaceItem.height);
|
||||
y = -lockSurfaceItem.height;
|
||||
openAnim.restart();
|
||||
}
|
||||
}
|
||||
sourceSize: Qt.size(lockSurfaceItem.width, lockSurfaceItem.height)
|
||||
source: Config.options.background.wallpaperPath
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
|
||||
PropertyAnimation {
|
||||
id: openAnim
|
||||
target: bg
|
||||
property: "y"
|
||||
to: 0
|
||||
duration: 350
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Looks.transition.easing.bezierCurve.easeIn
|
||||
}
|
||||
}
|
||||
|
||||
GaussianBlur {
|
||||
z: 1
|
||||
anchors.fill: parent
|
||||
anchors.fill: bg
|
||||
source: bg
|
||||
radius: 100
|
||||
samples: radius * 2 + 1
|
||||
@@ -67,7 +86,7 @@ LockScreen {
|
||||
Interactables {
|
||||
id: interactables
|
||||
z: 2
|
||||
anchors.fill: parent
|
||||
anchors.fill: bg
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,12 +102,31 @@ LockScreen {
|
||||
// }
|
||||
|
||||
function switchToFocusedView() {
|
||||
root.passwordView = true;
|
||||
switchToPasswordViewAnim.restart();
|
||||
}
|
||||
|
||||
SequentialAnimation {
|
||||
id: switchToPasswordViewAnim
|
||||
PropertyAnimation {
|
||||
target: unfocusedContent
|
||||
property: "y"
|
||||
from: 0
|
||||
to: -height * 1.1
|
||||
duration: 250
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Looks.transition.easing.bezierCurve.easeIn
|
||||
}
|
||||
ScriptAction {
|
||||
script: {
|
||||
root.passwordView = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: unfocusedContent
|
||||
anchors.fill: parent
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
visible: !root.passwordView
|
||||
ClockTextGroup {
|
||||
anchors {
|
||||
|
||||
@@ -177,7 +177,7 @@ Singleton {
|
||||
|
||||
property Component color: Component {
|
||||
ColorAnimation {
|
||||
duration: 120
|
||||
duration: 80
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: transition.easing.bezierCurve.easeIn
|
||||
}
|
||||
|
||||
@@ -6,5 +6,14 @@ import QtQuick.Controls
|
||||
ListView {
|
||||
id: root
|
||||
|
||||
boundsBehavior: Flickable.DragOverBounds
|
||||
|
||||
ScrollBar.vertical: WScrollBar {}
|
||||
|
||||
displaced: Transition {
|
||||
animations: [Looks.transition.enter.createObject(this, {
|
||||
property: "y"
|
||||
})]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-2
@@ -53,10 +53,9 @@ BodyRectangle {
|
||||
}
|
||||
}
|
||||
|
||||
StyledListView {
|
||||
WListView {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
animateAppearance: false
|
||||
clip: true
|
||||
|
||||
model: Notifications.appNameList
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import qs.modules.common
|
||||
import qs.modules.common.widgets
|
||||
import qs.modules.common.functions
|
||||
import qs.modules.waffle.looks
|
||||
|
||||
SequentialAnimation {
|
||||
id: root
|
||||
|
||||
required property var target
|
||||
|
||||
PropertyAction {
|
||||
target: root.target
|
||||
property: "ListView.delayRemove"
|
||||
value: true
|
||||
}
|
||||
NumberAnimation {
|
||||
target: root.target
|
||||
property: "x"
|
||||
to: root.target.width
|
||||
duration: 250
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Looks.transition.easing.bezierCurve.easeIn
|
||||
}
|
||||
PropertyAction {
|
||||
target: root.target
|
||||
property: "ListView.delayRemove"
|
||||
value: false
|
||||
}
|
||||
}
|
||||
+49
-10
@@ -1,3 +1,4 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
@@ -18,10 +19,44 @@ MouseArea {
|
||||
implicitWidth: contentLayout.implicitWidth
|
||||
implicitHeight: contentLayout.implicitHeight
|
||||
|
||||
function dismissAll() {
|
||||
root.notifications.forEach(notif => {
|
||||
Qt.callLater(() => {
|
||||
Notifications.discardNotification(notif.notificationId);
|
||||
});
|
||||
});
|
||||
removeAnimation.start();
|
||||
}
|
||||
|
||||
WNotificationDismissAnim {
|
||||
id: removeAnimation
|
||||
target: root
|
||||
}
|
||||
|
||||
property real dragDismissThreshold: 100
|
||||
drag {
|
||||
axis: Drag.XAxis
|
||||
target: contentLayout
|
||||
minimumX: 0
|
||||
onActiveChanged: {
|
||||
if (drag.active)
|
||||
return;
|
||||
if (contentLayout.x > root.dragDismissThreshold) {
|
||||
root.dismissAll();
|
||||
} else {
|
||||
contentLayout.x = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: contentLayout
|
||||
anchors.fill: parent
|
||||
spacing: 4
|
||||
width: root.width
|
||||
|
||||
Behavior on x {
|
||||
animation: Looks.transition.enter.createObject(this)
|
||||
}
|
||||
|
||||
GroupHeader {
|
||||
id: notifHeader
|
||||
@@ -29,7 +64,9 @@ MouseArea {
|
||||
Layout.margins: 11
|
||||
}
|
||||
|
||||
ListView {
|
||||
WListView {
|
||||
Layout.leftMargin: -Math.min(35, contentLayout.x)
|
||||
Layout.rightMargin: -Layout.leftMargin
|
||||
Layout.fillWidth: true
|
||||
implicitWidth: notifHeader.implicitWidth
|
||||
implicitHeight: contentHeight
|
||||
@@ -40,14 +77,20 @@ MouseArea {
|
||||
objectProp: "notificationId"
|
||||
}
|
||||
delegate: WSingleNotification {
|
||||
id: singleNotif
|
||||
required property int index
|
||||
required property var modelData
|
||||
|
||||
width: ListView.view.width
|
||||
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");
|
||||
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: {
|
||||
@@ -94,11 +137,7 @@ MouseArea {
|
||||
Layout.rightMargin: 3
|
||||
icon.name: "dismiss"
|
||||
onClicked: {
|
||||
root.notifications.forEach(notif => {
|
||||
Qt.callLater(() => {
|
||||
Notifications.discardNotification(notif.notificationId);
|
||||
});
|
||||
});
|
||||
root.dismissAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+34
-6
@@ -18,6 +18,18 @@ MouseArea {
|
||||
signal groupExpandToggle
|
||||
hoverEnabled: true
|
||||
|
||||
function dismiss() {
|
||||
Qt.callLater(() => {
|
||||
Notifications.discardNotification(root.notification?.notificationId);
|
||||
});
|
||||
removeAnimation.start();
|
||||
}
|
||||
|
||||
WNotificationDismissAnim {
|
||||
id: removeAnimation
|
||||
target: root
|
||||
}
|
||||
|
||||
implicitHeight: contentItem.implicitHeight
|
||||
implicitWidth: contentItem.implicitWidth
|
||||
|
||||
@@ -25,9 +37,25 @@ MouseArea {
|
||||
animation: Looks.transition.enter.createObject(this)
|
||||
}
|
||||
|
||||
property real dragDismissThreshold: 100
|
||||
drag {
|
||||
axis: Drag.XAxis
|
||||
target: contentItem
|
||||
minimumX: 0
|
||||
onActiveChanged: {
|
||||
if (drag.active)
|
||||
return;
|
||||
if (contentItem.x > root.dragDismissThreshold) {
|
||||
root.dismiss();
|
||||
} else {
|
||||
contentItem.x = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: contentItem
|
||||
anchors.fill: parent
|
||||
width: parent.width
|
||||
color: Looks.colors.bgPanelBody
|
||||
radius: Looks.radius.medium
|
||||
property real padding: 12
|
||||
@@ -36,6 +64,10 @@ MouseArea {
|
||||
border.width: 1
|
||||
border.color: ColorUtils.applyAlpha(Looks.colors.ambientShadow, 0.1)
|
||||
|
||||
Behavior on x {
|
||||
animation: Looks.transition.enter.createObject(this)
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: notificationContent
|
||||
anchors.fill: parent
|
||||
@@ -128,11 +160,7 @@ MouseArea {
|
||||
opacity: root.containsMouse ? 1 : 0
|
||||
icon.name: "dismiss"
|
||||
implicitSize: 12
|
||||
onClicked: {
|
||||
Qt.callLater(() => {
|
||||
Notifications.discardNotification(root.notification?.notificationId);
|
||||
});
|
||||
}
|
||||
onClicked: root.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ WBarAttachedPanelContent {
|
||||
id: searchBar
|
||||
Layout.fillWidth: true
|
||||
implicitWidth: 832 // TODO: Make sizes naturally inferred
|
||||
horizontalPadding: root.searching ? 24 : 32
|
||||
horizontalPadding: 32
|
||||
// verticalPadding: root.searching ? 32 : 16 // TODO: make this not nuke the panel
|
||||
Synchronizer on searching {
|
||||
property alias target: root.searching
|
||||
|
||||
@@ -1,44 +1,214 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Hyprland
|
||||
import qs
|
||||
import qs.services
|
||||
import qs.modules.common
|
||||
import qs.modules.common.functions
|
||||
import qs.modules.common.models
|
||||
import qs.modules.common.widgets
|
||||
import qs.modules.waffle.looks
|
||||
import "window-layout.js" as WindowLayout
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
color: ColorUtils.transparentize(Looks.colors.bg1Base, 0.5)
|
||||
property bool draggingWindow: false
|
||||
property real openProgress: 0
|
||||
property Item hoveredWorkspace: null
|
||||
signal closed
|
||||
|
||||
Component.onCompleted: {
|
||||
openAnim.start();
|
||||
}
|
||||
function close() {
|
||||
closeAnim.start();
|
||||
}
|
||||
|
||||
PropertyAnimation {
|
||||
id: openAnim
|
||||
target: root
|
||||
property: "openProgress"
|
||||
to: 1
|
||||
duration: 200
|
||||
duration: 250
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Looks.transition.easing.bezierCurve.easeIn
|
||||
}
|
||||
PropertyAnimation {
|
||||
SequentialAnimation {
|
||||
id: closeAnim
|
||||
target: root
|
||||
property: "openProgress"
|
||||
to: 0
|
||||
duration: 200
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Looks.transition.easing.bezierCurve.easeIn
|
||||
|
||||
PropertyAnimation {
|
||||
target: root
|
||||
property: "openProgress"
|
||||
to: 0
|
||||
duration: 250
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Looks.transition.easing.bezierCurve.easeIn
|
||||
}
|
||||
ScriptAction {
|
||||
script: {
|
||||
root.closed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Windows
|
||||
property real maxWindowHeight: 290
|
||||
property real maxWindowWidth: 738
|
||||
property real padding: 52
|
||||
property real spacing: 25
|
||||
readonly property list<var> toplevels: ToplevelManager.toplevels.values.filter(t => {
|
||||
const client = HyprlandData.clientForToplevel(t);
|
||||
return client && client.workspace.id === HyprlandData.activeWorkspace?.id;
|
||||
})
|
||||
readonly property list<var> arrangedToplevels: {
|
||||
const maxRowWidth = width - padding * 2;
|
||||
const count = toplevels.length;
|
||||
const resultLayout = [];
|
||||
|
||||
var i = 0;
|
||||
while (i < count) {
|
||||
var row = [];
|
||||
var rowWidth = 0;
|
||||
var j = i;
|
||||
|
||||
while (j < count) {
|
||||
const toplevel = toplevels[j];
|
||||
const client = HyprlandData.clientForToplevel(toplevel);
|
||||
const scaledSize = WindowLayout.scaleWindow(client, maxWindowWidth, maxWindowHeight);
|
||||
|
||||
if (rowWidth + scaledSize.width <= maxRowWidth || row.length === 0) {
|
||||
row.push(toplevel);
|
||||
rowWidth += scaledSize.width;
|
||||
j++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
resultLayout.push(row);
|
||||
i = j;
|
||||
}
|
||||
return resultLayout;
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
z: 0
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
GlobalStates.overviewOpen = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Windows
|
||||
WListView {
|
||||
id: windowListView
|
||||
z: root.openProgress == 1 ? 2 : 1
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
top: parent.top
|
||||
topMargin: (root.height - (wsBorder.height + 16) - height) / 2
|
||||
}
|
||||
spacing: root.spacing
|
||||
topMargin: root.padding
|
||||
bottomMargin: root.padding
|
||||
leftMargin: root.padding
|
||||
rightMargin: root.padding
|
||||
height: Math.min(contentHeight + topMargin + bottomMargin, root.height - (wsBorder.height + 16))
|
||||
|
||||
interactive: (height < contentHeight) && !root.draggingWindow
|
||||
clip: root.openProgress > 0.99 && !root.draggingWindow
|
||||
|
||||
model: ScriptModel {
|
||||
values: root.arrangedToplevels
|
||||
}
|
||||
delegate: RowLayout {
|
||||
id: clientRow
|
||||
required property var modelData
|
||||
spacing: root.spacing
|
||||
anchors.horizontalCenter: parent?.horizontalCenter ?? undefined
|
||||
|
||||
Repeater {
|
||||
model: ScriptModel {
|
||||
values: clientRow.modelData
|
||||
}
|
||||
delegate: Item {
|
||||
id: clientGridArea
|
||||
required property int index
|
||||
required property var modelData
|
||||
implicitWidth: windowItem.openedSize.width
|
||||
implicitHeight: windowItem.openedSize.height + windowItem.titleBarImplicitHeight
|
||||
|
||||
TaskViewWindow {
|
||||
id: windowItem
|
||||
z: Drag.active ? 2 : 1
|
||||
opacity: openAnim.running ? root.openProgress : 1
|
||||
|
||||
property int mappedX: {
|
||||
// print("AAAWAWAAWAWWA: ", -(clientRow.x + clientGridArea.x + root.padding));
|
||||
var rootPosToThis = -(clientRow.x + clientGridArea.x + root.padding);
|
||||
return rootPosToThis + hyprlandClient.at[0];
|
||||
}
|
||||
property int mappedY: {
|
||||
// print("AAAWAWAAWAWWA YYYY YUIUSDFOIU: ", clientRow.y + windowListView.y + root.padding + windowItem.titleBarImplicitHeight)
|
||||
var rootPosToThis = -(clientRow.y + windowListView.y + root.padding + windowItem.titleBarImplicitHeight);
|
||||
return rootPosToThis + hyprlandClient.at[1];
|
||||
}
|
||||
property int openedX: 0
|
||||
property int openedY: 0
|
||||
// property int openedX: Drag.active ? (dragHandler.xAxis.activeValue) : 0
|
||||
// property int openedY: Drag.active ? (dragHandler.yAxis.activeValue) : 0
|
||||
scaleSize: (root.openProgress > 0 && !closeAnim.running)
|
||||
x: mappedX + (openedX - mappedX) * root.openProgress
|
||||
y: mappedY + (openedY - mappedY) * root.openProgress
|
||||
|
||||
droppable: root.hoveredWorkspace !== null
|
||||
Drag.active: dragHandler.active
|
||||
Drag.hotSpot.x: mouseX
|
||||
Drag.hotSpot.y: mouseY
|
||||
|
||||
DragHandler {
|
||||
id: dragHandler
|
||||
target: null
|
||||
xAxis.onActiveValueChanged: {
|
||||
windowItem.openedX = dragHandler.xAxis.activeValue;
|
||||
}
|
||||
yAxis.onActiveValueChanged: {
|
||||
windowItem.openedY = dragHandler.yAxis.activeValue;
|
||||
}
|
||||
onActiveChanged: {
|
||||
if (active) {
|
||||
root.draggingWindow = true;
|
||||
} else {
|
||||
root.draggingWindow = false;
|
||||
if (root.hoveredWorkspace !== null && root.hoveredWorkspace.workspace !== windowItem.hyprlandClient.workspace.id) {
|
||||
Hyprland.dispatch(`movetoworkspacesilent ${root.hoveredWorkspace.workspace}, address:${windowItem.hyprlandClient.address}`);
|
||||
} else {
|
||||
windowItem.openedX = 0;
|
||||
windowItem.openedY = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Layout.alignment: Qt.AlignTop
|
||||
maxHeight: root.maxWindowHeight
|
||||
maxWidth: root.maxWindowWidth
|
||||
toplevel: clientGridArea.modelData
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Workspaces
|
||||
Rectangle {
|
||||
id: wsBorder
|
||||
z: root.openProgress == 1 ? 1 : 2
|
||||
property real sourceEdgeMargin: -(height + 8) + root.openProgress * (height + 16)
|
||||
anchors {
|
||||
left: parent.left
|
||||
@@ -64,8 +234,9 @@ Rectangle {
|
||||
color: Looks.colors.bgPanelFooterBase
|
||||
|
||||
implicitHeight: 174
|
||||
|
||||
ListView {
|
||||
|
||||
WListView {
|
||||
id: workspaceListView
|
||||
anchors {
|
||||
top: parent.top
|
||||
bottom: parent.bottom
|
||||
@@ -73,22 +244,56 @@ Rectangle {
|
||||
topMargin: 5
|
||||
bottomMargin: 5
|
||||
}
|
||||
flickableDirection: Flickable.HorizontalFlick
|
||||
orientation: ListView.Horizontal
|
||||
interactive: width == parent.width
|
||||
width: Math.min(contentWidth + leftMargin + rightMargin, parent.width)
|
||||
leftMargin: 5
|
||||
rightMargin: 5
|
||||
clip: true
|
||||
orientation: ListView.Horizontal
|
||||
spacing: 4
|
||||
|
||||
model: ScriptModel {
|
||||
values: {
|
||||
const maxWorkspaceId = Math.max.apply(null, HyprlandData.workspaces.map(ws => ws.id))
|
||||
return Array(maxWorkspaceId)
|
||||
function reposition() {
|
||||
positionViewAtIndex(HyprlandData.activeWorkspace.id - 1, ListView.Contain);
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: HyprlandData
|
||||
function onActiveWorkspaceChanged() {
|
||||
workspaceListView.reposition();
|
||||
}
|
||||
}
|
||||
model: IndexModel {
|
||||
id: workspaceIndexModel
|
||||
count: {
|
||||
const maxWorkspaceId = Math.max.apply(null, HyprlandData.workspaces.map(ws => ws.id));
|
||||
return Math.max(maxWorkspaceId, 1) + 1;
|
||||
}
|
||||
}
|
||||
delegate: TaskViewWorkspace {
|
||||
id: workspaceItem
|
||||
required property int index
|
||||
workspace: index + 1
|
||||
newWorkspace: index == workspaceIndexModel.count - 1
|
||||
|
||||
droppable: root.hoveredWorkspace === workspaceItem
|
||||
DropArea {
|
||||
anchors.fill: parent
|
||||
onEntered: drag => {
|
||||
root.hoveredWorkspace = workspaceItem;
|
||||
}
|
||||
onExited: {
|
||||
if (root.hoveredWorkspace === workspaceItem) {
|
||||
root.hoveredWorkspace = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
GlobalStates.overviewOpen = false;
|
||||
root.closed(); // Close immediately to avoid weird animations
|
||||
Hyprland.dispatch(`workspace ${workspaceItem.workspace}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Qt5Compat.GraphicalEffects
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Hyprland
|
||||
import qs
|
||||
import qs.services
|
||||
import qs.modules.common
|
||||
import qs.modules.common.functions
|
||||
import qs.modules.common.widgets
|
||||
import qs.modules.waffle.looks
|
||||
import "window-layout.js" as WindowLayout
|
||||
|
||||
WMouseAreaButton {
|
||||
id: root
|
||||
|
||||
required property var toplevel
|
||||
required property int maxHeight
|
||||
required property int maxWidth
|
||||
|
||||
property var hyprlandClient: HyprlandData.clientForToplevel(root.toplevel)
|
||||
property string address: hyprlandClient?.address
|
||||
|
||||
property string iconName: AppSearch.guessIcon(hyprlandClient?.class)
|
||||
|
||||
color: drag.active ? ColorUtils.transparentize(Looks.colors.bg1Base) : (containsMouse ? Looks.colors.bg1Base : Looks.colors.bgPanelFooterBase)
|
||||
borderColor: ColorUtils.transparentize(Looks.colors.bg2Border, drag.active ? 1 : 0)
|
||||
radius: Looks.radius.xLarge
|
||||
|
||||
property real titleBarImplicitHeight: titleBar.implicitHeight
|
||||
property bool scaleSize: true
|
||||
property size openedSize: WindowLayout.scaleWindow(hyprlandClient, maxWidth, maxHeight);
|
||||
property size fullSize: Qt.size(hyprlandClient?.size[0] ?? maxWidth, hyprlandClient?.size[1] ?? maxHeight)
|
||||
property size size: scaleSize ? openedSize : fullSize
|
||||
implicitWidth: Math.max(Math.round(contentItem.implicitWidth), 138)
|
||||
implicitHeight: Math.round(contentItem.implicitHeight)
|
||||
|
||||
layer.enabled: true
|
||||
layer.effect: OpacityMask {
|
||||
maskSource: Item {
|
||||
width: root.background.width
|
||||
height: root.background.height
|
||||
Rectangle {
|
||||
radius: root.background.radius
|
||||
anchors {
|
||||
fill: parent
|
||||
topMargin: root.drag.active ? root.titleBarImplicitHeight : 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
property bool droppable: false
|
||||
scale: (root.pressedButtons & Qt.LeftButton || root.Drag.active) ? (droppable ? 0.4 : 0.95) : 1
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
id: scaleAnim
|
||||
duration: 200
|
||||
easing.type: Easing.OutExpo
|
||||
}
|
||||
}
|
||||
|
||||
function closeWindow() {
|
||||
Hyprland.dispatch(`closewindow address:${root.hyprlandClient?.address}`);
|
||||
}
|
||||
|
||||
acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton
|
||||
onClicked: event => {
|
||||
if (event.button === Qt.LeftButton) {
|
||||
GlobalStates.overviewOpen = false;
|
||||
Hyprland.dispatch(`focuswindow address:${root.hyprlandClient?.address}`);
|
||||
GlobalStates.overviewOpen = false;
|
||||
} else if (event.button === Qt.MiddleButton) {
|
||||
root.closeWindow();
|
||||
event.accepted = true;
|
||||
} else if (event.button === Qt.RightButton) {
|
||||
if (!windowMenu.visible)
|
||||
windowMenu.popup();
|
||||
else
|
||||
windowMenu.close();
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: contentItem
|
||||
z: 2
|
||||
anchors.fill: parent
|
||||
anchors.margins: 1
|
||||
spacing: 0
|
||||
|
||||
RowLayout {
|
||||
id: titleBar
|
||||
opacity: root.drag.active ? 0 : 1
|
||||
spacing: 8
|
||||
WAppIcon {
|
||||
Layout.leftMargin: 10
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
iconName: root.iconName
|
||||
implicitSize: 16
|
||||
tryCustomIcon: false
|
||||
}
|
||||
WText {
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
elide: Text.ElideRight
|
||||
text: root.hyprlandClient?.title ?? ""
|
||||
}
|
||||
CloseButton {
|
||||
implicitWidth: 38
|
||||
implicitHeight: 38
|
||||
padding: 8
|
||||
onClicked: root.closeWindow()
|
||||
}
|
||||
}
|
||||
|
||||
ScreencopyView {
|
||||
Layout.fillHeight: true
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
implicitWidth: Math.round(root.size.width)
|
||||
implicitHeight: Math.round(root.size.height)
|
||||
constraintSize: Qt.size(Math.round(root.size.width), Math.round(root.size.height))
|
||||
|
||||
Behavior on implicitWidth {
|
||||
animation: Looks.transition.enter.createObject(this)
|
||||
}
|
||||
Behavior on implicitHeight {
|
||||
animation: Looks.transition.enter.createObject(this)
|
||||
}
|
||||
|
||||
captureSource: root.toplevel ?? null
|
||||
live: true
|
||||
}
|
||||
}
|
||||
|
||||
WMenu {
|
||||
id: windowMenu
|
||||
downDirection: true
|
||||
|
||||
Action {
|
||||
enabled: root.hyprlandClient?.floating
|
||||
property bool isPinned: root.hyprlandClient?.pinned
|
||||
icon.name: isPinned ? "checkmark" : "empty"
|
||||
text: Translation.tr("Show this window on all desktops")
|
||||
onTriggered: {
|
||||
Hyprland.dispatch(`pin address:${root.hyprlandClient?.address}`);
|
||||
}
|
||||
}
|
||||
Action {
|
||||
icon.name: "empty"
|
||||
text: Translation.tr("Close")
|
||||
onTriggered: root.closeWindow()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,22 +15,37 @@ WMouseAreaButton {
|
||||
id: root
|
||||
|
||||
required property int workspace
|
||||
property bool newWorkspace: false
|
||||
property bool droppable: false
|
||||
|
||||
readonly property real screenWidth: QsWindow.window.width
|
||||
readonly property real screenHeight: QsWindow.window.height
|
||||
readonly property bool isActiveWorkspace: HyprlandData.activeWorkspace?.id === root.workspace
|
||||
readonly property real screenWidth: QsWindow.window?.width ?? 0
|
||||
readonly property real screenHeight: QsWindow.window?.height ?? 0
|
||||
readonly property real screenAspectRatio: screenWidth / screenHeight
|
||||
readonly property real screenScale: QsWindow.window.devicePixelRatio
|
||||
readonly property real scale: 0.1148148148
|
||||
readonly property real windowScale: wallpaperHeight / screenHeight
|
||||
|
||||
height: ListView.view.height
|
||||
property real wallpaperHeight: 124
|
||||
|
||||
height: ListView.view?.height ?? 100
|
||||
implicitWidth: 244 // for now
|
||||
|
||||
onClicked: {
|
||||
GlobalStates.overviewOpen = false;
|
||||
Hyprland.dispatch(`workspace ${root.workspace}`);
|
||||
colBackground: ColorUtils.transparentize(Looks.colors.bg2, (isActiveWorkspace || droppable) ? 0 : 1)
|
||||
Behavior on color {
|
||||
animation: Looks.transition.color.createObject(this)
|
||||
}
|
||||
|
||||
scale: root.containsPress ? 0.95 : 1
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
id: scaleAnim
|
||||
duration: 300
|
||||
easing.type: Easing.OutExpo
|
||||
}
|
||||
}
|
||||
|
||||
// Content
|
||||
ColumnLayout {
|
||||
id: contentItem
|
||||
anchors {
|
||||
fill: parent
|
||||
leftMargin: 12
|
||||
@@ -45,15 +60,15 @@ WMouseAreaButton {
|
||||
Layout.fillHeight: false
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
elide: Text.ElideRight
|
||||
text: Translation.tr("Desktop %1").arg(root.workspace)
|
||||
text: root.newWorkspace ? Translation.tr("New desktop") : Translation.tr("Desktop %1").arg(root.workspace)
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: wsBg
|
||||
height: 124
|
||||
height: root.wallpaperHeight
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
color: Looks.colors.bg1Base
|
||||
color: Looks.colors.bg1
|
||||
|
||||
layer.enabled: true
|
||||
layer.effect: OpacityMask {
|
||||
@@ -64,34 +79,67 @@ WMouseAreaButton {
|
||||
}
|
||||
}
|
||||
|
||||
StyledImage {
|
||||
// Workspace content
|
||||
Loader {
|
||||
anchors.fill: parent
|
||||
cache: true
|
||||
sourceSize: Qt.size(root.screenAspectRatio * 124, 124)
|
||||
source: Config.options.background.wallpaperPath
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
active: !root.newWorkspace
|
||||
sourceComponent: StyledImage {
|
||||
cache: true
|
||||
sourceSize: Qt.size(root.screenAspectRatio * root.wallpaperHeight, root.wallpaperHeight)
|
||||
source: Config.options.background.wallpaperPath
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
|
||||
Repeater {
|
||||
model: ScriptModel {
|
||||
values: ToplevelManager.toplevels.values.filter(toplevel => {
|
||||
const address = `0x${toplevel.HyprlandToplevel?.address}`;
|
||||
var win = HyprlandData.windowByAddress[address];
|
||||
const inWorkspace = win?.workspace?.id === root.workspace;
|
||||
return inWorkspace;
|
||||
})
|
||||
}
|
||||
delegate: ScreencopyView {
|
||||
required property var modelData
|
||||
readonly property var hyprlandWindowData: HyprlandData.windowByAddress[`0x${modelData.HyprlandToplevel?.address}`]
|
||||
captureSource: modelData
|
||||
live: true
|
||||
width: hyprlandWindowData?.size[0] * root.scale
|
||||
height: hyprlandWindowData?.size[1] * root.scale
|
||||
x: hyprlandWindowData?.at[0] * root.scale
|
||||
y: hyprlandWindowData?.at[1] * root.scale
|
||||
Repeater {
|
||||
model: ScriptModel {
|
||||
values: HyprlandData.toplevelsForWorkspace(root.workspace)
|
||||
}
|
||||
delegate: ScreencopyView {
|
||||
required property var modelData
|
||||
readonly property var hyprlandWindowData: HyprlandData.windowByAddress[`0x${modelData.HyprlandToplevel?.address}`]
|
||||
captureSource: modelData
|
||||
live: true
|
||||
width: hyprlandWindowData?.size[0] * root.windowScale
|
||||
height: hyprlandWindowData?.size[1] * root.windowScale
|
||||
x: hyprlandWindowData?.at[0] * root.windowScale
|
||||
y: hyprlandWindowData?.at[1] * root.windowScale
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// New plus icon
|
||||
Loader {
|
||||
anchors.centerIn: parent
|
||||
active: root.newWorkspace
|
||||
sourceComponent: FluentIcon {
|
||||
icon: "add"
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
z: 2
|
||||
visible: root.droppable && !root.newWorkspace
|
||||
anchors.fill: parent
|
||||
color: Looks.colors.accent
|
||||
opacity: 0.2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Active indicator
|
||||
WFadeLoader {
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
bottom: parent.bottom
|
||||
}
|
||||
shown: root.isActiveWorkspace
|
||||
|
||||
sourceComponent: Rectangle {
|
||||
id: activeIndicator
|
||||
implicitWidth: 32
|
||||
implicitHeight: 3
|
||||
color: Looks.colors.accent
|
||||
radius: height / 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,14 @@ Scope {
|
||||
Loader {
|
||||
id: panelLoader
|
||||
required property var modelData
|
||||
active: GlobalStates.overviewOpen
|
||||
active: false
|
||||
Connections {
|
||||
target: GlobalStates
|
||||
function onOverviewOpenChanged() {
|
||||
if (GlobalStates.overviewOpen)
|
||||
panelLoader.active = true;
|
||||
}
|
||||
}
|
||||
sourceComponent: PanelWindow {
|
||||
id: root
|
||||
property string searchingText: ""
|
||||
@@ -33,7 +40,7 @@ Scope {
|
||||
|
||||
WlrLayershell.namespace: "quickshell:wTaskView"
|
||||
WlrLayershell.layer: WlrLayer.Overlay
|
||||
// WlrLayershell.keyboardFocus: GlobalStates.overviewOpen ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand
|
||||
color: "transparent"
|
||||
|
||||
anchors {
|
||||
@@ -44,7 +51,26 @@ Scope {
|
||||
}
|
||||
|
||||
TaskViewContent {
|
||||
id: taskViewContent
|
||||
anchors.fill: parent
|
||||
|
||||
Component.onCompleted: {
|
||||
taskViewContent.forceActiveFocus();
|
||||
}
|
||||
Keys.onPressed: event => {
|
||||
if (event.key === Qt.Key_Escape) {
|
||||
GlobalStates.overviewOpen = false;
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: GlobalStates
|
||||
function onOverviewOpenChanged() {
|
||||
if (!GlobalStates.overviewOpen)
|
||||
taskViewContent.close();
|
||||
}
|
||||
}
|
||||
onClosed: panelLoader.active = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
function scaleWindow(hyprlandClient, maxWindowWidth, maxWindowHeight) {
|
||||
const [width, height] = hyprlandClient.size;
|
||||
const [xScale, yScale] = [maxWindowWidth / width, maxWindowHeight / height];
|
||||
const scale = Math.min(xScale, yScale);
|
||||
return Qt.size(width * scale, height * scale)
|
||||
}
|
||||
|
||||
function arrangedClients(hyprlandClients, maxRowWidth, maxWindowWidth, maxWindowHeight) {
|
||||
const count = hyprlandClients.length;
|
||||
const resultLayout = [];
|
||||
|
||||
var i = 0;
|
||||
while (i < count) {
|
||||
var row = [];
|
||||
var rowWidth = 0;
|
||||
var j = i;
|
||||
|
||||
while (j < count) {
|
||||
const client = hyprlandClients[j];
|
||||
const scaledSize = scaleWindow(client, maxWindowWidth, maxWindowHeight);
|
||||
|
||||
if (rowWidth + scaledSize.width <= maxRowWidth || row.length === 0) {
|
||||
row.push(client);
|
||||
rowWidth += scaledSize.width;
|
||||
j++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
resultLayout.push(row);
|
||||
i = j;
|
||||
}
|
||||
|
||||
return resultLayout;
|
||||
}
|
||||
@@ -2,6 +2,6 @@
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
source $(eval echo $ILLOGICAL_IMPULSE_VIRTUAL_ENV)/bin/activate
|
||||
"$SCRIPT_DIR/thumbgen.py" "$@"
|
||||
GIO_USE_VFS=local "$SCRIPT_DIR/thumbgen.py" "$@"
|
||||
deactivate
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ import gi
|
||||
from loguru import logger
|
||||
from tqdm import tqdm
|
||||
|
||||
gi.require_version("GnomeDesktop", "3.0")
|
||||
gi.require_version("GnomeDesktop", "4.0")
|
||||
from gi.repository import Gio, GnomeDesktop # isort:skip
|
||||
|
||||
thumbnail_size_map = {
|
||||
|
||||
@@ -4,6 +4,7 @@ pragma ComponentBehavior: Bound
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Hyprland
|
||||
|
||||
/**
|
||||
@@ -21,6 +22,30 @@ Singleton {
|
||||
property var monitors: []
|
||||
property var layers: ({})
|
||||
|
||||
// Convenient stuff
|
||||
|
||||
function toplevelsForWorkspace(workspace) {
|
||||
return ToplevelManager.toplevels.values.filter(toplevel => {
|
||||
const address = `0x${toplevel.HyprlandToplevel?.address}`;
|
||||
var win = HyprlandData.windowByAddress[address];
|
||||
return win?.workspace?.id === workspace;
|
||||
})
|
||||
}
|
||||
|
||||
function hyprlandClientsForWorkspace(workspace) {
|
||||
return root.windowList.filter(win => win.workspace.id === workspace);
|
||||
}
|
||||
|
||||
function clientForToplevel(toplevel) {
|
||||
if (!toplevel || !toplevel.HyprlandToplevel) {
|
||||
return null;
|
||||
}
|
||||
const address = `0x${toplevel?.HyprlandToplevel?.address}`;
|
||||
return root.windowByAddress[address];
|
||||
}
|
||||
|
||||
// Internals
|
||||
|
||||
function updateWindowList() {
|
||||
getClients.running = true;
|
||||
}
|
||||
@@ -63,6 +88,7 @@ Singleton {
|
||||
|
||||
function onRawEvent(event) {
|
||||
// console.log("Hyprland raw event:", event.name);
|
||||
if (["openlayer", "closelayer", "screencast"].includes(event.name)) return;
|
||||
updateAll()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import qs.modules.common
|
||||
import qs.modules.common.models
|
||||
import qs.modules.common.functions
|
||||
import QtQuick
|
||||
import Qt.labs.folderlistmodel
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
|
||||
@@ -31,6 +32,34 @@ Singleton {
|
||||
return acc;
|
||||
}, []).sort()
|
||||
|
||||
// Load user action scripts from ~/.config/illogical-impulse/actions/
|
||||
// Uses FolderListModel to auto-reload when scripts are added/removed
|
||||
property var userActionScripts: {
|
||||
const actions = [];
|
||||
for (let i = 0; i < userActionsFolder.count; i++) {
|
||||
const fileName = userActionsFolder.get(i, "fileName");
|
||||
const filePath = userActionsFolder.get(i, "filePath");
|
||||
if (fileName && filePath) {
|
||||
const actionName = fileName.replace(/\.[^/.]+$/, ""); // strip extension
|
||||
actions.push({
|
||||
action: actionName,
|
||||
execute: ((path) => (args) => {
|
||||
Quickshell.execDetached([path, ...(args ? args.split(" ") : [])]);
|
||||
})(FileUtils.trimFileProtocol(filePath.toString()))
|
||||
});
|
||||
}
|
||||
}
|
||||
return actions;
|
||||
}
|
||||
|
||||
FolderListModel {
|
||||
id: userActionsFolder
|
||||
folder: Qt.resolvedUrl(Directories.userActions)
|
||||
showDirs: false
|
||||
showHidden: false
|
||||
sortField: FolderListModel.Name
|
||||
}
|
||||
|
||||
property var searchActions: [
|
||||
{
|
||||
action: "accentcolor",
|
||||
@@ -90,6 +119,9 @@ Singleton {
|
||||
},
|
||||
]
|
||||
|
||||
// Combined built-in and user actions
|
||||
property var allActions: searchActions.concat(userActionScripts)
|
||||
|
||||
property string mathResult: ""
|
||||
property bool clipboardWorkSafetyActive: {
|
||||
const enabled = Config.options.workSafety.enable.clipboard;
|
||||
@@ -273,7 +305,7 @@ Singleton {
|
||||
Qt.openUrlExternally(url);
|
||||
}
|
||||
});
|
||||
const launcherActionObjects = root.searchActions.map(action => {
|
||||
const launcherActionObjects = root.allActions.map(action => {
|
||||
const actionString = `${Config.options.search.prefix.action}${action.action}`;
|
||||
if (actionString.startsWith(root.query) || root.query.startsWith(actionString)) {
|
||||
return resultComp.createObject(null, {
|
||||
|
||||
@@ -111,6 +111,14 @@ ApiStrategy {
|
||||
return ({})
|
||||
}
|
||||
|
||||
// Error response handling
|
||||
if (dataJson.error) {
|
||||
const errorMsg = `**Error ${dataJson.error.code}**: ${dataJson.error.message}`;
|
||||
message.rawContent += errorMsg;
|
||||
message.content += errorMsg;
|
||||
return { finished: true };
|
||||
}
|
||||
|
||||
// No candidates?
|
||||
if (!dataJson.candidates) return {};
|
||||
|
||||
|
||||
@@ -58,8 +58,17 @@ ApiStrategy {
|
||||
// Real stuff
|
||||
try {
|
||||
const dataJson = JSON.parse(cleanData);
|
||||
|
||||
// Error response handling
|
||||
if (dataJson.error) {
|
||||
const errorMsg = `**Error**: ${dataJson.error.message || JSON.stringify(dataJson.error)}`;
|
||||
message.rawContent += errorMsg;
|
||||
message.content += errorMsg;
|
||||
return { finished: true };
|
||||
}
|
||||
|
||||
let newContent = "";
|
||||
|
||||
|
||||
const responseContent = dataJson.choices[0]?.delta?.content || dataJson.message?.content;
|
||||
const responseReasoning = dataJson.choices[0]?.delta?.reasoning || dataJson.choices[0]?.delta?.reasoning_content;
|
||||
|
||||
|
||||
@@ -49,8 +49,17 @@ ApiStrategy {
|
||||
// Real stuff
|
||||
try {
|
||||
const dataJson = JSON.parse(cleanData);
|
||||
|
||||
// Error response handling
|
||||
if (dataJson.error) {
|
||||
const errorMsg = `**Error**: ${dataJson.error.message || JSON.stringify(dataJson.error)}`;
|
||||
message.rawContent += errorMsg;
|
||||
message.content += errorMsg;
|
||||
return { finished: true };
|
||||
}
|
||||
|
||||
let newContent = "";
|
||||
|
||||
|
||||
const responseContent = dataJson.choices[0]?.delta?.content || dataJson.message?.content;
|
||||
const responseReasoning = dataJson.choices[0]?.delta?.reasoning || dataJson.choices[0]?.delta?.reasoning_content;
|
||||
|
||||
|
||||
@@ -63,8 +63,6 @@ Wayland and X11.
|
||||
%endif
|
||||
-DBUILD_SHARED_LIBS=OFF \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DDISTRIBUTOR="Fedora COPR (errornointernet/quickshell)" \
|
||||
-DDISTRIBUTOR_DEBUGINFO_AVAILABLE=YES \
|
||||
-DGIT_REVISION=%{commit} \
|
||||
-DINSTALL_QML_PREFIX=%{_lib}/qt6/qml
|
||||
%cmake_build
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
# COPR repositories list
|
||||
[copr]
|
||||
repos = [
|
||||
"ririko66z/dots-hyprland",
|
||||
"solopasha/hyprland",
|
||||
"deltacopy/darkly",
|
||||
"alternateved/eza",
|
||||
"atim/starship"
|
||||
]
|
||||
|
||||
# Fedora dependencies list
|
||||
|
||||
# Audio
|
||||
@@ -17,6 +27,7 @@ packages = [
|
||||
"brightnessctl",
|
||||
"ddcutil"
|
||||
]
|
||||
install_opts = ["--setopt=install_weak_deps=False"]
|
||||
|
||||
# Basic
|
||||
[groups.basic]
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
# This script is meant to be sourced.
|
||||
# It's not for directly running.
|
||||
# -------------------------
|
||||
# CONFIG
|
||||
# -------------------------
|
||||
user_config="${REPO_ROOT}/sdata/dist-fedora/user_data.yaml"
|
||||
rpmbuildroot="${REPO_ROOT}/cache/rpmbuild"
|
||||
deps_data_file="${REPO_ROOT}/sdata/dist-fedora/feddeps.toml"
|
||||
|
||||
|
||||
# Initialize the user configuration file
|
||||
user_config=${REPO_ROOT}/sdata/dist-fedora/user_data.yaml
|
||||
# -------------------------
|
||||
# FUNCTIONS
|
||||
# -------------------------
|
||||
|
||||
# Recording DNF Transaction ID
|
||||
function r() {
|
||||
@@ -16,6 +22,42 @@ function r() {
|
||||
[ "$original_id" == "$last_id" ] || yq -i ".dnf.transaction_ids += [ $last_id ]" "$user_config" || :
|
||||
}
|
||||
|
||||
# Start building and install the missing RPM package locally.
|
||||
function install_RPMS() {
|
||||
local local_specs local_rpms
|
||||
rpmbuildroot="${rpmbuildroot:-${REPO_ROOT}/cache/rpmbuild}"
|
||||
|
||||
x mkdir -p "$rpmbuildroot"/{BUILD,RPMS,SOURCES}
|
||||
x cp -r "${REPO_ROOT}/sdata/dist-fedora/SPECS" "$rpmbuildroot/"
|
||||
|
||||
x cd $rpmbuildroot/SPECS
|
||||
|
||||
mapfile -t -d '' local_specs < <(find "$rpmbuildroot/SPECS" -maxdepth 1 -type f -name "*.spec" -print0)
|
||||
for spec_file in ${local_specs[@]}; do
|
||||
# Download sources
|
||||
x spectool -g -C "$rpmbuildroot/SOURCES" "$spec_file"
|
||||
# Install build dependencies
|
||||
r x sudo dnf builddep -y "$spec_file"
|
||||
# Build the RPM package locally. If it fails, download it from COPR.
|
||||
if ! rpmbuild -bb --define "_topdir $rpmbuildroot" --define "debug_package %{nil}" "$spec_file"; then
|
||||
printf "${STY_RED}Local build encountered an issue. Downloading $(basename "$spec_file" .spec) from COPR. Report the issue to Discussions pls.${STY_RST}\n"
|
||||
sudo dnf install -y $(basename "$spec_file" .spec)
|
||||
nolock_qs=true
|
||||
fi
|
||||
done
|
||||
|
||||
mapfile -t -d '' local_rpms < <(find "$rpmbuildroot/RPMS" -maxdepth 2 -type f -name '*.rpm' -not -name '*debug*' -print0)
|
||||
if [[ ${#local_rpms[@]} -ge 1 ]]; then
|
||||
echo -e "${STY_BLUE}Next command:${STY_RST} sudo dnf install ${local_rpms[@]} -y"
|
||||
r x sudo dnf install "${local_rpms[@]}" -y
|
||||
fi
|
||||
x cd ${REPO_ROOT}
|
||||
}
|
||||
|
||||
# -------------------------
|
||||
# MAIN
|
||||
# -------------------------
|
||||
|
||||
if ! command -v dnf >/dev/null 2>&1; then
|
||||
printf "${STY_RED}[$0]: dnf not found, it seems that the system is not Fedora 42 or later distros. Aborting...${STY_RST}\n"
|
||||
exit 1
|
||||
@@ -33,61 +75,38 @@ v sudo dnf versionlock delete quickshell-git 2>/dev/null
|
||||
# Install yq for parsing config files
|
||||
v sudo dnf install yq -y
|
||||
|
||||
# Development-tools
|
||||
r v sudo dnf install @development-tools fedora-packager rpmdevtools fonts-rpm-macros qt6-rpm-macros -y
|
||||
# Install development tools
|
||||
r v sudo dnf install @development-tools fedora-packager -y
|
||||
|
||||
# COPR repositories
|
||||
v sudo dnf copr enable ririko66z/dots-hyprland -y
|
||||
v sudo dnf copr enable solopasha/hyprland -y
|
||||
v sudo dnf copr enable deltacopy/darkly -y
|
||||
v sudo dnf copr enable alternateved/eza -y
|
||||
v sudo dnf copr enable atim/starship -y
|
||||
|
||||
# Start building and install the missing RPM package locally.
|
||||
install_RPMS() {
|
||||
rpmbuildroot=${REPO_ROOT}/cache/rpmbuild
|
||||
x mkdir -p $rpmbuildroot/{BUILD,RPMS,SOURCES}
|
||||
x cp -r ${REPO_ROOT}/sdata/dist-fedora/SPECS $rpmbuildroot/
|
||||
x cd $rpmbuildroot/SPECS
|
||||
mapfile -t -d '' local_specs < <(find "$rpmbuildroot/SPECS" -maxdepth 1 -type f -name "*.spec" -print0)
|
||||
for spec_file in ${local_specs[@]}; do
|
||||
x spectool -g -C "$rpmbuildroot/SOURCES" $spec_file
|
||||
r x sudo dnf builddep -y $spec_file
|
||||
x rpmbuild -bb --define "_topdir $rpmbuildroot" $spec_file
|
||||
done
|
||||
mapfile -t -d '' local_rpms < <(find "$rpmbuildroot/RPMS" -maxdepth 2 -type f -name '*.rpm' -not -name '*debug*' -print0)
|
||||
echo -e "${STY_BLUE}Next command:${STY_RST} sudo dnf install ${local_rpms[@]} -y"
|
||||
r x sudo dnf install "${local_rpms[@]}" -y
|
||||
x cd ${REPO_ROOT}
|
||||
}
|
||||
# Install COPR repositories
|
||||
copr_repos_json=$(yq -o=j '.copr.repos // []' "$deps_data_file")
|
||||
eval "$(jq -r '@sh "copr_repos_array+=(\(.[]))"' <<<"$copr_repos_json")" # Fedora distro contains jq
|
||||
for copr in ${copr_repos_array[@]}; do
|
||||
v sudo dnf copr enable "$copr" -y
|
||||
done
|
||||
|
||||
# Build and install locally RPMS
|
||||
showfun install_RPMS
|
||||
v install_RPMS
|
||||
|
||||
deps_data_file="${REPO_ROOT}/sdata/dist-fedora/feddeps.toml"
|
||||
# Install packages from toml file
|
||||
deps_data=$(yq -o=j '.' "$deps_data_file")
|
||||
echo "Starting to install packages from $deps_data_file ..."
|
||||
|
||||
while IFS= read -r deps_list_key; do
|
||||
|
||||
echo "Installing package list: $deps_list_key"
|
||||
|
||||
install_opts=$(echo $deps_data | yq ".groups.\"$deps_list_key\" | select(has(\"install_opts\")) | .install_opts[]")
|
||||
package_list=$(echo $deps_data | yq ".groups.\"$deps_list_key\".packages | unique | .[]")
|
||||
|
||||
r v sudo dnf install -y $install_opts $package_list </dev/tty
|
||||
|
||||
echo "----------------------------------------"
|
||||
|
||||
done < <(echo "$deps_data" | yq '
|
||||
.groups |
|
||||
keys[] // [] |
|
||||
select(length > 0)
|
||||
')
|
||||
done < <(echo "$deps_data" | yq '.groups | keys[]? | select(length > 0)')
|
||||
|
||||
# Add back versionlock at the end
|
||||
v sudo dnf versionlock add quickshell-git
|
||||
[ -n $nolock_qs ] || v sudo dnf versionlock add quickshell-git || true
|
||||
|
||||
echo -e "\n========================================"
|
||||
echo "All installations are complete."
|
||||
echo "All installations are completed."
|
||||
echo "========================================"
|
||||
|
||||
|
||||
@@ -52,3 +52,29 @@ end
|
||||
- The Hyprland live ebuild sometimes has linkage issues, deleting _Hyprland_ and _hyprland_ from `/usr/bin/` and then re-emerging usually fixes this.
|
||||
- When emerging Hyprland if you get an issue relating to `undefined reference to ``Hyprutils::Math::Vector2D::˜Vector2D()`` `
|
||||
- Clear the cache folder (`rm -fr /var/tmp/portage/gui-wm/hyprland*`) then try again
|
||||
- If emerging ``hyprland-qtutils`` fails and gives you something like this...
|
||||
```cmake
|
||||
CMake Error at utils/dialog/CMakeLists.txt:26 (target_link_libraries):
|
||||
Target "hyprland-dialog" links to:
|
||||
Qt6::WaylandClientPrivate
|
||||
but the target was not found. Possible reasons include:
|
||||
* There is a typo in the target name.
|
||||
* A find_package call is missing for an IMPORTED target.
|
||||
* An ALIAS target is missing.
|
||||
CMake Error at utils/update-screen/CMakeLists.txt:34 (target_link_libraries):
|
||||
Target "hyprland-update-screen" links to:
|
||||
Qt6::WaylandClientPrivate
|
||||
but the target was not found. Possible reasons include:
|
||||
* There is a typo in the target name.
|
||||
* A find_package call is missing for an IMPORTED target.
|
||||
* An ALIAS target is missing.
|
||||
CMake Error at utils/donate-screen/CMakeLists.txt:32 (target_link_libraries):
|
||||
Target "hyprland-donate-screen" links to:
|
||||
Qt6::WaylandClientPrivate
|
||||
but the target was not found. Possible reasons include:
|
||||
* There is a typo in the target name.
|
||||
* A find_package call is missing for an IMPORTED target.
|
||||
* An ALIAS target is missing.
|
||||
```
|
||||
Try putting ``sdata/dist-gentoo/hyprland-qtutils-private.patch`` into ``/etc/portage/patches/gui-libs/hyprland-qtutils/``.
|
||||
- Patch Credit: fedeliallalinea on https://forums.gentoo.org/viewtopic-p-8874098.html
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
--- a/utils/dialog/CMakeLists.txt
|
||||
+++ b/utils/dialog/CMakeLists.txt
|
||||
@@ -8,7 +8,7 @@
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
-find_package(Qt6 6.5 REQUIRED COMPONENTS Widgets Quick QuickControls2 WaylandClient)
|
||||
+find_package(Qt6 6.5 REQUIRED COMPONENTS Widgets Quick QuickControls2 WaylandClient WaylandClientPrivate)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
pkg_check_modules(hyprutils REQUIRED IMPORTED_TARGET hyprutils)
|
||||
--- a/utils/donate-screen/CMakeLists.txt
|
||||
+++ b/utils/donate-screen/CMakeLists.txt
|
||||
@@ -8,7 +8,7 @@
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
-find_package(Qt6 6.5 REQUIRED COMPONENTS Widgets Quick QuickControls2 WaylandClient)
|
||||
+find_package(Qt6 6.5 REQUIRED COMPONENTS Widgets Quick QuickControls2 WaylandClient WaylandClientPrivate)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
pkg_check_modules(hyprutils REQUIRED IMPORTED_TARGET hyprutils)
|
||||
--- a/utils/update-screen/CMakeLists.txt
|
||||
+++ b/utils/update-screen/CMakeLists.txt
|
||||
@@ -8,7 +8,7 @@
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
-find_package(Qt6 6.5 REQUIRED COMPONENTS Widgets Quick QuickControls2 WaylandClient)
|
||||
+find_package(Qt6 6.5 REQUIRED COMPONENTS Widgets Quick QuickControls2 WaylandClient WaylandClientPrivate)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
pkg_check_modules(hyprutils REQUIRED IMPORTED_TARGET hyprutils)
|
||||
@@ -1,23 +1,12 @@
|
||||
printf "${STY_YELLOW}"
|
||||
printf "============WARNING/NOTE (1)============\n"
|
||||
printf "GCC in use: $(which gcc)\n"
|
||||
printf "GCC version info: $(gcc --version | grep gcc)\n"
|
||||
printf "GCC version number: $(gcc --version | grep gcc | awk '{print $3}')\n"
|
||||
printf "GCC-15>= is required for Hyprland\n"
|
||||
printf "If you have GCC-15>= and it's currently set then you can safely ignore this\n"
|
||||
printf "If not, you must ensure you are using the correct GCC version and set it (gcc-config <number>)\n"
|
||||
printf "It is heavily recommended to re-emerge @world with an empty tree after changing GCC version (emerge -e @world)\n\n"
|
||||
printf "${STY_RST}"
|
||||
pause
|
||||
|
||||
printf "${STY_YELLOW}"
|
||||
printf "============WARNING/NOTE (2)============\n"
|
||||
printf "Ensure you have a global use flag for elogind or systemd in your make.conf for simplicity\n"
|
||||
printf "Or you can manually add the use flags for each package that requires it\n"
|
||||
printf "${STY_RST}"
|
||||
pause
|
||||
|
||||
printf "${STY_YELLOW}"
|
||||
printf "============WARNING/NOTE (2)============\n"
|
||||
printf "https://github.com/end-4/dots-hyprland/blob/main/sdata/dist-gentoo/README.md\n"
|
||||
printf "Checkout the above README for potential bug fixes or additional information\n\n"
|
||||
printf "${STY_RST}"
|
||||
|
||||
@@ -64,7 +64,7 @@ function showfun(){
|
||||
function pause(){
|
||||
if [ ! "$ask" == "false" ];then
|
||||
printf "${STY_FAINT}${STY_SLANT}"
|
||||
local p; read -p "(Ctrl-C to abort, others to proceed)" p
|
||||
local p; read -p "(Ctrl-C to abort, Enter to proceed)" p
|
||||
printf "${STY_RST}"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ patterns:
|
||||
- from: "dots/.config/fish"
|
||||
to: "$XDG_CONFIG_HOME/fish"
|
||||
mode: "sync"
|
||||
excludes: ["conf.d"]
|
||||
condition:
|
||||
type: "shell"
|
||||
value: "fish"
|
||||
|
||||
@@ -30,7 +30,7 @@ esac
|
||||
case "${SKIP_FISH}" in
|
||||
true) sleep 0;;
|
||||
*)
|
||||
install_dir__sync dots/.config/fish "$XDG_CONFIG_HOME"/fish
|
||||
install_dir__sync_exclude dots/.config/fish "$XDG_CONFIG_HOME"/fish "conf.d"
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
@@ -67,6 +67,22 @@ rsync_dir__sync(){
|
||||
x mkdir -p "$(dirname ${INSTALLED_LISTFILE})"
|
||||
rsync -a --delete --out-format='%i %n' "$1"/ "$2"/ | awk -v d="$dest" '$1 ~ /^>/{ sub(/^[^ ]+ /,""); printf d "/" $0 "\n" }' >> "${INSTALLED_LISTFILE}"
|
||||
}
|
||||
rsync_dir__sync_exclude(){
|
||||
# NOTE: This function is only for using in other functions
|
||||
# Same as rsync_dir__sync but with exclude patterns support
|
||||
# Usage: rsync_dir__sync_exclude <src> <dest> <exclude_pattern1> [<exclude_pattern2> ...]
|
||||
local src="$1"
|
||||
local dest_dir="$2"
|
||||
shift 2
|
||||
local excludes=()
|
||||
for pattern in "$@"; do
|
||||
excludes+=(--exclude "$pattern")
|
||||
done
|
||||
x mkdir -p "$dest_dir"
|
||||
local dest="$(realpath -se $dest_dir)"
|
||||
x mkdir -p "$(dirname ${INSTALLED_LISTFILE})"
|
||||
rsync -a --delete "${excludes[@]}" --out-format='%i %n' "$src"/ "$dest_dir"/ | awk -v d="$dest" '$1 ~ /^>/{ sub(/^[^ ]+ /,""); printf d "/" $0 "\n" }' >> "${INSTALLED_LISTFILE}"
|
||||
}
|
||||
function install_file(){
|
||||
# NOTE: Do not add prefix `v` or `x` when using this function
|
||||
local s=$1
|
||||
@@ -124,6 +140,18 @@ function install_dir__skip_existed(){
|
||||
v rsync_dir $s $t
|
||||
fi
|
||||
}
|
||||
function install_dir__sync_exclude(){
|
||||
# NOTE: Do not add prefix `v` or `x` when using this function
|
||||
# Sync directory with exclude patterns
|
||||
# Usage: install_dir__sync_exclude <src> <dest> <exclude_pattern1> [<exclude_pattern2> ...]
|
||||
local s=$1
|
||||
local t=$2
|
||||
shift 2
|
||||
if [ -d $t ];then
|
||||
warning_overwrite
|
||||
fi
|
||||
rsync_dir__sync_exclude $s $t "$@"
|
||||
}
|
||||
function install_google_sans_flex(){
|
||||
local font_name="Google Sans Flex"
|
||||
local src_name="google-sans-flex"
|
||||
@@ -142,7 +170,7 @@ function install_google_sans_flex(){
|
||||
x fc-cache -fv
|
||||
x cd $REPO_ROOT
|
||||
x mkdir -p "$(dirname ${INSTALLED_LISTFILE})"
|
||||
realpath -se "$2" >> "${INSTALLED_LISTFILE}"
|
||||
realpath -se "$target_dir" >> "${INSTALLED_LISTFILE}"
|
||||
}
|
||||
|
||||
#####################################################################################
|
||||
|
||||
Reference in New Issue
Block a user