diff --git a/hyprland-cheatsheet/BarWidget.qml b/hyprland-cheatsheet/BarWidget.qml new file mode 100644 index 0000000..5b46d7b --- /dev/null +++ b/hyprland-cheatsheet/BarWidget.qml @@ -0,0 +1,31 @@ +import QtQuick +import QtQuick.Layouts +import Quickshell +import qs.Commons +import qs.Widgets + +Rectangle { + id: root + property var pluginApi: null + property ShellScreen screen + + implicitWidth: Style.barHeight + implicitHeight: Style.barHeight + color: "transparent" + radius: width * 0.5 + + NIcon { + anchors.centerIn: parent + icon: "keyboard" + applyUiScale: false + } + + MouseArea { + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onEntered: root.color = Qt.rgba(1, 1, 1, 0.1) + onExited: root.color = "transparent" + onClicked: if (pluginApi) pluginApi.openPanel(root.screen) + } +} diff --git a/hyprland-cheatsheet/Main.qml b/hyprland-cheatsheet/Main.qml new file mode 100644 index 0000000..3c6cdb6 --- /dev/null +++ b/hyprland-cheatsheet/Main.qml @@ -0,0 +1,164 @@ +import QtQuick +import Quickshell +import Quickshell.Io +import qs.Services.UI + +Item { + id: root + property var pluginApi: null + + onPluginApiChanged: { + if (pluginApi) { + console.log("Main: pluginApi załadowane, uruchamiam generator"); + runGenerator(); + } + } + + Component.onCompleted: { + if (pluginApi) { + console.log("Main: Component.onCompleted, uruchamiam generator"); + runGenerator(); + } + } + + function runGenerator() { + console.log("Main: === START GENERATORA ==="); + + // Pobierz HOME z environment + var homeDir = process.environment["HOME"]; + if (!homeDir) { + console.log("Main: BŁĄD - nie można pobrać $HOME"); + saveToDb([{ + "title": pluginApi?.tr("main.error") || "ERROR", + "binds": [{ "keys": "ERROR", "desc": pluginApi?.tr("main.cannot_get_home") || "Cannot get $HOME" }] + }]); + return; + } + + var filePath = homeDir + "/.config/hypr/keybind.conf"; + var cmd = "cat " + filePath; + + console.log("Main: HOME = " + homeDir); + console.log("Main: Pełna ścieżka = " + filePath); + console.log("Main: Komenda = " + cmd); + + var proc = process.create("bash", ["-c", cmd]); + + proc.finished.connect(function() { + console.log("Main: Proces zakończony. ExitCode: " + proc.exitCode); + console.log("Main: Stdout długość: " + proc.stdout.length); + console.log("Main: Stderr: " + proc.stderr); + + if (proc.exitCode !== 0) { + console.log("Main: BŁĄD! Kod: " + proc.exitCode); + console.log("Main: Stderr pełny: " + proc.stderr); + + saveToDb([{ + "title": pluginApi?.tr("main.read_error") || "READ ERROR", + "binds": [ + { "keys": pluginApi?.tr("main.exit_code") || "EXIT CODE", "desc": proc.exitCode.toString() }, + { "keys": pluginApi?.tr("main.stderr") || "STDERR", "desc": proc.stderr } + ] + }]); + return; + } + + var content = proc.stdout; + console.log("Main: Pobrano treść. Długość: " + content.length); + + // Pokaż pierwsze 200 znaków + if (content.length > 0) { + console.log("Main: Pierwsze 200 znaków: " + content.substring(0, 200)); + parseAndSave(content); + } else { + console.log("Main: Plik jest pusty!"); + saveToDb([{ + "title": pluginApi?.tr("main.file_empty") || "FILE EMPTY", + "binds": [{ "keys": "INFO", "desc": pluginApi?.tr("main.file_no_data") || "File contains no data" }] + }]); + } + }); + } + + Process { + id: process + function create(cmd, args) { + console.log("Main: Tworzę proces: " + cmd + " " + args.join(" ")); + command = [cmd].concat(args); + running = true; + return this; + } + } + + function parseAndSave(text) { + console.log("Main: Parsowanie rozpoczęte"); + var lines = text.split('\n'); + console.log("Main: Liczba linii: " + lines.length); + + var categories = []; + var currentCategory = null; + + for (var i = 0; i < lines.length; i++) { + var line = lines[i].trim(); + + if (line.startsWith("#") && line.match(/#\s*\d+\./)) { + if (currentCategory) { + console.log("Main: Zapisuję kategorię: " + currentCategory.title + " z " + currentCategory.binds.length + " bindami"); + categories.push(currentCategory); + } + var title = line.replace(/#\s*\d+\.\s*/, "").trim(); + console.log("Main: Nowa kategoria: " + title); + currentCategory = { "title": title, "binds": [] }; + } + else if (line.includes("bind") && line.includes('#"')) { + if (currentCategory) { + var descMatch = line.match(/#"(.*?)"$/); + var description = descMatch ? descMatch[1] : "Opis"; + + var parts = line.split(','); + if (parts.length >= 2) { + var mod = parts[0].split('=')[1].trim().replace("$mod", "SUPER"); + var key = parts[1].trim().toUpperCase(); + if (parts[0].includes("SHIFT")) mod += "+SHIFT"; + if (parts[0].includes("CTRL")) mod += "+CTRL"; + + currentCategory.binds.push({ + "keys": mod + " + " + key, + "desc": description + }); + console.log("Main: Dodano bind: " + mod + " + " + key); + } + } + } + } + + if (currentCategory) { + console.log("Main: Zapisuję ostatnią kategorię: " + currentCategory.title); + categories.push(currentCategory); + } + + console.log("Main: Znaleziono " + categories.length + " kategorii."); + saveToDb(categories); + } + + function saveToDb(data) { + if (pluginApi) { + pluginApi.pluginSettings.cheatsheetData = data; + pluginApi.saveSettings(); + console.log("Main: ZAPISANO DO BAZY " + data.length + " kategorii"); + } else { + console.log("Main: BŁĄD - pluginApi jest null!"); + } + } + + IpcHandler { + target: "plugin:hyprland-cheatsheet" + function toggle() { + console.log("Main: IPC toggle wywołany"); + if (pluginApi) { + runGenerator(); + pluginApi.withCurrentScreen(screen => pluginApi.openPanel(screen)); + } + } + } +} diff --git a/hyprland-cheatsheet/Panel.qml b/hyprland-cheatsheet/Panel.qml new file mode 100644 index 0000000..f595872 --- /dev/null +++ b/hyprland-cheatsheet/Panel.qml @@ -0,0 +1,438 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell +import Quickshell.Io +import qs.Commons +import qs.Widgets + +Item { + id: root + property var pluginApi: null + property var rawCategories: pluginApi?.pluginSettings?.cheatsheetData || [] + property var categories: processCategories(rawCategories) + property var column0Items: [] + property var column1Items: [] + property var column2Items: [] + + onRawCategoriesChanged: { + categories = processCategories(rawCategories); + updateColumnItems(); + } + + onCategoriesChanged: { + updateColumnItems(); + } + + function updateColumnItems() { + var assignments = distributeCategories(); + column0Items = buildColumnItems(assignments[0]); + column1Items = buildColumnItems(assignments[1]); + column2Items = buildColumnItems(assignments[2]); + } + property real contentPreferredWidth: 1400 + property real contentPreferredHeight: 850 + readonly property var geometryPlaceholder: panelContainer + readonly property bool allowAttach: false + readonly property bool panelAnchorHorizontalCenter: true + readonly property bool panelAnchorVerticalCenter: true + anchors.fill: parent + property var allLines: [] + property bool isLoading: false + + onPluginApiChanged: { if (pluginApi) checkAndGenerate(); } + Component.onCompleted: { if (pluginApi) checkAndGenerate(); } + + function checkAndGenerate() { + if (root.rawCategories.length === 0) { + isLoading = true; + allLines = []; + catProcess.running = true; + } + } + + Process { + id: catProcess + command: ["sh", "-c", "cat ~/.config/hypr/keybind.conf"] + running: false + + stdout: SplitParser { + onRead: data => { + root.allLines.push(data); + } + } + + onExited: (exitCode, exitStatus) => { + isLoading = false; + if (exitCode === 0 && root.allLines.length > 0) { + var fullContent = root.allLines.join("\n"); + parseAndSave(fullContent); + root.allLines = []; + } else { + errorText.text = pluginApi?.tr("panel.error_read_file") || "File read error"; + errorView.visible = true; + } + } + } + + function parseAndSave(text) { + var lines = text.split('\n'); + var cats = []; + var currentCat = null; + + for (var i = 0; i < lines.length; i++) { + var line = lines[i].trim(); + if (line.startsWith("#") && line.match(/#\s*\d+\./)) { + if (currentCat) cats.push(currentCat); + var title = line.replace(/#\s*\d+\.\s*/, "").trim(); + currentCat = { "title": title, "binds": [] }; + } + else if (line.includes("bind") && line.includes('#"')) { + if (currentCat) { + var descMatch = line.match(/#"(.*?)"$/); + var desc = descMatch ? descMatch[1] : (pluginApi?.tr("panel.no_description") || "No description"); + var parts = line.split(','); + if (parts.length >= 2) { + var bindPart = parts[0].trim(); + var keyPart = parts[1].trim(); + var mod = ""; + if (bindPart.includes("$mod")) mod = "Super"; + if (bindPart.includes("SHIFT")) mod += (mod ? " + Shift" : "Shift"); + if (bindPart.includes("CTRL")) mod += (mod ? " + Ctrl" : "Ctrl"); + if (bindPart.includes("ALT")) mod += (mod ? " + Alt" : "Alt"); + var key = keyPart.toUpperCase(); + var fullKey = mod + (mod && key ? " + " : "") + key; + currentCat.binds.push({ "keys": fullKey, "desc": desc }); + } + } + } + } + if (currentCat) cats.push(currentCat); + if (cats.length > 0) { + pluginApi.pluginSettings.cheatsheetData = cats; + pluginApi.saveSettings(); + } else { + errorText.text = pluginApi?.tr("panel.no_categories") || "No categories found"; + errorView.visible = true; + } + } + + Rectangle { + id: panelContainer + anchors.fill: parent + color: Color.mSurface + radius: Style.radiusL + clip: true + + Rectangle { + id: header + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + height: 45 + color: Color.mSurfaceVariant + radius: Style.radiusL + + RowLayout { + anchors.centerIn: parent + spacing: Style.marginS + NIcon { + icon: "keyboard" + pointSize: Style.fontSizeM + color: Color.mPrimary + } + NText { + text: pluginApi?.tr("panel.title") || "Cheat Sheet" + font.pointSize: Style.fontSizeM + font.weight: Font.Bold + color: Color.mPrimary + } + } + } + + NText { + id: loadingText + anchors.centerIn: parent + text: pluginApi?.tr("panel.loading") || "Loading..." + visible: root.isLoading + font.pointSize: Style.fontSizeL + color: Color.mOnSurface + } + + ColumnLayout { + id: errorView + anchors.centerIn: parent + visible: false + spacing: Style.marginM + NIcon { + icon: "alert-circle" + pointSize: 48 + Layout.alignment: Qt.AlignHCenter + color: Color.mError + } + NText { + id: errorText + text: pluginApi?.tr("panel.no_data") || "No data" + font.pointSize: Style.fontSizeM + color: Color.mOnSurface + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WordWrap + } + NButton { + text: pluginApi?.tr("panel.refresh_button") || "Refresh" + Layout.alignment: Qt.AlignHCenter + onClicked: { + pluginApi.pluginSettings.cheatsheetData = []; + pluginApi.saveSettings(); + checkAndGenerate(); + } + } + } + + RowLayout { + id: mainLayout + visible: root.categories.length > 0 && !root.isLoading + anchors.top: header.bottom + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: Style.marginM + spacing: Style.marginS + + ColumnLayout { + Layout.fillWidth: true + Layout.fillHeight: true + Layout.alignment: Qt.AlignTop + spacing: 2 + Repeater { + model: root.column0Items + Loader { + Layout.fillWidth: true + sourceComponent: modelData.type === "header" ? headerComponent : + (modelData.type === "spacer" ? spacerComponent : bindComponent) + property var itemData: modelData + } + } + } + + ColumnLayout { + Layout.fillWidth: true + Layout.fillHeight: true + Layout.alignment: Qt.AlignTop + spacing: 2 + Repeater { + model: root.column1Items + Loader { + Layout.fillWidth: true + sourceComponent: modelData.type === "header" ? headerComponent : + (modelData.type === "spacer" ? spacerComponent : bindComponent) + property var itemData: modelData + } + } + } + + ColumnLayout { + Layout.fillWidth: true + Layout.fillHeight: true + Layout.alignment: Qt.AlignTop + spacing: 2 + Repeater { + model: root.column2Items + Loader { + Layout.fillWidth: true + sourceComponent: modelData.type === "header" ? headerComponent : + (modelData.type === "spacer" ? spacerComponent : bindComponent) + property var itemData: modelData + } + } + } + } + } + + Component { + id: headerComponent + RowLayout { + spacing: Style.marginXS + Layout.topMargin: Style.marginM + Layout.bottomMargin: 4 + NIcon { + icon: "circle-dot" + pointSize: 10 + color: Color.mPrimary + } + NText { + text: itemData.title + font.pointSize: 11 + font.weight: Font.Bold + color: Color.mPrimary + } + } + } + + Component { + id: spacerComponent + Item { + height: 10 + Layout.fillWidth: true + } + } + + Component { + id: bindComponent + RowLayout { + spacing: Style.marginS + height: 22 + Layout.bottomMargin: 1 + Flow { + Layout.preferredWidth: 220 + Layout.alignment: Qt.AlignVCenter + spacing: 3 + Repeater { + model: itemData.keys.split(" + ") + Rectangle { + width: keyText.implicitWidth + 10 + height: 18 + color: getKeyColor(modelData) + radius: 3 + NText { + id: keyText + anchors.centerIn: parent + text: modelData + font.pointSize: modelData.length > 12 ? 7 : 8 + font.weight: Font.Bold + color: Color.mOnPrimary + } + } + } + } + NText { + Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter + text: itemData.desc + font.pointSize: 9 + color: Color.mOnSurface + elide: Text.ElideRight + } + } + } + + function getKeyColor(keyName) { + // Różne kolory dla różnych typów klawiszy + if (keyName === "Super") return Color.mPrimary; + if (keyName === "Ctrl") return Color.mSecondary; + if (keyName === "Shift") return Color.mTertiary; + if (keyName === "Alt") return "#FF6B6B"; // Czerwonawy + if (keyName.startsWith("XF86")) return "#4ECDC4"; // Turkusowy dla multimediów + if (keyName === "PRINT") return "#95E1D3"; // Jasny turkus dla print screen + if (keyName.match(/^[0-9]$/)) return "#A8DADC"; // Jasnoniebieski dla cyfr + if (keyName.includes("MOUSE")) return "#F38181"; // Różowy dla myszy + // Domyślny kolor dla innych klawiszy (litery, strzałki, itp.) + return Color.mPrimaryContainer || "#6C757D"; + } + + function buildColumnItems(categoryIndices) { + var result = []; + if (!categoryIndices) return result; + + for (var i = 0; i < categoryIndices.length; i++) { + var catIndex = categoryIndices[i]; + if (catIndex >= categories.length) continue; + + var cat = categories[catIndex]; + // Dodaj nagłówek + result.push({ type: "header", title: cat.title }); + // Dodaj wszystkie bindy + for (var j = 0; j < cat.binds.length; j++) { + result.push({ + type: "bind", + keys: cat.binds[j].keys, + desc: cat.binds[j].desc + }); + } + // Dodaj spacer po kategorii (oprócz ostatniej w kolumnie) + if (i < categoryIndices.length - 1) { + result.push({ type: "spacer" }); + } + } + return result; + } + + function processCategories(cats) { + if (!cats || cats.length === 0) return []; + + var result = []; + for (var i = 0; i < cats.length; i++) { + var cat = cats[i]; + + // Podziel duże kategorie (>12 itemów) + if (cat.binds && cat.binds.length > 12 && cat.title.includes("OBSZARY ROBOCZE")) { + var switching = []; + var moving = []; + var mouse = []; + + for (var j = 0; j < cat.binds.length; j++) { + var bind = cat.binds[j]; + if (bind.keys.includes("MOUSE")) { + mouse.push(bind); + } else if (bind.desc.includes("Wyślij") || bind.desc.includes("wyślij")) { + moving.push(bind); + } else { + switching.push(bind); + } + } + + if (switching.length > 0) { + result.push({ + title: pluginApi?.tr("panel.workspace_switching") || "WORKSPACES - SWITCHING", + binds: switching + }); + } + if (moving.length > 0) { + result.push({ + title: pluginApi?.tr("panel.workspace_moving") || "WORKSPACES - MOVING", + binds: moving + }); + } + if (mouse.length > 0) { + result.push({ + title: pluginApi?.tr("panel.workspace_mouse") || "WORKSPACES - MOUSE", + binds: mouse + }); + } + } else { + result.push(cat); + } + } + + return result; + } + + function distributeCategories() { + // Oblicz wagę każdej kategorii (nagłówek + bindy + spacer) + var weights = []; + var totalWeight = 0; + for (var i = 0; i < categories.length; i++) { + var weight = 1 + categories[i].binds.length + 1; // header + binds + spacer + weights.push(weight); + totalWeight += weight; + } + + var targetPerColumn = totalWeight / 3; + var columns = [[], [], []]; + var columnWeights = [0, 0, 0]; + + // Greedy algorithm: przypisz każdą kategorię do kolumny z najmniejszą wagą + for (var i = 0; i < categories.length; i++) { + var minCol = 0; + for (var c = 1; c < 3; c++) { + if (columnWeights[c] < columnWeights[minCol]) { + minCol = c; + } + } + columns[minCol].push(i); + columnWeights[minCol] += weights[i]; + } + + return columns; + } +} diff --git a/hyprland-cheatsheet/cheatsheet.json b/hyprland-cheatsheet/cheatsheet.json new file mode 100644 index 0000000..428a32e --- /dev/null +++ b/hyprland-cheatsheet/cheatsheet.json @@ -0,0 +1,403 @@ +[ + { + "title": "APLIKACJE I SYSTEM", + "binds": [ + { + "keys": "SUPER + RETURN", + "desc": "Terminal" + }, + { + "keys": "SUPER + Q", + "desc": "Przeglądarka" + }, + { + "keys": "SUPER + SHIFT + E", + "desc": "Wyjście z Hyprlanda" + }, + { + "keys": "SUPER + F1", + "desc": "Lista skrótów" + } + ] + }, + { + "title": "INTEGRACJA Z NOCTALIĄ (QUICKSHELL)", + "binds": [ + { + "keys": "SUPER + D", + "desc": "Menu Aplikacji" + }, + { + "keys": "SUPER + S", + "desc": "Centrum Sterowania" + }, + { + "keys": "SUPER + V", + "desc": "Historia Schowka" + }, + { + "keys": "SUPER + C", + "desc": "Kalkulator" + }, + { + "keys": "SUPER + B", + "desc": "Kalendarz" + }, + { + "keys": "SUPER + X", + "desc": "Menu Zasilania" + }, + { + "keys": "SUPER + Z", + "desc": "Zmień tapetę" + }, + { + "keys": "SUPER + N", + "desc": "Powiadomienia" + }, + { + "keys": "SUPER + ESCAPE", + "desc": "Zablokuj ekran" + } + ] + }, + { + "title": "ZARZĄDZANIE OKNAMI", + "binds": [ + { + "keys": "SUPER + W", + "desc": "Zamknij okno" + }, + { + "keys": "SUPER + F", + "desc": "Pełny ekran (z paskiem)" + }, + { + "keys": "SUPER + SHIFT + D", + "desc": "Pełny ekran (czysty)" + }, + { + "keys": "SUPER + SHIFT + T", + "desc": "Tryb pływający" + }, + { + "keys": "SUPER + G", + "desc": "Grupowanie okien" + }, + { + "keys": "SUPER + R", + "desc": "Obróć podział" + }, + { + "keys": "SUPER + BRACKETLEFT", + "desc": "Preselect Lewo" + }, + { + "keys": "SUPER + BRACKETRIGHT", + "desc": "Preselect Prawo" + }, + { + "keys": "SUPER + TAB", + "desc": "Następna zakładka" + }, + { + "keys": "SUPER + SHIFT + TAB", + "desc": "Poprzednia zakładka" + }, + { + "keys": "SUPER + O", + "desc": "Wyjmij z grupy" + }, + { + "keys": "SUPER + H", + "desc": "Włóż do grupy (Lewo)" + }, + { + "keys": "SUPER + L", + "desc": "Włóż do grupy (Prawo)" + }, + { + "keys": "SUPER + K", + "desc": "Włóż do grupy (Góra)" + }, + { + "keys": "SUPER + J", + "desc": "Włóż do grupy (Dół)" + } + ] + }, + { + "title": "SCREENSHOTY", + "binds": [ + { + "keys": " + PRINT", + "desc": "Zrzut wycinka (Schowek)" + }, + { + "keys": "CTRL + PRINT", + "desc": "Zrzut ekranu (Schowek)" + }, + { + "keys": "ALT + PRINT", + "desc": "Zrzut okna (Schowek)" + } + ] + }, + { + "title": "MULTIMEDIA I JASNOŚĆ", + "binds": [ + { + "keys": " + XF86AUDIORAISEVOLUME", + "desc": "Głośniej" + }, + { + "keys": " + XF86AUDIOLOWERVOLUME", + "desc": "Ciszej" + }, + { + "keys": " + XF86AUDIOMUTE", + "desc": "Wycisz" + }, + { + "keys": " + XF86AUDIOPLAY", + "desc": "Play / Pause" + }, + { + "keys": " + XF86AUDIONEXT", + "desc": "Następny utwór" + }, + { + "keys": " + XF86AUDIOPREV", + "desc": "Poprzedni utwór" + }, + { + "keys": " + XF86MONBRIGHTNESSUP", + "desc": "Jasność +" + }, + { + "keys": " + XF86MONBRIGHTNESSDOWN", + "desc": "Jasność -" + } + ] + }, + { + "title": "NAWIGACJA (FOCUS)", + "binds": [ + { + "keys": "SUPER + LEFT", + "desc": "Fokus lewo" + }, + { + "keys": "SUPER + RIGHT", + "desc": "Fokus prawo" + }, + { + "keys": "SUPER + UP", + "desc": "Fokus góra" + }, + { + "keys": "SUPER + DOWN", + "desc": "Fokus dół" + }, + { + "keys": "SUPER + H", + "desc": "Fokus lewo (Vim)" + }, + { + "keys": "SUPER + J", + "desc": "Fokus dół (Vim)" + }, + { + "keys": "SUPER + K", + "desc": "Fokus góra (Vim)" + }, + { + "keys": "SUPER + L", + "desc": "Fokus prawo (Vim)" + } + ] + }, + { + "title": "PRZESUWANIE OKIEN", + "binds": [ + { + "keys": "SUPER + SHIFT + LEFT", + "desc": "Przesuń lewo" + }, + { + "keys": "SUPER + SHIFT + RIGHT", + "desc": "Przesuń prawo" + }, + { + "keys": "SUPER + SHIFT + UP", + "desc": "Przesuń górę" + }, + { + "keys": "SUPER + SHIFT + DOWN", + "desc": "Przesuń dół" + }, + { + "keys": "SUPER + SHIFT + H", + "desc": "Przesuń lewo (Vim)" + }, + { + "keys": "SUPER + SHIFT + J", + "desc": "Przesuń dół (Vim)" + }, + { + "keys": "SUPER + SHIFT + K", + "desc": "Przesuń górę (Vim)" + }, + { + "keys": "SUPER + SHIFT + L", + "desc": "Przesuń prawo (Vim)" + } + ] + }, + { + "title": "MONITORY", + "binds": [ + { + "keys": "SUPER + CTRL + LEFT", + "desc": "Fokus monitor lewy" + }, + { + "keys": "SUPER + CTRL + RIGHT", + "desc": "Fokus monitor prawy" + }, + { + "keys": "SUPER + CTRL + H", + "desc": "Fokus monitor lewy" + }, + { + "keys": "SUPER + CTRL + J", + "desc": "Fokus monitor dolny" + }, + { + "keys": "SUPER + CTRL + K", + "desc": "Fokus monitor górny" + }, + { + "keys": "SUPER + CTRL + L", + "desc": "Fokus monitor prawy" + }, + { + "keys": "SUPER + CTRL + SHIFT + LEFT", + "desc": "Wyślij na monitor lewy" + }, + { + "keys": "SUPER + CTRL + SHIFT + RIGHT", + "desc": "Wyślij na monitor prawy" + }, + { + "keys": "SUPER + CTRL + SHIFT + H", + "desc": "Wyślij na monitor lewy" + }, + { + "keys": "SUPER + CTRL + SHIFT + J", + "desc": "Wyślij na monitor dolny" + }, + { + "keys": "SUPER + CTRL + SHIFT + K", + "desc": "Wyślij na monitor górny" + }, + { + "keys": "SUPER + CTRL + SHIFT + L", + "desc": "Wyślij na monitor prawy" + } + ] + }, + { + "title": "OBSZARY ROBOCZE (WORKSPACES)", + "binds": [ + { + "keys": "SUPER + 1", + "desc": "Obszar 1" + }, + { + "keys": "SUPER + 2", + "desc": "Obszar 2" + }, + { + "keys": "SUPER + 3", + "desc": "Obszar 3" + }, + { + "keys": "SUPER + 4", + "desc": "Obszar 4" + }, + { + "keys": "SUPER + 5", + "desc": "Obszar 5" + }, + { + "keys": "SUPER + 6", + "desc": "Obszar 6" + }, + { + "keys": "SUPER + 7", + "desc": "Obszar 7" + }, + { + "keys": "SUPER + 8", + "desc": "Obszar 8" + }, + { + "keys": "SUPER + 9", + "desc": "Obszar 9" + }, + { + "keys": "SUPER + CTRL + 1", + "desc": "Wyślij do obszaru 1" + }, + { + "keys": "SUPER + CTRL + 2", + "desc": "Wyślij do obszaru 2" + }, + { + "keys": "SUPER + CTRL + 3", + "desc": "Wyślij do obszaru 3" + }, + { + "keys": "SUPER + CTRL + 4", + "desc": "Wyślij do obszaru 4" + }, + { + "keys": "SUPER + CTRL + 5", + "desc": "Wyślij do obszaru 5" + }, + { + "keys": "SUPER + SHIFT + 6", + "desc": "Wyślij do obszaru 6" + }, + { + "keys": "SUPER + SHIFT + 7", + "desc": "Wyślij do obszaru 7" + }, + { + "keys": "SUPER + SHIFT + 8", + "desc": "Wyślij do obszaru 8" + }, + { + "keys": "SUPER + SHIFT + 9", + "desc": "Wyślij do obszaru 9" + }, + { + "keys": "SUPER + MOUSE_DOWN", + "desc": "Następny obszar" + }, + { + "keys": "SUPER + MOUSE_UP", + "desc": "Poprzedni obszar" + }, + { + "keys": "SUPER + MOUSE:272", + "desc": "Przesuń okno myszą" + }, + { + "keys": "SUPER + MOUSE:273", + "desc": "Zmień rozmiar myszą" + } + ] + } +] \ No newline at end of file diff --git a/hyprland-cheatsheet/i18n/de.json b/hyprland-cheatsheet/i18n/de.json new file mode 100644 index 0000000..c0bbb0f --- /dev/null +++ b/hyprland-cheatsheet/i18n/de.json @@ -0,0 +1,23 @@ +{ + "panel": { + "title": "Spickzettel", + "loading": "Wird geladen...", + "error_read_file": "Dateilesefehler", + "no_data": "Keine Daten", + "refresh_button": "Aktualisieren", + "no_description": "Keine Beschreibung", + "no_categories": "Keine Kategorien gefunden", + "workspace_switching": "ARBEITSBEREICHE - UMSCHALTEN", + "workspace_moving": "ARBEITSBEREICHE - VERSCHIEBEN", + "workspace_mouse": "ARBEITSBEREICHE - MAUS" + }, + "main": { + "error": "FEHLER", + "cannot_get_home": "$HOME kann nicht abgerufen werden", + "read_error": "LESEFEHLER", + "exit_code": "EXIT CODE", + "stderr": "STDERR", + "file_empty": "DATEI LEER", + "file_no_data": "Datei enthält keine Daten" + } +} diff --git a/hyprland-cheatsheet/i18n/en.json b/hyprland-cheatsheet/i18n/en.json new file mode 100644 index 0000000..456476c --- /dev/null +++ b/hyprland-cheatsheet/i18n/en.json @@ -0,0 +1,23 @@ +{ + "panel": { + "title": "Cheat Sheet", + "loading": "Loading...", + "error_read_file": "File read error", + "no_data": "No data", + "refresh_button": "Refresh", + "no_description": "No description", + "no_categories": "No categories found", + "workspace_switching": "WORKSPACES - SWITCHING", + "workspace_moving": "WORKSPACES - MOVING", + "workspace_mouse": "WORKSPACES - MOUSE" + }, + "main": { + "error": "ERROR", + "cannot_get_home": "Cannot get $HOME", + "read_error": "READ ERROR", + "exit_code": "EXIT CODE", + "stderr": "STDERR", + "file_empty": "FILE EMPTY", + "file_no_data": "File contains no data" + } +} diff --git a/hyprland-cheatsheet/i18n/es.json b/hyprland-cheatsheet/i18n/es.json new file mode 100644 index 0000000..7eae875 --- /dev/null +++ b/hyprland-cheatsheet/i18n/es.json @@ -0,0 +1,23 @@ +{ + "panel": { + "title": "Hoja de Trucos", + "loading": "Cargando...", + "error_read_file": "Error al leer el archivo", + "no_data": "Sin datos", + "refresh_button": "Actualizar", + "no_description": "Sin descripción", + "no_categories": "No se encontraron categorías", + "workspace_switching": "ESPACIOS DE TRABAJO - CAMBIAR", + "workspace_moving": "ESPACIOS DE TRABAJO - MOVER", + "workspace_mouse": "ESPACIOS DE TRABAJO - RATÓN" + }, + "main": { + "error": "ERROR", + "cannot_get_home": "No se puede obtener $HOME", + "read_error": "ERROR DE LECTURA", + "exit_code": "CÓDIGO DE SALIDA", + "stderr": "STDERR", + "file_empty": "ARCHIVO VACÍO", + "file_no_data": "El archivo no contiene datos" + } +} diff --git a/hyprland-cheatsheet/i18n/fr.json b/hyprland-cheatsheet/i18n/fr.json new file mode 100644 index 0000000..bce5db5 --- /dev/null +++ b/hyprland-cheatsheet/i18n/fr.json @@ -0,0 +1,23 @@ +{ + "panel": { + "title": "Aide-Mémoire", + "loading": "Chargement...", + "error_read_file": "Erreur de lecture du fichier", + "no_data": "Aucune donnée", + "refresh_button": "Actualiser", + "no_description": "Aucune description", + "no_categories": "Aucune catégorie trouvée", + "workspace_switching": "ESPACES DE TRAVAIL - BASCULER", + "workspace_moving": "ESPACES DE TRAVAIL - DÉPLACER", + "workspace_mouse": "ESPACES DE TRAVAIL - SOURIS" + }, + "main": { + "error": "ERREUR", + "cannot_get_home": "Impossible d'obtenir $HOME", + "read_error": "ERREUR DE LECTURE", + "exit_code": "CODE DE SORTIE", + "stderr": "STDERR", + "file_empty": "FICHIER VIDE", + "file_no_data": "Le fichier ne contient aucune donnée" + } +} diff --git a/hyprland-cheatsheet/i18n/it.json b/hyprland-cheatsheet/i18n/it.json new file mode 100644 index 0000000..93c3b0b --- /dev/null +++ b/hyprland-cheatsheet/i18n/it.json @@ -0,0 +1,23 @@ +{ + "panel": { + "title": "Foglio di Riferimento", + "loading": "Caricamento...", + "error_read_file": "Errore di lettura del file", + "no_data": "Nessun dato", + "refresh_button": "Aggiorna", + "no_description": "Nessuna descrizione", + "no_categories": "Nessuna categoria trovata", + "workspace_switching": "SPAZI DI LAVORO - CAMBIO", + "workspace_moving": "SPAZI DI LAVORO - SPOSTAMENTO", + "workspace_mouse": "SPAZI DI LAVORO - MOUSE" + }, + "main": { + "error": "ERRORE", + "cannot_get_home": "Impossibile ottenere $HOME", + "read_error": "ERRORE DI LETTURA", + "exit_code": "CODICE DI USCITA", + "stderr": "STDERR", + "file_empty": "FILE VUOTO", + "file_no_data": "Il file non contiene dati" + } +} diff --git a/hyprland-cheatsheet/i18n/ja.json b/hyprland-cheatsheet/i18n/ja.json new file mode 100644 index 0000000..ba3eb20 --- /dev/null +++ b/hyprland-cheatsheet/i18n/ja.json @@ -0,0 +1,23 @@ +{ + "panel": { + "title": "チートシート", + "loading": "読み込み中...", + "error_read_file": "ファイル読み取りエラー", + "no_data": "データなし", + "refresh_button": "更新", + "no_description": "説明なし", + "no_categories": "カテゴリが見つかりません", + "workspace_switching": "ワークスペース - 切り替え", + "workspace_moving": "ワークスペース - 移動", + "workspace_mouse": "ワークスペース - マウス" + }, + "main": { + "error": "エラー", + "cannot_get_home": "$HOMEを取得できません", + "read_error": "読み取りエラー", + "exit_code": "終了コード", + "stderr": "STDERR", + "file_empty": "ファイルが空", + "file_no_data": "ファイルにデータが含まれていません" + } +} diff --git a/hyprland-cheatsheet/i18n/nl.json b/hyprland-cheatsheet/i18n/nl.json new file mode 100644 index 0000000..332a319 --- /dev/null +++ b/hyprland-cheatsheet/i18n/nl.json @@ -0,0 +1,23 @@ +{ + "panel": { + "title": "Spiekbriefje", + "loading": "Laden...", + "error_read_file": "Bestandsleesfout", + "no_data": "Geen gegevens", + "refresh_button": "Vernieuwen", + "no_description": "Geen beschrijving", + "no_categories": "Geen categorieën gevonden", + "workspace_switching": "WERKRUIMTES - WISSELEN", + "workspace_moving": "WERKRUIMTES - VERPLAATSEN", + "workspace_mouse": "WERKRUIMTES - MUIS" + }, + "main": { + "error": "FOUT", + "cannot_get_home": "Kan $HOME niet ophalen", + "read_error": "LEESFOUT", + "exit_code": "EXITCODE", + "stderr": "STDERR", + "file_empty": "BESTAND LEEG", + "file_no_data": "Bestand bevat geen gegevens" + } +} diff --git a/hyprland-cheatsheet/i18n/pl.json b/hyprland-cheatsheet/i18n/pl.json new file mode 100644 index 0000000..4f9284c --- /dev/null +++ b/hyprland-cheatsheet/i18n/pl.json @@ -0,0 +1,23 @@ +{ + "panel": { + "title": "Cheat Sheet", + "loading": "Wczytywanie...", + "error_read_file": "Błąd odczytu pliku", + "no_data": "Brak danych", + "refresh_button": "Odśwież", + "no_description": "Brak opisu", + "no_categories": "Nie znaleziono kategorii", + "workspace_switching": "OBSZARY ROBOCZE - PRZEŁĄCZANIE", + "workspace_moving": "OBSZARY ROBOCZE - PRZENOSZENIE", + "workspace_mouse": "OBSZARY ROBOCZE - MYSZ" + }, + "main": { + "error": "BŁĄD", + "cannot_get_home": "Nie można pobrać $HOME", + "read_error": "BŁĄD ODCZYTU", + "exit_code": "KOD WYJŚCIA", + "stderr": "STDERR", + "file_empty": "PLIK PUSTY", + "file_no_data": "Plik nie zawiera danych" + } +} diff --git a/hyprland-cheatsheet/i18n/pt.json b/hyprland-cheatsheet/i18n/pt.json new file mode 100644 index 0000000..4d5f120 --- /dev/null +++ b/hyprland-cheatsheet/i18n/pt.json @@ -0,0 +1,23 @@ +{ + "panel": { + "title": "Folha de Dicas", + "loading": "Carregando...", + "error_read_file": "Erro ao ler o arquivo", + "no_data": "Sem dados", + "refresh_button": "Atualizar", + "no_description": "Sem descrição", + "no_categories": "Nenhuma categoria encontrada", + "workspace_switching": "ESPAÇOS DE TRABALHO - ALTERNAR", + "workspace_moving": "ESPAÇOS DE TRABALHO - MOVER", + "workspace_mouse": "ESPAÇOS DE TRABALHO - MOUSE" + }, + "main": { + "error": "ERRO", + "cannot_get_home": "Não é possível obter $HOME", + "read_error": "ERRO DE LEITURA", + "exit_code": "CÓDIGO DE SAÍDA", + "stderr": "STDERR", + "file_empty": "ARQUIVO VAZIO", + "file_no_data": "O arquivo não contém dados" + } +} diff --git a/hyprland-cheatsheet/i18n/ru.json b/hyprland-cheatsheet/i18n/ru.json new file mode 100644 index 0000000..21174b8 --- /dev/null +++ b/hyprland-cheatsheet/i18n/ru.json @@ -0,0 +1,23 @@ +{ + "panel": { + "title": "Шпаргалка", + "loading": "Загрузка...", + "error_read_file": "Ошибка чтения файла", + "no_data": "Нет данных", + "refresh_button": "Обновить", + "no_description": "Нет описания", + "no_categories": "Категории не найдены", + "workspace_switching": "РАБОЧИЕ ОБЛАСТИ - ПЕРЕКЛЮЧЕНИЕ", + "workspace_moving": "РАБОЧИЕ ОБЛАСТИ - ПЕРЕМЕЩЕНИЕ", + "workspace_mouse": "РАБОЧИЕ ОБЛАСТИ - МЫШЬ" + }, + "main": { + "error": "ОШИБКА", + "cannot_get_home": "Не удается получить $HOME", + "read_error": "ОШИБКА ЧТЕНИЯ", + "exit_code": "КОД ВЫХОДА", + "stderr": "STDERR", + "file_empty": "ФАЙЛ ПУСТ", + "file_no_data": "Файл не содержит данных" + } +} diff --git a/hyprland-cheatsheet/i18n/tr.json b/hyprland-cheatsheet/i18n/tr.json new file mode 100644 index 0000000..3dc0939 --- /dev/null +++ b/hyprland-cheatsheet/i18n/tr.json @@ -0,0 +1,23 @@ +{ + "panel": { + "title": "Kopya Kağıdı", + "loading": "Yükleniyor...", + "error_read_file": "Dosya okuma hatası", + "no_data": "Veri yok", + "refresh_button": "Yenile", + "no_description": "Açıklama yok", + "no_categories": "Kategori bulunamadı", + "workspace_switching": "ÇALIŞMA ALANLARI - DEĞİŞTİRME", + "workspace_moving": "ÇALIŞMA ALANLARI - TAŞIMA", + "workspace_mouse": "ÇALIŞMA ALANLARI - FARE" + }, + "main": { + "error": "HATA", + "cannot_get_home": "$HOME alınamıyor", + "read_error": "OKUMA HATASI", + "exit_code": "ÇIKIŞ KODU", + "stderr": "STDERR", + "file_empty": "DOSYA BOŞ", + "file_no_data": "Dosya veri içermiyor" + } +} diff --git a/hyprland-cheatsheet/i18n/uk-UA.json b/hyprland-cheatsheet/i18n/uk-UA.json new file mode 100644 index 0000000..02ab2b1 --- /dev/null +++ b/hyprland-cheatsheet/i18n/uk-UA.json @@ -0,0 +1,23 @@ +{ + "panel": { + "title": "Шпаргалка", + "loading": "Завантаження...", + "error_read_file": "Помилка читання файлу", + "no_data": "Немає даних", + "refresh_button": "Оновити", + "no_description": "Немає опису", + "no_categories": "Категорії не знайдено", + "workspace_switching": "РОБОЧІ ОБЛАСТІ - ПЕРЕМИКАННЯ", + "workspace_moving": "РОБОЧІ ОБЛАСТІ - ПЕРЕМІЩЕННЯ", + "workspace_mouse": "РОБОЧІ ОБЛАСТІ - МИША" + }, + "main": { + "error": "ПОМИЛКА", + "cannot_get_home": "Не вдається отримати $HOME", + "read_error": "ПОМИЛКА ЧИТАННЯ", + "exit_code": "КОД ВИХОДУ", + "stderr": "STDERR", + "file_empty": "ФАЙЛ ПОРОЖНІЙ", + "file_no_data": "Файл не містить даних" + } +} diff --git a/hyprland-cheatsheet/i18n/zh-CN.json b/hyprland-cheatsheet/i18n/zh-CN.json new file mode 100644 index 0000000..2a4e345 --- /dev/null +++ b/hyprland-cheatsheet/i18n/zh-CN.json @@ -0,0 +1,23 @@ +{ + "panel": { + "title": "速查表", + "loading": "加载中...", + "error_read_file": "文件读取错误", + "no_data": "无数据", + "refresh_button": "刷新", + "no_description": "无描述", + "no_categories": "未找到类别", + "workspace_switching": "工作区 - 切换", + "workspace_moving": "工作区 - 移动", + "workspace_mouse": "工作区 - 鼠标" + }, + "main": { + "error": "错误", + "cannot_get_home": "无法获取 $HOME", + "read_error": "读取错误", + "exit_code": "退出代码", + "stderr": "STDERR", + "file_empty": "文件为空", + "file_no_data": "文件不包含数据" + } +} diff --git a/hyprland-cheatsheet/manifest.json b/hyprland-cheatsheet/manifest.json new file mode 100644 index 0000000..b03fdc5 --- /dev/null +++ b/hyprland-cheatsheet/manifest.json @@ -0,0 +1,22 @@ +{ + "id": "hyprland-cheatsheet", + "name": "Keybind Cheatsheet (Hyprland)", + "version": "1.1.0", + "minNoctaliaVersion": "3.6.0", + "author": "blacku", + "license": "MIT", + "description": "Dynamic keyboard shortcuts cheatsheet that reads and displays Hyprland keybindings. Requires Hyprland window manager.", + "entryPoints": { + "main": "Main.qml", + "barWidget": "BarWidget.qml", + "panel": "Panel.qml" + }, + "dependencies": { + "plugins": [] + }, + "metadata": { + "defaultSettings": { + "parsedData": [] + } + } +} diff --git a/hyprland-cheatsheet/settings.json b/hyprland-cheatsheet/settings.json new file mode 100644 index 0000000..cb8783b --- /dev/null +++ b/hyprland-cheatsheet/settings.json @@ -0,0 +1,13 @@ +{ + "cheatsheetData": [ + { + "title": "BŁĄD", + "binds": [ + { + "keys": "ERROR", + "desc": "Nie można pobrać $HOME" + } + ] + } + ] +} diff --git a/hyprland-steam-overlay/BarWidget.qml b/hyprland-steam-overlay/BarWidget.qml new file mode 100644 index 0000000..d3e2f84 --- /dev/null +++ b/hyprland-steam-overlay/BarWidget.qml @@ -0,0 +1,174 @@ +import QtQuick +import QtQuick.Layouts +import Quickshell +import Quickshell.Io +import qs.Commons +import qs.Widgets + +Rectangle { + id: root + + property var pluginApi: null + property ShellScreen screen + property string widgetId: "" + property string section: "" + + implicitWidth: barIsVertical ? Style.capsuleHeight : contentRow.implicitWidth + Style.marginM * 2 + implicitHeight: Style.capsuleHeight + + property bool hasNewMessages: pluginApi?.pluginSettings?.hasNewMessages || false + property bool steamRunning: false + + readonly property string barPosition: Settings.data.bar.position || "top" + readonly property bool barIsVertical: barPosition === "left" || barPosition === "right" + + color: Style.capsuleColor + radius: Style.radiusL + + // Process to check Steam status + Process { + id: checkSteamProcess + command: ["pidof", "steam"] + running: false + + onExited: (exitCode, exitStatus) => { + steamRunning = (exitCode === 0); + } + } + + // Update steam status periodically + Timer { + interval: 5000 + repeat: true + running: true + onTriggered: { + checkSteamProcess.running = true; + } + } + + Component.onCompleted: { + checkSteamProcess.running = true; + } + + RowLayout { + id: contentRow + anchors.centerIn: parent + spacing: Style.marginS + + Item { + implicitWidth: 24 + implicitHeight: 24 + + // Steam icon - using stacked rectangles to create Steam-like logo + Item { + id: steamIcon + anchors.centerIn: parent + width: 20 + height: 20 + + // Simple Steam-inspired icon using rectangles + Rectangle { + anchors.centerIn: parent + width: 20 + height: 20 + color: "transparent" + border.color: steamRunning ? Color.mPrimary : (mouseArea.containsMouse ? Color.mOnHover : Color.mOnSurface) + border.width: 2 + radius: 10 + + // Inner circles for Steam logo effect + Rectangle { + anchors.centerIn: parent + anchors.horizontalCenterOffset: -4 + anchors.verticalCenterOffset: 2 + width: 6 + height: 6 + radius: 3 + color: steamRunning ? Color.mPrimary : (mouseArea.containsMouse ? Color.mOnHover : Color.mOnSurface) + } + + Rectangle { + anchors.centerIn: parent + anchors.horizontalCenterOffset: 4 + anchors.verticalCenterOffset: 2 + width: 4 + height: 4 + radius: 2 + color: steamRunning ? Color.mPrimary : (mouseArea.containsMouse ? Color.mOnHover : Color.mOnSurface) + } + + Rectangle { + anchors.top: parent.top + anchors.horizontalCenter: parent.horizontalCenter + anchors.topMargin: 4 + width: 8 + height: 8 + radius: 4 + color: steamRunning ? Color.mPrimary : (mouseArea.containsMouse ? Color.mOnHover : Color.mOnSurface) + } + } + + // Notification dot + Rectangle { + visible: hasNewMessages + anchors.top: parent.top + anchors.right: parent.right + width: 8 + height: 8 + radius: 4 + color: "#F44336" + border.color: Color.mSurface + border.width: 1 + + SequentialAnimation on opacity { + loops: Animation.Infinite + running: hasNewMessages + + NumberAnimation { + from: 1.0 + to: 0.3 + duration: 800 + easing.type: Easing.InOutQuad + } + NumberAnimation { + from: 0.3 + to: 1.0 + duration: 800 + easing.type: Easing.InOutQuad + } + } + } + } + } + + } + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + + onEntered: { + root.color = Color.mHover; + } + + onExited: { + root.color = Style.capsuleColor; + } + + onClicked: { + if (pluginApi) { + console.log("BarWidget: Calling Steam overlay toggle"); + // Use direct IPC call + var ipc = Qt.createQmlObject(' + import Quickshell.Io + Process { + command: ["qs", "ipc", "-c", "noctalia-shell", "call", "plugin:hyprland-steam-overlay", "toggle"] + running: true + } + ', root, "ipcProcess"); + } + } + } +} diff --git a/hyprland-steam-overlay/Main.qml b/hyprland-steam-overlay/Main.qml new file mode 100644 index 0000000..ff5197f --- /dev/null +++ b/hyprland-steam-overlay/Main.qml @@ -0,0 +1,230 @@ +import QtQuick +import Quickshell +import Quickshell.Io + +Item { + id: root + property var pluginApi: null + + property bool steamRunning: false + property bool overlayActive: false + property var steamWindows: [] + + // Auto-detect screen resolution + property int screenWidth: 3440 // Default, will be updated + property int screenHeight: 1440 // Default, will be updated + + // Percentage-based layout (10% / 60% / 25% + gaps) + property int gapSize: 10 + property int topMargin: screenHeight * 0.025 // 2.5% top + property int windowHeight: screenHeight * 0.95 // 95% height + + property int friendsWidth: (screenWidth * 0.10) - gapSize + property int mainWidth: (screenWidth * 0.60) - (gapSize * 2) + property int chatWidth: (screenWidth * 0.25) - gapSize + + // Calculate center offset for horizontal centering + property int totalWidth: friendsWidth + gapSize + mainWidth + gapSize + chatWidth + property int centerOffset: (screenWidth - totalWidth) / 2 + + onPluginApiChanged: { + if (pluginApi) { + console.log("SteamOverlay:", pluginApi?.tr("main.plugin_loaded")); + checkSteam.running = true; + } + } + + Component.onCompleted: { + if (pluginApi) { + checkSteam.running = true; + } + detectResolution.running = true; + monitorTimer.start(); + } + + // Check if Steam is running + Process { + id: checkSteam + command: ["pidof", "steam"] + running: false + + onExited: (exitCode, exitStatus) => { + steamRunning = (exitCode === 0); + } + } + + // Launch Steam + Process { + id: launchSteam + command: ["steam", "steam://open/main"] + running: false + + onExited: (exitCode, exitStatus) => { + console.log("SteamOverlay:", pluginApi?.tr("main.steam_launched")); + } + } + + // Detect screen resolution + Process { + id: detectResolution + command: ["bash", "-c", "hyprctl monitors -j | jq -r '.[0] | \"\\(.width) \\(.height)\"'"] + running: false + + stdout: SplitParser { + onRead: data => { + var parts = data.trim().split(" "); + if (parts.length === 2) { + screenWidth = parseInt(parts[0]); + screenHeight = parseInt(parts[1]); + var msg = pluginApi?.tr("main.resolution_detected") + .replace("{width}", screenWidth) + .replace("{height}", screenHeight); + console.log("SteamOverlay:", msg); + } + } + } + } + + // Detect Steam windows + Process { + id: detectWindows + command: ["bash", "-c", "hyprctl clients -j | jq -c '.[] | select(.class == \"steam\") | {address: .address, title: .title, x: .at[0], y: .at[1], w: .size[0], h: .size[1]}'"] + running: false + + property var lines: [] + + stdout: SplitParser { + onRead: data => { + detectWindows.lines.push(data.trim()); + } + } + + onExited: (exitCode, exitStatus) => { + if (exitCode === 0 && lines.length > 0) { + steamWindows = lines.map(line => JSON.parse(line)); + var msg = pluginApi?.tr("main.windows_found").replace("{count}", steamWindows.length); + console.log("SteamOverlay:", msg); + lines = []; + } + } + } + + // Move and position windows + Process { + id: moveWindows + command: ["bash", "-c", ""] + running: false + + onExited: (exitCode, exitStatus) => { + var msg = pluginApi?.tr("main.windows_moved").replace("{code}", exitCode); + console.log("SteamOverlay:", msg); + if (exitCode === 0) { + // Show the special workspace + showWorkspace.running = true; + } + } + } + + // Show special workspace + Process { + id: showWorkspace + command: ["hyprctl", "dispatch", "togglespecialworkspace", "steam"] + running: false + + onExited: (exitCode, exitStatus) => { + console.log("SteamOverlay:", pluginApi?.tr("main.workspace_toggled")); + } + } + + // Timer to monitor Steam + Timer { + id: monitorTimer + interval: 3000 + repeat: true + running: false + + onTriggered: { + checkSteam.running = true; + } + } + + function toggleOverlay() { + console.log("SteamOverlay:", pluginApi?.tr("main.toggle_called")); + + if (!steamRunning) { + console.log("SteamOverlay:", pluginApi?.tr("main.launching_steam")); + launchSteam.running = true; + return; + } + + if (overlayActive) { + // Hide overlay + showWorkspace.running = true; + overlayActive = false; + } else { + // Show overlay - detect and move windows + detectWindows.running = true; + + // Wait for detection to complete, then move windows + Qt.callLater(() => { + if (steamWindows.length > 0) { + moveWindowsToOverlay(); + } else { + console.log("SteamOverlay:", pluginApi?.tr("main.no_windows_found")); + } + }); + + overlayActive = true; + } + } + + function moveWindowsToOverlay() { + var commands = []; + + for (var i = 0; i < steamWindows.length; i++) { + var win = steamWindows[i]; + var addr = win.address; + var title = win.title; + + // Move to special workspace + commands.push("hyprctl dispatch movetoworkspacesilent special:steam,address:" + addr); + + // Position based on title with percentage layout + center offset + var x = 0, y = topMargin, w = 800, h = windowHeight; + + if (title === "Steam") { + // Main window: center + friends + gap + x = centerOffset + friendsWidth + gapSize; + w = mainWidth; + } else if (title === "Friends List") { + // Friends: center offset (left side) + x = centerOffset; + w = friendsWidth; + } else { + // Chat: center + friends + gap + main + gap + x = centerOffset + friendsWidth + gapSize + mainWidth + gapSize; + w = chatWidth; + } + + // Set floating first, then position and size + commands.push("hyprctl dispatch setfloating address:" + addr); + commands.push("hyprctl dispatch resizewindowpixel exact " + w + " " + h + ",address:" + addr); + commands.push("hyprctl dispatch movewindowpixel exact " + x + " " + y + ",address:" + addr); + } + + if (commands.length > 0) { + moveWindows.command = ["bash", "-c", commands.join(" && ")]; + moveWindows.running = true; + } + } + + // IPC Handler + IpcHandler { + target: "plugin:hyprland-steam-overlay" + + function toggle() { + console.log("SteamOverlay:", pluginApi?.tr("main.ipc_received")); + root.toggleOverlay(); + } + } +} diff --git a/hyprland-steam-overlay/Panel.qml b/hyprland-steam-overlay/Panel.qml new file mode 100644 index 0000000..111d778 --- /dev/null +++ b/hyprland-steam-overlay/Panel.qml @@ -0,0 +1,171 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell +import qs.Commons +import qs.Widgets + +Item { + id: root + property var pluginApi: null + property real contentPreferredWidth: 3440 + property real contentPreferredHeight: 1080 + readonly property var geometryPlaceholder: panelContainer + readonly property bool allowAttach: false + readonly property bool panelAnchorHorizontalCenter: true + readonly property bool panelAnchorTop: true + anchors.fill: parent + + // Semi-transparent background + Rectangle { + id: panelContainer + anchors.fill: parent + color: "transparent" + + // Top bar with status and close button + Rectangle { + id: topBar + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + height: 40 + color: Color.mSurfaceVariant + opacity: 0.95 + + RowLayout { + anchors.fill: parent + anchors.leftMargin: Style.marginM + anchors.rightMargin: Style.marginM + spacing: Style.marginM + + NIcon { + icon: "steam" + pointSize: Style.fontSizeL + color: Color.mPrimary + } + + NText { + text: "Steam Overlay" + font.pointSize: Style.fontSizeM + font.weight: Font.Bold + color: Color.mOnSurface + } + + Item { + Layout.fillWidth: true + } + + // Steam status indicator + RowLayout { + spacing: Style.marginS + + Rectangle { + width: 10 + height: 10 + radius: 5 + color: steamRunning ? "#4CAF50" : "#F44336" + } + + NText { + text: steamRunning ? "Steam Running" : "Steam Stopped" + font.pointSize: Style.fontSizeS + color: Color.mOnSurface + } + } + + // Close button + NButton { + text: "Zamknij (ESC)" + onClicked: { + if (pluginApi) { + pluginApi.closePanel(); + } + } + } + } + } + + // Window layout guide (semi-transparent overlays showing where windows should be) + Row { + anchors.top: topBar.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + spacing: 0 + + // Friends List area + Rectangle { + width: friendsWidth + height: parent.height + color: "#1976D2" + opacity: 0.1 + border.color: Color.mPrimary + border.width: 2 + + NText { + anchors.centerIn: parent + text: "Friends List\n" + friendsWidth + "px" + font.pointSize: Style.fontSizeL + color: Color.mPrimary + horizontalAlignment: Text.AlignHCenter + opacity: 0.5 + } + } + + // Main Steam area + Rectangle { + width: mainWidth + height: parent.height + color: "#388E3C" + opacity: 0.1 + border.color: Color.mSecondary + border.width: 2 + + NText { + anchors.centerIn: parent + text: "Main Steam\n" + mainWidth + "px" + font.pointSize: Style.fontSizeL + color: Color.mSecondary + horizontalAlignment: Text.AlignHCenter + opacity: 0.5 + } + } + + // Chat area + Rectangle { + width: chatWidth + height: parent.height + color: "#D32F2F" + opacity: 0.1 + border.color: Color.mTertiary + border.width: 2 + + NText { + anchors.centerIn: parent + text: "Steam Chat\n" + chatWidth + "px" + font.pointSize: Style.fontSizeL + color: Color.mTertiary + horizontalAlignment: Text.AlignHCenter + opacity: 0.5 + } + } + } + } + + // Settings + property bool steamRunning: false + property int friendsWidth: pluginApi?.pluginSettings?.friendsWidth || 375 + property int mainWidth: pluginApi?.pluginSettings?.mainWidth || 2600 + property int chatWidth: pluginApi?.pluginSettings?.chatWidth || 465 + + // Keyboard shortcut to close + Keys.onEscapePressed: { + if (pluginApi) { + pluginApi.closePanel(); + } + } + + Component.onCompleted: { + forceActiveFocus(); + } +} diff --git a/hyprland-steam-overlay/README.md b/hyprland-steam-overlay/README.md new file mode 100644 index 0000000..6ec82e4 --- /dev/null +++ b/hyprland-steam-overlay/README.md @@ -0,0 +1,94 @@ +# Steam Overlay for Noctalia + +Steam overlay plugin for Noctalia/Quickshell with automatic window management using Hyprland special workspace. + +## Features + +- 🎮 **Automatic Steam window detection** and positioning +- 🖥️ **Multi-monitor support** with automatic resolution detection +- 📐 **Responsive layout**: 10% / 60% / 25% split (Friends / Main / Chat) +- 🎯 **Centered overlay** with 95% screen height +- 🔔 **Chat notifications** indicator +- ⌨️ **Keyboard shortcut** support via IPC +- 🎨 **Bar widget** with Steam status indicator + +## Installation + +1. Copy the plugin to your Noctalia plugins directory: +```bash +cp -r steam-overlay ~/.config/noctalia/plugins/ +``` + +2. Restart Quickshell: +```bash +pkill -f "qs.*noctalia" && qs -c noctalia-shell & +``` + +## Usage + +### Via Bar Widget +Click the gamepad icon in your top bar to toggle the Steam overlay. + +### Via Keyboard Shortcut +Add to your Hyprland config (`~/.config/hypr/hyprland.conf`): +``` +bind = SUPER, G, exec, qs ipc -c noctalia-shell call plugin:steam-overlay toggle +``` + +### Via IPC Command +```bash +qs ipc -c noctalia-shell call plugin:steam-overlay toggle +``` + +## How It Works + +1. **Detection**: Automatically detects Steam windows by class and title +2. **Workspace**: Moves all Steam windows to Hyprland special workspace `special:steam` +3. **Positioning**: Arranges windows in a centered layout: + - Friends List: 10% width (left) + - Main Steam: 60% width (center) + - Chat: 25% width (right) +4. **Toggle**: Shows/hides the special workspace as an overlay + +## Layout + +``` +┌─────────────────────────────────────────┐ +│ [Friends] [ Main Steam ] [Chat] │ 95% height +│ 10% 60% 25% │ Centered +└─────────────────────────────────────────┘ +``` + +## Configuration + +Default settings in `settings.json`: +```json +{ + "autoLaunchSteam": true, + "hasNewMessages": false +} +``` + +## Requirements + +- Noctalia/Quickshell 3.6.0+ +- Hyprland compositor +- Steam +- `jq` for JSON parsing +- `hyprctl` for window management + +## Files + +- `Main.qml` - Core plugin logic +- `BarWidget.qml` - Top bar widget with icon +- `Panel.qml` - Overlay panel (optional) +- `manifest.json` - Plugin metadata +- `settings.json` - Plugin settings + +## Author + +Created with ❤️ using Claude Code + +## License + +MIT diff --git a/hyprland-steam-overlay/i18n/de.json b/hyprland-steam-overlay/i18n/de.json new file mode 100644 index 0000000..94336ac --- /dev/null +++ b/hyprland-steam-overlay/i18n/de.json @@ -0,0 +1,25 @@ +{ + "main": { + "plugin_loaded": "Plugin-API geladen", + "resolution_detected": "Auflösung erkannt: {width} x {height}", + "windows_found": "{count} Steam-Fenster gefunden", + "windows_moved": "Fenster verschoben, Exit-Code: {code}", + "workspace_toggled": "Arbeitsbereich umgeschaltet", + "toggle_called": "Umschaltung aufgerufen", + "launching_steam": "Steam wird gestartet...", + "steam_launched": "Steam gestartet", + "no_windows_found": "Keine Steam-Fenster gefunden", + "ipc_received": "IPC-Umschaltung empfangen" + }, + "bar_widget": { + "tooltip": "Steam-Overlay", + "tooltip_active": "Steam-Overlay (Aktiv)", + "tooltip_inactive": "Steam-Overlay (Klicken zum Aktivieren)" + }, + "notifications": { + "steam_launching": "Steam wird gestartet...", + "steam_not_running": "Steam läuft nicht", + "overlay_shown": "Steam-Overlay angezeigt", + "overlay_hidden": "Steam-Overlay ausgeblendet" + } +} diff --git a/hyprland-steam-overlay/i18n/en.json b/hyprland-steam-overlay/i18n/en.json new file mode 100644 index 0000000..b100095 --- /dev/null +++ b/hyprland-steam-overlay/i18n/en.json @@ -0,0 +1,25 @@ +{ + "main": { + "plugin_loaded": "Plugin API loaded", + "resolution_detected": "Detected resolution: {width} x {height}", + "windows_found": "Found {count} Steam windows", + "windows_moved": "Windows moved, exit code: {code}", + "workspace_toggled": "Workspace toggled", + "toggle_called": "Toggle called", + "launching_steam": "Launching Steam...", + "steam_launched": "Steam launched", + "no_windows_found": "No Steam windows found", + "ipc_received": "IPC toggle received" + }, + "bar_widget": { + "tooltip": "Steam Overlay", + "tooltip_active": "Steam Overlay (Active)", + "tooltip_inactive": "Steam Overlay (Click to activate)" + }, + "notifications": { + "steam_launching": "Launching Steam...", + "steam_not_running": "Steam is not running", + "overlay_shown": "Steam overlay shown", + "overlay_hidden": "Steam overlay hidden" + } +} diff --git a/hyprland-steam-overlay/i18n/es.json b/hyprland-steam-overlay/i18n/es.json new file mode 100644 index 0000000..70ccbcd --- /dev/null +++ b/hyprland-steam-overlay/i18n/es.json @@ -0,0 +1,25 @@ +{ + "main": { + "plugin_loaded": "API del plugin cargada", + "resolution_detected": "Resolución detectada: {width} x {height}", + "windows_found": "Se encontraron {count} ventanas de Steam", + "windows_moved": "Ventanas movidas, código de salida: {code}", + "workspace_toggled": "Espacio de trabajo alternado", + "toggle_called": "Alternancia llamada", + "launching_steam": "Iniciando Steam...", + "steam_launched": "Steam iniciado", + "no_windows_found": "No se encontraron ventanas de Steam", + "ipc_received": "Alternancia IPC recibida" + }, + "bar_widget": { + "tooltip": "Superposición de Steam", + "tooltip_active": "Superposición de Steam (Activa)", + "tooltip_inactive": "Superposición de Steam (Clic para activar)" + }, + "notifications": { + "steam_launching": "Iniciando Steam...", + "steam_not_running": "Steam no está en ejecución", + "overlay_shown": "Superposición de Steam mostrada", + "overlay_hidden": "Superposición de Steam ocultada" + } +} diff --git a/hyprland-steam-overlay/i18n/fr.json b/hyprland-steam-overlay/i18n/fr.json new file mode 100644 index 0000000..5db129e --- /dev/null +++ b/hyprland-steam-overlay/i18n/fr.json @@ -0,0 +1,25 @@ +{ + "main": { + "plugin_loaded": "API du plugin chargée", + "resolution_detected": "Résolution détectée: {width} x {height}", + "windows_found": "{count} fenêtres Steam trouvées", + "windows_moved": "Fenêtres déplacées, code de sortie: {code}", + "workspace_toggled": "Espace de travail basculé", + "toggle_called": "Basculement appelé", + "launching_steam": "Lancement de Steam...", + "steam_launched": "Steam lancé", + "no_windows_found": "Aucune fenêtre Steam trouvée", + "ipc_received": "Basculement IPC reçu" + }, + "bar_widget": { + "tooltip": "Superposition Steam", + "tooltip_active": "Superposition Steam (Active)", + "tooltip_inactive": "Superposition Steam (Cliquer pour activer)" + }, + "notifications": { + "steam_launching": "Lancement de Steam...", + "steam_not_running": "Steam n'est pas en cours d'exécution", + "overlay_shown": "Superposition Steam affichée", + "overlay_hidden": "Superposition Steam masquée" + } +} diff --git a/hyprland-steam-overlay/i18n/it.json b/hyprland-steam-overlay/i18n/it.json new file mode 100644 index 0000000..dce0ca9 --- /dev/null +++ b/hyprland-steam-overlay/i18n/it.json @@ -0,0 +1,25 @@ +{ + "main": { + "plugin_loaded": "API del plugin caricata", + "resolution_detected": "Risoluzione rilevata: {width} x {height}", + "windows_found": "Trovate {count} finestre Steam", + "windows_moved": "Finestre spostate, codice di uscita: {code}", + "workspace_toggled": "Area di lavoro alternata", + "toggle_called": "Alternanza chiamata", + "launching_steam": "Avvio di Steam...", + "steam_launched": "Steam avviato", + "no_windows_found": "Nessuna finestra Steam trovata", + "ipc_received": "Alternanza IPC ricevuta" + }, + "bar_widget": { + "tooltip": "Sovrapposizione Steam", + "tooltip_active": "Sovrapposizione Steam (Attiva)", + "tooltip_inactive": "Sovrapposizione Steam (Clicca per attivare)" + }, + "notifications": { + "steam_launching": "Avvio di Steam...", + "steam_not_running": "Steam non è in esecuzione", + "overlay_shown": "Sovrapposizione Steam mostrata", + "overlay_hidden": "Sovrapposizione Steam nascosta" + } +} diff --git a/hyprland-steam-overlay/i18n/ja.json b/hyprland-steam-overlay/i18n/ja.json new file mode 100644 index 0000000..f80f714 --- /dev/null +++ b/hyprland-steam-overlay/i18n/ja.json @@ -0,0 +1,25 @@ +{ + "main": { + "plugin_loaded": "プラグインAPIが読み込まれました", + "resolution_detected": "解像度を検出:{width} x {height}", + "windows_found": "{count}個のSteamウィンドウが見つかりました", + "windows_moved": "ウィンドウを移動、終了コード:{code}", + "workspace_toggled": "ワークスペースを切り替えました", + "toggle_called": "トグルが呼び出されました", + "launching_steam": "Steamを起動中...", + "steam_launched": "Steamを起動しました", + "no_windows_found": "Steamウィンドウが見つかりません", + "ipc_received": "IPCトグルを受信しました" + }, + "bar_widget": { + "tooltip": "Steamオーバーレイ", + "tooltip_active": "Steamオーバーレイ(アクティブ)", + "tooltip_inactive": "Steamオーバーレイ(クリックして有効化)" + }, + "notifications": { + "steam_launching": "Steamを起動中...", + "steam_not_running": "Steamが実行されていません", + "overlay_shown": "Steamオーバーレイを表示しました", + "overlay_hidden": "Steamオーバーレイを非表示にしました" + } +} diff --git a/hyprland-steam-overlay/i18n/nl.json b/hyprland-steam-overlay/i18n/nl.json new file mode 100644 index 0000000..98ef6fa --- /dev/null +++ b/hyprland-steam-overlay/i18n/nl.json @@ -0,0 +1,25 @@ +{ + "main": { + "plugin_loaded": "Plugin-API geladen", + "resolution_detected": "Resolutie gedetecteerd: {width} x {height}", + "windows_found": "{count} Steam-vensters gevonden", + "windows_moved": "Vensters verplaatst, afsluitcode: {code}", + "workspace_toggled": "Werkruimte gewisseld", + "toggle_called": "Wisselen aangeroepen", + "launching_steam": "Steam wordt gestart...", + "steam_launched": "Steam gestart", + "no_windows_found": "Geen Steam-vensters gevonden", + "ipc_received": "IPC-wisseling ontvangen" + }, + "bar_widget": { + "tooltip": "Steam-overlay", + "tooltip_active": "Steam-overlay (Actief)", + "tooltip_inactive": "Steam-overlay (Klik om te activeren)" + }, + "notifications": { + "steam_launching": "Steam wordt gestart...", + "steam_not_running": "Steam is niet actief", + "overlay_shown": "Steam-overlay getoond", + "overlay_hidden": "Steam-overlay verborgen" + } +} diff --git a/hyprland-steam-overlay/i18n/pl.json b/hyprland-steam-overlay/i18n/pl.json new file mode 100644 index 0000000..e385768 --- /dev/null +++ b/hyprland-steam-overlay/i18n/pl.json @@ -0,0 +1,25 @@ +{ + "main": { + "plugin_loaded": "API pluginu załadowane", + "resolution_detected": "Wykryto rozdzielczość: {width} x {height}", + "windows_found": "Znaleziono {count} okien Steam", + "windows_moved": "Okna przeniesione, kod wyjścia: {code}", + "workspace_toggled": "Przestrzeń robocza przełączona", + "toggle_called": "Wywołano przełącznik", + "launching_steam": "Uruchamianie Steam...", + "steam_launched": "Steam uruchomiony", + "no_windows_found": "Nie znaleziono okien Steam", + "ipc_received": "Otrzymano przełącznik IPC" + }, + "bar_widget": { + "tooltip": "Nakładka Steam", + "tooltip_active": "Nakładka Steam (Aktywna)", + "tooltip_inactive": "Nakładka Steam (Kliknij aby aktywować)" + }, + "notifications": { + "steam_launching": "Uruchamianie Steam...", + "steam_not_running": "Steam nie jest uruchomiony", + "overlay_shown": "Nakładka Steam pokazana", + "overlay_hidden": "Nakładka Steam ukryta" + } +} diff --git a/hyprland-steam-overlay/i18n/pt.json b/hyprland-steam-overlay/i18n/pt.json new file mode 100644 index 0000000..b10aa87 --- /dev/null +++ b/hyprland-steam-overlay/i18n/pt.json @@ -0,0 +1,25 @@ +{ + "main": { + "plugin_loaded": "API do plugin carregada", + "resolution_detected": "Resolução detectada: {width} x {height}", + "windows_found": "{count} janelas do Steam encontradas", + "windows_moved": "Janelas movidas, código de saída: {code}", + "workspace_toggled": "Espaço de trabalho alternado", + "toggle_called": "Alternância chamada", + "launching_steam": "Iniciando Steam...", + "steam_launched": "Steam iniciado", + "no_windows_found": "Nenhuma janela do Steam encontrada", + "ipc_received": "Alternância IPC recebida" + }, + "bar_widget": { + "tooltip": "Sobreposição do Steam", + "tooltip_active": "Sobreposição do Steam (Ativa)", + "tooltip_inactive": "Sobreposição do Steam (Clique para ativar)" + }, + "notifications": { + "steam_launching": "Iniciando Steam...", + "steam_not_running": "Steam não está em execução", + "overlay_shown": "Sobreposição do Steam mostrada", + "overlay_hidden": "Sobreposição do Steam ocultada" + } +} diff --git a/hyprland-steam-overlay/i18n/ru.json b/hyprland-steam-overlay/i18n/ru.json new file mode 100644 index 0000000..2c19d50 --- /dev/null +++ b/hyprland-steam-overlay/i18n/ru.json @@ -0,0 +1,25 @@ +{ + "main": { + "plugin_loaded": "API плагина загружен", + "resolution_detected": "Обнаружено разрешение: {width} x {height}", + "windows_found": "Найдено {count} окон Steam", + "windows_moved": "Окна перемещены, код выхода: {code}", + "workspace_toggled": "Рабочее пространство переключено", + "toggle_called": "Переключение вызвано", + "launching_steam": "Запуск Steam...", + "steam_launched": "Steam запущен", + "no_windows_found": "Окна Steam не найдены", + "ipc_received": "Получено переключение IPC" + }, + "bar_widget": { + "tooltip": "Оверлей Steam", + "tooltip_active": "Оверлей Steam (Активен)", + "tooltip_inactive": "Оверлей Steam (Нажмите для активации)" + }, + "notifications": { + "steam_launching": "Запуск Steam...", + "steam_not_running": "Steam не запущен", + "overlay_shown": "Оверлей Steam показан", + "overlay_hidden": "Оверлей Steam скрыт" + } +} diff --git a/hyprland-steam-overlay/i18n/tr.json b/hyprland-steam-overlay/i18n/tr.json new file mode 100644 index 0000000..c826b4b --- /dev/null +++ b/hyprland-steam-overlay/i18n/tr.json @@ -0,0 +1,25 @@ +{ + "main": { + "plugin_loaded": "Eklenti API'si yüklendi", + "resolution_detected": "Çözünürlük algılandı: {width} x {height}", + "windows_found": "{count} Steam penceresi bulundu", + "windows_moved": "Pencereler taşındı, çıkış kodu: {code}", + "workspace_toggled": "Çalışma alanı değiştirildi", + "toggle_called": "Değiştirme çağrıldı", + "launching_steam": "Steam başlatılıyor...", + "steam_launched": "Steam başlatıldı", + "no_windows_found": "Steam penceresi bulunamadı", + "ipc_received": "IPC değiştirme alındı" + }, + "bar_widget": { + "tooltip": "Steam Katmanı", + "tooltip_active": "Steam Katmanı (Aktif)", + "tooltip_inactive": "Steam Katmanı (Etkinleştirmek için tıklayın)" + }, + "notifications": { + "steam_launching": "Steam başlatılıyor...", + "steam_not_running": "Steam çalışmıyor", + "overlay_shown": "Steam katmanı gösterildi", + "overlay_hidden": "Steam katmanı gizlendi" + } +} diff --git a/hyprland-steam-overlay/i18n/uk-UA.json b/hyprland-steam-overlay/i18n/uk-UA.json new file mode 100644 index 0000000..a18e0ff --- /dev/null +++ b/hyprland-steam-overlay/i18n/uk-UA.json @@ -0,0 +1,25 @@ +{ + "main": { + "plugin_loaded": "API плагіна завантажено", + "resolution_detected": "Виявлено роздільну здатність: {width} x {height}", + "windows_found": "Знайдено {count} вікон Steam", + "windows_moved": "Вікна переміщено, код виходу: {code}", + "workspace_toggled": "Робочий простір перемкнуто", + "toggle_called": "Перемикання викликано", + "launching_steam": "Запуск Steam...", + "steam_launched": "Steam запущено", + "no_windows_found": "Вікна Steam не знайдено", + "ipc_received": "Отримано перемикання IPC" + }, + "bar_widget": { + "tooltip": "Оверлей Steam", + "tooltip_active": "Оверлей Steam (Активний)", + "tooltip_inactive": "Оверлей Steam (Натисніть для активації)" + }, + "notifications": { + "steam_launching": "Запуск Steam...", + "steam_not_running": "Steam не запущено", + "overlay_shown": "Оверлей Steam показано", + "overlay_hidden": "Оверлей Steam приховано" + } +} diff --git a/hyprland-steam-overlay/i18n/zh-CN.json b/hyprland-steam-overlay/i18n/zh-CN.json new file mode 100644 index 0000000..e744371 --- /dev/null +++ b/hyprland-steam-overlay/i18n/zh-CN.json @@ -0,0 +1,25 @@ +{ + "main": { + "plugin_loaded": "插件API已加载", + "resolution_detected": "检测到分辨率:{width} x {height}", + "windows_found": "找到 {count} 个Steam窗口", + "windows_moved": "窗口已移动,退出代码:{code}", + "workspace_toggled": "工作区已切换", + "toggle_called": "切换已调用", + "launching_steam": "正在启动Steam...", + "steam_launched": "Steam已启动", + "no_windows_found": "未找到Steam窗口", + "ipc_received": "已接收IPC切换" + }, + "bar_widget": { + "tooltip": "Steam叠加层", + "tooltip_active": "Steam叠加层(活动)", + "tooltip_inactive": "Steam叠加层(点击激活)" + }, + "notifications": { + "steam_launching": "正在启动Steam...", + "steam_not_running": "Steam未运行", + "overlay_shown": "Steam叠加层已显示", + "overlay_hidden": "Steam叠加层已隐藏" + } +} diff --git a/hyprland-steam-overlay/manifest.json b/hyprland-steam-overlay/manifest.json new file mode 100644 index 0000000..1a825b8 --- /dev/null +++ b/hyprland-steam-overlay/manifest.json @@ -0,0 +1,27 @@ +{ + "id": "hyprland-steam-overlay", + "name": "Steam Overlay (Hyprland)", + "version": "1.4.0", + "minNoctaliaVersion": "3.6.0", + "author": "blacku", + "license": "MIT", + "description": "Steam overlay with automatic window management and chat notifications for Hyprland. Requires Hyprland window manager.", + "entryPoints": { + "main": "Main.qml", + "barWidget": "BarWidget.qml", + "panel": "Panel.qml" + }, + "dependencies": { + "plugins": [] + }, + "metadata": { + "defaultSettings": { + "friendsWidth": 375, + "mainWidth": 2600, + "chatWidth": 465, + "screenWidth": 3440, + "hasNewMessages": false, + "autoLaunchSteam": true + } + } +} diff --git a/hyprland-steam-overlay/preview.png b/hyprland-steam-overlay/preview.png new file mode 100644 index 0000000..0a43ec8 Binary files /dev/null and b/hyprland-steam-overlay/preview.png differ diff --git a/hyprland-steam-overlay/settings.json b/hyprland-steam-overlay/settings.json new file mode 100644 index 0000000..e8fc5e4 --- /dev/null +++ b/hyprland-steam-overlay/settings.json @@ -0,0 +1,8 @@ +{ + "friendsWidth": 375, + "mainWidth": 2600, + "chatWidth": 465, + "screenWidth": 3440, + "hasNewMessages": false, + "autoLaunchSteam": true +}