pax_global_header00006660000000000000000000000064151245225300014511gustar00rootroot0000000000000052 comment=c2e906261142f5dd1ee0bfc44abba23e2754c660 hyprwm-hyprland-guiutils-c2e9062/000077500000000000000000000000001512452253000170555ustar00rootroot00000000000000hyprwm-hyprland-guiutils-c2e9062/.clang-format000066400000000000000000000034161512452253000214340ustar00rootroot00000000000000--- 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-c2e9062/.github/000077500000000000000000000000001512452253000204155ustar00rootroot00000000000000hyprwm-hyprland-guiutils-c2e9062/.github/workflows/000077500000000000000000000000001512452253000224525ustar00rootroot00000000000000hyprwm-hyprland-guiutils-c2e9062/.github/workflows/nix.yml000066400000000000000000000031011512452253000237660ustar00rootroot00000000000000name: Build on: [push, pull_request, workflow_dispatch] jobs: nix: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install Nix uses: nixbuild/nix-quick-install-action@v31 with: nix_conf: | keep-env-derivations = true keep-outputs = true - name: Restore and save Nix store uses: nix-community/cache-nix-action@v6 with: # restore and save a cache using this key primary-key: nix-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/flake.lock') }} # if there's no cache hit, restore a cache by this prefix restore-prefixes-first-match: nix-${{ runner.os }}- # collect garbage until the Nix store size (in bytes) is at most this number # before trying to save a new cache # 1G = 1073741824 gc-max-store-size-linux: 1G # do purge caches purge: true # purge all versions of the cache purge-prefixes: nix-${{ runner.os }}- # created more than this number of seconds ago purge-created: 0 # or, last accessed more than this number of seconds ago # relative to the start of the `Post Restore and save Nix store` phase purge-last-accessed: 0 # except any version with the key that is the same as the `primary-key` purge-primary-key: never # not needed (yet) # - uses: cachix/cachix-action@v12 # with: # name: hyprland # authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' - name: Build run: nix build --print-build-logs --keep-going hyprwm-hyprland-guiutils-c2e9062/.gitignore000066400000000000000000000004731512452253000210510ustar00rootroot00000000000000CMakeLists.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 hyprwm-hyprland-guiutils-c2e9062/CMakeLists.txt000066400000000000000000000040061512452253000216150ustar00rootroot00000000000000cmake_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) 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-c2e9062/LICENSE000066400000000000000000000027371512452253000200730ustar00rootroot00000000000000BSD 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-c2e9062/README.md000066400000000000000000000001131512452253000203270ustar00rootroot00000000000000# hyprland-guiutils Hyprland GUI utilities (successor to hyprland-qtutils) hyprwm-hyprland-guiutils-c2e9062/VERSION000066400000000000000000000000061512452253000201210ustar00rootroot000000000000000.2.1 hyprwm-hyprland-guiutils-c2e9062/flake.lock000066400000000000000000000117621512452253000210200ustar00rootroot00000000000000{ "nodes": { "aquamarine": { "inputs": { "hyprutils": [ "hyprutils" ], "hyprwayland-scanner": [ "hyprwayland-scanner" ], "nixpkgs": [ "nixpkgs" ], "systems": [ "systems" ] }, "locked": { "lastModified": 1762356719, "narHash": "sha256-qwd/xdoOya1m8FENle+4hWnydCtlXUWLAW/Auk6WL7s=", "owner": "hyprwm", "repo": "aquamarine", "rev": "6d0b3567584691bf9d8fedb5d0093309e2f979c7", "type": "github" }, "original": { "owner": "hyprwm", "repo": "aquamarine", "type": "github" } }, "hyprgraphics": { "inputs": { "hyprutils": [ "hyprutils" ], "nixpkgs": [ "nixpkgs" ], "systems": [ "systems" ] }, "locked": { "lastModified": 1763487816, "narHash": "sha256-DNjvMaSOM1xkyQa+qUqWEPQKGuAGmpQiF3ubHXc2K4s=", "owner": "hyprwm", "repo": "hyprgraphics", "rev": "1fb5bfbd6268eddb9117229f89879cc131775f0b", "type": "github" }, "original": { "owner": "hyprwm", "repo": "hyprgraphics", "type": "github" } }, "hyprlang": { "inputs": { "hyprutils": [ "hyprutils" ], "nixpkgs": [ "nixpkgs" ], "systems": [ "systems" ] }, "locked": { "lastModified": 1763404580, "narHash": "sha256-APyQ4L05EHRbQFS1t7nXex4u+g9Sh8J70W80djOnmI4=", "owner": "hyprwm", "repo": "hyprlang", "rev": "3d3057837c2e9e2c67d8570b08390599b7c528bf", "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": 1764592794, "narHash": "sha256-7CcO+wbTJ1L1NBQHierHzheQGPWwkIQug/w+fhTAVuU=", "owner": "hyprwm", "repo": "hyprtoolkit", "rev": "5cfe0743f0e608e1462972303778d8a0859ee63e", "type": "github" }, "original": { "owner": "hyprwm", "repo": "hyprtoolkit", "type": "github" } }, "hyprutils": { "inputs": { "nixpkgs": [ "nixpkgs" ], "systems": [ "systems" ] }, "locked": { "lastModified": 1763513463, "narHash": "sha256-72YmF4QUEAZfIFwN/v+KMCottqQdcTcJdLLa+QbggNQ=", "owner": "hyprwm", "repo": "hyprutils", "rev": "671792bcfeaaa58022941ed40c3993cd7f04e38d", "type": "github" }, "original": { "owner": "hyprwm", "repo": "hyprutils", "type": "github" } }, "hyprwayland-scanner": { "inputs": { "nixpkgs": [ "nixpkgs" ], "systems": [ "systems" ] }, "locked": { "lastModified": 1763640274, "narHash": "sha256-Uan1Nl9i4TF/kyFoHnTq1bd/rsWh4GAK/9/jDqLbY5A=", "owner": "hyprwm", "repo": "hyprwayland-scanner", "rev": "f6cf414ca0e16a4d30198fd670ec86df3c89f671", "type": "github" }, "original": { "owner": "hyprwm", "repo": "hyprwayland-scanner", "type": "github" } }, "nixpkgs": { "locked": { "lastModified": 1763421233, "narHash": "sha256-Stk9ZYRkGrnnpyJ4eqt9eQtdFWRRIvMxpNRf4sIegnw=", "owner": "NixOS", "repo": "nixpkgs", "rev": "89c2b2330e733d6cdb5eae7b899326930c2c0648", "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-c2e9062/flake.nix000066400000000000000000000046111512452253000206610ustar00rootroot00000000000000{ 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.default ]; } ); 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; }; }); }; } hyprwm-hyprland-guiutils-c2e9062/nix/000077500000000000000000000000001512452253000176535ustar00rootroot00000000000000hyprwm-hyprland-guiutils-c2e9062/nix/default.nix000066400000000000000000000017661512452253000220310ustar00rootroot00000000000000{ lib, stdenv, cmake, pkg-config, aquamarine, cairo, hyprgraphics, hyprlang, hyprtoolkit, hyprutils, libdrm, 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 libxkbcommon pixman ]; meta = { description = "Hyprland GUI utilities (successor to hyprland-guiutils)"; homepage = "https://github.com/hyprwm/hyprland-qtlibs"; license = lib.licenses.bsd3; maintainers = [ lib.maintainers.fufexan ]; platforms = lib.platforms.linux; }; } hyprwm-hyprland-guiutils-c2e9062/nix/overlays.nix000066400000000000000000000014661512452253000222460ustar00rootroot00000000000000{ 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 = lib.composeManyExtensions [ inputs.aquamarine.overlays.default inputs.hyprgraphics.overlays.default inputs.hyprlang.overlays.default inputs.hyprtoolkit.overlays.default inputs.hyprutils.overlays.default (final: prev: { hyprland-guiutils = final.callPackage ./. { stdenv = final.gcc15Stdenv; version = "${version}+date=${date}_${self.shortRev or "dirty"}"; }; }) ]; } hyprwm-hyprland-guiutils-c2e9062/nix/shell.nix000066400000000000000000000013671512452253000215110ustar00rootroot00000000000000{ 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-c2e9062/utils/000077500000000000000000000000001512452253000202155ustar00rootroot00000000000000hyprwm-hyprland-guiutils-c2e9062/utils/dialog/000077500000000000000000000000001512452253000214545ustar00rootroot00000000000000hyprwm-hyprland-guiutils-c2e9062/utils/dialog/CMakeLists.txt000066400000000000000000000021561512452253000242200ustar00rootroot00000000000000cmake_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-c2e9062/utils/dialog/src/000077500000000000000000000000001512452253000222435ustar00rootroot00000000000000hyprwm-hyprland-guiutils-c2e9062/utils/dialog/src/main.cpp000066400000000000000000000145231512452253000237000ustar00rootroot00000000000000#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) { setenv("HT_QUIET", "1", true); backend = IBackend::create(); 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; } std::print(stderr, "invalid arg {}\n", argv[i]); return 1; } // 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-c2e9062/utils/donate-screen/000077500000000000000000000000001512452253000227445ustar00rootroot00000000000000hyprwm-hyprland-guiutils-c2e9062/utils/donate-screen/CMakeLists.txt000066400000000000000000000022701512452253000255050ustar00rootroot00000000000000cmake_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-c2e9062/utils/donate-screen/src/000077500000000000000000000000001512452253000235335ustar00rootroot00000000000000hyprwm-hyprland-guiutils-c2e9062/utils/donate-screen/src/main.cpp000066400000000000000000000124311512452253000251640ustar00rootroot00000000000000#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 maintained by volunteers, and led by one person in their free time. Your support is valuable, and helps fund Hyprland's continued existence. You can donate once, or monthly, and it takes less than 5 minutes. We also have Hyprperks, which is 5€ + tax / mo, and gives you access to a few "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 * 20.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); 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-c2e9062/utils/run/000077500000000000000000000000001512452253000210215ustar00rootroot00000000000000hyprwm-hyprland-guiutils-c2e9062/utils/run/CMakeLists.txt000066400000000000000000000021261512452253000235620ustar00rootroot00000000000000cmake_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-c2e9062/utils/run/src/000077500000000000000000000000001512452253000216105ustar00rootroot00000000000000hyprwm-hyprland-guiutils-c2e9062/utils/run/src/main.cpp000066400000000000000000000153651512452253000232520ustar00rootroot00000000000000#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) { 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-c2e9062/utils/update-screen/000077500000000000000000000000001512452253000227545ustar00rootroot00000000000000hyprwm-hyprland-guiutils-c2e9062/utils/update-screen/CMakeLists.txt000066400000000000000000000022601512452253000255140ustar00rootroot00000000000000cmake_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-c2e9062/utils/update-screen/src/000077500000000000000000000000001512452253000235435ustar00rootroot00000000000000hyprwm-hyprland-guiutils-c2e9062/utils/update-screen/src/main.cpp000066400000000000000000000146371512452253000252060ustar00rootroot00000000000000#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! 😄 Please check the release notes, which can be found on GitHub, as well as the news page on hypr.land. Every release may come with breaking changes, so if you get any config errors, try checking the latest release notes. If you are using plugins, you will need to rebuild them. You can disable this screen in your Hyprland config.)#"; // int main(int argc, char** argv, char** envp) { setenv("HT_QUIET", "1", true); backend = IBackend::create(); 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; } std::print(stderr, "invalid arg {}\n", argv[i]); return 1; } // 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-c2e9062/utils/welcome/000077500000000000000000000000001512452253000216505ustar00rootroot00000000000000hyprwm-hyprland-guiutils-c2e9062/utils/welcome/CMakeLists.txt000066400000000000000000000021731512452253000244130ustar00rootroot00000000000000cmake_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-c2e9062/utils/welcome/src/000077500000000000000000000000001512452253000224375ustar00rootroot00000000000000hyprwm-hyprland-guiutils-c2e9062/utils/welcome/src/main.cpp000066400000000000000000000771251512452253000241030ustar00rootroot00000000000000#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 accomodated 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.conf, and add "exec-once = appname" to launch your apps, for example: exec-once = hyprpaper exec-once = waybar 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.conf. 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 trim(std::string((std::istreambuf_iterator(file)), (std::istreambuf_iterator()))); } static std::optional updateDefaultConfigVar(const std::string_view& var, const char* newValue) { const auto HOME = getenv("HOME"); if (!HOME) return "Can't save: no $HOME env"; const auto PATH = std::string{HOME} + "/.config/hypr/hyprland.conf"; const auto STR = readFileAsString(PATH); if (!STR) return "Can't save: failed to read config"; std::string newConfig = *STR; size_t varPos = newConfig.find("\n$"s + std::string{var}); if (varPos == std::string::npos) return "Can't save: config isn't default, doesn't have variable"; varPos++; size_t varEnd = newConfig.find('\n', varPos + 1); if (varEnd == std::string::npos) newConfig = std::format("{}${} = {}", newConfig.substr(0, varPos), var, newValue); else newConfig = std::format("{}${} = {}{}", newConfig.substr(0, varPos), var, newValue, newConfig.substr(varEnd)); std::ofstream ofs(PATH, std::ios::trunc); ofs << newConfig; ofs.close(); return std::nullopt; } static void removeAutogen() { const auto HOME = getenv("HOME"); if (!HOME) return; const auto PATH = std::string{HOME} + "/.config/hypr/hyprland.conf"; const auto STR = readFileAsString(PATH); if (!STR) return; std::string newConfig = *STR; size_t varPos = newConfig.find("\nautogenerated = 1"); if (varPos == std::string::npos) return; varPos++; size_t varEnd = newConfig.find('\n', varPos); newConfig = newConfig.substr(0, varPos) + newConfig.substr(varEnd); 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.conf") ->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) { 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; }