pax_global_header00006660000000000000000000000064152273516170014523gustar00rootroot0000000000000052 comment=a16ad89ed5fb4192c966018a80c652de8d96f748 hyprwm-hyprland-guiutils-a16ad89/000077500000000000000000000000001522735161700171525ustar00rootroot00000000000000hyprwm-hyprland-guiutils-a16ad89/.clang-format000066400000000000000000000034161522735161700215310ustar00rootroot00000000000000--- Language: Cpp BasedOnStyle: LLVM AccessModifierOffset: -2 AlignAfterOpenBracket: Align AlignConsecutiveMacros: true AlignConsecutiveAssignments: true AlignEscapedNewlines: Right AlignOperands: false AlignTrailingComments: true AllowAllArgumentsOnNextLine: true AllowAllConstructorInitializersOnNextLine: true AllowAllParametersOfDeclarationOnNextLine: true AllowShortBlocksOnASingleLine: true AllowShortCaseLabelsOnASingleLine: true AllowShortFunctionsOnASingleLine: Empty AllowShortIfStatementsOnASingleLine: Never AllowShortLambdasOnASingleLine: All AllowShortLoopsOnASingleLine: false AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: false AlwaysBreakTemplateDeclarations: Yes BreakBeforeBraces: Attach BreakBeforeTernaryOperators: false BreakConstructorInitializers: AfterColon ColumnLimit: 180 CompactNamespaces: false ConstructorInitializerAllOnOneLineOrOnePerLine: false ExperimentalAutoDetectBinPacking: false FixNamespaceComments: false IncludeBlocks: Preserve IndentCaseLabels: true IndentWidth: 4 PointerAlignment: Left ReflowComments: false SortIncludes: false SortUsingDeclarations: false SpaceAfterCStyleCast: false SpaceAfterLogicalNot: false SpaceAfterTemplateKeyword: true SpaceBeforeCtorInitializerColon: true SpaceBeforeInheritanceColon: true SpaceBeforeParens: ControlStatements SpaceBeforeRangeBasedForLoopColon: true SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 1 SpacesInAngles: false SpacesInCStyleCastParentheses: false SpacesInContainerLiterals: false SpacesInParentheses: false SpacesInSquareBrackets: false Standard: Auto TabWidth: 4 UseTab: Never AllowShortEnumsOnASingleLine: false BraceWrapping: AfterEnum: false AlignConsecutiveDeclarations: AcrossEmptyLines NamespaceIndentation: All hyprwm-hyprland-guiutils-a16ad89/.github/000077500000000000000000000000001522735161700205125ustar00rootroot00000000000000hyprwm-hyprland-guiutils-a16ad89/.github/workflows/000077500000000000000000000000001522735161700225475ustar00rootroot00000000000000hyprwm-hyprland-guiutils-a16ad89/.github/workflows/nix.yml000066400000000000000000000004611522735161700240710ustar00rootroot00000000000000name: Build on: [push, pull_request, workflow_dispatch] jobs: nix: if: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork) uses: hyprwm/actions/.github/workflows/nix.yml@main secrets: inherit with: command: nix build --print-build-logs --keep-going hyprwm-hyprland-guiutils-a16ad89/.gitignore000066400000000000000000000005141522735161700211420ustar00rootroot00000000000000CMakeLists.txt.user CMakeCache.txt CMakeFiles CMakeScripts Testing cmake_install.cmake install_manifest.txt compile_commands.json CTestTestfile.cmake _deps build/ result /.vscode/ /.idea *.o *-protocol.c *-protocol.h .ccls-cache protocols/*.hpp protocols/*.cpp .cache/ hyprctl/hyprctl gmon.out *.out *.tar.gz .envrc .direnv/ hyprwm-hyprland-guiutils-a16ad89/CMakeLists.txt000066400000000000000000000040751522735161700217200ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.12) file(READ "${CMAKE_SOURCE_DIR}/VERSION" VER_RAW) string(STRIP ${VER_RAW} VERSION) project( hyprland-guiutils DESCRIPTION "Hyprland GUI utilities" VERSION ${VERSION}) set(CMAKE_MESSAGE_LOG_LEVEL "STATUS") message(STATUS "Configuring hyprland-guiutils!") # Get git info hash and branch execute_process( COMMAND git rev-parse --abbrev-ref HEAD WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE GIT_BRANCH OUTPUT_STRIP_TRAILING_WHITESPACE) execute_process( COMMAND git rev-parse HEAD WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE GIT_COMMIT_HASH OUTPUT_STRIP_TRAILING_WHITESPACE) execute_process( COMMAND bash -c "git show ${GIT_COMMIT_HASH} | head -n 5 | tail -n 1 | sed -s 's/\#//g; s/^[[:space:]]*//'" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE GIT_COMMIT_MESSAGE OUTPUT_STRIP_TRAILING_WHITESPACE) execute_process( COMMAND bash -c "git diff-index --quiet HEAD -- || echo \"dirty\"" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE GIT_DIRTY OUTPUT_STRIP_TRAILING_WHITESPACE) include_directories(.) set(CMAKE_CXX_STANDARD 23) add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-unused-value -Wno-missing-field-initializers -Wno-narrowing) add_compile_definitions(GUIUTILS_VERSION="${VERSION}") find_package(Threads REQUIRED) find_package(PkgConfig REQUIRED) if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pg -no-pie -fno-builtin") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pg -no-pie -fno-builtin") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -pg -no-pie -fno-builtin") endif(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG) pkg_check_modules( deps REQUIRED IMPORTED_TARGET hyprlang>=0.6.0 hyprutils>=0.10.2 hyprtoolkit>=0.4.0 pixman-1 xkbcommon libdrm) add_subdirectory(utils/dialog) add_subdirectory(utils/donate-screen) add_subdirectory(utils/update-screen) add_subdirectory(utils/welcome) add_subdirectory(utils/run) hyprwm-hyprland-guiutils-a16ad89/LICENSE000066400000000000000000000027371522735161700201700ustar00rootroot00000000000000BSD 3-Clause License Copyright (c) 2025, Hypr Development Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. hyprwm-hyprland-guiutils-a16ad89/README.md000066400000000000000000000001131522735161700204240ustar00rootroot00000000000000# hyprland-guiutils Hyprland GUI utilities (successor to hyprland-qtutils) hyprwm-hyprland-guiutils-a16ad89/VERSION000066400000000000000000000000061522735161700202160ustar00rootroot000000000000000.2.2 hyprwm-hyprland-guiutils-a16ad89/flake.lock000066400000000000000000000117621522735161700211150ustar00rootroot00000000000000{ "nodes": { "aquamarine": { "inputs": { "hyprutils": [ "hyprutils" ], "hyprwayland-scanner": [ "hyprwayland-scanner" ], "nixpkgs": [ "nixpkgs" ], "systems": [ "systems" ] }, "locked": { "lastModified": 1782073106, "narHash": "sha256-dnS5SaZlPqR1E0dPXaPc+lFkBwLUbAgbwsVMk7uA6dY=", "owner": "hyprwm", "repo": "aquamarine", "rev": "6d6e2384f381def4ea4ea81543cba4bbdac72457", "type": "github" }, "original": { "owner": "hyprwm", "repo": "aquamarine", "type": "github" } }, "hyprgraphics": { "inputs": { "hyprutils": [ "hyprutils" ], "nixpkgs": [ "nixpkgs" ], "systems": [ "systems" ] }, "locked": { "lastModified": 1782311097, "narHash": "sha256-mfcLh1/ZXEhaHE5uNGCSjlmSSQSV14X9PRX/2Cu8YD8=", "owner": "hyprwm", "repo": "hyprgraphics", "rev": "090db94649f25b476918f8afcfd443c02cc0a4b9", "type": "github" }, "original": { "owner": "hyprwm", "repo": "hyprgraphics", "type": "github" } }, "hyprlang": { "inputs": { "hyprutils": [ "hyprutils" ], "nixpkgs": [ "nixpkgs" ], "systems": [ "systems" ] }, "locked": { "lastModified": 1777320127, "narHash": "sha256-Qu+Wf2Bp5qUjyn2YpZNq8a7JyzTGowhT1knrwE38a9U=", "owner": "hyprwm", "repo": "hyprlang", "rev": "090117506ddc3d7f26e650ff344d378c2ec329cc", "type": "github" }, "original": { "owner": "hyprwm", "repo": "hyprlang", "type": "github" } }, "hyprtoolkit": { "inputs": { "aquamarine": [ "aquamarine" ], "hyprgraphics": [ "hyprgraphics" ], "hyprlang": [ "hyprlang" ], "hyprutils": [ "hyprutils" ], "hyprwayland-scanner": [ "hyprwayland-scanner" ], "nixpkgs": [ "nixpkgs" ], "systems": [ "systems" ] }, "locked": { "lastModified": 1782554491, "narHash": "sha256-+p3MlyN/nqRefcf2IckPlGRUn9+hielqpS9XClbLleM=", "owner": "hyprwm", "repo": "hyprtoolkit", "rev": "bdba25ced39ea39ab004a8f31593ba0b0ff1ca35", "type": "github" }, "original": { "owner": "hyprwm", "repo": "hyprtoolkit", "type": "github" } }, "hyprutils": { "inputs": { "nixpkgs": [ "nixpkgs" ], "systems": [ "systems" ] }, "locked": { "lastModified": 1782035033, "narHash": "sha256-pUtCphVzH1iNUTMGdJr4+e/yzUXA6/DZwsn+cyfIVJU=", "owner": "hyprwm", "repo": "hyprutils", "rev": "9d8bf6e810597152eef8906c670b96679af2faec", "type": "github" }, "original": { "owner": "hyprwm", "repo": "hyprutils", "type": "github" } }, "hyprwayland-scanner": { "inputs": { "nixpkgs": [ "nixpkgs" ], "systems": [ "systems" ] }, "locked": { "lastModified": 1777159683, "narHash": "sha256-Jxixw6wZphUp+nHYxOKUYSckL17QMBx2d5Zp0rJHr1g=", "owner": "hyprwm", "repo": "hyprwayland-scanner", "rev": "b8632713a6beaf28b56f2a7b0ab2fb7088dbb404", "type": "github" }, "original": { "owner": "hyprwm", "repo": "hyprwayland-scanner", "type": "github" } }, "nixpkgs": { "locked": { "lastModified": 1782467914, "narHash": "sha256-pGvFkM8N0xEkIIXDe5YYfbEAvHrk4IxBrjB/x8OomhE=", "owner": "NixOS", "repo": "nixpkgs", "rev": "e73de5be04e0eff4190a1432b946d469c794e7b4", "type": "github" }, "original": { "owner": "NixOS", "ref": "nixos-unstable", "repo": "nixpkgs", "type": "github" } }, "root": { "inputs": { "aquamarine": "aquamarine", "hyprgraphics": "hyprgraphics", "hyprlang": "hyprlang", "hyprtoolkit": "hyprtoolkit", "hyprutils": "hyprutils", "hyprwayland-scanner": "hyprwayland-scanner", "nixpkgs": "nixpkgs", "systems": "systems" } }, "systems": { "locked": { "lastModified": 1689347949, "narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=", "owner": "nix-systems", "repo": "default-linux", "rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68", "type": "github" }, "original": { "owner": "nix-systems", "repo": "default-linux", "type": "github" } } }, "root": "root", "version": 7 } hyprwm-hyprland-guiutils-a16ad89/flake.nix000066400000000000000000000047441522735161700207650ustar00rootroot00000000000000{ description = "Hyprland GUI utilities (successor to hyprland-qtutils)"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; systems.url = "github:nix-systems/default-linux"; aquamarine = { url = "github:hyprwm/aquamarine"; inputs = { nixpkgs.follows = "nixpkgs"; systems.follows = "systems"; hyprutils.follows = "hyprutils"; hyprwayland-scanner.follows = "hyprwayland-scanner"; }; }; hyprgraphics = { url = "github:hyprwm/hyprgraphics"; inputs = { nixpkgs.follows = "nixpkgs"; systems.follows = "systems"; hyprutils.follows = "hyprutils"; }; }; hyprlang = { url = "github:hyprwm/hyprlang"; inputs = { nixpkgs.follows = "nixpkgs"; systems.follows = "systems"; hyprutils.follows = "hyprutils"; }; }; hyprutils = { url = "github:hyprwm/hyprutils"; inputs = { nixpkgs.follows = "nixpkgs"; systems.follows = "systems"; }; }; hyprtoolkit = { url = "github:hyprwm/hyprtoolkit"; inputs = { nixpkgs.follows = "nixpkgs"; systems.follows = "systems"; aquamarine.follows = "aquamarine"; hyprgraphics.follows = "hyprgraphics"; hyprlang.follows = "hyprlang"; hyprutils.follows = "hyprutils"; hyprwayland-scanner.follows = "hyprwayland-scanner"; }; }; hyprwayland-scanner = { url = "github:hyprwm/hyprwayland-scanner"; inputs = { nixpkgs.follows = "nixpkgs"; systems.follows = "systems"; }; }; }; outputs = { self, nixpkgs, systems, ... }@inputs: let inherit (nixpkgs) lib; eachSystem = lib.genAttrs (import systems); pkgsFor = eachSystem ( system: import nixpkgs { localSystem = system; overlays = [ self.overlays.hyprland-guiutils-with-deps ]; } ); in { overlays = import ./nix/overlays.nix { inherit inputs self lib; }; packages = eachSystem (system: { default = self.packages.${system}.hyprland-guiutils; inherit (pkgsFor.${system}) hyprland-guiutils; }); devShells = eachSystem (system: { default = import ./nix/shell.nix { pkgs = pkgsFor.${system}; inherit (pkgsFor.${system}) hyprland-guiutils; }; }); formatter = eachSystem (system: pkgsFor.${system}.nixfmt-tree); }; } hyprwm-hyprland-guiutils-a16ad89/nix/000077500000000000000000000000001522735161700177505ustar00rootroot00000000000000hyprwm-hyprland-guiutils-a16ad89/nix/default.nix000066400000000000000000000020351522735161700221140ustar00rootroot00000000000000{ lib, stdenv, cmake, pkg-config, aquamarine, cairo, hyprgraphics, hyprlang, hyprtoolkit, hyprutils, libdrm, libGL, pango, pixman, libxkbcommon, version ? "0", }: let inherit (lib.sources) cleanSource cleanSourceWith; inherit (lib.strings) hasSuffix; in stdenv.mkDerivation { pname = "hyprland-guiutils"; inherit version; src = cleanSourceWith { filter = name: _type: let baseName = baseNameOf (toString name); in !(hasSuffix ".nix" baseName); src = cleanSource ../.; }; nativeBuildInputs = [ cmake pkg-config ]; buildInputs = [ aquamarine cairo hyprgraphics hyprlang hyprtoolkit hyprutils libdrm libGL libxkbcommon pango pixman ]; meta = { description = "Hyprland GUI utilities (successor to hyprland-qtutils)"; homepage = "https://github.com/hyprwm/hyprland-guiutils"; license = lib.licenses.bsd3; maintainers = [ lib.maintainers.fufexan ]; platforms = lib.platforms.linux; }; } hyprwm-hyprland-guiutils-a16ad89/nix/overlays.nix000066400000000000000000000015741522735161700223430ustar00rootroot00000000000000{ inputs, self, lib, }: let mkDate = longDate: (lib.concatStringsSep "-" [ (builtins.substring 0 4 longDate) (builtins.substring 4 2 longDate) (builtins.substring 6 2 longDate) ]); date = mkDate (self.lastModifiedDate or "19700101"); version = lib.removeSuffix "\n" (builtins.readFile ../VERSION); in { default = self.overlays.hyprland-guiutils; hyprland-guiutils-with-deps = lib.composeManyExtensions [ inputs.aquamarine.overlays.default inputs.hyprgraphics.overlays.default inputs.hyprlang.overlays.default inputs.hyprtoolkit.overlays.default inputs.hyprutils.overlays.default self.overlays.hyprland-guiutils ]; hyprland-guiutils = final: prev: { hyprland-guiutils = final.callPackage ./. { stdenv = final.gcc15Stdenv; version = "${version}+date=${date}_${self.shortRev or "dirty"}"; }; }; } hyprwm-hyprland-guiutils-a16ad89/nix/shell.nix000066400000000000000000000015531522735161700216030ustar00rootroot00000000000000{ pkgs ? import { }, hyprland-qtutils ? pkgs.callPackage ./default.nix { }, ... }: pkgs.mkShell { inputsFrom = [ hyprland-qtutils ]; nativeBuildInputs = [ pkgs.clang-tools pkgs.pciutils ]; shellHook = let inherit (pkgs.lib.strings) concatMapStringsSep; qtLibPath = f: concatMapStringsSep ":" f ( with pkgs.qt6; [ qtbase qtdeclarative qtwayland pkgs.hyprland-qt-support ] ); in '' # Add Qt-related environment variables. export QT_PLUGIN_PATH=${qtLibPath (p: "${p}/lib/qt-6/plugins")} export QML2_IMPORT_PATH=${qtLibPath (p: "${p}/lib/qt-6/qml")} # Generate compile_commands.json CMAKE_EXPORT_COMPILE_COMMANDS=1 cmake -S . -B ./build ln -s build/compile_commands.json . ''; } hyprwm-hyprland-guiutils-a16ad89/utils/000077500000000000000000000000001522735161700203125ustar00rootroot00000000000000hyprwm-hyprland-guiutils-a16ad89/utils/dialog/000077500000000000000000000000001522735161700215515ustar00rootroot00000000000000hyprwm-hyprland-guiutils-a16ad89/utils/dialog/CMakeLists.txt000066400000000000000000000021561522735161700243150ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.12) file(READ "${CMAKE_SOURCE_DIR}/VERSION" VER_RAW) string(STRIP ${VER_RAW} VERSION) project( hyprland-dialog DESCRIPTION "A hyprland dialog box" VERSION ${VERSION}) set(CMAKE_MESSAGE_LOG_LEVEL "STATUS") file(GLOB_RECURSE SRCFILES "src/*.cpp") add_executable(hyprland-dialog ${SRCFILES}) string(REPLACE "\"" " " GIT_COMMIT_MESSAGE_ESCAPED "${GIT_COMMIT_MESSAGE}") target_compile_definitions(hyprland-dialog PRIVATE "-DGIT_COMMIT_HASH=\"${GIT_COMMIT_HASH}\"") target_compile_definitions(hyprland-dialog PRIVATE "-DGIT_BRANCH=\"${GIT_BRANCH}\"") target_compile_definitions(hyprland-dialog PRIVATE "-DGIT_COMMIT_MESSAGE=\"${GIT_COMMIT_MESSAGE_ESCAPED}\"") target_compile_definitions(hyprland-dialog PRIVATE "-DGIT_DIRTY=\"${GIT_DIRTY}\"") set(CPACK_PROJECT_NAME ${PROJECT_NAME}) set(CPACK_PROJECT_VERSION ${PROJECT_VERSION}) include(CPack) target_link_libraries(hyprland-dialog PkgConfig::deps) target_link_libraries( hyprland-dialog pthread ${CMAKE_THREAD_LIBS_INIT}) include(GNUInstallDirs) install(TARGETS hyprland-dialog) hyprwm-hyprland-guiutils-a16ad89/utils/dialog/src/000077500000000000000000000000001522735161700223405ustar00rootroot00000000000000hyprwm-hyprland-guiutils-a16ad89/utils/dialog/src/main.cpp000066400000000000000000000157031522735161700237760ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Hyprutils::Memory; using namespace Hyprutils::Math; using namespace Hyprutils::String; using namespace Hyprtoolkit; #define SP CSharedPointer #define WP CWeakPointer #define UP CUniquePointer static SP backend; static SP window; // int main(int argc, char** argv, char** envp) { std::string appTitle = "", titleStr = "", textStr = ""; std::vector buttonsStrs; for (int i = 1; i < argc; ++i) { std::string_view arg = argv[i]; if (arg == "--title") { if (i + 1 >= argc) { std::print(stderr, "--title requires a parameter\n"); return 1; } titleStr = argv[i + 1]; i++; continue; } if (arg == "--apptitle") { if (i + 1 >= argc) { std::print(stderr, "--apptitle requires a parameter\n"); return 1; } appTitle = argv[i + 1]; i++; continue; } if (arg == "--text") { if (i + 1 >= argc) { std::print(stderr, "--text requires a parameter\n"); return 1; } textStr = argv[i + 1]; i++; continue; } if (arg == "--buttons") { if (i + 1 >= argc) { std::print(stderr, "--buttons requires a parameter\n"); return 1; } CConstVarList buttonz(argv[i + 1], 0, ';', true); for (auto& b : buttonz) { buttonsStrs.emplace_back(b); } i++; continue; } if (arg == "--help" || arg == "-h") { std::println(R"#(hyprland-dialog, part of hyprland-guiutils v{} Usage: --title - Set window title --apptitle - Set big title --text - Message to show --buttons - Semicolon-separated list of buttons )#", GUIUTILS_VERSION); return 0; } std::print(stderr, "invalid arg {}\n", argv[i]); return 1; } setenv("HT_QUIET", "1", true); backend = IBackend::create(); // for compatibility, let's fix newlines. replaceInString(textStr, "
", "\n"); replaceInString(textStr, "\\n", "\n"); const auto FONT_SIZE = CFontSize{CFontSize::HT_FONT_TEXT}.ptSize(); const float WINDOW_X = FONT_SIZE * 50.F; // for now do auto to estimate size auto layout = CColumnLayoutBuilder::begin()->size({CDynamicSize::HT_SIZE_ABSOLUTE, CDynamicSize::HT_SIZE_AUTO, {WINDOW_X, 1.F}})->commence(); layout->setMargin(3); auto layoutInner = CColumnLayoutBuilder::begin()->size({CDynamicSize::HT_SIZE_PERCENT, CDynamicSize::HT_SIZE_AUTO, {0.85F, 1.F}})->commence(); layout->addChild(layoutInner); layoutInner->setGrow(true); layoutInner->setPositionMode(Hyprtoolkit::IElement::HT_POSITION_ABSOLUTE); layoutInner->setPositionFlag(Hyprtoolkit::IElement::HT_POSITION_FLAG_HCENTER, true); auto title = CTextBuilder::begin()->text(std::move(titleStr))->fontSize({CFontSize::HT_FONT_H2})->async(false)->color([] { return backend->getPalette()->m_colors.text; })->commence(); auto hr = CRectangleBuilder::begin() // ->color([] { return CHyprColor{backend->getPalette()->m_colors.text.darken(0.65)}; }) ->size({CDynamicSize::HT_SIZE_PERCENT, CDynamicSize::HT_SIZE_ABSOLUTE, {0.5F, 9.F}}) ->commence(); hr->setMargin(4); auto content = CTextBuilder::begin() ->text(std::move(textStr)) ->fontSize(CFontSize{CFontSize::HT_FONT_TEXT}) ->async(false) ->color([] { return backend->getPalette()->m_colors.text; }) ->commence(); std::vector> buttons; for (const auto& bstr : buttonsStrs) { buttons.emplace_back(CButtonBuilder::begin() ->label(std::string{bstr}) ->onMainClick([str = bstr](auto) { std::println("{}", str); if (window) window->close(); backend->destroy(); }) ->size({CDynamicSize::HT_SIZE_AUTO, CDynamicSize::HT_SIZE_AUTO, {1, 1}}) ->commence()); } auto null2 = CNullBuilder::begin()->commence(); auto layout2 = CRowLayoutBuilder::begin()->gap(3)->size({CDynamicSize::HT_SIZE_PERCENT, CDynamicSize::HT_SIZE_AUTO, {1, 1}})->commence(); null2->setGrow(true); layoutInner->addChild(title); layoutInner->addChild(hr); layoutInner->addChild(content); layout2->addChild(null2); for (const auto& b : buttons) { layout2->addChild(b); } layout->addChild(layout2); { // calculate the layout size before we open the window to size it properly SP null = CNullBuilder::begin()->size({CDynamicSize::HT_SIZE_ABSOLUTE, CDynamicSize::HT_SIZE_ABSOLUTE, {WINDOW_X, 99999999.F}})->commence(); null->addChild(layout); layout->forceReposition(); } const float WINDOW_Y = layout->size().y + 50 /* pad */; layout->rebuild()->size({CDynamicSize::HT_SIZE_PERCENT, CDynamicSize::HT_SIZE_PERCENT, {1.F, 1.F}})->commence(); // window = CWindowBuilder::begin() ->preferredSize({WINDOW_X, WINDOW_Y}) ->minSize({WINDOW_X, WINDOW_Y}) ->maxSize({WINDOW_X, WINDOW_Y}) ->appTitle(std::move(appTitle)) ->appClass("hyprland-dialog") ->commence(); window->m_rootElement->addChild(CRectangleBuilder::begin()->color([] { return backend->getPalette()->m_colors.background; })->commence()); window->m_rootElement->addChild(layout); window->m_events.closeRequest.listenStatic([w = WP{window}] { w->close(); backend->destroy(); }); window->open(); backend->enterLoop(); return 0; }hyprwm-hyprland-guiutils-a16ad89/utils/donate-screen/000077500000000000000000000000001522735161700230415ustar00rootroot00000000000000hyprwm-hyprland-guiutils-a16ad89/utils/donate-screen/CMakeLists.txt000066400000000000000000000022701522735161700256020ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.12) file(READ "${CMAKE_SOURCE_DIR}/VERSION" VER_RAW) string(STRIP ${VER_RAW} VERSION) project( hyprland-donate-screen DESCRIPTION "A hyprland donate request screen" VERSION ${VERSION}) set(CMAKE_MESSAGE_LOG_LEVEL "STATUS") file(GLOB_RECURSE SRCFILES "src/*.cpp") add_executable(hyprland-donate-screen ${SRCFILES}) string(REPLACE "\"" " " GIT_COMMIT_MESSAGE_ESCAPED "${GIT_COMMIT_MESSAGE}") target_compile_definitions(hyprland-donate-screen PRIVATE "-DGIT_COMMIT_HASH=\"${GIT_COMMIT_HASH}\"") target_compile_definitions(hyprland-donate-screen PRIVATE "-DGIT_BRANCH=\"${GIT_BRANCH}\"") target_compile_definitions(hyprland-donate-screen PRIVATE "-DGIT_COMMIT_MESSAGE=\"${GIT_COMMIT_MESSAGE_ESCAPED}\"") target_compile_definitions(hyprland-donate-screen PRIVATE "-DGIT_DIRTY=\"${GIT_DIRTY}\"") set(CPACK_PROJECT_NAME ${PROJECT_NAME}) set(CPACK_PROJECT_VERSION ${PROJECT_VERSION}) include(CPack) target_link_libraries(hyprland-donate-screen PkgConfig::deps) target_link_libraries( hyprland-donate-screen pthread ${CMAKE_THREAD_LIBS_INIT}) include(GNUInstallDirs) install(TARGETS hyprland-donate-screen) hyprwm-hyprland-guiutils-a16ad89/utils/donate-screen/src/000077500000000000000000000000001522735161700236305ustar00rootroot00000000000000hyprwm-hyprland-guiutils-a16ad89/utils/donate-screen/src/main.cpp000066400000000000000000000125771522735161700252740ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Hyprutils::Memory; using namespace Hyprutils::Math; using namespace Hyprutils::String; using namespace Hyprutils::OS; using namespace Hyprtoolkit; #define SP CSharedPointer #define WP CWeakPointer #define UP CUniquePointer static SP backend; static SP donateButton; constexpr const char* SUPPORT_MESSAGE = R"#(Hyprland is built and maintained by volunteers, with one person working on it full-time. If Hyprland is useful to you, supporting the project helps keep that work sustainable and lets us keep improving it. You can make a one-time donation or support us monthly. There's also Hyprperks for 5€ + tax / month, which includes a few small "thank you" goodies from us. )#"; // int main(int argc, char** argv, char** envp) { setenv("HT_QUIET", "1", true); backend = IBackend::create(); const auto FONT_SIZE = CFontSize{CFontSize::HT_FONT_TEXT}.ptSize(); const auto WINDOW_SIZE = Vector2D{FONT_SIZE * 70.F, FONT_SIZE * 26.F}; auto window = CWindowBuilder::begin() ->preferredSize(WINDOW_SIZE) ->minSize(WINDOW_SIZE) ->maxSize(WINDOW_SIZE) ->appTitle("Support Hyprland") ->appClass("hyprland-donate-screen") ->commence(); window->m_rootElement->addChild(CRectangleBuilder::begin()->color([] { return backend->getPalette()->m_colors.background; })->commence()); auto layout = CColumnLayoutBuilder::begin()->size({CDynamicSize::HT_SIZE_PERCENT, CDynamicSize::HT_SIZE_PERCENT, {1.F, 1.F}})->commence(); layout->setMargin(3); auto layoutInner = CColumnLayoutBuilder::begin()->size({CDynamicSize::HT_SIZE_PERCENT, CDynamicSize::HT_SIZE_AUTO, {0.85F, 1.F}})->commence(); window->m_rootElement->addChild(layout); layout->addChild(layoutInner); layoutInner->setGrow(true); layoutInner->setPositionMode(Hyprtoolkit::IElement::HT_POSITION_ABSOLUTE); layoutInner->setPositionFlag(Hyprtoolkit::IElement::HT_POSITION_FLAG_HCENTER, true); auto title = CTextBuilder::begin()->text("Support Hyprland")->fontSize({CFontSize::HT_FONT_H2})->color([] { return backend->getPalette()->m_colors.text; })->commence(); auto hr = CRectangleBuilder::begin() // ->color([] { return CHyprColor{backend->getPalette()->m_colors.text.darken(0.65)}; }) ->size({CDynamicSize::HT_SIZE_PERCENT, CDynamicSize::HT_SIZE_ABSOLUTE, {0.5F, 9.F}}) ->commence(); hr->setMargin(4); auto content = CTextBuilder::begin() ->text(SUPPORT_MESSAGE) ->fontSize(CFontSize{CFontSize::HT_FONT_TEXT}) ->color([] { return backend->getPalette()->m_colors.text; }) ->align(Hyprtoolkit::HT_FONT_ALIGN_CENTER) ->size(CDynamicSize{CDynamicSize::HT_SIZE_PERCENT, Hyprtoolkit::CDynamicSize::HT_SIZE_AUTO, {1, 1}}) ->commence(); content->setPositionFlag(Hyprtoolkit::IElement::HT_POSITION_FLAG_HCENTER, true); content->setGrow(true); donateButton = CButtonBuilder::begin() ->label("💝 Support") ->onMainClick([w = WP{window}](auto) { donateButton->rebuild()->label("💝 Thank you!")->commence(); CProcess proc("xdg-open", {"https://hypr.land/support"}); proc.runAsync(); }) ->size({CDynamicSize::HT_SIZE_AUTO, CDynamicSize::HT_SIZE_AUTO, {1, 1}}) ->commence(); auto noThanksButton = CButtonBuilder::begin() ->label("No thanks") ->onMainClick([w = WP{window}](auto) { if (w) w->close(); backend->destroy(); }) ->size({CDynamicSize::HT_SIZE_AUTO, CDynamicSize::HT_SIZE_AUTO, {1, 1}}) ->commence(); auto null2 = CNullBuilder::begin()->commence(); auto layout2 = CRowLayoutBuilder::begin()->gap(3)->size({CDynamicSize::HT_SIZE_PERCENT, CDynamicSize::HT_SIZE_AUTO, {1, 1}})->commence(); null2->setGrow(true); layoutInner->addChild(title); layoutInner->addChild(hr); layoutInner->addChild(content); layout2->addChild(null2); layout2->addChild(donateButton); layout2->addChild(noThanksButton); layout->addChild(layout2); window->m_events.closeRequest.listenStatic([w = WP{window}] { w->close(); backend->destroy(); }); window->open(); backend->enterLoop(); return 0; }hyprwm-hyprland-guiutils-a16ad89/utils/run/000077500000000000000000000000001522735161700211165ustar00rootroot00000000000000hyprwm-hyprland-guiutils-a16ad89/utils/run/CMakeLists.txt000066400000000000000000000021261522735161700236570ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.12) file(READ "${CMAKE_SOURCE_DIR}/VERSION" VER_RAW) string(STRIP ${VER_RAW} VERSION) project( hyprland-run DESCRIPTION "A basic hyprland run box" VERSION ${VERSION}) set(CMAKE_MESSAGE_LOG_LEVEL "STATUS") file(GLOB_RECURSE SRCFILES "src/*.cpp") add_executable(hyprland-run ${SRCFILES}) string(REPLACE "\"" " " GIT_COMMIT_MESSAGE_ESCAPED "${GIT_COMMIT_MESSAGE}") target_compile_definitions(hyprland-run PRIVATE "-DGIT_COMMIT_HASH=\"${GIT_COMMIT_HASH}\"") target_compile_definitions(hyprland-run PRIVATE "-DGIT_BRANCH=\"${GIT_BRANCH}\"") target_compile_definitions(hyprland-run PRIVATE "-DGIT_COMMIT_MESSAGE=\"${GIT_COMMIT_MESSAGE_ESCAPED}\"") target_compile_definitions(hyprland-run PRIVATE "-DGIT_DIRTY=\"${GIT_DIRTY}\"") set(CPACK_PROJECT_NAME ${PROJECT_NAME}) set(CPACK_PROJECT_VERSION ${PROJECT_VERSION}) include(CPack) target_link_libraries(hyprland-run PkgConfig::deps) target_link_libraries( hyprland-run pthread ${CMAKE_THREAD_LIBS_INIT}) include(GNUInstallDirs) install(TARGETS hyprland-run) hyprwm-hyprland-guiutils-a16ad89/utils/run/src/000077500000000000000000000000001522735161700217055ustar00rootroot00000000000000hyprwm-hyprland-guiutils-a16ad89/utils/run/src/main.cpp000066400000000000000000000161411522735161700233400ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Hyprutils::Memory; using namespace Hyprutils::Math; using namespace Hyprutils::String; using namespace Hyprutils::OS; using namespace Hyprtoolkit; #define SP CSharedPointer #define WP CWeakPointer #define UP CUniquePointer static SP backend; static struct { SP textbox; SP errorText; SP content; SP layoutInner; } state; // // TODO: move to utils static bool executableExistsInPath(const std::string_view& exe) { const char* PATHENV = std::getenv("PATH"); if (!PATHENV) return false; CVarList2 paths(PATHENV, 0, ':', true); std::error_code ec; for (const auto& PATH : paths) { std::filesystem::path candidate = std::filesystem::path(PATH) / exe; if (!std::filesystem::exists(candidate, ec) || ec) continue; if (!std::filesystem::is_regular_file(candidate, ec) || ec) continue; auto perms = std::filesystem::status(candidate, ec).permissions(); if (ec) continue; if ((perms & std::filesystem::perms::others_exec) != std::filesystem::perms::none) return true; } return false; } static std::expected commenceRun(const std::string_view& sv) { if (!executableExistsInPath(sv)) return std::unexpected("Executable doesn't exist"); CProcess proc(std::string{sv}, {}); if (!proc.runAsync()) return std::unexpected("Couldn't execute process."); if (!proc.pid()) return std::unexpected("Process couldn't start"); return {}; } static bool tryRunApp() { if (const auto RES = commenceRun(state.textbox->currentText()); !RES) { if (!state.errorText) { state.errorText = CTextBuilder::begin() ->text(std::format("{}", RES.error())) ->fontSize(CFontSize{CFontSize::HT_FONT_TEXT}) ->color([] { return CHyprColor{0xFFEE2222}; }) ->commence(); state.layoutInner->clearChildren(); state.layoutInner->addChild(state.content); state.layoutInner->addChild(state.textbox); state.layoutInner->addChild(state.errorText); } else state.errorText->rebuild()->text(std::format("{}", RES.error()))->commence(); return false; } return true; } int main(int argc, char** argv, char** envp) { for (int i = 1; i < argc; ++i) { std::string_view arg = argv[i]; if (arg == "--help" || arg == "-h") { std::println(R"#(hyprland-run, part of hyprland-guiutils v{})#", GUIUTILS_VERSION); return 0; } std::print(stderr, "invalid arg {}\n", argv[i]); return 1; } backend = IBackend::create(); // const Vector2D WINDOW_SIZE = {350, 100}; auto window = CWindowBuilder::begin()->preferredSize(WINDOW_SIZE)->minSize(WINDOW_SIZE)->maxSize(WINDOW_SIZE)->appTitle("Run")->appClass("hyprland-run")->commence(); window->m_rootElement->addChild(CRectangleBuilder::begin()->color([] { return backend->getPalette()->m_colors.background; })->commence()); auto layout = CColumnLayoutBuilder::begin()->size({CDynamicSize::HT_SIZE_PERCENT, CDynamicSize::HT_SIZE_PERCENT, {1.F, 1.F}})->commence(); layout->setMargin(3); state.layoutInner = CColumnLayoutBuilder::begin()->size({CDynamicSize::HT_SIZE_PERCENT, CDynamicSize::HT_SIZE_AUTO, {0.85F, 1.F}})->gap(10)->commence(); window->m_rootElement->addChild(layout); layout->addChild(state.layoutInner); state.layoutInner->setGrow(true); state.content = CTextBuilder::begin()->text("Run an application")->fontSize(CFontSize{CFontSize::HT_FONT_TEXT})->color([] { return backend->getPalette()->m_colors.text; })->commence(); state.textbox = CTextboxBuilder::begin() ->placeholder("Input the app name...") ->size({CDynamicSize::HT_SIZE_ABSOLUTE, CDynamicSize::HT_SIZE_ABSOLUTE, {250, 25}}) ->multiline(false) ->commence(); std::vector> buttons; buttons.emplace_back(CButtonBuilder::begin() ->label("Cancel") ->onMainClick([w = WP{window}](auto) { if (w) w->close(); backend->destroy(); }) ->size({CDynamicSize::HT_SIZE_AUTO, CDynamicSize::HT_SIZE_AUTO, {1, 1}}) ->commence()); buttons.emplace_back(CButtonBuilder::begin() ->label("Run") ->onMainClick([w = WP{window}](auto) { if (!tryRunApp()) return; if (state.textbox->currentText().empty()) return; if (w) w->close(); backend->destroy(); }) ->size({CDynamicSize::HT_SIZE_AUTO, CDynamicSize::HT_SIZE_AUTO, {1, 1}}) ->commence()); auto null2 = CNullBuilder::begin()->commence(); auto layout2 = CRowLayoutBuilder::begin()->gap(3)->size({CDynamicSize::HT_SIZE_PERCENT, CDynamicSize::HT_SIZE_AUTO, {1, 1}})->commence(); null2->setGrow(true); window->m_events.keyboardKey.listenStatic([w = WP{window}](Input::SKeyboardKeyEvent ev) { if (ev.xkbKeysym == XKB_KEY_Escape || (ev.xkbKeysym == XKB_KEY_Return && tryRunApp())) { if (w) w->close(); backend->destroy(); } }); state.layoutInner->addChild(state.content); state.layoutInner->addChild(state.textbox); layout2->addChild(null2); for (const auto& b : buttons) { layout2->addChild(b); } layout->addChild(layout2); window->m_events.closeRequest.listenStatic([w = WP{window}] { w->close(); backend->destroy(); }); state.textbox->focus(true); window->open(); backend->enterLoop(); return 0; }hyprwm-hyprland-guiutils-a16ad89/utils/update-screen/000077500000000000000000000000001522735161700230515ustar00rootroot00000000000000hyprwm-hyprland-guiutils-a16ad89/utils/update-screen/CMakeLists.txt000066400000000000000000000022601522735161700256110ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.12) file(READ "${CMAKE_SOURCE_DIR}/VERSION" VER_RAW) string(STRIP ${VER_RAW} VERSION) project( hyprland-update-screen DESCRIPTION "A hyprland update screen" VERSION ${VERSION}) set(CMAKE_MESSAGE_LOG_LEVEL "STATUS") file(GLOB_RECURSE SRCFILES "src/*.cpp") add_executable(hyprland-update-screen ${SRCFILES}) string(REPLACE "\"" " " GIT_COMMIT_MESSAGE_ESCAPED "${GIT_COMMIT_MESSAGE}") target_compile_definitions(hyprland-update-screen PRIVATE "-DGIT_COMMIT_HASH=\"${GIT_COMMIT_HASH}\"") target_compile_definitions(hyprland-update-screen PRIVATE "-DGIT_BRANCH=\"${GIT_BRANCH}\"") target_compile_definitions(hyprland-update-screen PRIVATE "-DGIT_COMMIT_MESSAGE=\"${GIT_COMMIT_MESSAGE_ESCAPED}\"") target_compile_definitions(hyprland-update-screen PRIVATE "-DGIT_DIRTY=\"${GIT_DIRTY}\"") set(CPACK_PROJECT_NAME ${PROJECT_NAME}) set(CPACK_PROJECT_VERSION ${PROJECT_VERSION}) include(CPack) target_link_libraries(hyprland-update-screen PkgConfig::deps) target_link_libraries( hyprland-update-screen pthread ${CMAKE_THREAD_LIBS_INIT}) include(GNUInstallDirs) install(TARGETS hyprland-update-screen) hyprwm-hyprland-guiutils-a16ad89/utils/update-screen/src/000077500000000000000000000000001522735161700236405ustar00rootroot00000000000000hyprwm-hyprland-guiutils-a16ad89/utils/update-screen/src/main.cpp000066400000000000000000000153421522735161700252750ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Hyprutils::Memory; using namespace Hyprutils::Math; using namespace Hyprutils::String; using namespace Hyprutils::OS; using namespace Hyprtoolkit; #define SP CSharedPointer #define WP CWeakPointer #define UP CUniquePointer static SP backend; static SP donateButton, openNewsButton; constexpr const char* TEXT_CONTENT = R"#(Hyprland has been updated! 😄 Check out the release notes on GitHub and the news page on hypr.land to see what's new. Some releases include breaking changes, so if you run into any config errors, the latest release notes are a good place to start. If you use plugins, make sure to rebuild them. You can turn off this screen in your Hyprland config.)#"; // int main(int argc, char** argv, char** envp) { std::string versionStr = ""; std::vector buttonsStrs; for (int i = 1; i < argc; ++i) { std::string_view arg = argv[i]; if (arg == "--new-version") { if (i + 1 >= argc) { std::print(stderr, "--new-version requires a parameter\n"); return 1; } versionStr = argv[i + 1]; i++; continue; } if (arg == "--help" || arg == "-h") { std::println(R"#(hyprland-update-screen, part of hyprland-guiutils v{} Usage: --new-version - Set the displayed new version string )#", GUIUTILS_VERSION); return 0; } std::print(stderr, "invalid arg {}\n", argv[i]); return 1; } setenv("HT_QUIET", "1", true); backend = IBackend::create(); // const auto FONT_SIZE = CFontSize{CFontSize::HT_FONT_TEXT}.ptSize(); const auto WINDOW_SIZE = Vector2D{FONT_SIZE * 90.F, FONT_SIZE * 30.F}; auto window = CWindowBuilder::begin() ->preferredSize(WINDOW_SIZE) ->minSize(WINDOW_SIZE) ->maxSize(WINDOW_SIZE) ->appTitle("Hyprland Updated") ->appClass("hyprland-donate-screen") ->commence(); window->m_rootElement->addChild(CRectangleBuilder::begin()->color([] { return backend->getPalette()->m_colors.background; })->commence()); auto layout = CColumnLayoutBuilder::begin()->size({CDynamicSize::HT_SIZE_PERCENT, CDynamicSize::HT_SIZE_PERCENT, {1.F, 1.F}})->commence(); layout->setMargin(3); auto layoutInner = CColumnLayoutBuilder::begin()->size({CDynamicSize::HT_SIZE_PERCENT, CDynamicSize::HT_SIZE_AUTO, {0.85F, 1.F}})->commence(); window->m_rootElement->addChild(layout); layout->addChild(layoutInner); layoutInner->setGrow(true); layoutInner->setPositionMode(Hyprtoolkit::IElement::HT_POSITION_ABSOLUTE); layoutInner->setPositionFlag(Hyprtoolkit::IElement::HT_POSITION_FLAG_HCENTER, true); auto title = CTextBuilder::begin() ->text(std::move(std::format("Hyprland updated to {}!", versionStr))) ->fontSize({CFontSize::HT_FONT_H2}) ->color([] { return backend->getPalette()->m_colors.text; }) ->commence(); auto hr = CRectangleBuilder::begin() // ->color([] { return CHyprColor{backend->getPalette()->m_colors.text.darken(0.65)}; }) ->size({CDynamicSize::HT_SIZE_PERCENT, CDynamicSize::HT_SIZE_ABSOLUTE, {0.5F, 9.F}}) ->commence(); hr->setMargin(4); auto content = CTextBuilder::begin() ->text(TEXT_CONTENT) ->fontSize(CFontSize{CFontSize::HT_FONT_TEXT}) ->align(Hyprtoolkit::HT_FONT_ALIGN_CENTER) ->color([] { return backend->getPalette()->m_colors.text; }) ->commence(); content->setPositionFlag(Hyprtoolkit::IElement::HT_POSITION_FLAG_HCENTER, true); auto null2 = CNullBuilder::begin()->commence(); auto layout2 = CRowLayoutBuilder::begin()->gap(3)->size({CDynamicSize::HT_SIZE_PERCENT, CDynamicSize::HT_SIZE_AUTO, {1, 1}})->commence(); donateButton = CButtonBuilder::begin() ->label("💝 Support") ->onMainClick([w = WP{window}](auto) { donateButton->rebuild()->label("💝 Thank you!")->commence(); CProcess proc("xdg-open", {"https://hypr.land/support"}); proc.runAsync(); }) ->size({CDynamicSize::HT_SIZE_AUTO, CDynamicSize::HT_SIZE_AUTO, {1, 1}}) ->commence(); openNewsButton = CButtonBuilder::begin() ->label("🔗 Open news") ->onMainClick([w = WP{window}](auto) { openNewsButton->rebuild()->label("🔗 Right away!")->commence(); CProcess proc("xdg-open", {"https://hypr.land/news"}); proc.runAsync(); }) ->size({CDynamicSize::HT_SIZE_AUTO, CDynamicSize::HT_SIZE_AUTO, {1, 1}}) ->commence(); auto closeButton = CButtonBuilder::begin() ->label("Thanks") ->onMainClick([w = WP{window}](auto) { if (w) w->close(); backend->destroy(); }) ->size({CDynamicSize::HT_SIZE_AUTO, CDynamicSize::HT_SIZE_AUTO, {1, 1}}) ->commence(); null2->setGrow(true); layoutInner->addChild(title); layoutInner->addChild(hr); layoutInner->addChild(content); layout2->addChild(null2); layout2->addChild(donateButton); layout2->addChild(openNewsButton); layout2->addChild(closeButton); layout->addChild(layout2); window->m_events.closeRequest.listenStatic([w = WP{window}] { w->close(); backend->destroy(); }); window->open(); backend->enterLoop(); return 0; }hyprwm-hyprland-guiutils-a16ad89/utils/welcome/000077500000000000000000000000001522735161700217455ustar00rootroot00000000000000hyprwm-hyprland-guiutils-a16ad89/utils/welcome/CMakeLists.txt000066400000000000000000000021731522735161700245100ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.12) file(READ "${CMAKE_SOURCE_DIR}/VERSION" VER_RAW) string(STRIP ${VER_RAW} VERSION) project( hyprland-welcome DESCRIPTION "A hyprland welcome screen" VERSION ${VERSION}) set(CMAKE_MESSAGE_LOG_LEVEL "STATUS") file(GLOB_RECURSE SRCFILES "src/*.cpp") add_executable(hyprland-welcome ${SRCFILES}) string(REPLACE "\"" " " GIT_COMMIT_MESSAGE_ESCAPED "${GIT_COMMIT_MESSAGE}") target_compile_definitions(hyprland-welcome PRIVATE "-DGIT_COMMIT_HASH=\"${GIT_COMMIT_HASH}\"") target_compile_definitions(hyprland-welcome PRIVATE "-DGIT_BRANCH=\"${GIT_BRANCH}\"") target_compile_definitions(hyprland-welcome PRIVATE "-DGIT_COMMIT_MESSAGE=\"${GIT_COMMIT_MESSAGE_ESCAPED}\"") target_compile_definitions(hyprland-welcome PRIVATE "-DGIT_DIRTY=\"${GIT_DIRTY}\"") set(CPACK_PROJECT_NAME ${PROJECT_NAME}) set(CPACK_PROJECT_VERSION ${PROJECT_VERSION}) include(CPack) target_link_libraries(hyprland-welcome PkgConfig::deps) target_link_libraries( hyprland-welcome pthread ${CMAKE_THREAD_LIBS_INIT}) include(GNUInstallDirs) install(TARGETS hyprland-welcome) hyprwm-hyprland-guiutils-a16ad89/utils/welcome/src/000077500000000000000000000000001522735161700225345ustar00rootroot00000000000000hyprwm-hyprland-guiutils-a16ad89/utils/welcome/src/main.cpp000066400000000000000000001075351522735161700241770ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Hyprutils::Memory; using namespace Hyprutils::Math; using namespace Hyprutils::String; using namespace Hyprutils::OS; using namespace Hyprtoolkit; using namespace std::string_literals; #define SP CSharedPointer #define ASP CAtomicSharedPointer #define WP CWeakPointer #define UP CUniquePointer constexpr const size_t TABS_NUMBER = 6; constexpr const size_t INNER_NULL_MARGIN = 5; constexpr std::array TITLES = { "Welcome to Hyprland!", "Getting started", "Default apps", "Basic configuration", "Hypr Ecosystem", "That's it!", }; const std::vector TERMINALS = { "kitty", "alacritty", "wezterm", "foot", "konsole", "gnome-terminal", }; const std::vector FILE_MANAGERS = {"dolphin", "thunar", "pcmanfm", "nautilus", "nemo"}; const std::vector LAUNCHERS = {"hyprlauncher", "fuzzel", "wofi", "rofi -show run", "anyrun", "tofi-drun --drun-launch=true"}; constexpr const char* TAB1_CONTENT = R"#(We hope you enjoy your stay. In order to help you get accommodated to Hyprland in an easier manner, we prepared a little basic setup tutorial, just for you. If you feel adventurous, or are an advanced user, you can click the "Thanks, but I don't need help" button on the bottom. It will close this window and never show it again. If you want to manually launch this welcome app, just execute hyprland-welcome in your terminal. Click the "next" button to proceed to the next step of your setup :) )#"; constexpr const char* TAB2_CONTENT = R"#(The first thing we'll need to do is get some packages installed that you absolutely need in order for your system to be working properly. Apps with a * are absolutely necessary for a working system. All other are highly recommended, as they provide core parts of a working environment. You can proceed without any of those, but it's not advised. There is a possibility that this app is unable to detect some of your installed binaries. In that case, it's okay to ignore them. Use the launch terminal button to launch a terminal. Use SUPER+M to exit hyprland. Supported terminals: kitty, alacritty, foot, wezterm, konsole, gnome-terminal, xterm. Hint: Hover on the different components to see what options are accepted. Green means the component is found to be installed, blue means it's running. This list refreshes automatically.)#"; constexpr const char* TAB4_CONTENT = R"#(Now that you've installed the basic apps, you might want some of them to autostart. Hyprland doesn't automatically start anything for you, you need to tell it to. Go to ~/.config/hypr/hyprland.lua, and add "hl.exec_cmd("appname")" surrounded by hl.on() to launch your apps, for example: hl.on("hyprland.start", function () hl.exec_cmd("hyprpaper") hl.exec_cmd("waybar") end) In general, configuring apps is something for you to do. Each app you install may come with its own config file and options. A great point to start is the Hyprland wiki at https://wiki.hypr.land. There, the master tutorial will teach you everything and link to further docs. If you prefer pre-configured settings, or "dotfiles", you can see the "preconfigured configs" section on the wiki, or search online. Important note: dotfiles can run anything on your computer. Make sure you trust the source.)#"; constexpr const char* TAB3_PREAMBLE = R"#(We know that not everyone uses kitty and dolphin. That's why we let you choose. If you wish to change the defaults, use the dropdowns below.)#"; constexpr const char* TAB5_CONTENT = R"#(Hyprland has a wide ecosystem of apps specifically made for it. Unlike some other popular DEs, it does not force you to use most of them by default. You can install those elements separately, only those that you need. Check the wiki under Hypr Ecosystem to see all of the apps, their usage and configuration.)#"; constexpr const char* TAB6_CONTENT = R"#(That's it for this small introduction! Explore the wiki, and various apps, and enjoy your journey! Here are some important default shortcuts: • SUPER + Q = Terminal • SUPER + E = File Manager • SUPER + R = Launcher • SUPER + C = Close window • SUPER + V = Toggle floating • SUPER + M = Exit Hyprland • SUPER + [1 - 9] = Workspaces 1 - 9 • SUPER + SHIFT + [1 - 9] = Move window to workspace 1 - 9 • SUPER + Arrows = Move focus around You can easily change these in your hyprland.lua. Thank you for choosing Hyprland! ❤️)#"; struct SAppState { std::string name; std::vector binaryNames; bool mandatory = false; SP labelEl; }; static struct { SP backend; SP tabContainer; std::array, TABS_NUMBER> tabs; SP topText; SP buttonLayout; SP buttonSpacer; SP buttonBack, buttonNext, buttonQuit, buttonFinish, buttonOpenWiki, buttonLaunchTerm; size_t tab = 0; std::vector> appStates; ASP appRefreshTimer, wikiOpenTimer; } state; static bool appExists(std::string binName) { static auto PATH = getenv("PATH"); if (!PATH) return false; static CVarList paths(PATH, 0, ':', true); for (const auto& p : paths) { std::error_code ec; if (!std::filesystem::exists(std::filesystem::path(p) / binName, ec) || ec) continue; return true; } return false; } static bool appIsRunning(std::string binName) { // loop over /proc/ entries, check exe std::error_code ec_it; for (const std::filesystem::path& procEntry : std::filesystem::directory_iterator("/proc", ec_it)) { if (ec_it) continue; std::error_code ec; if (!std::filesystem::exists(procEntry / "exe", ec) || ec) continue; const auto CANONICAL = std::filesystem::canonical(procEntry / "exe", ec); if (ec) continue; if (!CANONICAL.has_filename()) continue; if (CANONICAL.filename() == binName) return true; } return false; } static void updateApps() { if (state.tab != 1) return; state.appRefreshTimer = state.backend->addTimer(std::chrono::seconds(1), [](ASP t, void* d) { updateApps(); }, nullptr); for (const auto& a : state.appStates) { bool found = false; for (const auto& bn : a->binaryNames) { if (!appIsRunning(bn)) continue; found = true; a->labelEl->rebuild() ->text(std::format("{}{}: Running: {}", a->name, (a->mandatory ? "*" : ""), bn)) ->commence(); break; } if (!found) { for (const auto& bn : a->binaryNames) { if (!appExists(bn)) continue; found = true; a->labelEl->rebuild() ->text(std::format("{}{}: Installed: {}", a->name, (a->mandatory ? "*" : ""), bn)) ->commence(); break; } } if (!found) a->labelEl->rebuild() ->text(std::format("{}{}: Missing", a->name, (a->mandatory ? "*" : ""))) ->commence(); } } static void updateTab() { state.tabContainer->clearChildren(); state.tabContainer->addChild(state.tabs[state.tab]); state.topText->rebuild()->text(TITLES[state.tab])->commence(); updateApps(); state.buttonLayout->clearChildren(); if (state.tab == 0) { state.buttonLayout->addChild(state.buttonSpacer); state.buttonLayout->addChild(state.buttonQuit); state.buttonLayout->addChild(state.buttonNext); } else if (state.tab == 1) { state.buttonLayout->addChild(state.buttonBack); state.buttonLayout->addChild(state.buttonSpacer); state.buttonLayout->addChild(state.buttonLaunchTerm); state.buttonLayout->addChild(state.buttonNext); } else if (state.tab == 2) { state.buttonLayout->addChild(state.buttonBack); state.buttonLayout->addChild(state.buttonSpacer); state.buttonLayout->addChild(state.buttonNext); } else if (state.tab == 3) { state.buttonLayout->addChild(state.buttonBack); state.buttonLayout->addChild(state.buttonSpacer); state.buttonLayout->addChild(state.buttonOpenWiki); state.buttonLayout->addChild(state.buttonNext); } else if (state.tab == 4) { state.buttonLayout->addChild(state.buttonBack); state.buttonLayout->addChild(state.buttonSpacer); state.buttonLayout->addChild(state.buttonOpenWiki); state.buttonLayout->addChild(state.buttonNext); } else if (state.tab == 5) { state.buttonLayout->addChild(state.buttonBack); state.buttonLayout->addChild(state.buttonSpacer); state.buttonLayout->addChild(state.buttonOpenWiki); state.buttonLayout->addChild(state.buttonFinish); } } static void tabBack() { if (state.tab == 0) return; state.tab--; updateTab(); } static void tabNext() { if (state.tab == TITLES.size() - 1) return; state.tab++; updateTab(); } static void registerAppState(std::string&& name, std::vector&& binaries, bool mandatory, const std::string& recommend = "", const std::string& note = "") { auto appState = makeShared(); appState->name = std::move(name); appState->binaryNames = std::move(binaries); appState->labelEl = CTextBuilder::begin()->color([] { return state.backend->getPalette()->m_colors.text; })->fontSize({CFontSize::HT_FONT_TEXT})->text("")->commence(); appState->mandatory = mandatory; std::string acceptedStr = ""; for (const auto& b : appState->binaryNames) { acceptedStr += b + ", "; } if (!acceptedStr.empty()) acceptedStr = acceptedStr.substr(0, acceptedStr.length() - 2); std::string tooltip = recommend.empty() ? std::format("Accepted: {}", acceptedStr) : std::format("Recommended: {}\nAccepted: {}", recommend, acceptedStr); if (!note.empty()) tooltip += std::format("\n{}", note); appState->labelEl->setTooltip(std::move(tooltip)); state.appStates.emplace_back(std::move(appState)); } static SP spaceOut(std::string&& label, SP el) { auto text = CTextBuilder::begin()->text(std::move(label))->commence(); auto spacer = CNullBuilder::begin()->commence(); spacer->setGrow(true, false); auto layout = CRowLayoutBuilder::begin()->size({CDynamicSize::HT_SIZE_PERCENT, CDynamicSize::HT_SIZE_AUTO, {1, 1}})->commence(); layout->addChild(text); layout->addChild(spacer); layout->addChild(el); return layout; } static std::optional readFileAsString(const std::string& path) { std::error_code ec; if (!std::filesystem::exists(path, ec) || ec) return std::nullopt; std::ifstream file(path); if (!file.good()) return std::nullopt; return std::string((std::istreambuf_iterator(file)), (std::istreambuf_iterator())); } static std::optional getHyprlandLuaConfigPath() { if (const auto XDG_CONFIG_HOME = getenv("XDG_CONFIG_HOME"); XDG_CONFIG_HOME && XDG_CONFIG_HOME[0] != '\0') return std::filesystem::path{XDG_CONFIG_HOME} / "hypr" / "hyprland.lua"; if (const auto HOME = getenv("HOME"); HOME && HOME[0] != '\0') return std::filesystem::path{HOME} / ".config" / "hypr" / "hyprland.lua"; return std::nullopt; } static bool isLuaWhitespace(char c) { return c == ' ' || c == '\t' || c == '\r'; } static std::string luaQuotedString(const std::string_view& str) { std::string result = "\""; result.reserve(str.length() + 2); for (const auto c : str) { switch (c) { case '\\': result += "\\\\"; break; case '"': result += "\\\""; break; case '\n': result += "\\n"; break; case '\r': result += "\\r"; break; case '\t': result += "\\t"; break; default: result += c; break; } } result += '"'; return result; } static std::optional> findLuaLocalLine(const std::string& config, const std::string_view& var) { for (size_t lineStart = 0; lineStart <= config.length();) { size_t lineEnd = config.find('\n', lineStart); if (lineEnd == std::string::npos) lineEnd = config.length(); const std::string_view line{config.data() + lineStart, lineEnd - lineStart}; size_t pos = 0; while (pos < line.length() && isLuaWhitespace(line[pos])) { pos++; } if (line.substr(pos).starts_with("local")) { pos += 5; if (pos < line.length() && isLuaWhitespace(line[pos])) { while (pos < line.length() && isLuaWhitespace(line[pos])) { pos++; } if (line.substr(pos, var.length()) == var) { pos += var.length(); while (pos < line.length() && isLuaWhitespace(line[pos])) { pos++; } if (pos < line.length() && line[pos] == '=') return std::pair{lineStart, lineEnd}; } } } if (lineEnd == config.length()) break; lineStart = lineEnd + 1; } return std::nullopt; } static std::string luaLocalLineReplacement(const std::string& config, const std::pair& line, const std::string_view& var, const char* newValue) { size_t firstNonWhitespace = line.first; while (firstNonWhitespace < line.second && isLuaWhitespace(config[firstNonWhitespace])) { firstNonWhitespace++; } return std::format("{}local {} = {}", config.substr(line.first, firstNonWhitespace - line.first), var, luaQuotedString(newValue)); } static bool isLuaAutogeneratedLine(const std::string_view& line) { const auto COMMENT_POS = line.find("--"); const auto CODE = line.substr(0, COMMENT_POS); std::string compact; compact.reserve(CODE.length()); for (const auto c : CODE) { if (!isLuaWhitespace(c)) compact += c; } return compact == "hl.config({autogenerated=true})" || compact == "hl.config({autogenerated=1})"; } static std::optional> findLuaAutogeneratedLine(const std::string& config) { for (size_t lineStart = 0; lineStart <= config.length();) { size_t lineEnd = config.find('\n', lineStart); if (lineEnd == std::string::npos) lineEnd = config.length(); if (isLuaAutogeneratedLine({config.data() + lineStart, lineEnd - lineStart})) { const size_t removeEnd = lineEnd == config.length() ? lineEnd : lineEnd + 1; return std::pair{lineStart, removeEnd}; } if (lineEnd == config.length()) break; lineStart = lineEnd + 1; } return std::nullopt; } static std::optional updateDefaultConfigVar(const std::string_view& var, const char* newValue) { const auto PATH = getHyprlandLuaConfigPath(); if (!PATH) return "Can't save: neither $XDG_CONFIG_HOME nor $HOME env is set"; const auto STR = readFileAsString(PATH->string()); if (!STR) return "Can't save: failed to read Lua config"; std::string newConfig = *STR; const auto VAR_LINE = findLuaLocalLine(newConfig, var); if (!VAR_LINE) return "Can't save: config isn't default, doesn't have Lua default variable"; newConfig.replace(VAR_LINE->first, VAR_LINE->second - VAR_LINE->first, luaLocalLineReplacement(newConfig, *VAR_LINE, var, newValue)); std::ofstream ofs(*PATH, std::ios::trunc); if (!ofs.good()) return "Can't save: failed to open Lua config"; ofs << newConfig; ofs.close(); if (ofs.fail()) return "Can't save: failed to write Lua config"; return std::nullopt; } static void removeAutogen() { const auto PATH = getHyprlandLuaConfigPath(); if (!PATH) return; const auto STR = readFileAsString(PATH->string()); if (!STR) return; std::string newConfig = *STR; const auto AUTOGEN_LINE = findLuaAutogeneratedLine(newConfig); if (!AUTOGEN_LINE) return; newConfig.erase(AUTOGEN_LINE->first, AUTOGEN_LINE->second - AUTOGEN_LINE->first); std::ofstream ofs(*PATH, std::ios::trunc); ofs << newConfig; ofs.close(); } static void initTabs() { { // Tab 1 auto nullEl = CNullBuilder::begin()->size({CDynamicSize::HT_SIZE_PERCENT, CDynamicSize::HT_SIZE_AUTO, {1, 1}})->commence(); auto layout = CColumnLayoutBuilder::begin()->size({CDynamicSize::HT_SIZE_PERCENT, CDynamicSize::HT_SIZE_AUTO, {1, 1}})->commence(); auto text = CTextBuilder::begin()->text(TAB1_CONTENT)->color([] { return state.backend->getPalette()->m_colors.text; })->commence(); auto spacer = CNullBuilder::begin()->size({CDynamicSize::HT_SIZE_ABSOLUTE, CDynamicSize::HT_SIZE_ABSOLUTE, {1, 1}})->commence(); spacer->setGrow(true); layout->addChild(text); layout->addChild(spacer); nullEl->addChild(layout); nullEl->setGrow(true); nullEl->setMargin(INNER_NULL_MARGIN); state.tabs[0] = nullEl; } { // Tab 2 auto nullEl = CNullBuilder::begin()->size({CDynamicSize::HT_SIZE_PERCENT, CDynamicSize::HT_SIZE_AUTO, {1, 1}})->commence(); auto layout = CColumnLayoutBuilder::begin()->size({CDynamicSize::HT_SIZE_PERCENT, CDynamicSize::HT_SIZE_AUTO, {1, 1}})->gap(20)->commence(); auto text = CTextBuilder::begin()->text(TAB2_CONTENT)->color([] { return state.backend->getPalette()->m_colors.text; })->commence(); auto spacer = CNullBuilder::begin()->size({CDynamicSize::HT_SIZE_ABSOLUTE, CDynamicSize::HT_SIZE_ABSOLUTE, {1, 1}})->commence(); spacer->setGrow(true); layout->addChild(text); nullEl->addChild(layout); nullEl->setGrow(true); nullEl->setMargin(INNER_NULL_MARGIN); auto appLayoutParent = CRowLayoutBuilder::begin()->size(CDynamicSize{CDynamicSize::HT_SIZE_PERCENT, Hyprtoolkit::CDynamicSize::HT_SIZE_AUTO, {1, 1}})->commence(); SP appLayouts[2] = { CColumnLayoutBuilder::begin()->gap(4)->size(CDynamicSize{CDynamicSize::HT_SIZE_PERCENT, Hyprtoolkit::CDynamicSize::HT_SIZE_AUTO, {0.5F, 1.F}})->commence(), CColumnLayoutBuilder::begin()->gap(4)->size(CDynamicSize{CDynamicSize::HT_SIZE_PERCENT, Hyprtoolkit::CDynamicSize::HT_SIZE_AUTO, {0.5F, 1.F}})->commence(), }; appLayouts[0]->setGrow(false, true); appLayouts[0]->setPositionMode(Hyprtoolkit::IElement::HT_POSITION_ABSOLUTE); appLayouts[0]->setPositionFlag(Hyprtoolkit::IElement::HT_POSITION_FLAG_LEFT, true); appLayouts[1]->setGrow(false, true); appLayouts[1]->setPositionMode(Hyprtoolkit::IElement::HT_POSITION_ABSOLUTE); appLayouts[1]->setPositionFlag(Hyprtoolkit::IElement::HT_POSITION_FLAG_LEFT, true); appLayoutParent->addChild(appLayouts[0]); appLayoutParent->addChild(appLayouts[1]); layout->addChild(appLayoutParent); // app states registerAppState("Authentication agent", {"hyprpolkitagent", "polkit-kde-agent"}, true, "hyprpolkitagent"); registerAppState("File manager", {"dolphin", "ranger", "thunar", "pcmanfm", "nautilus", "nemo", "nnn", "yazi"}, true); registerAppState("Terminal", {"kitty", "alacritty", "wezterm", "foot", "konsole", "gnome-terminal"}, true, "kitty"); registerAppState("Pipewire", {"pipewire", "wireplumber"}, true); registerAppState("Wallpaper", {"hyprpaper", "swww", "awww", "swaybg", "wpaperd"}, false, "hyprpaper"); registerAppState("XDG Desktop Portal", {"xdg-desktop-portal-hyprland"}, true); registerAppState("Notification Daemon", {"dunst", "mako"}, true, "", "Please note you can have custom notification daemons with your shell, e.g. quickshell."); registerAppState("Status bar / shell", {"quickshell", "waybar", "eww", "ags"}, false, "", "For new users we recommend waybar, for advanced users quickshell."); registerAppState("Application launcher", {"hyprlauncher", "fuzzel", "wofi", "rofi", "anyrun", "walker", "tofi"}, false, "hyprlauncher"); registerAppState("Clipboard", {"wl-copy"}, true, "", "wl-copy is provided by wl-clipboard in most distros."); // register them bool flip = false; for (const auto& e : state.appStates) { appLayouts[flip ? 1 : 0]->addChild(e->labelEl); flip = !flip; } state.tabs[1] = nullEl; } { // Tab 3 auto nullEl = CNullBuilder::begin()->size({CDynamicSize::HT_SIZE_PERCENT, CDynamicSize::HT_SIZE_AUTO, {1, 1}})->commence(); auto layout = CColumnLayoutBuilder::begin()->size({CDynamicSize::HT_SIZE_PERCENT, CDynamicSize::HT_SIZE_AUTO, {1, 1}})->gap(4)->commence(); auto text = CTextBuilder::begin()->text(TAB3_PREAMBLE)->color([] { return state.backend->getPalette()->m_colors.text; })->commence(); auto spacer = CNullBuilder::begin()->size({CDynamicSize::HT_SIZE_ABSOLUTE, CDynamicSize::HT_SIZE_ABSOLUTE, {1, 1}})->commence(); auto hr = CRectangleBuilder::begin() ->size({CDynamicSize::HT_SIZE_PERCENT, CDynamicSize::HT_SIZE_ABSOLUTE, {0.5F, 11.F}}) ->color([] { return state.backend->getPalette()->m_colors.base; }) ->commence(); auto hr2 = CRectangleBuilder::begin() ->size({CDynamicSize::HT_SIZE_PERCENT, CDynamicSize::HT_SIZE_ABSOLUTE, {0.5F, 11.F}}) ->color([] { return state.backend->getPalette()->m_colors.base; }) ->commence(); auto defaultContainer = CNullBuilder::begin()->size({CDynamicSize::HT_SIZE_PERCENT, CDynamicSize::HT_SIZE_AUTO, {0.6F, 1.F}})->commence(); auto defaultLayout = CColumnLayoutBuilder::begin()->size({CDynamicSize::HT_SIZE_PERCENT, CDynamicSize::HT_SIZE_AUTO, {1, 1}})->gap(4)->commence(); spacer->setGrow(true); hr->setPositionMode(Hyprtoolkit::IElement::HT_POSITION_ABSOLUTE); hr->setPositionFlag(Hyprtoolkit::IElement::HT_POSITION_FLAG_HCENTER, true); hr->setMargin(5); hr2->setPositionMode(Hyprtoolkit::IElement::HT_POSITION_ABSOLUTE); hr2->setPositionFlag(Hyprtoolkit::IElement::HT_POSITION_FLAG_HCENTER, true); hr2->setMargin(5); auto addSelector = [&](const char* name, const char* label, const auto& arr) { auto text = CTextBuilder::begin()->text("")->color([] { return state.backend->getPalette()->m_colors.text; })->commence(); auto textNull = CNullBuilder::begin()->size({CDynamicSize::HT_SIZE_PERCENT, CDynamicSize::HT_SIZE_AUTO, {1, 1}})->commence(); std::vector strs; strs.reserve(arr.size()); for (const auto& t : arr) { strs.emplace_back(t); } text->setPositionMode(Hyprtoolkit::IElement::HT_POSITION_ABSOLUTE); text->setPositionFlag(sc(Hyprtoolkit::IElement::HT_POSITION_FLAG_VCENTER | Hyprtoolkit::IElement::HT_POSITION_FLAG_RIGHT), true); auto updateText = [](SP textEl, const std::string_view& app, std::string err = "") -> void { if (!err.empty()) { textEl->rebuild()->text(std::format("⚠ Error: {}", err))->commence(); return; } const std::string_view APP_STEM = app.contains(' ') ? app.substr(0, app.find(' ')) : app; if (appExists(std::string{APP_STEM})) textEl->rebuild()->text(std::format("✓ {} is installed", app))->commence(); else textEl->rebuild()->text(std::format("⚠ {} is not installed", app))->commence(); }; defaultLayout->addChild(spaceOut(label, CComboboxBuilder::begin() ->items(std::move(strs)) ->size({CDynamicSize::HT_SIZE_ABSOLUTE, CDynamicSize::HT_SIZE_ABSOLUTE, {200, 25}}) ->onChanged([tt = text, updateText, arr, name](SP el, size_t idx) { const auto& TERM_NAME = arr[idx]; const auto RESULT = updateDefaultConfigVar(name, TERM_NAME); if (RESULT) updateText(tt, TERM_NAME, *RESULT); else updateText(tt, TERM_NAME); }) ->commence())); textNull->addChild(text); defaultLayout->addChild(textNull); updateText(text, arr[0]); }; addSelector("terminal", "Terminal", TERMINALS); addSelector("fileManager", "File Manager", FILE_MANAGERS); addSelector("menu", "Launcher", LAUNCHERS); defaultContainer->addChild(defaultLayout); layout->addChild(text); layout->addChild(hr); layout->addChild(defaultContainer); layout->addChild(hr); layout->addChild(CTextBuilder::begin() ->text("You can always change these later in your hyprland.lua") ->color([] { return state.backend->getPalette()->m_colors.text; }) ->commence()); layout->addChild(spacer); nullEl->addChild(layout); nullEl->setGrow(true); nullEl->setMargin(INNER_NULL_MARGIN); state.tabs[2] = nullEl; } { // Tab 4 auto nullEl = CNullBuilder::begin()->size({CDynamicSize::HT_SIZE_PERCENT, CDynamicSize::HT_SIZE_AUTO, {1, 1}})->commence(); auto layout = CColumnLayoutBuilder::begin()->size({CDynamicSize::HT_SIZE_PERCENT, CDynamicSize::HT_SIZE_AUTO, {1, 1}})->commence(); auto text = CTextBuilder::begin()->text(TAB4_CONTENT)->color([] { return state.backend->getPalette()->m_colors.text; })->commence(); auto spacer = CNullBuilder::begin()->size({CDynamicSize::HT_SIZE_ABSOLUTE, CDynamicSize::HT_SIZE_ABSOLUTE, {1, 1}})->commence(); spacer->setGrow(true); layout->addChild(text); layout->addChild(spacer); nullEl->addChild(layout); nullEl->setGrow(true); nullEl->setMargin(INNER_NULL_MARGIN); state.tabs[3] = nullEl; } { // Tab 5 auto nullEl = CNullBuilder::begin()->size({CDynamicSize::HT_SIZE_PERCENT, CDynamicSize::HT_SIZE_AUTO, {1, 1}})->commence(); auto layout = CColumnLayoutBuilder::begin()->size({CDynamicSize::HT_SIZE_PERCENT, CDynamicSize::HT_SIZE_AUTO, {1, 1}})->commence(); auto text = CTextBuilder::begin()->text(TAB5_CONTENT)->color([] { return state.backend->getPalette()->m_colors.text; })->commence(); auto spacer = CNullBuilder::begin()->size({CDynamicSize::HT_SIZE_ABSOLUTE, CDynamicSize::HT_SIZE_ABSOLUTE, {1, 1}})->commence(); spacer->setGrow(true); layout->addChild(text); layout->addChild(spacer); nullEl->addChild(layout); nullEl->setGrow(true); nullEl->setMargin(INNER_NULL_MARGIN); state.tabs[4] = nullEl; } { // Tab 6 auto nullEl = CNullBuilder::begin()->size({CDynamicSize::HT_SIZE_PERCENT, CDynamicSize::HT_SIZE_AUTO, {1, 1}})->commence(); auto layout = CColumnLayoutBuilder::begin()->size({CDynamicSize::HT_SIZE_PERCENT, CDynamicSize::HT_SIZE_AUTO, {1, 1}})->commence(); auto text = CTextBuilder::begin()->text(TAB6_CONTENT)->color([] { return state.backend->getPalette()->m_colors.text; })->commence(); auto spacer = CNullBuilder::begin()->size({CDynamicSize::HT_SIZE_ABSOLUTE, CDynamicSize::HT_SIZE_ABSOLUTE, {1, 1}})->commence(); spacer->setGrow(true); layout->addChild(text); layout->addChild(spacer); nullEl->addChild(layout); nullEl->setGrow(true); nullEl->setMargin(INNER_NULL_MARGIN); state.tabs[5] = nullEl; } } int main(int argc, char** argv, char** envp) { for (int i = 1; i < argc; ++i) { std::string_view arg = argv[i]; if (arg == "--help" || arg == "-h") { std::println(R"#(hyprland-welcome, part of hyprland-guiutils v{})#", GUIUTILS_VERSION); return 0; } std::print(stderr, "invalid arg {}\n", argv[i]); return 1; } state.backend = IBackend::create(); const auto FONT_SIZE = CFontSize{CFontSize::HT_FONT_TEXT}.ptSize(); const auto WINDOW_SIZE = Vector2D{FONT_SIZE * 90.F, FONT_SIZE * 50.F}; // auto window = CWindowBuilder::begin()->preferredSize(WINDOW_SIZE)->minSize(WINDOW_SIZE)->maxSize(WINDOW_SIZE)->appTitle("Welcome to Hyprland")->appClass("hyprland-welcome")->commence(); initTabs(); window->m_rootElement->addChild(CRectangleBuilder::begin()->color([] { return state.backend->getPalette()->m_colors.background; })->commence()); auto rootLayout = CColumnLayoutBuilder::begin()->size({CDynamicSize::HT_SIZE_PERCENT, CDynamicSize::HT_SIZE_PERCENT, {1.F, 1.F}})->gap(10)->commence(); rootLayout->setMargin(3); window->m_rootElement->addChild(rootLayout); // top null: title auto topNull = CNullBuilder::begin()->size({CDynamicSize::HT_SIZE_PERCENT, CDynamicSize::HT_SIZE_AUTO, {1, 10}})->commence(); topNull->setMargin(4); state.topText = CTextBuilder::begin()->color([] { return state.backend->getPalette()->m_colors.text; })->text(TITLES[state.tab])->fontSize(CFontSize::HT_FONT_H2)->commence(); state.topText->setPositionMode(Hyprtoolkit::IElement::HT_POSITION_ABSOLUTE); state.topText->setPositionFlag(Hyprtoolkit::IElement::HT_POSITION_FLAG_CENTER, true); topNull->addChild(state.topText); rootLayout->addChild(topNull); // // content state.tabContainer = CRectangleBuilder::begin() ->size({CDynamicSize::HT_SIZE_PERCENT, CDynamicSize::HT_SIZE_AUTO, {1, 1}}) ->color([] { return state.backend->getPalette()->m_colors.background; }) ->borderThickness(1) ->borderColor([] { return state.backend->getPalette()->m_colors.background.brighten(0.2F); }) ->rounding(state.backend->getPalette()->m_vars.smallRounding) ->commence(); state.tabContainer->setGrow(false, true); rootLayout->addChild(state.tabContainer); state.buttonLayout = CRowLayoutBuilder::begin()->size({CDynamicSize::HT_SIZE_PERCENT, CDynamicSize::HT_SIZE_AUTO, {1, 1}})->gap(5)->commence(); state.buttonLayout->setMargin(2); state.buttonBack = CButtonBuilder::begin()->label("Back")->onMainClick([](SP self) { tabBack(); })->commence(); state.buttonNext = CButtonBuilder::begin()->label("Next")->onMainClick([](SP self) { tabNext(); })->commence(); state.buttonQuit = CButtonBuilder::begin() ->label("Thanks, but I don't need help") ->onMainClick([w = WP{window}](SP self) { if (w) w->close(); state.backend->destroy(); }) ->commence(); state.buttonLaunchTerm = CButtonBuilder::begin() ->label("Launch terminal") ->onMainClick([w = WP{window}](SP self) { for (const auto& t : TERMINALS) { if (!appExists(t)) continue; CProcess proc(t, {}); proc.runAsync(); break; } }) ->commence(); state.buttonFinish = CButtonBuilder::begin() ->label("Finish") ->onMainClick([w = WP{window}](SP self) { removeAutogen(); if (w) w->close(); state.backend->destroy(); }) ->commence(); state.buttonOpenWiki = CButtonBuilder::begin() ->label("🔗 Open wiki") ->onMainClick([w = WP{window}](SP self) { CProcess proc("xdg-open", {"https://wiki.hypr.land/"}); proc.runAsync(); state.buttonOpenWiki->rebuild()->label("🔗 Opened in your browser")->commence(); state.wikiOpenTimer = state.backend->addTimer( std::chrono::seconds(1), [](ASP t, void* d) { state.buttonOpenWiki->rebuild()->label("🔗 Open wiki")->commence(); }, nullptr); }) ->commence(); state.buttonSpacer = CNullBuilder::begin()->size({CDynamicSize::HT_SIZE_ABSOLUTE, CDynamicSize::HT_SIZE_ABSOLUTE, {1, 1}})->commence(); state.buttonSpacer->setGrow(true); rootLayout->addChild(state.buttonLayout); window->m_events.closeRequest.listenStatic([w = WP{window}] { w->close(); state.backend->destroy(); }); updateTab(); window->open(); state.backend->enterLoop(); return 0; }