window switcher start
This commit is contained in:
@@ -52,11 +52,14 @@ Scope {
|
|||||||
x: 0
|
x: 0
|
||||||
y: 34
|
y: 34
|
||||||
|
|
||||||
width: bar.width
|
property list<Region> nullRegions: []
|
||||||
height: bar.screen.height - backgroundRect.implicitHeight
|
property bool hcurrent: panels.popouts.hasCurrent && panels.popouts.currentName.startsWith("traymenu")
|
||||||
|
|
||||||
|
width: hcurrent ? 0 : bar.width
|
||||||
|
height: hcurrent ? 0 : bar.screen.height - backgroundRect.implicitHeight
|
||||||
intersection: Intersection.Xor
|
intersection: Intersection.Xor
|
||||||
|
|
||||||
regions: panels.popouts.hasCurrent ? None : popoutRegions.instances
|
regions: hcurrent ? nullRegions : popoutRegions.instances
|
||||||
}
|
}
|
||||||
|
|
||||||
Variants {
|
Variants {
|
||||||
@@ -69,7 +72,7 @@ Scope {
|
|||||||
x: modelData.x
|
x: modelData.x
|
||||||
y: modelData.y + backgroundRect.implicitHeight
|
y: modelData.y + backgroundRect.implicitHeight
|
||||||
width: modelData.width
|
width: modelData.width
|
||||||
height: panels.popouts.hasCurrent ? modelData.height + 70 : 0
|
height: panels.popouts.hasCurrent ? modelData.height : 0
|
||||||
intersection: Intersection.Subtract
|
intersection: Intersection.Subtract
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -110,6 +113,19 @@ Scope {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onPressed: event => {
|
||||||
|
var withinX = mouseX >= panels.popouts.x + 8 && mouseX < panels.popouts.x + panels.popouts.implicitWidth;
|
||||||
|
var withinY = mouseY >= panels.popouts.y + exclusionZone.implicitHeight && mouseY < panels.popouts.y + exclusionZone.implicitHeight + panels.popouts.implicitHeight;
|
||||||
|
|
||||||
|
|
||||||
|
if ( panels.popouts.hasCurrent ) {
|
||||||
|
if ( withinX && withinY ) {
|
||||||
|
} else {
|
||||||
|
panels.popouts.hasCurrent = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Panels {
|
Panels {
|
||||||
id: panels
|
id: panels
|
||||||
screen: bar.modelData
|
screen: bar.modelData
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Templates
|
||||||
|
import qs.Config
|
||||||
|
import qs.Modules
|
||||||
|
|
||||||
|
Slider {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property real peak
|
||||||
|
|
||||||
|
background: Item {
|
||||||
|
CustomRect {
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.topMargin: root.implicitHeight / 3
|
||||||
|
anchors.bottomMargin: root.implicitHeight / 3
|
||||||
|
|
||||||
|
implicitWidth: root.handle.x - root.implicitHeight / 6
|
||||||
|
|
||||||
|
color: DynamicColors.palette.m3primaryContainer
|
||||||
|
radius: 1000
|
||||||
|
topRightRadius: root.implicitHeight / 15
|
||||||
|
bottomRightRadius: root.implicitHeight / 15
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.left: parent.left
|
||||||
|
|
||||||
|
implicitWidth: parent.width * root.peak
|
||||||
|
radius: 1000
|
||||||
|
topRightRadius: root.implicitHeight / 15
|
||||||
|
bottomRightRadius: root.implicitHeight / 15
|
||||||
|
|
||||||
|
color: DynamicColors.palette.m3primary
|
||||||
|
|
||||||
|
Behavior on implicitWidth {
|
||||||
|
Anim { duration: 50 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.topMargin: root.implicitHeight / 3
|
||||||
|
anchors.bottomMargin: root.implicitHeight / 3
|
||||||
|
|
||||||
|
implicitWidth: parent.width - root.handle.x - root.handle.implicitWidth - root.implicitHeight / 6
|
||||||
|
|
||||||
|
color: DynamicColors.tPalette.m3surfaceContainer
|
||||||
|
radius: 1000
|
||||||
|
topLeftRadius: root.implicitHeight / 15
|
||||||
|
bottomLeftRadius: root.implicitHeight / 15
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handle: CustomRect {
|
||||||
|
x: root.visualPosition * root.availableWidth - implicitWidth / 2
|
||||||
|
|
||||||
|
implicitWidth: 5
|
||||||
|
implicitHeight: 15
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
|
color: DynamicColors.palette.m3primary
|
||||||
|
radius: 1000
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
acceptedButtons: Qt.NoButton
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -339,6 +339,11 @@ Item {
|
|||||||
objects: appBox.modelData ? [appBox.modelData] : []
|
objects: appBox.modelData ? [appBox.modelData] : []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PwNodePeakMonitor {
|
||||||
|
id: peak
|
||||||
|
node: appBox.modelData
|
||||||
|
}
|
||||||
|
|
||||||
readonly property bool isCaptureStream: {
|
readonly property bool isCaptureStream: {
|
||||||
if (!modelData || !modelData.properties)
|
if (!modelData || !modelData.properties)
|
||||||
return false;
|
return false;
|
||||||
@@ -409,9 +414,10 @@ Item {
|
|||||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||||
Layout.bottomMargin: 5
|
Layout.bottomMargin: 5
|
||||||
implicitHeight: 10
|
implicitHeight: 10
|
||||||
CustomSlider {
|
CustomAudioSlider {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
value: appBox.modelData.audio.volume
|
value: appBox.modelData.audio.volume
|
||||||
|
peak: peak.peak
|
||||||
onMoved: {
|
onMoved: {
|
||||||
Audio.setAppAudioVolume(appBox.modelData, value)
|
Audio.setAppAudioVolume(appBox.modelData, value)
|
||||||
console.log(icon.iconPath1, icon.iconPath2)
|
console.log(icon.iconPath1, icon.iconPath2)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
pragma ComponentBehavior: Bound
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
import Quickshell
|
import Quickshell
|
||||||
|
import Quickshell.Hyprland
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import qs.Modules
|
import qs.Modules
|
||||||
@@ -19,7 +20,7 @@ RowLayout {
|
|||||||
function checkPopout(x: real): void {
|
function checkPopout(x: real): void {
|
||||||
const ch = childAt(x, height / 2) as WrappedLoader;
|
const ch = childAt(x, height / 2) as WrappedLoader;
|
||||||
|
|
||||||
if (!ch) {
|
if (!ch && !popouts.currentName.includes("traymenu")) {
|
||||||
popouts.hasCurrent = false;
|
popouts.hasCurrent = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -42,11 +43,11 @@ RowLayout {
|
|||||||
const index = Math.floor((( x - top ) / item.implicitWidth ) * item.items.count );
|
const index = Math.floor((( x - top ) / item.implicitWidth ) * item.items.count );
|
||||||
const trayItem = item.items.itemAt( index );
|
const trayItem = item.items.itemAt( index );
|
||||||
if ( trayItem ) {
|
if ( trayItem ) {
|
||||||
popouts.currentName = `traymenu${ index }`;
|
// popouts.currentName = `traymenu${ index }`;
|
||||||
popouts.currentCenter = Qt.binding( () => trayItem.mapToItem( root, trayItem.implicitWidth / 2, 0 ).x );
|
// popouts.currentCenter = Qt.binding( () => trayItem.mapToItem( root, trayItem.implicitWidth / 2, 0 ).x );
|
||||||
popouts.hasCurrent = true;
|
// popouts.hasCurrent = true;
|
||||||
} else {
|
} else {
|
||||||
popouts.hasCurrent = false;
|
// popouts.hasCurrent = false;
|
||||||
}
|
}
|
||||||
} else if ( id === "clock" && Config.barConfig.popouts.clock ) {
|
} else if ( id === "clock" && Config.barConfig.popouts.clock ) {
|
||||||
Calendar.displayYear = new Date().getFullYear();
|
Calendar.displayYear = new Date().getFullYear();
|
||||||
@@ -57,6 +58,23 @@ RowLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GlobalShortcut {
|
||||||
|
name: "toggle-overview"
|
||||||
|
appid: "zshell"
|
||||||
|
|
||||||
|
onPressed: {
|
||||||
|
Hyprland.refreshWorkspaces();
|
||||||
|
Hyprland.refreshMonitors();
|
||||||
|
if ( root.popouts.hasCurrent && root.popouts.currentName === "overview" ) {
|
||||||
|
root.popouts.hasCurrent = false;
|
||||||
|
} else {
|
||||||
|
root.popouts.currentName = "overview";
|
||||||
|
root.popouts.currentCenter = root.width / 2;
|
||||||
|
root.popouts.hasCurrent = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
id: repeater
|
id: repeater
|
||||||
model: Config.barConfig.entries
|
model: Config.barConfig.entries
|
||||||
@@ -90,6 +108,7 @@ RowLayout {
|
|||||||
sourceComponent: TrayWidget {
|
sourceComponent: TrayWidget {
|
||||||
bar: root.bar
|
bar: root.bar
|
||||||
popouts: root.popouts
|
popouts: root.popouts
|
||||||
|
loader: root
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import Quickshell.Services.SystemTray
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import qs.Config
|
import qs.Config
|
||||||
import qs.Modules.Calendar
|
import qs.Modules.Calendar
|
||||||
|
import qs.Modules.WSOverview
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
@@ -77,6 +78,15 @@ Item {
|
|||||||
wrapper: root.wrapper
|
wrapper: root.wrapper
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Popout {
|
||||||
|
name: "overview"
|
||||||
|
|
||||||
|
sourceComponent: OverviewPopout {
|
||||||
|
wrapper: root.wrapper
|
||||||
|
screen: root.wrapper.screen
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
component Popout: Loader {
|
component Popout: Loader {
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
|
import QtQuick.Layouts
|
||||||
|
import QtQuick.Effects
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Services.SystemTray
|
import Quickshell.Services.SystemTray
|
||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
import Quickshell.Widgets
|
import Quickshell.Widgets
|
||||||
import qs.Modules
|
import qs.Modules
|
||||||
|
import qs.Components
|
||||||
import qs.Config
|
import qs.Config
|
||||||
import QtQuick.Effects
|
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
@@ -14,17 +16,20 @@ Item {
|
|||||||
required property PanelWindow bar
|
required property PanelWindow bar
|
||||||
required property int ind
|
required property int ind
|
||||||
required property Wrapper popouts
|
required property Wrapper popouts
|
||||||
|
required property RowLayout loader
|
||||||
property bool hasLoaded: false
|
property bool hasLoaded: false
|
||||||
|
|
||||||
MouseArea {
|
StateLayer {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
anchors.margins: 3
|
||||||
|
radius: 6
|
||||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if ( mouse.button === Qt.LeftButton ) {
|
if ( mouse.button === Qt.LeftButton ) {
|
||||||
root.item.activate();
|
root.item.activate();
|
||||||
} else if ( mouse.button === Qt.RightButton ) {
|
} else if ( mouse.button === Qt.RightButton ) {
|
||||||
root.popouts.currentName = `traymenu${ root.ind }`;
|
root.popouts.currentName = `traymenu${ root.ind }`;
|
||||||
root.popouts.currentCenter = Qt.binding( () => root.mapToItem( root.bar, root.implicitWidth / 2, 0 ).x );
|
root.popouts.currentCenter = Qt.binding( () => root.mapToItem( root.loader, root.implicitWidth / 2, 0 ).x );
|
||||||
root.popouts.hasCurrent = true;
|
root.popouts.hasCurrent = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ Row {
|
|||||||
|
|
||||||
required property PanelWindow bar
|
required property PanelWindow bar
|
||||||
required property Wrapper popouts
|
required property Wrapper popouts
|
||||||
|
required property RowLayout loader
|
||||||
readonly property alias items: repeater
|
readonly property alias items: repeater
|
||||||
|
|
||||||
spacing: 0
|
spacing: 0
|
||||||
@@ -26,8 +27,9 @@ Row {
|
|||||||
required property int index
|
required property int index
|
||||||
ind: index
|
ind: index
|
||||||
popouts: root.popouts
|
popouts: root.popouts
|
||||||
|
loader: root.loader
|
||||||
implicitHeight: 34
|
implicitHeight: 34
|
||||||
implicitWidth: 28
|
implicitWidth: 34
|
||||||
item: modelData
|
item: modelData
|
||||||
bar: root.bar
|
bar: root.bar
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,68 +0,0 @@
|
|||||||
pragma Singleton
|
|
||||||
import Quickshell
|
|
||||||
|
|
||||||
Singleton {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
function colorWithHueOf(color1, color2) {
|
|
||||||
var c1 = Qt.color(color1);
|
|
||||||
var c2 = Qt.color(color2);
|
|
||||||
var hue = c2.hsvHue;
|
|
||||||
var sat = c1.hsvSaturation;
|
|
||||||
var val = c1.hsvValue;
|
|
||||||
var alpha = c1.a;
|
|
||||||
return Qt.hsva(hue, sat, val, alpha);
|
|
||||||
}
|
|
||||||
|
|
||||||
function colorWithSaturationOf(color1, color2) {
|
|
||||||
var c1 = Qt.color(color1);
|
|
||||||
var c2 = Qt.color(color2);
|
|
||||||
var hue = c1.hsvHue;
|
|
||||||
var sat = c2.hsvSaturation;
|
|
||||||
var val = c1.hsvValue;
|
|
||||||
var alpha = c1.a;
|
|
||||||
return Qt.hsva(hue, sat, val, alpha);
|
|
||||||
}
|
|
||||||
|
|
||||||
function colorWithLightness(color, lightness) {
|
|
||||||
var c = Qt.color(color);
|
|
||||||
return Qt.hsla(c.hslHue, c.hslSaturation, lightness, c.a);
|
|
||||||
}
|
|
||||||
|
|
||||||
function colorWithLightnessOf(color1, color2) {
|
|
||||||
var c2 = Qt.color(color2);
|
|
||||||
return colorWithLightness(color1, c2.hslLightness);
|
|
||||||
}
|
|
||||||
|
|
||||||
function adaptToAccent(color1, color2) {
|
|
||||||
var c1 = Qt.color(color1);
|
|
||||||
var c2 = Qt.color(color2);
|
|
||||||
var hue = c2.hslHue;
|
|
||||||
var sat = c2.hslSaturation;
|
|
||||||
var light = c1.hslLightness;
|
|
||||||
var alpha = c1.a;
|
|
||||||
return Qt.hsla(hue, sat, light, alpha);
|
|
||||||
}
|
|
||||||
|
|
||||||
function mix(color1, color2, percentage = 0.5) {
|
|
||||||
var c1 = Qt.color(color1);
|
|
||||||
var c2 = Qt.color(color2);
|
|
||||||
return Qt.rgba(
|
|
||||||
percentage * c1.r + (1 - percentage) * c2.r,
|
|
||||||
percentage * c1.g + (1 - percentage) * c2.g,
|
|
||||||
percentage * c1.b + (1 - percentage) * c2.b,
|
|
||||||
percentage * c1.a + (1 - percentage) * c2.a
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function transparentize(color, percentage = 1) {
|
|
||||||
var c = Qt.color(color);
|
|
||||||
return Qt.rgba(c.r, c.g, c.b, c.a * (1 - percentage));
|
|
||||||
}
|
|
||||||
|
|
||||||
function applyAlpha(color, alpha) {
|
|
||||||
var c = Qt.color(color);
|
|
||||||
var a = Math.max(0, Math.min(1, alpha));
|
|
||||||
return Qt.rgba(c.r, c.g, c.b, a);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,134 +0,0 @@
|
|||||||
pragma Singleton
|
|
||||||
pragma ComponentBehavior: Bound
|
|
||||||
|
|
||||||
import QtQuick
|
|
||||||
import Quickshell
|
|
||||||
import Quickshell.Io
|
|
||||||
import Quickshell.Hyprland
|
|
||||||
|
|
||||||
Singleton {
|
|
||||||
id: root
|
|
||||||
property var windowList: []
|
|
||||||
property var addresses: []
|
|
||||||
property var windowByAddress: ({})
|
|
||||||
property var workspaces: []
|
|
||||||
property var workspaceIds: []
|
|
||||||
property var workspaceById: ({})
|
|
||||||
property var activeWorkspace: null
|
|
||||||
property var monitors: []
|
|
||||||
property var layers: ({})
|
|
||||||
|
|
||||||
function updateWindowList() {
|
|
||||||
getClients.running = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateLayers() {
|
|
||||||
getLayers.running = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateMonitors() {
|
|
||||||
getMonitors.running = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateWorkspaces() {
|
|
||||||
getWorkspaces.running = true;
|
|
||||||
getActiveWorkspace.running = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateAll() {
|
|
||||||
updateWindowList();
|
|
||||||
updateMonitors();
|
|
||||||
updateLayers();
|
|
||||||
updateWorkspaces();
|
|
||||||
}
|
|
||||||
|
|
||||||
function biggestWindowForWorkspace(workspaceId) {
|
|
||||||
const windowsInThisWorkspace = HyprlandData.windowList.filter(w => w.workspace.id == workspaceId);
|
|
||||||
return windowsInThisWorkspace.reduce((maxWin, win) => {
|
|
||||||
const maxArea = (maxWin?.size?.[0] ?? 0) * (maxWin?.size?.[1] ?? 0);
|
|
||||||
const winArea = (win?.size?.[0] ?? 0) * (win?.size?.[1] ?? 0);
|
|
||||||
return winArea > maxArea ? win : maxWin;
|
|
||||||
}, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
Component.onCompleted: {
|
|
||||||
updateAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: Hyprland
|
|
||||||
|
|
||||||
function onRawEvent(event) {
|
|
||||||
updateAll()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Process {
|
|
||||||
id: getClients
|
|
||||||
command: ["hyprctl", "clients", "-j"]
|
|
||||||
stdout: StdioCollector {
|
|
||||||
id: clientsCollector
|
|
||||||
onStreamFinished: {
|
|
||||||
root.windowList = JSON.parse(clientsCollector.text)
|
|
||||||
let tempWinByAddress = {};
|
|
||||||
for (var i = 0; i < root.windowList.length; ++i) {
|
|
||||||
var win = root.windowList[i];
|
|
||||||
tempWinByAddress[win.address] = win;
|
|
||||||
}
|
|
||||||
root.windowByAddress = tempWinByAddress;
|
|
||||||
root.addresses = root.windowList.map(win => win.address);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Process {
|
|
||||||
id: getMonitors
|
|
||||||
command: ["hyprctl", "monitors", "-j"]
|
|
||||||
stdout: StdioCollector {
|
|
||||||
id: monitorsCollector
|
|
||||||
onStreamFinished: {
|
|
||||||
root.monitors = JSON.parse(monitorsCollector.text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Process {
|
|
||||||
id: getLayers
|
|
||||||
command: ["hyprctl", "layers", "-j"]
|
|
||||||
stdout: StdioCollector {
|
|
||||||
id: layersCollector
|
|
||||||
onStreamFinished: {
|
|
||||||
root.layers = JSON.parse(layersCollector.text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Process {
|
|
||||||
id: getWorkspaces
|
|
||||||
command: ["hyprctl", "workspaces", "-j"]
|
|
||||||
stdout: StdioCollector {
|
|
||||||
id: workspacesCollector
|
|
||||||
onStreamFinished: {
|
|
||||||
root.workspaces = JSON.parse(workspacesCollector.text);
|
|
||||||
let tempWorkspaceById = {};
|
|
||||||
for (var i = 0; i < root.workspaces.length; ++i) {
|
|
||||||
var ws = root.workspaces[i];
|
|
||||||
tempWorkspaceById[ws.id] = ws;
|
|
||||||
}
|
|
||||||
root.workspaceById = tempWorkspaceById;
|
|
||||||
root.workspaceIds = root.workspaces.map(ws => ws.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Process {
|
|
||||||
id: getActiveWorkspace
|
|
||||||
command: ["hyprctl", "activeworkspace", "-j"]
|
|
||||||
stdout: StdioCollector {
|
|
||||||
id: activeWorkspaceCollector
|
|
||||||
onStreamFinished: {
|
|
||||||
root.activeWorkspace = JSON.parse(activeWorkspaceCollector.text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,147 +0,0 @@
|
|||||||
pragma ComponentBehavior: Bound
|
|
||||||
|
|
||||||
import QtQuick
|
|
||||||
import QtQuick.Controls
|
|
||||||
import QtQuick.Layouts
|
|
||||||
import Quickshell
|
|
||||||
import Quickshell.Io
|
|
||||||
import Quickshell.Wayland
|
|
||||||
import Quickshell.Hyprland
|
|
||||||
import qs.Config
|
|
||||||
|
|
||||||
Scope {
|
|
||||||
id: overviewScope
|
|
||||||
Variants {
|
|
||||||
id: overviewVariants
|
|
||||||
model: Quickshell.screens
|
|
||||||
PanelWindow {
|
|
||||||
id: root
|
|
||||||
required property var modelData
|
|
||||||
readonly property HyprlandMonitor monitor: Hyprland.monitorFor(root.screen)
|
|
||||||
property bool monitorIsFocused: (Hyprland.focusedMonitor?.id == monitor?.id)
|
|
||||||
screen: modelData
|
|
||||||
visible: false
|
|
||||||
|
|
||||||
WlrLayershell.namespace: "quickshell:overview"
|
|
||||||
WlrLayershell.layer: WlrLayer.Overlay
|
|
||||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive
|
|
||||||
color: "transparent"
|
|
||||||
|
|
||||||
mask: Region {
|
|
||||||
item: keyHandler
|
|
||||||
}
|
|
||||||
|
|
||||||
anchors {
|
|
||||||
top: true
|
|
||||||
bottom: true
|
|
||||||
left: true
|
|
||||||
right: true
|
|
||||||
}
|
|
||||||
|
|
||||||
HyprlandFocusGrab {
|
|
||||||
id: grab
|
|
||||||
windows: [root]
|
|
||||||
property bool canBeActive: root.monitorIsFocused
|
|
||||||
active: false
|
|
||||||
onCleared: () => {
|
|
||||||
if (!active)
|
|
||||||
root.visible = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
implicitWidth: columnLayout.implicitWidth
|
|
||||||
implicitHeight: columnLayout.implicitHeight
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: keyHandler
|
|
||||||
anchors.fill: parent
|
|
||||||
visible: root.visible
|
|
||||||
focus: root.visible
|
|
||||||
|
|
||||||
Keys.onPressed: event => {
|
|
||||||
// close: Escape or Enter
|
|
||||||
if (event.key === Qt.Key_Escape || event.key === Qt.Key_Return) {
|
|
||||||
root.visible = false;
|
|
||||||
event.accepted = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper: compute current group bounds
|
|
||||||
const workspacesPerGroup = Config.overview.rows * Config.overview.columns;
|
|
||||||
const currentId = Hyprland.focusedMonitor?.activeWorkspace?.id ?? 1;
|
|
||||||
const currentGroup = Math.floor((currentId - 1) / workspacesPerGroup);
|
|
||||||
const minWorkspaceId = currentGroup * workspacesPerGroup + 1;
|
|
||||||
const maxWorkspaceId = minWorkspaceId + workspacesPerGroup - 1;
|
|
||||||
|
|
||||||
let targetId = null;
|
|
||||||
|
|
||||||
// Arrow keys and vim-style hjkl
|
|
||||||
if (event.key === Qt.Key_Left || event.key === Qt.Key_H) {
|
|
||||||
targetId = currentId - 1;
|
|
||||||
if (targetId < minWorkspaceId) targetId = maxWorkspaceId;
|
|
||||||
} else if (event.key === Qt.Key_Right || event.key === Qt.Key_L) {
|
|
||||||
targetId = currentId + 1;
|
|
||||||
if (targetId > maxWorkspaceId) targetId = minWorkspaceId;
|
|
||||||
} else if (event.key === Qt.Key_Up || event.key === Qt.Key_K) {
|
|
||||||
targetId = currentId - Config.overview.columns;
|
|
||||||
if (targetId < minWorkspaceId) targetId += workspacesPerGroup;
|
|
||||||
} else if (event.key === Qt.Key_Down || event.key === Qt.Key_J) {
|
|
||||||
targetId = currentId + Config.overview.columns;
|
|
||||||
if (targetId > maxWorkspaceId) targetId -= workspacesPerGroup;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Number keys: jump to workspace within the current group
|
|
||||||
// 1-9 map to positions 1-9, 0 maps to position 10
|
|
||||||
else if (event.key >= Qt.Key_1 && event.key <= Qt.Key_9) {
|
|
||||||
const position = event.key - Qt.Key_0; // 1-9
|
|
||||||
if (position <= workspacesPerGroup) {
|
|
||||||
targetId = minWorkspaceId + position - 1;
|
|
||||||
}
|
|
||||||
} else if (event.key === Qt.Key_0) {
|
|
||||||
// 0 = 10th workspace in the group (if group has 10+ workspaces)
|
|
||||||
if (workspacesPerGroup >= 10) {
|
|
||||||
targetId = minWorkspaceId + 9; // 10th position = offset 9
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (targetId !== null) {
|
|
||||||
Hyprland.dispatch("workspace " + targetId);
|
|
||||||
event.accepted = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
id: columnLayout
|
|
||||||
visible: root.visible
|
|
||||||
anchors {
|
|
||||||
horizontalCenter: parent.horizontalCenter
|
|
||||||
top: parent.top
|
|
||||||
topMargin: 100
|
|
||||||
}
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
id: overviewLoader
|
|
||||||
active: true && (Config.overview.enable ?? true)
|
|
||||||
sourceComponent: OverviewWidget {
|
|
||||||
panelWindow: root
|
|
||||||
visible: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
IpcHandler {
|
|
||||||
target: "overview"
|
|
||||||
|
|
||||||
function toggle() {
|
|
||||||
root.visible = !root.visible;
|
|
||||||
}
|
|
||||||
function close() {
|
|
||||||
root.visible = false;
|
|
||||||
}
|
|
||||||
function open() {
|
|
||||||
root.visible = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
import Quickshell
|
||||||
|
import Quickshell.Hyprland
|
||||||
|
import Quickshell.Wayland
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import qs.Config
|
||||||
|
import qs.Components
|
||||||
|
import qs.Modules
|
||||||
|
import qs.Helpers
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property Item wrapper
|
||||||
|
required property ShellScreen screen
|
||||||
|
|
||||||
|
implicitWidth: layout.implicitWidth + 16
|
||||||
|
implicitHeight: layout.implicitHeight + 16
|
||||||
|
|
||||||
|
GridLayout {
|
||||||
|
id: layout
|
||||||
|
anchors.centerIn: parent
|
||||||
|
|
||||||
|
columnSpacing: 8
|
||||||
|
rowSpacing: 8
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: Hypr.workspaces
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
id: workspacePreview
|
||||||
|
required property HyprlandWorkspace modelData
|
||||||
|
|
||||||
|
border.color: "white"
|
||||||
|
border.width: 1
|
||||||
|
radius: 8
|
||||||
|
Layout.preferredWidth: 320 + 10
|
||||||
|
Layout.preferredHeight: 180 + 10
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: workspacePreview.modelData.toplevels
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: preview
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 5
|
||||||
|
|
||||||
|
required property HyprlandToplevel modelData
|
||||||
|
property rect appPosition: {
|
||||||
|
let {
|
||||||
|
at: [cx, cy],
|
||||||
|
size: [cw, ch]
|
||||||
|
} = modelData.lastIpcObject;
|
||||||
|
|
||||||
|
cx -= modelData.monitor.x;
|
||||||
|
cy -= modelData.monitor.y;
|
||||||
|
|
||||||
|
return Qt.rect( (cx / 8), (cy / 8), (cw / 8), (ch / 8) )
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomRect {
|
||||||
|
border.color: DynamicColors.tPalette.m3outline
|
||||||
|
border.width: 1
|
||||||
|
radius: 4
|
||||||
|
implicitWidth: preview.appPosition.width
|
||||||
|
implicitHeight: preview.appPosition.height
|
||||||
|
|
||||||
|
x: preview.appPosition.x
|
||||||
|
y: preview.appPosition.y - 3.4
|
||||||
|
|
||||||
|
ScreencopyView {
|
||||||
|
id: previewCopy
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
captureSource: preview.modelData.wayland
|
||||||
|
live: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,298 +0,0 @@
|
|||||||
import QtQuick
|
|
||||||
import QtQuick.Layouts
|
|
||||||
import Quickshell
|
|
||||||
import Quickshell.Wayland
|
|
||||||
import Quickshell.Hyprland
|
|
||||||
import qs.Config
|
|
||||||
import qs.Modules
|
|
||||||
import qs.Components
|
|
||||||
import qs.Effects
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: root
|
|
||||||
required property var panelWindow
|
|
||||||
readonly property HyprlandMonitor monitor: Hyprland.monitorFor(panelWindow.screen)
|
|
||||||
readonly property var toplevels: ToplevelManager.toplevels
|
|
||||||
readonly property int workspacesShown: Config.overview.rows * Config.overview.columns
|
|
||||||
readonly property int workspaceGroup: Math.floor((monitor.activeWorkspace?.id - 1) / workspacesShown)
|
|
||||||
property bool monitorIsFocused: (Hyprland.focusedMonitor?.name == monitor.name)
|
|
||||||
property var windows: HyprlandData.windowList
|
|
||||||
property var windowByAddress: HyprlandData.windowByAddress
|
|
||||||
property var windowAddresses: HyprlandData.addresses
|
|
||||||
property var monitorData: HyprlandData.monitors.find(m => m.id === root.monitor?.id)
|
|
||||||
property real scale: Config.overview.scale
|
|
||||||
property color activeBorderColor: Appearance.colors.colSecondary
|
|
||||||
|
|
||||||
property real workspaceImplicitWidth: (monitorData?.transform % 2 === 1) ?
|
|
||||||
((monitor.height / monitor.scale - (monitorData?.reserved?.[0] ?? 0) - (monitorData?.reserved?.[2] ?? 0)) * root.scale) :
|
|
||||||
((monitor.width / monitor.scale - (monitorData?.reserved?.[0] ?? 0) - (monitorData?.reserved?.[2] ?? 0)) * root.scale)
|
|
||||||
property real workspaceImplicitHeight: (monitorData?.transform % 2 === 1) ?
|
|
||||||
((monitor.width / monitor.scale - (monitorData?.reserved?.[1] ?? 0) - (monitorData?.reserved?.[3] ?? 0)) * root.scale) :
|
|
||||||
((monitor.height / monitor.scale - (monitorData?.reserved?.[1] ?? 0) - (monitorData?.reserved?.[3] ?? 0)) * root.scale)
|
|
||||||
|
|
||||||
property real workspaceNumberMargin: 80
|
|
||||||
property real workspaceNumberSize: 250 * monitor.scale
|
|
||||||
property int workspaceZ: 0
|
|
||||||
property int windowZ: 1
|
|
||||||
property int windowDraggingZ: 99999
|
|
||||||
property real workspaceSpacing: 5
|
|
||||||
|
|
||||||
property int draggingFromWorkspace: -1
|
|
||||||
property int draggingTargetWorkspace: -1
|
|
||||||
|
|
||||||
implicitWidth: overviewBackground.implicitWidth + Appearance.sizes.elevationMargin * 2
|
|
||||||
implicitHeight: overviewBackground.implicitHeight + Appearance.sizes.elevationMargin * 2
|
|
||||||
|
|
||||||
property Component windowComponent: OverviewWindow {}
|
|
||||||
property list<OverviewWindow> windowWidgets: []
|
|
||||||
|
|
||||||
ShadowRect {
|
|
||||||
anchors.fill: overviewBackground
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle { // Background
|
|
||||||
id: overviewBackground
|
|
||||||
property real padding: 10
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: Appearance.sizes.elevationMargin
|
|
||||||
|
|
||||||
implicitWidth: workspaceColumnLayout.implicitWidth + padding * 2
|
|
||||||
implicitHeight: workspaceColumnLayout.implicitHeight + padding * 2
|
|
||||||
radius: Appearance.rounding.screenRounding * root.scale + padding
|
|
||||||
color: Appearance.colors.colLayer0
|
|
||||||
border.width: 1
|
|
||||||
border.color: Appearance.colors.colLayer0Border
|
|
||||||
|
|
||||||
ColumnLayout { // Workspaces
|
|
||||||
id: workspaceColumnLayout
|
|
||||||
|
|
||||||
z: root.workspaceZ
|
|
||||||
anchors.centerIn: parent
|
|
||||||
spacing: workspaceSpacing
|
|
||||||
Repeater {
|
|
||||||
model: Config.overview.rows
|
|
||||||
delegate: RowLayout {
|
|
||||||
id: row
|
|
||||||
property int rowIndex: index
|
|
||||||
spacing: workspaceSpacing
|
|
||||||
|
|
||||||
Repeater { // Workspace repeater
|
|
||||||
model: Config.overview.columns
|
|
||||||
Rectangle { // Workspace
|
|
||||||
id: workspace
|
|
||||||
property int colIndex: index
|
|
||||||
property int workspaceValue: root.workspaceGroup * workspacesShown + rowIndex * Config.overview.columns + colIndex + 1
|
|
||||||
property color defaultWorkspaceColor: DynamicColors.tPalette.m3surfaceContainerLow
|
|
||||||
property color hoveredWorkspaceColor: ColorUtils.mix(defaultWorkspaceColor, Appearance.colors.colLayer1Hover, 0.1)
|
|
||||||
property color hoveredBorderColor: DynamicColors.tPalette.m3surfaceContainer
|
|
||||||
property bool hoveredWhileDragging: false
|
|
||||||
|
|
||||||
implicitWidth: root.workspaceImplicitWidth
|
|
||||||
implicitHeight: root.workspaceImplicitHeight
|
|
||||||
color: hoveredWhileDragging ? hoveredWorkspaceColor : defaultWorkspaceColor
|
|
||||||
radius: 8
|
|
||||||
border.width: 2
|
|
||||||
border.color: hoveredWhileDragging ? hoveredBorderColor : "transparent"
|
|
||||||
|
|
||||||
CustomText {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
text: workspaceValue
|
|
||||||
color: DynamicColor.tPalette.m3onSurfaceVariant
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: workspaceArea
|
|
||||||
anchors.fill: parent
|
|
||||||
acceptedButtons: Qt.LeftButton
|
|
||||||
onClicked: {
|
|
||||||
if (root.draggingTargetWorkspace === -1) {
|
|
||||||
root.panelWindow.visible = false
|
|
||||||
Hyprland.dispatch(`workspace ${workspaceValue}`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DropArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
onEntered: {
|
|
||||||
root.draggingTargetWorkspace = workspaceValue
|
|
||||||
if (root.draggingFromWorkspace == root.draggingTargetWorkspace) return;
|
|
||||||
hoveredWhileDragging = true
|
|
||||||
}
|
|
||||||
onExited: {
|
|
||||||
hoveredWhileDragging = false
|
|
||||||
if (root.draggingTargetWorkspace == workspaceValue) root.draggingTargetWorkspace = -1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Item { // Windows & focused workspace indicator
|
|
||||||
id: windowSpace
|
|
||||||
anchors.centerIn: parent
|
|
||||||
implicitWidth: workspaceColumnLayout.implicitWidth
|
|
||||||
implicitHeight: workspaceColumnLayout.implicitHeight
|
|
||||||
|
|
||||||
Repeater { // Window repeater
|
|
||||||
model: ScriptModel {
|
|
||||||
values: {
|
|
||||||
return ToplevelManager.toplevels.values.filter((toplevel) => {
|
|
||||||
const address = `0x${toplevel.HyprlandToplevel.address}`
|
|
||||||
var win = windowByAddress[address]
|
|
||||||
const inWorkspaceGroup = (root.workspaceGroup * root.workspacesShown < win?.workspace?.id && win?.workspace?.id <= (root.workspaceGroup + 1) * root.workspacesShown)
|
|
||||||
return inWorkspaceGroup;
|
|
||||||
}).sort((a, b) => {
|
|
||||||
// Proper stacking order based on Hyprland's window properties
|
|
||||||
const addrA = `0x${a.HyprlandToplevel.address}`
|
|
||||||
const addrB = `0x${b.HyprlandToplevel.address}`
|
|
||||||
const winA = windowByAddress[addrA]
|
|
||||||
const winB = windowByAddress[addrB]
|
|
||||||
|
|
||||||
// 1. Pinned windows are always on top
|
|
||||||
if (winA?.pinned !== winB?.pinned) {
|
|
||||||
return winA?.pinned ? 1 : -1
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Floating windows above tiled windows
|
|
||||||
if (winA?.floating !== winB?.floating) {
|
|
||||||
return winA?.floating ? 1 : -1
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. Within same category, sort by focus history
|
|
||||||
// Lower focusHistoryID = more recently focused = higher in stack
|
|
||||||
return (winB?.focusHistoryID ?? 0) - (winA?.focusHistoryID ?? 0)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
delegate: OverviewWindow {
|
|
||||||
id: window
|
|
||||||
required property var modelData
|
|
||||||
required property int index
|
|
||||||
property var overviewRoot: root.panelWindow
|
|
||||||
property int monitorId: windowData?.monitor
|
|
||||||
property var monitor: HyprlandData.monitors.find(m => m.id === monitorId)
|
|
||||||
property var address: `0x${modelData.HyprlandToplevel.address}`
|
|
||||||
windowData: windowByAddress[address]
|
|
||||||
toplevel: modelData
|
|
||||||
monitorData: monitor
|
|
||||||
|
|
||||||
// Calculate scale relative to window's source monitor
|
|
||||||
property real sourceMonitorWidth: (monitor?.transform % 2 === 1) ?
|
|
||||||
(monitor?.height ?? 1920) / (monitor?.scale ?? 1) - (monitor?.reserved?.[0] ?? 0) - (monitor?.reserved?.[2] ?? 0) :
|
|
||||||
(monitor?.width ?? 1920) / (monitor?.scale ?? 1) - (monitor?.reserved?.[0] ?? 0) - (monitor?.reserved?.[2] ?? 0)
|
|
||||||
property real sourceMonitorHeight: (monitor?.transform % 2 === 1) ?
|
|
||||||
(monitor?.width ?? 1080) / (monitor?.scale ?? 1) - (monitor?.reserved?.[1] ?? 0) - (monitor?.reserved?.[3] ?? 0) :
|
|
||||||
(monitor?.height ?? 1080) / (monitor?.scale ?? 1) - (monitor?.reserved?.[1] ?? 0) - (monitor?.reserved?.[3] ?? 0)
|
|
||||||
|
|
||||||
// Scale windows to fit the workspace size, accounting for different monitor sizes
|
|
||||||
scale: Math.min(
|
|
||||||
root.workspaceImplicitWidth / sourceMonitorWidth,
|
|
||||||
root.workspaceImplicitHeight / sourceMonitorHeight
|
|
||||||
)
|
|
||||||
|
|
||||||
availableWorkspaceWidth: root.workspaceImplicitWidth
|
|
||||||
availableWorkspaceHeight: root.workspaceImplicitHeight
|
|
||||||
widgetMonitorId: root.monitor.id
|
|
||||||
|
|
||||||
property bool atInitPosition: (initX == x && initY == y)
|
|
||||||
|
|
||||||
property int workspaceColIndex: (windowData?.workspace.id - 1) % Config.overview.columns
|
|
||||||
property int workspaceRowIndex: Math.floor((windowData?.workspace.id - 1) % root.workspacesShown / Config.overview.columns)
|
|
||||||
xOffset: (root.workspaceImplicitWidth + workspaceSpacing) * workspaceColIndex
|
|
||||||
yOffset: (root.workspaceImplicitHeight + workspaceSpacing) * workspaceRowIndex
|
|
||||||
|
|
||||||
Timer {
|
|
||||||
id: updateWindowPosition
|
|
||||||
interval: Config.options.hacks.arbitraryRaceConditionDelay
|
|
||||||
repeat: false
|
|
||||||
running: false
|
|
||||||
onTriggered: {
|
|
||||||
window.x = Math.round(Math.max((windowData?.at[0] - (monitor?.x ?? 0) - (monitorData?.reserved?.[0] ?? 0)) * root.scale, 0) + xOffset)
|
|
||||||
window.y = Math.round(Math.max((windowData?.at[1] - (monitor?.y ?? 0) - (monitorData?.reserved?.[1] ?? 0)) * root.scale, 0) + yOffset)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
z: atInitPosition ? (root.windowZ + index) : root.windowDraggingZ
|
|
||||||
Drag.hotSpot.x: targetWindowWidth / 2
|
|
||||||
Drag.hotSpot.y: targetWindowHeight / 2
|
|
||||||
MouseArea {
|
|
||||||
id: dragArea
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
onEntered: hovered = true
|
|
||||||
onExited: hovered = false
|
|
||||||
acceptedButtons: Qt.LeftButton | Qt.MiddleButton
|
|
||||||
drag.target: parent
|
|
||||||
onPressed: (mouse) => {
|
|
||||||
root.draggingFromWorkspace = windowData?.workspace.id
|
|
||||||
window.pressed = true
|
|
||||||
window.Drag.active = true
|
|
||||||
window.Drag.source = window
|
|
||||||
window.Drag.hotSpot.x = mouse.x
|
|
||||||
window.Drag.hotSpot.y = mouse.y
|
|
||||||
}
|
|
||||||
onReleased: {
|
|
||||||
const targetWorkspace = root.draggingTargetWorkspace
|
|
||||||
window.pressed = false
|
|
||||||
window.Drag.active = false
|
|
||||||
root.draggingFromWorkspace = -1
|
|
||||||
if (targetWorkspace !== -1 && targetWorkspace !== windowData?.workspace.id) {
|
|
||||||
Hyprland.dispatch(`movetoworkspacesilent ${targetWorkspace}, address:${window.windowData?.address}`)
|
|
||||||
updateWindowPosition.restart()
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
window.x = window.initX
|
|
||||||
window.y = window.initY
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onClicked: (event) => {
|
|
||||||
if (!windowData) return;
|
|
||||||
|
|
||||||
if (event.button === Qt.LeftButton) {
|
|
||||||
GlobalStates.overviewOpen = false
|
|
||||||
Hyprland.dispatch(`focuswindow address:${windowData.address}`)
|
|
||||||
event.accepted = true
|
|
||||||
} else if (event.button === Qt.MiddleButton) {
|
|
||||||
Hyprland.dispatch(`closewindow address:${windowData.address}`)
|
|
||||||
event.accepted = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CustomTooltip {
|
|
||||||
extraVisibleCondition: false
|
|
||||||
alternativeVisibleCondition: dragArea.containsMouse && !window.Drag.active
|
|
||||||
text: `${windowData?.title ?? "Unknown"}\n[${windowData?.class ?? "unknown"}] ${windowData?.xwayland ? "[XWayland] " : ""}`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: focusedWorkspaceIndicator
|
|
||||||
property int activeWorkspaceInGroup: monitor.activeWorkspace?.id - (root.workspaceGroup * root.workspacesShown)
|
|
||||||
property int activeWorkspaceRowIndex: Math.floor((activeWorkspaceInGroup - 1) / Config.overview.columns)
|
|
||||||
property int activeWorkspaceColIndex: (activeWorkspaceInGroup - 1) % Config.overview.columns
|
|
||||||
x: (root.workspaceImplicitWidth + workspaceSpacing) * activeWorkspaceColIndex
|
|
||||||
y: (root.workspaceImplicitHeight + workspaceSpacing) * activeWorkspaceRowIndex
|
|
||||||
z: root.windowZ
|
|
||||||
width: root.workspaceImplicitWidth
|
|
||||||
height: root.workspaceImplicitHeight
|
|
||||||
color: "transparent"
|
|
||||||
radius: Appearance.rounding.screenRounding * root.scale
|
|
||||||
border.width: 2
|
|
||||||
border.color: root.activeBorderColor
|
|
||||||
Behavior on x {
|
|
||||||
Anim {}
|
|
||||||
}
|
|
||||||
Behavior on y {
|
|
||||||
Anim {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
import QtQuick
|
|
||||||
import QtQuick.Layouts
|
|
||||||
import Quickshell
|
|
||||||
import Quickshell.Wayland
|
|
||||||
import qs.Config
|
|
||||||
import qs.Modules
|
|
||||||
|
|
||||||
Item { // Window
|
|
||||||
id: root
|
|
||||||
|
|
||||||
required property var overviewRoot
|
|
||||||
|
|
||||||
property var toplevel
|
|
||||||
property var windowData
|
|
||||||
property var monitorData
|
|
||||||
property var scale
|
|
||||||
property var availableWorkspaceWidth
|
|
||||||
property var availableWorkspaceHeight
|
|
||||||
property bool restrictToWorkspace: true
|
|
||||||
property real initX: Math.max(((windowData?.at[0] ?? 0) - (monitorData?.x ?? 0) - (monitorData?.reserved?.[0] ?? 0)) * root.scale, 0) + xOffset
|
|
||||||
property real initY: Math.max(((windowData?.at[1] ?? 0) - (monitorData?.y ?? 0) - (monitorData?.reserved?.[1] ?? 0)) * root.scale, 0) + yOffset
|
|
||||||
property real xOffset: 0
|
|
||||||
property real yOffset: 0
|
|
||||||
property int widgetMonitorId: 0
|
|
||||||
|
|
||||||
property var targetWindowWidth: (windowData?.size[0] ?? 100) * scale
|
|
||||||
property var targetWindowHeight: (windowData?.size[1] ?? 100) * scale
|
|
||||||
property bool hovered: false
|
|
||||||
property bool pressed: false
|
|
||||||
|
|
||||||
property var iconToWindowRatio: 0.25
|
|
||||||
property var xwaylandIndicatorToIconRatio: 0.35
|
|
||||||
property var iconToWindowRatioCompact: 0.45
|
|
||||||
property var entry: DesktopEntries.heuristicLookup(windowData?.class)
|
|
||||||
property var iconPath: Quickshell.iconPath(entry?.icon ?? windowData?.class ?? "application-x-executable", "image-missing")
|
|
||||||
property bool compactMode: false
|
|
||||||
|
|
||||||
property bool indicateXWayland: windowData?.xwayland ?? false
|
|
||||||
|
|
||||||
x: initX
|
|
||||||
y: initY
|
|
||||||
width: Math.min((windowData?.size[0] ?? 100) * root.scale, availableWorkspaceWidth)
|
|
||||||
height: Math.min((windowData?.size[1] ?? 100) * root.scale, availableWorkspaceHeight)
|
|
||||||
opacity: (windowData?.monitor ?? -1) == widgetMonitorId ? 1 : 0.4
|
|
||||||
|
|
||||||
clip: true
|
|
||||||
|
|
||||||
Behavior on x {
|
|
||||||
Anim {}
|
|
||||||
}
|
|
||||||
Behavior on y {
|
|
||||||
Anim {}
|
|
||||||
}
|
|
||||||
Behavior on width {
|
|
||||||
Anim {}
|
|
||||||
}
|
|
||||||
Behavior on height {
|
|
||||||
Anim {}
|
|
||||||
}
|
|
||||||
|
|
||||||
ScreencopyView {
|
|
||||||
id: windowPreview
|
|
||||||
anchors.fill: parent
|
|
||||||
captureSource: root.overviewRoot.visible ? root.toplevel : null
|
|
||||||
live: true
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
radius: 8
|
|
||||||
color: pressed ? ColorUtils.transparentize(Appearance.colors.colLayer2Active, 0.5) :
|
|
||||||
hovered ? ColorUtils.transparentize(Appearance.colors.colLayer2Hover, 0.7) :
|
|
||||||
ColorUtils.transparentize(Appearance.colors.colLayer2)
|
|
||||||
border.color : ColorUtils.transparentize(Appearance.m3colors.m3outline, 0.7)
|
|
||||||
border.width : 1
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout {
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
spacing: 8
|
|
||||||
|
|
||||||
Image {
|
|
||||||
id: windowIcon
|
|
||||||
property var iconSize: {
|
|
||||||
return Math.min(targetWindowWidth, targetWindowHeight) * (root.compactMode ? root.iconToWindowRatioCompact : root.iconToWindowRatio) / (root.monitorData?.scale ?? 1);
|
|
||||||
}
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
|
||||||
source: root.iconPath
|
|
||||||
width: iconSize
|
|
||||||
height: iconSize
|
|
||||||
sourceSize: Qt.size(iconSize, iconSize)
|
|
||||||
|
|
||||||
Behavior on width {
|
|
||||||
Anim {}
|
|
||||||
}
|
|
||||||
Behavior on height {
|
|
||||||
Anim {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,7 +3,6 @@
|
|||||||
import Quickshell
|
import Quickshell
|
||||||
import qs.Modules
|
import qs.Modules
|
||||||
import qs.Modules.Lock
|
import qs.Modules.Lock
|
||||||
import qs.Modules.WSOverview
|
|
||||||
import qs.Helpers
|
import qs.Helpers
|
||||||
|
|
||||||
Scope {
|
Scope {
|
||||||
@@ -22,6 +21,4 @@ Scope {
|
|||||||
NotificationCenter {
|
NotificationCenter {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Overview {}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user