Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion modules/bar/workspaces/HyprlandData.qml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ Singleton {
let ignoreList = [
"activewindow", "focusedmon", "monitoradded",
"createworkspace", "destroyworkspace", "moveworkspace",
"activespecial", "movewindow", "windowtitle"
"activespecial", "movewindow", "windowtitle",
"workspace"
]
if (ignoreList.includes(event.name)) return
updateWindowList()
Expand Down
58 changes: 43 additions & 15 deletions modules/widgets/overview/Overview.qml
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ Item {

// Use the screen's monitor instead of focused monitor for multi-monitor support
property var currentScreen: null // This will be set from parent
property int trackedWorkspaceId: 1
signal workspaceNavigated(int wsId)
readonly property var monitor: currentScreen ? Hyprland.monitorFor(currentScreen) : Hyprland.focusedMonitor
readonly property int workspaceGroup: Math.floor((monitor?.activeWorkspace?.id - 1 || 0) / workspacesShown)
readonly property int workspaceGroup: Math.floor((trackedWorkspaceId - 1 || 0) / workspacesShown)

// Cache these references
readonly property var windowList: HyprlandData.windowList
Expand Down Expand Up @@ -236,7 +238,7 @@ Item {

implicitWidth: overviewRoot.workspaceImplicitWidth + workspacePadding
implicitHeight: overviewRoot.workspaceImplicitHeight + workspacePadding
color: "transparent"
color: Colors.background
radius: Styling.radius(2)
border.width: 2
border.color: hoveredWhileDragging ? hoveredBorderColor : "transparent"
Expand All @@ -263,15 +265,15 @@ Item {
acceptedButtons: Qt.LeftButton
onClicked: {
if (overviewRoot.draggingTargetWorkspace === -1) {
// Only switch workspace, don't close overview
Hyprland.dispatch(`workspace ${workspaceValue}`);
overviewRoot.workspaceNavigated(workspaceValue);
}
}
onDoubleClicked: {
if (overviewRoot.draggingTargetWorkspace === -1) {
// Double click closes overview and switches workspace
Visibilities.setActiveModule("");
Hyprland.dispatch(`workspace ${workspaceValue}`);
if (workspaceValue !== (overviewRoot.monitor?.activeWorkspace?.id || -1)) {
Hyprland.dispatch(`workspace ${workspaceValue}`);
}
}
}
}
Expand Down Expand Up @@ -302,16 +304,15 @@ Item {
implicitWidth: workspaceColumnLayout.implicitWidth
implicitHeight: workspaceColumnLayout.implicitHeight

// Pre-filter windows for this monitor and workspace group
// Pre-filter windows for workspace group (all monitors)
readonly property var filteredWindowData: {
const minWs = overviewRoot.workspaceGroup * overviewRoot.workspacesShown;
const maxWs = (overviewRoot.workspaceGroup + 1) * overviewRoot.workspacesShown;
const monId = overviewRoot.monitorId;
const toplevels = ToplevelManager.toplevels.values;

return overviewRoot.windowList.filter(win => {
const wsId = win?.workspace?.id;
return wsId > minWs && wsId <= maxWs && win.monitor === monId;
return wsId > minWs && wsId <= maxWs;
}).map(win => ({
windowData: win,
toplevel: toplevels.find(t => `0x${t.HyprlandToplevel.address}` === win.address) || null
Expand All @@ -327,9 +328,28 @@ Item {
windowData: modelData.windowData
toplevel: modelData.toplevel
scale: overviewRoot.scale
crossScaleX: {
if (modelData.windowData.monitor === overviewRoot.monitorId) return 1.0;
const winMon = overviewRoot.monitors.find(m => m.id === modelData.windowData.monitor);
if (!winMon) return 1.0;
const ovW = (overviewRoot.monitorData?.width || 1920) / (overviewRoot.monitorData?.scale || 1.0);
const winW = (winMon.width || 1920) / (winMon.scale || 1.0);
return ovW / winW;
}
crossScaleY: {
if (modelData.windowData.monitor === overviewRoot.monitorId) return 1.0;
const winMon = overviewRoot.monitors.find(m => m.id === modelData.windowData.monitor);
if (!winMon) return 1.0;
const ovH = (overviewRoot.monitorData?.height || 1080) / (overviewRoot.monitorData?.scale || 1.0);
const winH = (winMon.height || 1080) / (winMon.scale || 1.0);
return ovH / winH;
}
availableWorkspaceWidth: overviewRoot.workspaceImplicitWidth
availableWorkspaceHeight: overviewRoot.workspaceImplicitHeight
monitorData: overviewRoot.monitorData
monitorData: {
const winMon = overviewRoot.monitors.find(m => m.id === modelData.windowData.monitor);
return winMon ?? overviewRoot.monitorData;
}
barPosition: overviewRoot.barPosition
barReserved: overviewRoot.barReserved

Expand All @@ -350,23 +370,31 @@ Item {
Hyprland.dispatch(`movetoworkspacesilent ${targetWorkspace}, address:${windowData?.address}`);
}
}
onWindowClicked: {
// Close overview and focus the specific clicked window
// Skip generic focus restoration since we're handling it specifically
onWindowClicked: (clickSceneX, clickSceneY) => {
// Capture values before closing — delegate gets destroyed after close
var addr = windowData.address;
var sameMonitor = (windowData.monitor === overviewRoot.monitorId);
var absX = Math.round((overviewRoot.monitorData?.x || 0) + clickSceneX);
var absY = Math.round((overviewRoot.monitorData?.y || 0) + clickSceneY);
Visibilities.setActiveModule("", true);
Qt.callLater(() => {
Hyprland.dispatch(`focuswindow address:${windowData.address}`);
Hyprland.dispatch(`focuswindow address:${addr}`);
if (sameMonitor) {
Hyprland.dispatch(`movecursor ${absX} ${absY}`);
}
});
}
onWindowClosed: {
Hyprland.dispatch(`closewindow address:${windowData.address}`);
}
onWorkspaceNavigated: wsId => overviewRoot.workspaceNavigated(wsId)
}
}

Rectangle {
id: focusedWorkspaceIndicator
property int activeWorkspaceInGroup: (monitor?.activeWorkspace?.id || 1) - (overviewRoot.workspaceGroup * overviewRoot.workspacesShown)
z: 10
property int activeWorkspaceInGroup: overviewRoot.trackedWorkspaceId - (overviewRoot.workspaceGroup * overviewRoot.workspacesShown)
property int activeWorkspaceRowIndex: Math.floor((activeWorkspaceInGroup - 1) / overviewRoot.columns)
property int activeWorkspaceColIndex: (activeWorkspaceInGroup - 1) % overviewRoot.columns

Expand Down
67 changes: 36 additions & 31 deletions modules/widgets/overview/OverviewPopup.qml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ PanelWindow {
readonly property var screenVisibilities: Visibilities.getForScreen(screen.name)
readonly property bool overviewOpen: screenVisibilities ? screenVisibilities.overview : false

property int trackedWorkspaceId: 1
readonly property int navigableWorkspaces: Math.max(Config.workspaces.shown, 1)

visible: overviewOpen
exclusionMode: ExclusionMode.Ignore

Expand Down Expand Up @@ -192,34 +195,34 @@ PanelWindow {
}

onAccepted: {
if (overviewLoader.item) {
overviewLoader.item.navigateToSelectedWindow();
if (searchInput.text.length > 0) {
if (overviewLoader.item) {
overviewLoader.item.navigateToSelectedWindow();
}
} else {
Visibilities.setActiveModule("");
var mon = overviewPopup.screen ? Hyprland.monitorFor(overviewPopup.screen) : null;
if (overviewPopup.trackedWorkspaceId !== (mon?.activeWorkspace?.id || -1)) {
Hyprland.dispatch("workspace " + overviewPopup.trackedWorkspaceId);
}
}
}

onTabPressed: {
if (searchInput.text.length === 0) {
const current = Hyprland.focusedWorkspace?.id || 1;
const next = current + 1;
if (next > Config.workspaces.shown) {
Hyprland.dispatch("workspace 1");
} else {
Hyprland.dispatch("workspace r+1");
}
var next = overviewPopup.trackedWorkspaceId + 1;
if (next > overviewPopup.navigableWorkspaces) next = 1;
overviewPopup.trackedWorkspaceId = next;
} else if (overviewLoader.item) {
overviewLoader.item.selectNextMatch();
}
}

onShiftTabPressed: {
if (searchInput.text.length === 0) {
const current = Hyprland.focusedWorkspace?.id || 1;
const prev = current - 1;
if (prev < 1) {
Hyprland.dispatch("workspace " + Config.workspaces.shown);
} else {
Hyprland.dispatch("workspace r-1");
}
var prev = overviewPopup.trackedWorkspaceId - 1;
if (prev < 1) prev = overviewPopup.navigableWorkspaces;
overviewPopup.trackedWorkspaceId = prev;
} else if (overviewLoader.item) {
overviewLoader.item.selectPrevMatch();
}
Expand Down Expand Up @@ -250,27 +253,19 @@ PanelWindow {

onLeftPressed: {
if (searchInput.text.length === 0) {
const current = Hyprland.focusedWorkspace?.id || 1;
const prev = current - 1;
if (prev < 1) {
Hyprland.dispatch("workspace " + Config.workspaces.shown);
} else {
Hyprland.dispatch("workspace r-1");
}
var prev = overviewPopup.trackedWorkspaceId - 1;
if (prev < 1) prev = overviewPopup.navigableWorkspaces;
overviewPopup.trackedWorkspaceId = prev;
} else if (overviewLoader.item) {
overviewLoader.item.selectPrevMatch();
}
}

onRightPressed: {
if (searchInput.text.length === 0) {
const current = Hyprland.focusedWorkspace?.id || 1;
const next = current + 1;
if (next > Config.workspaces.shown) {
Hyprland.dispatch("workspace 1");
} else {
Hyprland.dispatch("workspace r+1");
}
var next = overviewPopup.trackedWorkspaceId + 1;
if (next > overviewPopup.navigableWorkspaces) next = 1;
overviewPopup.trackedWorkspaceId = next;
} else if (overviewLoader.item) {
overviewLoader.item.selectNextMatch();
}
Expand Down Expand Up @@ -307,10 +302,18 @@ PanelWindow {

sourceComponent: OverviewView {
currentScreen: overviewPopup.screen
trackedWorkspaceId: overviewPopup.trackedWorkspaceId
}
}
}

Connections {
target: overviewLoader.item
function onWorkspaceNavigated(wsId) {
overviewPopup.trackedWorkspaceId = wsId;
}
}

// External scrollbar for scrolling mode (to the right of overview)
StyledRect {
id: scrollbarContainer
Expand Down Expand Up @@ -388,6 +391,8 @@ PanelWindow {
// Ensure focus when overview opens
onOverviewOpenChanged: {
if (overviewOpen) {
var mon = screen ? Hyprland.monitorFor(screen) : null;
trackedWorkspaceId = mon?.activeWorkspace?.id || 1;
Qt.callLater(() => {
searchInput.clear();
if (overviewLoader.item) {
Expand Down
9 changes: 9 additions & 0 deletions modules/widgets/overview/OverviewView.qml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import qs.config
Item {
id: root
property var currentScreen
property int trackedWorkspaceId: 1
signal workspaceNavigated(int wsId)

// Detect if we're in scrolling layout mode
readonly property bool isScrollingLayout: GlobalStates.hyprlandLayout === "scrolling"
Expand Down Expand Up @@ -51,11 +53,17 @@ Item {
sourceComponent: isScrollingLayout ? scrollingOverviewComponent : standardOverviewComponent
}

Connections {
target: overviewLoader.item
function onWorkspaceNavigated(wsId) { root.workspaceNavigated(wsId) }
}

// Standard grid overview
Component {
id: standardOverviewComponent
Overview {
currentScreen: root.currentScreen
trackedWorkspaceId: root.trackedWorkspaceId

Keys.onPressed: event => {
if (event.key === Qt.Key_Escape) {
Expand All @@ -75,6 +83,7 @@ Item {
id: scrollingOverviewComponent
ScrollingOverview {
currentScreen: root.currentScreen
trackedWorkspaceId: root.trackedWorkspaceId

Keys.onPressed: event => {
if (event.key === Qt.Key_Escape) {
Expand Down
Loading