diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 8adef5c4..77c9c48b 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -13,34 +13,44 @@ jobs:
sed -i 's/SigLevel = Required DatabaseOptional/SigLevel = Optional TrustAll/' /etc/pacman.conf
pacman --noconfirm --noprogressbar -Syyu
pacman --noconfirm --noprogressbar -Sy glslang libepoxy libfontenc libxcvt libxfont2 libxkbfile vulkan-headers vulkan-validation-layers xcb-util-errors xcb-util-renderutil xcb-util-wm xorg-fonts-encodings xorg-server-common xorg-setxkbmap xorg-xkbcomp xorg-xwayland git cmake go clang lld libc++ pkgconf meson ninja wayland wayland-protocols libinput libxkbcommon pixman glm libdrm libglvnd cairo pango systemd scdoc base-devel seatd
-
- name: Set up user
run: |
useradd -m githubuser
echo -e "root ALL=(ALL:ALL) ALL\ngithubuser ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers
-
- name: Build wlroots
run: |
su githubuser -c "cd ~ && git clone https://gitlab.freedesktop.org/wlroots/wlroots"
su githubuser -c "cd ~/wlroots && meson build/ --prefix=/usr && ninja -C build/ && sudo ninja -C build/ install && cd .."
-
- name: Fix permissions for git
run: |
git config --global --add safe.directory /__w/Hyprland/Hyprland
-
- name: Checkout Hyprland
uses: actions/checkout@v3
with:
submodules: recursive
-
- - name: Build Hyprland With default settings
+ - name: Build Hyprland
run: |
git submodule sync --recursive && git submodule update --init --force --recursive
make all
-
- - name: Build Hyprland with LEGACY_RENDERER
+ - name: Compress and package artifacts
run: |
- make legacyrenderer
+ mkdir x86_64-pc-linux-gnu
+ mkdir hyprland
+ mkdir hyprland/example
+ mkdir hyprland/assets
+ cp ./LICENSE hyprland/
+ cp build/Hyprland hyprland/
+ cp hyprctl/hyprctl hyprland/
+ cp subprojects/wlroots/build/libwlroots.so.11032 hyprland/
+ cp build/Hyprland hyprland/
+ cp -r example/ hyprland/
+ cp -r assets/ hyprland/
+ tar -cvf Hyprland.tar.xz hyprland
+ - name: Release
+ uses: actions/upload-artifact@v3
+ with:
+ name: Build archive
+ path: Hyprland.tar.xz
meson:
name: "Build Hyprland with Meson (Arch)"
@@ -63,13 +73,13 @@ jobs:
-Ddefault_library=static
- name: Compile
run: ninja -C obj-x86_64-pc-linux-gnu
- - name: Compress artifacts
- run: |
- mkdir x86_64-pc-linux-gnu
- DESTDIR=$PWD/x86_64-pc-linux-gnu meson install -C obj-x86_64-pc-linux-gnu --tags runtime
- tar -cvf x86_64-pc-linux-gnu.tar.xz x86_64-pc-linux-gnu
- - name: Upload artifacts
- uses: actions/upload-artifact@v3
- with:
- name: Build artifacts (x86_64-pc-linux-gnu)
- path: x86_64-pc-linux-gnu.tar.xz
+# - name: Compress artifacts
+# run: |
+# mkdir x86_64-pc-linux-gnu
+# DESTDIR=$PWD/x86_64-pc-linux-gnu meson install -C obj-x86_64-pc-linux-gnu --tags runtime
+# tar -cvf x86_64-pc-linux-gnu.tar.xz x86_64-pc-linux-gnu
+# - name: Upload artifacts
+# uses: actions/upload-artifact@v3
+# with:
+# name: Build artifacts (x86_64-pc-linux-gnu)
+# path: x86_64-pc-linux-gnu.tar.xz
diff --git a/.github/workflows/version-update.sh b/.github/workflows/version-update.sh
new file mode 100644
index 00000000..1bf95af9
--- /dev/null
+++ b/.github/workflows/version-update.sh
@@ -0,0 +1,26 @@
+name: "Nix & Meson: update version"
+
+on: [push, workflow_dispatch]
+
+jobs:
+ update:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Clone repository
+ uses: actions/checkout@v3
+ - name: Update flake and meson version
+ run: |
+ REGEX="([0-9]+(\.[0-9a-zA-Z]+)+)"
+
+ CRT_REV=$(git show-ref --tags --head --abbrev | head -n 1 | head -c 7)
+ TAG_REV=$(git show-ref --tags --abbrev | tail -n 1 | head -c 7)
+ CRT_VER=$(sed -nEe "/$REGEX/{p;q;}" meson.build | awk -F\' '{print $2}')
+ VERSION=$(git show-ref --tags --abbrev | tail -n 1 | tail -c +20)
+
+ if [[ $TAG_REV = $CRT_REV ]] || [[ $CRT_VER != $VERSION ]]; then
+ sed -Ei "s/$REGEX/$VERSION/g" meson.build
+ sed -Ei "s/$REGEX/$VERSION/g" flake.nix
+ fi
+ - uses: stefanzweifel/git-auto-commit-action@v4
+ with:
+ commit_message: "[gha] bump flake and meson version"
diff --git a/.gitmodules b/.gitmodules
index 01c7b0d5..61cb4cef 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,3 @@
[submodule "wlroots"]
path = subprojects/wlroots
- url = https://github.com/ThatOneCalculator/wlroots-mirror
+ url = https://gitlab.freedesktop.org/wlroots/wlroots.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e78eea0e..44246e7e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -59,6 +59,7 @@ ENDIF(NO_XWAYLAND MATCHES true)
IF(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
message(STATUS "Configuring Hyprland in Debug with CMake!")
+ add_definitions( -DHYPRLAND_DEBUG )
ELSE()
# add_compile_options(-O3) # may crash for some
message(STATUS "Configuring Hyprland in Release with CMake!")
diff --git a/Makefile b/Makefile
index eb306932..bb753451 100644
--- a/Makefile
+++ b/Makefile
@@ -136,4 +136,4 @@ config:
cd subprojects/wlroots && meson ./build --prefix=/usr --buildtype=release
cd subprojects/wlroots && ninja -C build/
- cd subprojects/wlroots && sudo ninja -C build/ install
+ cd subprojects/wlroots && ninja -C build/ install
diff --git a/README.md b/README.md
index 68ff18d5..faf8acca 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
-![Banner]
+
@@ -151,7 +151,6 @@ Try it out and report bugs / suggestions!
[Preview A]: https://i.imgur.com/NbrTnZH.png
[Preview B]: https://i.imgur.com/ZA4Fa8R.png
[Preview C]: https://i.imgur.com/BpXxM8H.png
-[Banner]: https://raw.githubusercontent.com/vaxerski/Hyprland/main/assets/hyprland.png
diff --git a/assets/header.svg b/assets/header.svg
new file mode 100644
index 00000000..922313be
--- /dev/null
+++ b/assets/header.svg
@@ -0,0 +1,83 @@
+
diff --git a/aur/PKGBUILD b/aur/PKGBUILD
deleted file mode 100644
index deab5a93..00000000
--- a/aur/PKGBUILD
+++ /dev/null
@@ -1,72 +0,0 @@
-# Maintainer: ThatOneCalculator
-
-_pkgname="hyprland"
-pkgname="${_pkgname}"
-pkgver="0.4.0beta"
-pkgrel=2
-pkgdesc="A dynamic tiling Wayland compositor based on wlroots that doesn't sacrifice on its looks."
-arch=(any)
-url="https://github.com/vaxerski/Hyprland"
-license=('BSD')
-depends=(
- libxcb
- xcb-proto
- xcb-util
- xcb-util-keysyms
- libxfixes
- libx11
- libxcomposite
- xorg-xinput
- libxrender
- pixman
- wayland-protocols
- cairo
- pango
- polkit
- glslang
- libinput
- libxcb
- libxkbcommon
- opengl-driver
- pixman
- wayland
- xcb-util-errors
- xcb-util-renderutil
- xcb-util-wm
- seatd
- vulkan-icd-loader
- vulkan-validation-layers
- xorg-xwayland)
-makedepends=(
- git
- cmake
- ninja
- gcc
- gdb
- meson
- vulkan-headers
- wayland-protocols
- xorgproto)
-source=("${pkgname}-${pkgver}.tar.gz::https://github.com/vaxerski/hyprland/archive/v${pkgver}.tar.gz")
-sha256sums=('5969e5f88426f90acdfb5958644733d8a9409389c2d345514c58a66cf74d2f91')
-conflicts=("${_pkgname}")
-provides=(hyprland)
-options=(!makeflags !buildflags)
-
-build() {
- cd "$srcdir/Hyprland-$pkgver"
- git submodule update --init
- make all
-}
-
-package() {
- cd "$srcdir/Hyprland-$pkgver"
- mkdir -p "${pkgdir}/usr/share/wayland-sessions"
- mkdir -p "${pkgdir}/usr/share/hyprland"
- install -Dm755 build/Hyprland -t "${pkgdir}/usr/bin"
- install -Dm755 hyprctl/hyprctl -t "${pkgdir}/usr/bin"
- install -Dm644 assets/*.png -t "${pkgdir}/usr/share/hyprland"
- install -Dm644 example/hyprland.desktop -t "${pkgdir}/usr/share/wayland-sessions"
- install -Dm644 example/hyprland.conf -t "${pkgdir}/usr/share/hyprland"
- install -Dm644 LICENSE -t "${pkgdir}/usr/share/licenses/${_pkgname}"
-}
diff --git a/aur/PKGBUILD-bin b/aur/PKGBUILD-bin
deleted file mode 100644
index 62c3a9fa..00000000
--- a/aur/PKGBUILD-bin
+++ /dev/null
@@ -1,56 +0,0 @@
-# Maintainer: ThatOneCalculator
-
-_pkgname="hyprland"
-pkgname="${_pkgname}-bin"
-pkgver="0.4.0beta"
-pkgrel=2
-pkgdesc="A dynamic tiling Wayland compositor based on wlroots that doesn't sacrifice on its looks."
-arch=(any)
-url="https://github.com/vaxerski/Hyprland"
-license=('BSD')
-depends=(
- libxcb
- xcb-proto
- xcb-util
- xcb-util-keysyms
- libxfixes
- libx11
- libxcomposite
- xorg-xinput
- libxrender
- pixman
- wayland-protocols
- cairo
- pango
- polkit
- glslang
- libinput
- libxcb
- libxkbcommon
- opengl-driver
- pixman
- wayland
- xcb-util-errors
- xcb-util-renderutil
- xcb-util-wm
- seatd
- vulkan-icd-loader
- vulkan-validation-layers
- xorg-xwayland)
-source=("${pkgname}-${pkgver}.tar.gz::https://github.com/vaxerski/Hyprland/releases/download/v${pkgver}/v${pkgver}.tar.gz")
-sha256sums=('5969e5f88426f90acdfb5958644733d8a9409389c2d345514c58a66cf74d2f91')
-conflicts=("${_pkgname}")
-provides=(hyprland)
-
-package() {
- cd "$srcdir/Hyprland-$pkgver"
- mkdir -p "${pkgdir}/usr/share/wayland-sessions"
- mkdir -p "${pkgdir}/usr/share/hyprland"
- install -Dm755 ./Hyprland -t "${pkgdir}/usr/bin"
- install -Dm755 ./hyprctl -t "${pkgdir}/usr/bin"
- install -Dm755 ./libwlroots.so.11032 -t "${pkgdir}/usr/lib"
- install -Dm644 assets/*.png -t "${pkgdir}/usr/share/hyprland"
- install -Dm644 example/hyprland.desktop -t "${pkgdir}/usr/share/wayland-sessions"
- install -Dm644 example/hyprland.conf -t "${pkgdir}/usr/share/hyprland"
- install -Dm644 LICENSE -t "${pkgdir}/usr/share/licenses/${_pkgname}"
-}
diff --git a/aur/PKGBUILD-git b/aur/PKGBUILD-git
deleted file mode 100644
index b6443a2c..00000000
--- a/aur/PKGBUILD-git
+++ /dev/null
@@ -1,80 +0,0 @@
-# Maintainer: ThatOneCalculator , Sander van Kasteel
-
-_pkgname="hyprland"
-pkgname="${_pkgname}-git"
-pkgver=r673.gb62e530
-pkgrel=2
-pkgdesc="A dynamic tiling Wayland compositor based on wlroots that doesn't sacrifice on its looks."
-arch=(any)
-url="https://github.com/vaxerski/Hyprland"
-license=('BSD')
-depends=(
- libxcb
- xcb-proto
- xcb-util
- xcb-util-keysyms
- libxfixes
- libx11
- libxcomposite
- xorg-xinput
- libxrender
- pixman
- wayland-protocols
- cairo
- pango
- polkit
- glslang
- libinput
- libxcb
- libxkbcommon
- opengl-driver
- pixman
- wayland
- xcb-util-errors
- xcb-util-renderutil
- xcb-util-wm
- seatd
- vulkan-icd-loader
- vulkan-validation-layers
- xorg-xwayland)
-makedepends=(
- git
- cmake
- ninja
- gcc
- gdb
- meson
- vulkan-headers
- wayland-protocols
- xorgproto)
-source=("${_pkgname}::git+https://github.com/vaxerski/Hyprland.git")
-conflicts=("${_pkgname}")
-provides=(hyprland)
-sha256sums=('SKIP')
-options=(!makeflags !buildflags)
-
-pkgver() {
- cd "$_pkgname"
- ( set -o pipefail
- git describe --long 2>/dev/null | sed 's/\([^-]*-g\)/r\1/;s/-/./g' ||
- printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
- )
-}
-
-build() {
- cd "${srcdir}/${_pkgname}"
- git submodule update --init
- make all
-}
-
-package() {
- cd "${srcdir}/${_pkgname}"
- mkdir -p "${pkgdir}/usr/share/wayland-sessions"
- mkdir -p "${pkgdir}/usr/share/hyprland"
- install -Dm755 build/Hyprland -t "${pkgdir}/usr/bin"
- install -Dm755 hyprctl/hyprctl -t "${pkgdir}/usr/bin"
- install -Dm644 assets/*.png -t "${pkgdir}/usr/share/hyprland"
- install -Dm644 example/hyprland.desktop -t "${pkgdir}/usr/share/wayland-sessions"
- install -Dm644 example/hyprland.conf -t "${pkgdir}/usr/share/hyprland"
- install -Dm644 LICENSE -t "${pkgdir}/usr/share/licenses/${_pkgname}"
-}
diff --git a/example/hyprland.conf b/example/hyprland.conf
index d67355aa..931baf49 100644
--- a/example/hyprland.conf
+++ b/example/hyprland.conf
@@ -27,6 +27,8 @@ general {
col.active_border=0x66ee1111
col.inactive_border=0x66333333
+ apply_sens_to_raw=0 # do not apply the sensitivity to raw input (e.g. used by games where you aim)
+
damage_tracking=full # leave it on full unless you hate your GPU and want to make it suffer
}
diff --git a/flake.lock b/flake.lock
index 06d8ffcf..71e49721 100644
--- a/flake.lock
+++ b/flake.lock
@@ -2,11 +2,11 @@
"nodes": {
"nixpkgs": {
"locked": {
- "lastModified": 1654593855,
- "narHash": "sha256-c+SyXvj7THre87OyIdZfRVR+HhI/g1ZDrQ3VUtTuHkU=",
+ "lastModified": 1655807518,
+ "narHash": "sha256-5YV29Ry/DpAJc/0Hc/+ISVBAjwHpJvAkeKkcUG5lWsc=",
"owner": "NixOS",
"repo": "nixpkgs",
- "rev": "033bd4fa9a8fbe0c68a88e925d9a884161044b25",
+ "rev": "a72d7811be1162dd6804c4e36e5402d76fb6e921",
"type": "github"
},
"original": {
diff --git a/flake.nix b/flake.nix
index a756ed90..882569a8 100644
--- a/flake.nix
+++ b/flake.nix
@@ -16,40 +16,37 @@
}: let
inherit (nixpkgs) lib;
genSystems = lib.genAttrs [
+ # Add more systems if they are supported
"x86_64-linux"
];
pkgsFor = nixpkgs.legacyPackages;
- # https://github.com/NixOS/rfcs/pull/107
- mkVersion = longDate:
- lib.concatStrings [
- "0.pre"
- "+date="
- (lib.concatStringsSep "-" [
- (__substring 0 4 longDate)
- (__substring 4 2 longDate)
- (__substring 6 2 longDate)
- ])
- ];
+ mkDate = longDate: (lib.concatStringsSep "-" [
+ (__substring 0 4 longDate)
+ (__substring 4 2 longDate)
+ (__substring 6 2 longDate)
+ ]);
in {
- packages = genSystems (system: {
- wlroots = pkgsFor.${system}.wlroots.overrideAttrs (prev: {
- version = mkVersion (toString (inputs.wlroots.lastModifiedDate or inputs.wlroots.lastModified or "19700101"));
+ overlays.default = _: prev: rec {
+ wlroots-hyprland = prev.wlroots.overrideAttrs (__: {
+ version = mkDate (inputs.wlroots.lastModifiedDate or "19700101");
src = inputs.wlroots;
});
- default = pkgsFor.${system}.callPackage ./nix/default.nix {
- version = mkVersion (toString (self.lastModifiedDate or self.lastModified or "19700101"));
- inherit (self.packages.${system}) wlroots;
+ hyprland = prev.callPackage ./nix/default.nix {
+ version = "0.5.0beta" + "+date=" + (mkDate (self.lastModifiedDate or "19700101"));
+ wlroots = wlroots-hyprland;
};
- });
+ };
+
+ packages = genSystems (system:
+ (self.overlays.default null pkgsFor.${system})
+ // {
+ default = self.packages.${system}.hyprland;
+ });
formatter = genSystems (system: pkgsFor.${system}.alejandra);
nixosModules.default = import ./nix/module.nix self;
- # Deprecated
- overlays.default = _: prev: {
- hyprland = self.packages.${prev.system}.default;
- };
- overlay = self.overlays.default;
+ overlay = throw "Hyprland: .overlay output is deprecated, please use the .overlays.default output";
};
}
diff --git a/meson.build b/meson.build
index b902c80a..f75f64fd 100644
--- a/meson.build
+++ b/meson.build
@@ -1,5 +1,5 @@
project('Hyprland', 'cpp', 'c',
- version : '0.1',
+ version : '0.5.0beta',
default_options : ['warning_level=3', 'cpp_std=c++20', 'default_library=static'])
wlroots = subproject('wlroots', default_options: ['examples=false'])
diff --git a/nix/default.nix b/nix/default.nix
index 20586b9f..18570f12 100644
--- a/nix/default.nix
+++ b/nix/default.nix
@@ -3,7 +3,7 @@
stdenv,
fetchFromGitHub,
pkg-config,
- cmake,
+ meson,
ninja,
libdrm,
libinput,
@@ -27,7 +27,7 @@ stdenv.mkDerivation {
src = ../.;
nativeBuildInputs = [
- cmake
+ meson
ninja
pkg-config
];
@@ -48,33 +48,14 @@ stdenv.mkDerivation {
]
++ lib.optional enableXWayland xwayland;
- cmakeFlags =
- ["-DCMAKE_BUILD_TYPE=Release"]
- ++ lib.optional (!enableXWayland) "-DNO_XWAYLAND=true";
+ mesonBuildType = "release";
- # enables building with nix-supplied wlroots instead of submodule
- prePatch = ''
- sed -Ei 's/"\.\.\/wlroots\/include\/([a-zA-Z0-9./_-]+)"/<\1>/g' src/includes.hpp
- '';
- postPatch = ''
- make protocols
- '';
+ mesonFlags = lib.optional (!enableXWayland) "-DNO_XWAYLAND=true";
- postBuild = ''
- pushd ../hyprctl
- make all
- popd
- '';
-
- installPhase = ''
- pushd ..
- install -Dm644 ./example/hyprland.desktop -t $out/share/wayland-sessions
- install -Dm755 ./build/Hyprland -t $out/bin
- install -Dm755 ./hyprctl/hyprctl -t $out/bin
- install -Dm644 ./assets/* -t $out/share/hyprland
- install -Dm644 ./example/hyprland.conf -t $out/share/hyprland
- popd
- '';
+ patches = [
+ # make meson use the provided wlroots instead of the git submodule
+ ./meson-build.patch
+ ];
passthru.providedSessions = ["hyprland"];
diff --git a/nix/meson-build.patch b/nix/meson-build.patch
new file mode 100644
index 00000000..57950de9
--- /dev/null
+++ b/nix/meson-build.patch
@@ -0,0 +1,36 @@
+diff --git a/meson.build b/meson.build
+index 22ee4bf..5528613 100644
+--- a/meson.build
++++ b/meson.build
+@@ -2,16 +2,10 @@ project('Hyprland', 'cpp', 'c',
+ version : '0.1',
+ default_options : ['warning_level=3', 'cpp_std=c++20', 'default_library=static'])
+
+-wlroots = subproject('wlroots', default_options: ['examples=false'])
+-have_xwlr = wlroots.get_variable('features').get('xwayland')
++wlroots = dependency('wlroots', version: '>=0.16.0')
+ xcb_dep = dependency('xcb', required: get_option('xwayland'))
+
+-if get_option('xwayland').enabled() and not have_xwlr
+- error('Cannot enable Xwayland in Hyprland: wlroots has been built without Xwayland support')
+-endif
+-have_xwayland = xcb_dep.found() and have_xwlr
+-
+-if not have_xwayland
++if not xcb_dep.found()
+ add_project_arguments('-DNO_XWAYLAND', language: 'cpp')
+ endif
+
+diff --git a/src/meson.build b/src/meson.build
+index 5d64188..a676333 100644
+--- a/src/meson.build
++++ b/src/meson.build
+@@ -7,7 +7,7 @@ executable('Hyprland', src,
+ server_protos,
+ dependency('wayland-server'),
+ dependency('wayland-client'),
+- wlroots.get_variable('wlroots'),
++ wlroots,
+ dependency('cairo'),
+ dependency('pango'),
+ dependency('pangocairo'),
diff --git a/nix/module.nix b/nix/module.nix
index a7460b34..383eebb7 100644
--- a/nix/module.nix
+++ b/nix/module.nix
@@ -19,7 +19,7 @@ in {
package = mkOption {
type = types.package;
- default = self.packages.${pkgs.system}.default;
+ default = pkgs.hyprland or self.packages.${pkgs.system}.default;
defaultText = literalExpression ".packages..default";
example = literalExpression ".packages..default.override { }";
description = ''
diff --git a/src/Compositor.cpp b/src/Compositor.cpp
index 32ffab34..be94c093 100644
--- a/src/Compositor.cpp
+++ b/src/Compositor.cpp
@@ -443,7 +443,11 @@ wlr_surface* CCompositor::vectorWindowToSurface(const Vector2D& pos, CWindow* pW
double subx, suby;
- const auto PFOUND = wlr_xdg_surface_surface_at(PSURFACE, pos.x - pWindow->m_vRealPosition.vec().x, pos.y - pWindow->m_vRealPosition.vec().y, &subx, &suby);
+ // calc for oversized windows... fucking bullshit, again.
+ wlr_box geom;
+ wlr_xdg_surface_get_geometry(pWindow->m_uSurface.xdg, &geom);
+
+ const auto PFOUND = wlr_xdg_surface_surface_at(PSURFACE, pos.x - pWindow->m_vRealPosition.vec().x + geom.x, pos.y - pWindow->m_vRealPosition.vec().y + geom.y, &subx, &suby);
if (PFOUND) {
sl.x = subx;
@@ -454,6 +458,9 @@ wlr_surface* CCompositor::vectorWindowToSurface(const Vector2D& pos, CWindow* pW
sl.x = pos.x - pWindow->m_vRealPosition.vec().x;
sl.y = pos.y - pWindow->m_vRealPosition.vec().y;
+ sl.x += geom.x;
+ sl.y += geom.y;
+
return PSURFACE->surface;
}
@@ -763,18 +770,24 @@ void CCompositor::cleanupFadingOut() {
}
CWindow* CCompositor::getWindowInDirection(CWindow* pWindow, char dir) {
- const auto POSA = pWindow->m_vPosition;
- const auto SIZEA = pWindow->m_vSize;
+
+ const auto WINDOWIDEALBB = pWindow->getWindowIdealBoundingBoxIgnoreReserved();
+
+ const auto POSA = Vector2D(WINDOWIDEALBB.x, WINDOWIDEALBB.y);
+ const auto SIZEA = Vector2D(WINDOWIDEALBB.width, WINDOWIDEALBB.height);
auto longestIntersect = -1;
CWindow* longestIntersectWindow = nullptr;
for (auto& w : m_lWindows) {
- if (&w == pWindow || !windowValidMapped(&w) || w.m_bIsFloating || w.m_iWorkspaceID != pWindow->m_iWorkspaceID)
+ if (&w == pWindow || !windowValidMapped(&w) || w.m_bIsFloating || !isWorkspaceVisible(w.m_iWorkspaceID))
continue;
- const auto POSB = w.m_vPosition;
- const auto SIZEB = w.m_vSize;
+ const auto BWINDOWIDEALBB = w.getWindowIdealBoundingBoxIgnoreReserved();
+
+ const auto POSB = Vector2D(BWINDOWIDEALBB.x, BWINDOWIDEALBB.y);
+ const auto SIZEB = Vector2D(BWINDOWIDEALBB.width, BWINDOWIDEALBB.height);
+
switch (dir) {
case 'l':
if (STICKS(POSA.x, POSB.x + SIZEB.x)) {
diff --git a/src/Window.cpp b/src/Window.cpp
index 2182d47c..8476360a 100644
--- a/src/Window.cpp
+++ b/src/Window.cpp
@@ -43,4 +43,29 @@ wlr_box CWindow::getFullWindowBoundingBox() {
m_vRealSize.vec().y + maxExtents.topLeft.y + maxExtents.bottomRight.y};
return finalBox;
+}
+
+wlr_box CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
+
+ const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
+
+ auto POS = m_vPosition;
+ auto SIZE = m_vSize;
+
+ if (DELTALESSTHAN(POS.y - PMONITOR->vecPosition.y, PMONITOR->vecReservedTopLeft.y, 1)) {
+ POS.y = PMONITOR->vecPosition.y;
+ SIZE.y += PMONITOR->vecReservedTopLeft.y;
+ }
+ if (DELTALESSTHAN(POS.x - PMONITOR->vecPosition.x, PMONITOR->vecReservedTopLeft.x, 1)) {
+ POS.x = PMONITOR->vecPosition.x;
+ SIZE.x += PMONITOR->vecReservedTopLeft.x;
+ }
+ if (DELTALESSTHAN(POS.x + SIZE.x - PMONITOR->vecPosition.x, PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x, 1)) {
+ SIZE.x += PMONITOR->vecReservedBottomRight.x;
+ }
+ if (DELTALESSTHAN(POS.y + SIZE.y - PMONITOR->vecPosition.y, PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y, 1)) {
+ SIZE.y += PMONITOR->vecReservedBottomRight.y;
+ }
+
+ return wlr_box{(int)POS.x, (int)POS.y, (int)SIZE.x, (int)SIZE.y};
}
\ No newline at end of file
diff --git a/src/Window.hpp b/src/Window.hpp
index 7d357292..06140303 100644
--- a/src/Window.hpp
+++ b/src/Window.hpp
@@ -108,5 +108,6 @@ public:
// methods
wlr_box getFullWindowBoundingBox();
+ wlr_box getWindowIdealBoundingBoxIgnoreReserved();
};
\ No newline at end of file
diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp
index d511c05a..c3621847 100644
--- a/src/config/ConfigManager.cpp
+++ b/src/config/ConfigManager.cpp
@@ -20,7 +20,7 @@ CConfigManager::CConfigManager() {
void CConfigManager::setDefaultVars() {
configValues["general:max_fps"].intValue = 240;
configValues["general:sensitivity"].floatValue = 0.25f;
- configValues["general:apply_sens_to_raw"].intValue = 1;
+ configValues["general:apply_sens_to_raw"].intValue = 0;
configValues["general:main_mod"].strValue = "SUPER"; // exposed to the user for easier configuring
configValues["general:main_mod_internal"].intValue = g_pKeybindManager->stringToModMask("SUPER"); // actually used and automatically calculated
@@ -28,6 +28,7 @@ void CConfigManager::setDefaultVars() {
configValues["general:damage_tracking_internal"].intValue = DAMAGE_TRACKING_NONE;
configValues["general:border_size"].intValue = 1;
+ configValues["general:no_border_on_floating"].intValue = 0;
configValues["general:gaps_in"].intValue = 5;
configValues["general:gaps_out"].intValue = 20;
configValues["general:col.active_border"].intValue = 0xffffffff;
@@ -46,6 +47,7 @@ void CConfigManager::setDefaultVars() {
configValues["decoration:inactive_opacity"].floatValue = 1;
configValues["decoration:fullscreen_opacity"].floatValue = 1;
configValues["decoration:multisample_edges"].intValue = 0;
+ configValues["decoration:no_blur_on_oversized"].intValue = 1;
configValues["dwindle:pseudotile"].intValue = 0;
configValues["dwindle:col.group_border"].intValue = 0x66777700;
@@ -415,7 +417,7 @@ void CConfigManager::handleAnimation(const std::string& command, const std::stri
configSetValueSafe("animations:" + ANIMNAME + "_style", curitem);
}
-void CConfigManager::handleBind(const std::string& command, const std::string& value) {
+void CConfigManager::handleBind(const std::string& command, const std::string& value, bool locked) {
// example:
// bind=SUPER,G,exec,dmenu_run
@@ -448,7 +450,7 @@ void CConfigManager::handleBind(const std::string& command, const std::string& v
}
if (KEY != "")
- g_pKeybindManager->addKeybind(SKeybind{KEY, MOD, HANDLER, COMMAND});
+ g_pKeybindManager->addKeybind(SKeybind{KEY, MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap});
}
void CConfigManager::handleUnbind(const std::string& command, const std::string& value) {
@@ -495,16 +497,23 @@ void CConfigManager::handleWindowRule(const std::string& command, const std::str
void CConfigManager::handleDefaultWorkspace(const std::string& command, const std::string& value) {
const auto DISPLAY = value.substr(0, value.find_first_of(','));
- const auto WORKSPACEID = stoi(value.substr(value.find_first_of(',') + 1));
+ const auto WORKSPACE = value.substr(value.find_first_of(',') + 1);
for (auto& mr : m_dMonitorRules) {
if (mr.name == DISPLAY) {
- mr.defaultWorkspaceID = WORKSPACEID;
+ mr.defaultWorkspace = WORKSPACE;
break;
}
}
}
+void CConfigManager::handleSubmap(const std::string& command, const std::string& submap) {
+ if (submap == "reset")
+ m_szCurrentSubmap = "";
+ else
+ m_szCurrentSubmap = submap;
+}
+
void CConfigManager::handleSource(const std::string& command, const std::string& rawpath) {
static const char* const ENVHOME = getenv("HOME");
@@ -578,12 +587,14 @@ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std::
}
else if (COMMAND == "monitor") handleMonitor(COMMAND, VALUE);
else if (COMMAND == "bind") handleBind(COMMAND, VALUE);
+ else if (COMMAND == "bindl") handleBind(COMMAND, VALUE, true);
else if (COMMAND == "unbind") handleUnbind(COMMAND, VALUE);
else if (COMMAND == "workspace") handleDefaultWorkspace(COMMAND, VALUE);
else if (COMMAND == "windowrule") handleWindowRule(COMMAND, VALUE);
else if (COMMAND == "bezier") handleBezier(COMMAND, VALUE);
else if (COMMAND == "animation") handleAnimation(COMMAND, VALUE);
else if (COMMAND == "source") handleSource(COMMAND, VALUE);
+ else if (COMMAND == "submap") handleSubmap(COMMAND, VALUE);
else
configSetValueSafe(currentCategory + (currentCategory == "" ? "" : ":") + COMMAND, VALUE);
@@ -900,15 +911,26 @@ std::vector CConfigManager::getMatchingRules(CWindow* pWindow) {
std::string title = g_pXWaylandManager->getTitle(pWindow);
std::string appidclass = g_pXWaylandManager->getAppIDClass(pWindow);
+ Debug::log(LOG, "Searching for matching rules for %s (title: %s)", appidclass.c_str(), title.c_str());
+
for (auto& rule : m_dWindowRules) {
// check if we have a matching rule
try {
- std::regex classCheck(rule.szValue);
+ if (rule.szValue.find("title:") == 0) {
+ // we have a title rule.
+ std::regex RULECHECK(rule.szValue.substr(6));
- if (!std::regex_search(title, classCheck) && !std::regex_search(appidclass, classCheck))
- continue;
+ if (!std::regex_search(title, RULECHECK))
+ continue;
+ } else {
+ std::regex classCheck(rule.szValue);
+
+ if (!std::regex_search(appidclass, classCheck))
+ continue;
+ }
} catch (...) {
Debug::log(ERR, "Regex error at %s", rule.szValue.c_str());
+ continue;
}
// applies. Read the rule and behave accordingly
diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp
index 866b8b8e..8c0bd857 100644
--- a/src/config/ConfigManager.hpp
+++ b/src/config/ConfigManager.hpp
@@ -28,7 +28,7 @@ struct SMonitorRule {
Vector2D offset = Vector2D(0,0);
float scale = 1;
float refreshRate = 60;
- int defaultWorkspaceID = -1;
+ std::string defaultWorkspace = "";
bool disabled = false;
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
};
@@ -88,6 +88,8 @@ private:
std::string parseError = ""; // For storing a parse error to display later
+ std::string m_szCurrentSubmap = ""; // For storing the current keybind submap
+
bool isFirstLaunch = true; // For exec-once
std::deque m_dMonitorRules;
@@ -106,13 +108,14 @@ private:
void configSetValueSafe(const std::string&, const std::string&);
void handleRawExec(const std::string&, const std::string&);
void handleMonitor(const std::string&, const std::string&);
- void handleBind(const std::string&, const std::string&);
+ void handleBind(const std::string&, const std::string&, bool locked = false);
void handleUnbind(const std::string&, const std::string&);
void handleWindowRule(const std::string&, const std::string&);
void handleDefaultWorkspace(const std::string&, const std::string&);
void handleBezier(const std::string&, const std::string&);
void handleAnimation(const std::string&, const std::string&);
void handleSource(const std::string&, const std::string&);
+ void handleSubmap(const std::string&, const std::string&);
};
inline std::unique_ptr g_pConfigManager;
\ No newline at end of file
diff --git a/src/config/defaultConfig.hpp b/src/config/defaultConfig.hpp
index 30ef5009..fbf3981d 100644
--- a/src/config/defaultConfig.hpp
+++ b/src/config/defaultConfig.hpp
@@ -34,6 +34,8 @@ general {
col.active_border=0x66ee1111
col.inactive_border=0x66333333
+ apply_sens_to_raw=0 # do not apply the sensitivity to raw input (e.g. used by games where you aim)
+
damage_tracking=full # leave it on full unless you hate your GPU and want to make it suffer
}
diff --git a/src/events/Monitors.cpp b/src/events/Monitors.cpp
index e5fa7c55..afbc0745 100644
--- a/src/events/Monitors.cpp
+++ b/src/events/Monitors.cpp
@@ -114,7 +114,15 @@ void Events::listener_newOutput(wl_listener* listener, void* data) {
wlr_ext_workspace_group_handle_v1_output_enter(PNEWMONITOR->pWLRWorkspaceGroupHandle, PNEWMONITOR->output);
// Workspace
- const auto WORKSPACEID = monitorRule.defaultWorkspaceID == -1 ? g_pCompositor->m_lWorkspaces.size() + 1 /* Cuz workspaces doesnt have the new one yet and we start with 1 */ : monitorRule.defaultWorkspaceID;
+ std::string newDefaultWorkspaceName = "";
+ auto WORKSPACEID = monitorRule.defaultWorkspace == "" ? g_pCompositor->m_lWorkspaces.size() + 1 : getWorkspaceIDFromString(monitorRule.defaultWorkspace, newDefaultWorkspaceName);
+
+ if (WORKSPACEID == INT_MAX || WORKSPACEID == (long unsigned int)SPECIAL_WORKSPACE_ID) {
+ WORKSPACEID = g_pCompositor->m_lWorkspaces.size() + 1;
+ newDefaultWorkspaceName = std::to_string(WORKSPACEID);
+
+ Debug::log(LOG, "Invalid workspace= directive name in monitor parsing, workspace name \"%s\" is invalid.", monitorRule.defaultWorkspace);
+ }
auto PNEWWORKSPACE = g_pCompositor->getWorkspaceByID(WORKSPACEID);
@@ -127,19 +135,20 @@ void Events::listener_newOutput(wl_listener* listener, void* data) {
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PNEWMONITOR->ID);
PNEWWORKSPACE->startAnim(true,true,true);
} else {
- g_pCompositor->m_lWorkspaces.emplace_back(newMonitor.ID);
- PNEWWORKSPACE = &g_pCompositor->m_lWorkspaces.back();
+ PNEWWORKSPACE = &g_pCompositor->m_lWorkspaces.emplace_back(newMonitor.ID);
// We are required to set the name here immediately
- wlr_ext_workspace_handle_v1_set_name(PNEWWORKSPACE->m_pWlrHandle, std::to_string(WORKSPACEID).c_str());
+ wlr_ext_workspace_handle_v1_set_name(PNEWWORKSPACE->m_pWlrHandle, newDefaultWorkspaceName.c_str());
PNEWWORKSPACE->m_iID = WORKSPACEID;
- PNEWWORKSPACE->m_szName = std::to_string(WORKSPACEID);
+ PNEWWORKSPACE->m_szName = newDefaultWorkspaceName;
}
PNEWMONITOR->activeWorkspace = PNEWWORKSPACE->m_iID;
PNEWMONITOR->scale = monitorRule.scale;
+ PNEWMONITOR->forceFullFrames = 3; // force 3 full frames to make sure there is no blinking due to double-buffering.
+
g_pCompositor->deactivateAllWLRWorkspaces(PNEWWORKSPACE->m_pWlrHandle);
PNEWWORKSPACE->setActive(true);
@@ -216,7 +225,7 @@ void Events::listener_monitorFrame(void* owner, void* data) {
return;
}
- if (!hasChanged && *PDAMAGETRACKINGMODE != DAMAGE_TRACKING_NONE) {
+ if (!hasChanged && *PDAMAGETRACKINGMODE != DAMAGE_TRACKING_NONE && PMONITOR->forceFullFrames == 0) {
pixman_region32_fini(&damage);
wlr_output_rollback(PMONITOR->output);
wlr_output_schedule_frame(PMONITOR->output); // we update shit at the monitor's Hz so we need to schedule frames because rollback wont
@@ -224,7 +233,7 @@ void Events::listener_monitorFrame(void* owner, void* data) {
}
// if we have no tracking or full tracking, invalidate the entire monitor
- if (*PDAMAGETRACKINGMODE == DAMAGE_TRACKING_NONE || *PDAMAGETRACKINGMODE == DAMAGE_TRACKING_MONITOR) {
+ if (*PDAMAGETRACKINGMODE == DAMAGE_TRACKING_NONE || *PDAMAGETRACKINGMODE == DAMAGE_TRACKING_MONITOR || PMONITOR->forceFullFrames > 0) {
pixman_region32_union_rect(&damage, &damage, 0, 0, (int)PMONITOR->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y);
pixman_region32_copy(&g_pHyprOpenGL->m_rOriginalDamageRegion, &damage);
@@ -247,6 +256,9 @@ void Events::listener_monitorFrame(void* owner, void* data) {
}
}
+ if (PMONITOR->forceFullFrames > 0)
+ PMONITOR->forceFullFrames -= 1;
+
// TODO: this is getting called with extents being 0,0,0,0 should it be?
// potentially can save on resources.
diff --git a/src/events/Popups.cpp b/src/events/Popups.cpp
index 0b075295..7e619632 100644
--- a/src/events/Popups.cpp
+++ b/src/events/Popups.cpp
@@ -26,6 +26,14 @@ void addPopupGlobalCoords(void* pPopup, int* x, int* y) {
px += curPopup->popup->current.geometry.x;
py += curPopup->popup->current.geometry.y;
+ // fix oversized fucking popups
+ // kill me
+ if (curPopup->pSurfaceTree && curPopup->pSurfaceTree->pSurface && !curPopup->parentPopup) {
+ const auto EXTENTSSURFACE = pixman_region32_extents(&curPopup->pSurfaceTree->pSurface->input_region);
+ px -= EXTENTSSURFACE->x1;
+ py -= EXTENTSSURFACE->y1;
+ }
+
if (curPopup->parentPopup) {
curPopup = curPopup->parentPopup;
} else {
diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp
index b84b9d2d..48571892 100644
--- a/src/events/Windows.cpp
+++ b/src/events/Windows.cpp
@@ -19,6 +19,14 @@ void addViewCoords(void* pWindow, int* x, int* y) {
const auto PWINDOW = (CWindow*)pWindow;
*x += PWINDOW->m_vRealPosition.goalv().x;
*y += PWINDOW->m_vRealPosition.goalv().y;
+
+ if (!PWINDOW->m_bIsX11) {
+ wlr_box geom;
+ wlr_xdg_surface_get_geometry(PWINDOW->m_uSurface.xdg, &geom);
+
+ *x -= geom.x;
+ *y -= geom.y;
+ }
}
void Events::listener_mapWindow(void* owner, void* data) {
diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp
index 6f9b465e..55b0ec83 100644
--- a/src/helpers/MiscFunctions.cpp
+++ b/src/helpers/MiscFunctions.cpp
@@ -158,6 +158,12 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
outName = WORKSPACENAME;
} else {
if (in[0] == 'm') {
+ if (!g_pCompositor->m_pLastMonitor) {
+ Debug::log(ERR, "Relative monitor workspace on monitor null!");
+ result = INT_MAX;
+ return result;
+ }
+
// monitor relative
result = (int)getPlusMinusKeywordResult(in.substr(1), 0);
@@ -207,7 +213,14 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
outName = g_pCompositor->getWorkspaceByID(currentID)->m_szName;
} else {
- result = std::clamp((int)getPlusMinusKeywordResult(in, g_pCompositor->m_pLastMonitor->activeWorkspace), 1, INT_MAX);
+ if (g_pCompositor->m_pLastMonitor)
+ result = std::clamp((int)getPlusMinusKeywordResult(in, g_pCompositor->m_pLastMonitor->activeWorkspace), 1, INT_MAX);
+ else if (isNumber(in))
+ result = std::clamp(std::stoi(in), 1, INT_MAX);
+ else {
+ Debug::log(ERR, "Relative workspace on no mon!");
+ result = INT_MAX;
+ }
outName = std::to_string(result);
}
}
diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp
index 4767fd78..24e555f9 100644
--- a/src/helpers/Monitor.hpp
+++ b/src/helpers/Monitor.hpp
@@ -28,6 +28,7 @@ struct SMonitor {
float refreshRate = 60;
wlr_output_damage* damage = nullptr;
int framesToSkip = 0;
+ int forceFullFrames = 0;
bool noFrameSchedule = false;
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp
index ce63ace6..fb966153 100644
--- a/src/layout/DwindleLayout.cpp
+++ b/src/layout/DwindleLayout.cpp
@@ -545,11 +545,7 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, CWindow*
const auto PNODE = getNodeFromWindow(PWINDOW);
if (!PNODE) {
- PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goalv() + pixResize);
- PWINDOW->m_vRealSize.setValueAndWarp(Vector2D(std::clamp(PWINDOW->m_vRealSize.vec().x, (double)20, (double)999999), std::clamp(PWINDOW->m_vRealSize.vec().y, (double)20, (double)999999)));
-
- g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goalv());
-
+ PWINDOW->m_vRealSize = Vector2D(std::clamp((PWINDOW->m_vRealSize.goalv() + pixResize).x, (double)20, (double)999999), std::clamp((PWINDOW->m_vRealSize.goalv() + pixResize).y, (double)20, (double)999999));
return;
}
@@ -906,6 +902,11 @@ void CHyprDwindleLayout::switchWindows(CWindow* pWindow, CWindow* pWindow2) {
if (!PNODE2 || !PNODE)
return;
+ if (PNODE->workspaceID != PNODE2->workspaceID) {
+ Debug::log(ERR, "Dwindle: Rejecting a swap between workspaces");
+ return;
+ }
+
// we will not delete the nodes, just fix the tree
if (PNODE2->pParent == PNODE->pParent) {
const auto PPARENT = PNODE->pParent;
@@ -992,4 +993,20 @@ void CHyprDwindleLayout::toggleSplit(CWindow* pWindow) {
std::string CHyprDwindleLayout::getLayoutName() {
return "dwindle";
+}
+
+void CHyprDwindleLayout::moveActiveWindow(const Vector2D& delta, CWindow* pWindow) {
+ const auto PWINDOW = pWindow ? pWindow : g_pCompositor->m_pLastWindow;
+
+ if (!g_pCompositor->windowValidMapped(PWINDOW))
+ return;
+
+ if (!PWINDOW->m_bIsFloating) {
+ Debug::log(LOG, "Dwindle cannot move a tiled window in moveActiveWindow!");
+ return;
+ }
+
+ PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.goalv() + delta;
+
+ g_pHyprRenderer->damageWindow(PWINDOW);
}
\ No newline at end of file
diff --git a/src/layout/DwindleLayout.hpp b/src/layout/DwindleLayout.hpp
index 766e9f6a..55c123ae 100644
--- a/src/layout/DwindleLayout.hpp
+++ b/src/layout/DwindleLayout.hpp
@@ -49,6 +49,7 @@ public:
virtual void changeWindowFloatingMode(CWindow*);
virtual void onBeginDragWindow();
virtual void resizeActiveWindow(const Vector2D&, CWindow* pWindow = nullptr);
+ virtual void moveActiveWindow(const Vector2D&, CWindow* pWindow = nullptr);
virtual void onEndDragWindow();
virtual void onMouseMove(const Vector2D&);
virtual void onWindowCreatedFloating(CWindow*);
diff --git a/src/layout/IHyprLayout.hpp b/src/layout/IHyprLayout.hpp
index 8052fe42..a7268301 100644
--- a/src/layout/IHyprLayout.hpp
+++ b/src/layout/IHyprLayout.hpp
@@ -55,6 +55,12 @@ public:
Optional pWindow for a specific window
*/
virtual void resizeActiveWindow(const Vector2D&, CWindow* pWindow = nullptr) = 0;
+ /*
+ Called when a user requests a move of the current window by a vec
+ Vector2D holds pixel values
+ Optional pWindow for a specific window
+ */
+ virtual void moveActiveWindow(const Vector2D&, CWindow* pWindow = nullptr) = 0;
/*
Called when a window is ended being dragged
(mouse up)
diff --git a/src/managers/EventManager.cpp b/src/managers/EventManager.cpp
index eed0e6e5..e42e87c2 100644
--- a/src/managers/EventManager.cpp
+++ b/src/managers/EventManager.cpp
@@ -105,9 +105,15 @@ void CEventManager::startThread() {
}
void CEventManager::postEvent(const SHyprIPCEvent event) {
+
+ if (m_bIgnoreEvents) {
+ Debug::log(WARN, "Suppressed (ignoreevents true) event of type %s, content: %s",event.event.c_str(), event.data.c_str());
+ return;
+ }
+
std::thread([&](const SHyprIPCEvent ev) {
eventQueueMutex.lock();
m_dQueuedEvents.push_back(ev);
eventQueueMutex.unlock();
}, event).detach();
-}
\ No newline at end of file
+}
diff --git a/src/managers/EventManager.hpp b/src/managers/EventManager.hpp
index f8ec6afc..ae630ce8 100644
--- a/src/managers/EventManager.hpp
+++ b/src/managers/EventManager.hpp
@@ -19,6 +19,8 @@ public:
void startThread();
+ bool m_bIgnoreEvents = false;
+
private:
std::mutex eventQueueMutex;
diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp
index 123e560c..85fb3919 100644
--- a/src/managers/KeybindManager.cpp
+++ b/src/managers/KeybindManager.cpp
@@ -28,8 +28,10 @@ CKeybindManager::CKeybindManager() {
m_mDispatchers["togglespecialworkspace"] = toggleSpecialWorkspace;
m_mDispatchers["forcerendererreload"] = forceRendererReload;
m_mDispatchers["resizeactive"] = resizeActive;
+ m_mDispatchers["moveactive"] = moveActive;
m_mDispatchers["cyclenext"] = circleNext;
m_mDispatchers["focuswindowbyclass"] = focusWindowByClass;
+ m_mDispatchers["submap"] = setSubmap;
}
void CKeybindManager::addKeybind(SKeybind kb) {
@@ -72,13 +74,11 @@ bool CKeybindManager::handleKeybinds(const uint32_t& modmask, const xkb_keysym_t
if (handleInternalKeybinds(key))
return true;
- if (g_pCompositor->m_sSeat.exclusiveClient){
- Debug::log(LOG, "Not handling keybinds due to there being an exclusive inhibited client.");
- return false;
- }
+ if (g_pCompositor->m_sSeat.exclusiveClient)
+ Debug::log(LOG, "Keybind handling only locked (inhibitor)");
for (auto& k : m_lKeybinds) {
- if (modmask != k.modmask)
+ if (modmask != k.modmask || (g_pCompositor->m_sSeat.exclusiveClient && !k.locked) || k.submap != m_szCurrentSelectedSubmap)
continue;
// oMg such performance hit!!11!
@@ -280,9 +280,7 @@ void CKeybindManager::changeworkspace(std::string args) {
// start anim on new workspace
PWORKSPACETOCHANGETO->startAnim(true, ANIMTOLEFT);
- // Event ONLY if workspace is actually "changed" and we arent just focusing
- if (!m_bSuppressWorkspaceChangeEvents)
- g_pEventManager->postEvent(SHyprIPCEvent("workspace", PWORKSPACETOCHANGETO->m_szName));
+ g_pEventManager->postEvent(SHyprIPCEvent("workspace", PWORKSPACETOCHANGETO->m_szName));
}
// If the monitor is not the one our cursor's at, warp to it.
@@ -291,9 +289,6 @@ void CKeybindManager::changeworkspace(std::string args) {
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, middle.x, middle.y);
}
- // focus the first window
- g_pCompositor->focusWindow(g_pCompositor->getFirstWindowOnWorkspace(workspaceToChangeTo));
-
// set active and deactivate all other in wlr
g_pCompositor->deactivateAllWLRWorkspaces(PWORKSPACETOCHANGETO->m_pWlrHandle);
PWORKSPACETOCHANGETO->setActive(true);
@@ -360,8 +355,7 @@ void CKeybindManager::changeworkspace(std::string args) {
g_pInputManager->refocus();
// Event
- if (!m_bSuppressWorkspaceChangeEvents)
- g_pEventManager->postEvent(SHyprIPCEvent("workspace", PWORKSPACE->m_szName));
+ g_pEventManager->postEvent(SHyprIPCEvent("workspace", PWORKSPACE->m_szName));
Debug::log(LOG, "Changed to workspace %i", workspaceToChangeTo);
}
@@ -491,7 +485,7 @@ void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) {
const auto POLDWORKSPACEONMON = g_pCompositor->getWorkspaceByID(OLDWORKSPACEIDONMONITOR);
const auto POLDWORKSPACEIDRETURN = g_pCompositor->getWorkspaceByID(OLDWORKSPACEIDRETURN);
- m_bSuppressWorkspaceChangeEvents = true;
+ g_pEventManager->m_bIgnoreEvents = true;
moveActiveToWorkspace(args);
@@ -510,7 +504,7 @@ void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) {
POLDWORKSPACEONMON->m_vRenderOffset.setValueAndWarp(Vector2D(0, 0));
POLDWORKSPACEONMON->m_fAlpha.setValueAndWarp(255.f);
- m_bSuppressWorkspaceChangeEvents = false;
+ g_pEventManager->m_bIgnoreEvents = false;
g_pInputManager->refocus();
}
@@ -899,6 +893,37 @@ void CKeybindManager::resizeActive(std::string args) {
std::string x = args.substr(0, args.find_first_of(' '));
std::string y = args.substr(args.find_first_of(' ') + 1);
+ if (x == "exact") {
+ std::string newX = y.substr(0, y.find_first_of(' '));
+ std::string newY = y.substr(y.find_first_of(' ') + 1);
+
+ if (!isNumber(newX) || !isNumber(newY)) {
+ Debug::log(ERR, "resizeTiledWindow: exact args not numbers");
+ return;
+ }
+
+ const int X = std::stoi(newX);
+ const int Y = std::stoi(newY);
+
+ if (X < 10 || Y < 10) {
+ Debug::log(ERR, "resizeTiledWindow: exact args cannot be < 10");
+ return;
+ }
+
+ // calc the delta
+ if (!g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow))
+ return; // ignore
+
+ const auto PWINDOW = g_pCompositor->m_pLastWindow;
+
+ const int DX = X - PWINDOW->m_vRealSize.goalv().x;
+ const int DY = Y - PWINDOW->m_vRealSize.goalv().y;
+
+ g_pLayoutManager->getCurrentLayout()->resizeActiveWindow(Vector2D(DX, DY));
+
+ return;
+ }
+
if (!isNumber(x) || !isNumber(y)) {
Debug::log(ERR, "resizeTiledWindow: args not numbers");
return;
@@ -910,6 +935,55 @@ void CKeybindManager::resizeActive(std::string args) {
g_pLayoutManager->getCurrentLayout()->resizeActiveWindow(Vector2D(X, Y));
}
+void CKeybindManager::moveActive(std::string args) {
+ if (args.find_first_of(' ') == std::string::npos)
+ return;
+
+ std::string x = args.substr(0, args.find_first_of(' '));
+ std::string y = args.substr(args.find_first_of(' ') + 1);
+
+ if (x == "exact") {
+ std::string newX = y.substr(0, y.find_first_of(' '));
+ std::string newY = y.substr(y.find_first_of(' ') + 1);
+
+ if (!isNumber(newX) || !isNumber(newY)) {
+ Debug::log(ERR, "moveActive: exact args not numbers");
+ return;
+ }
+
+ const int X = std::stoi(newX);
+ const int Y = std::stoi(newY);
+
+ if (X < 10 || Y < 10) {
+ Debug::log(ERR, "moveActive: exact args cannot be < 10");
+ return;
+ }
+
+ // calc the delta
+ if (!g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow))
+ return; // ignore
+
+ const auto PWINDOW = g_pCompositor->m_pLastWindow;
+
+ const int DX = X - PWINDOW->m_vRealPosition.goalv().x;
+ const int DY = Y - PWINDOW->m_vRealPosition.goalv().y;
+
+ g_pLayoutManager->getCurrentLayout()->moveActiveWindow(Vector2D(DX, DY));
+
+ return;
+ }
+
+ if (!isNumber(x) || !isNumber(y)) {
+ Debug::log(ERR, "moveActive: args not numbers");
+ return;
+ }
+
+ const int X = std::stoi(x);
+ const int Y = std::stoi(y);
+
+ g_pLayoutManager->getCurrentLayout()->moveActiveWindow(Vector2D(X, Y));
+}
+
void CKeybindManager::circleNext(std::string) {
if (!g_pCompositor->windowValidMapped(g_pCompositor->m_pLastWindow))
return;
@@ -943,3 +1017,21 @@ void CKeybindManager::focusWindowByClass(std::string clazz) {
break;
}
}
+
+void CKeybindManager::setSubmap(std::string submap) {
+ if (submap == "reset" || submap == "") {
+ m_szCurrentSelectedSubmap = "";
+ Debug::log(LOG, "Reset active submap to the default one.");
+ return;
+ }
+
+ for (auto& k : g_pKeybindManager->m_lKeybinds) {
+ if (k.submap == submap) {
+ m_szCurrentSelectedSubmap = submap;
+ Debug::log(LOG, "Changed keybind submap to %s", submap.c_str());
+ return;
+ }
+ }
+
+ Debug::log(ERR, "Cannot set submap %s, submap doesn't exist (wasn't registered!)", submap.c_str());
+}
diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp
index 782f2ead..c9132a11 100644
--- a/src/managers/KeybindManager.hpp
+++ b/src/managers/KeybindManager.hpp
@@ -11,6 +11,8 @@ struct SKeybind {
uint32_t modmask = 0;
std::string handler = "";
std::string arg = "";
+ bool locked = false;
+ std::string submap = "";
};
class CKeybindManager {
@@ -28,9 +30,9 @@ public:
private:
std::list m_lKeybinds;
- bool handleInternalKeybinds(xkb_keysym_t);
+ inline static std::string m_szCurrentSelectedSubmap = "";
- inline static bool m_bSuppressWorkspaceChangeEvents = false;
+ bool handleInternalKeybinds(xkb_keysym_t);
// -------------- Dispatchers -------------- //
static void killActive(std::string);
@@ -56,8 +58,10 @@ private:
static void toggleSpecialWorkspace(std::string);
static void forceRendererReload(std::string);
static void resizeActive(std::string);
+ static void moveActive(std::string);
static void circleNext(std::string);
static void focusWindowByClass(std::string);
+ static void setSubmap(std::string);
friend class CCompositor;
};
diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp
index 5927274e..65f5ddd8 100644
--- a/src/managers/XWaylandManager.cpp
+++ b/src/managers/XWaylandManager.cpp
@@ -124,14 +124,8 @@ void CHyprXWaylandManager::sendCloseWindow(CWindow* pWindow) {
void CHyprXWaylandManager::setWindowSize(CWindow* pWindow, const Vector2D& size) {
if (pWindow->m_bIsX11)
wlr_xwayland_surface_configure(pWindow->m_uSurface.xwayland, pWindow->m_vRealPosition.vec().x, pWindow->m_vRealPosition.vec().y, size.x, size.y);
- else {
- // I don't know if this is fucking correct, but the fucking idea of putting shadows into a window's surface is borderline criminal.
-
- const auto XDELTA = pWindow->m_uSurface.xdg->current.geometry.width && pWindow->m_uSurface.xdg->current.geometry.height ? pWindow->m_uSurface.xdg->surface->current.width - pWindow->m_uSurface.xdg->current.geometry.width : 0;
- const auto YDELTA = pWindow->m_uSurface.xdg->current.geometry.width && pWindow->m_uSurface.xdg->current.geometry.height ? pWindow->m_uSurface.xdg->surface->current.height - pWindow->m_uSurface.xdg->current.geometry.height : 0;
-
- wlr_xdg_toplevel_set_size(pWindow->m_uSurface.xdg->toplevel, size.x - XDELTA, size.y - YDELTA);
- }
+ else
+ wlr_xdg_toplevel_set_size(pWindow->m_uSurface.xdg->toplevel, size.x, size.y);
}
void CHyprXWaylandManager::setWindowStyleTiled(CWindow* pWindow, uint32_t edgez) {
diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp
index 826354f1..131be576 100644
--- a/src/managers/input/InputManager.cpp
+++ b/src/managers/input/InputManager.cpp
@@ -35,6 +35,8 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
Vector2D mouseCoords = getMouseCoordsInternal();
const auto PMONITOR = g_pCompositor->getMonitorFromCursor();
+ bool didConstraintOnCursor = false;
+
// constraints
// All constraints TODO: multiple mice?
if (g_pCompositor->m_sSeat.mouse->currentConstraint) {
@@ -50,23 +52,25 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
const auto CONSTRAINTPOS = CONSTRAINTWINDOW->m_bIsX11 ? Vector2D(CONSTRAINTWINDOW->m_uSurface.xwayland->x, CONSTRAINTWINDOW->m_uSurface.xwayland->y) : CONSTRAINTWINDOW->m_vRealPosition.vec();
const auto CONSTRAINTSIZE = CONSTRAINTWINDOW->m_bIsX11 ? Vector2D(CONSTRAINTWINDOW->m_uSurface.xwayland->width, CONSTRAINTWINDOW->m_uSurface.xwayland->height) : CONSTRAINTWINDOW->m_vRealSize.vec();
- if (!VECINRECT(mouseCoords, CONSTRAINTPOS.x, CONSTRAINTPOS.y, CONSTRAINTPOS.x + CONSTRAINTSIZE.x, CONSTRAINTPOS.y + CONSTRAINTSIZE.y)) {
+ if (!VECINRECT(mouseCoords, CONSTRAINTPOS.x, CONSTRAINTPOS.y, CONSTRAINTPOS.x + CONSTRAINTSIZE.x - 1.0, CONSTRAINTPOS.y + CONSTRAINTSIZE.y - 1.0)) {
if (g_pCompositor->m_sSeat.mouse->constraintActive) {
- Vector2D deltaToFit;
+ Vector2D newConstrainedCoords = mouseCoords;
if (mouseCoords.x < CONSTRAINTPOS.x)
- deltaToFit.x = CONSTRAINTPOS.x - mouseCoords.x;
- else if (mouseCoords.x > CONSTRAINTPOS.x + CONSTRAINTSIZE.x)
- deltaToFit.x = CONSTRAINTPOS.x + CONSTRAINTSIZE.x - mouseCoords.x;
+ newConstrainedCoords.x = CONSTRAINTPOS.x;
+ else if (mouseCoords.x >= CONSTRAINTPOS.x + CONSTRAINTSIZE.x)
+ newConstrainedCoords.x = CONSTRAINTPOS.x + CONSTRAINTSIZE.x - 1.0;
if (mouseCoords.y < CONSTRAINTPOS.y)
- deltaToFit.y = CONSTRAINTPOS.y - mouseCoords.y;
- else if (mouseCoords.y > CONSTRAINTPOS.y + CONSTRAINTSIZE.y)
- deltaToFit.y = CONSTRAINTPOS.y + CONSTRAINTSIZE.y - mouseCoords.y;
+ newConstrainedCoords.y = CONSTRAINTPOS.y;
+ else if (mouseCoords.y >= CONSTRAINTPOS.y + CONSTRAINTSIZE.y)
+ newConstrainedCoords.y = CONSTRAINTPOS.y + CONSTRAINTSIZE.y - 1.0;
- wlr_cursor_move(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, deltaToFit.x, deltaToFit.y);
+ wlr_cursor_warp_closest(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sSeat.mouse->mouse, newConstrainedCoords.x, newConstrainedCoords.y);
- mouseCoords = mouseCoords + deltaToFit;
+ mouseCoords = newConstrainedCoords;
+
+ didConstraintOnCursor = true;
}
} else {
if ((!CONSTRAINTWINDOW->m_bIsX11 && PMONITOR && CONSTRAINTWINDOW->m_iWorkspaceID == PMONITOR->activeWorkspace) || (CONSTRAINTWINDOW->m_bIsX11)) {
@@ -84,6 +88,9 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
// focus
wlr_surface* foundSurface = nullptr;
+ if (didConstraintOnCursor)
+ return; // don't process when cursor constrained
+
if (PMONITOR && PMONITOR != g_pCompositor->m_pLastMonitor) {
g_pCompositor->m_pLastMonitor = PMONITOR;
@@ -116,7 +123,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
wlr_box box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
if (((w->m_bIsFloating && w->m_bIsMapped && w->m_bCreatedOverFullscreen) || (w->m_iWorkspaceID == SPECIAL_WORKSPACE_ID && PMONITOR->specialWorkspaceOpen)) && wlr_box_contains_point(&box, mouseCoords.x, mouseCoords.y) && g_pCompositor->isWorkspaceVisible(w->m_iWorkspaceID) && !w->m_bHidden) {
pFoundWindow = &(*w);
-
+
if (!pFoundWindow->m_bIsX11) {
foundSurface = g_pCompositor->vectorWindowToSurface(mouseCoords, pFoundWindow, surfaceCoords);
} else {
@@ -152,7 +159,6 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
if (!foundSurface)
foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLists[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &surfaceCoords);
-
if (!foundSurface) {
wlr_xcursor_manager_set_cursor_image(g_pCompositor->m_sWLRXCursorMgr, "left_ptr", g_pCompositor->m_sWLRCursor);
@@ -166,6 +172,14 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
Vector2D surfaceLocal = surfacePos == Vector2D(-1337, -1337) ? surfaceCoords : mouseCoords - surfacePos;
+ if (pFoundWindow && !pFoundWindow->m_bIsX11 && surfacePos != Vector2D(-1337, -1337)) {
+ // calc for oversized windows... fucking bullshit.
+ wlr_box geom;
+ wlr_xdg_surface_get_geometry(pFoundWindow->m_uSurface.xdg, &geom);
+
+ surfaceLocal = mouseCoords - surfacePos + Vector2D(geom.x, geom.y);
+ }
+
if (pFoundWindow) {
static auto *const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
if (*PFOLLOWMOUSE != 1 && !refocus) {
@@ -173,17 +187,15 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
// enter if change floating style
g_pCompositor->focusWindow(pFoundWindow, foundSurface);
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
- }
- else if (*PFOLLOWMOUSE == 2) {
+ } else if (*PFOLLOWMOUSE == 2) {
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
}
wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, time, surfaceLocal.x, surfaceLocal.y);
- return; // don't enter any new surfaces
+ return; // don't enter any new surfaces
} else {
g_pCompositor->focusWindow(pFoundWindow, foundSurface);
}
- }
- else
+ } else
g_pCompositor->focusSurface(foundSurface);
wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y);
@@ -195,6 +207,11 @@ void CInputManager::onMouseButton(wlr_pointer_button_event* e) {
const auto PKEYBOARD = wlr_seat_get_keyboard(g_pCompositor->m_sSeat.seat);
+ if (!PKEYBOARD) { // ???
+ Debug::log(ERR, "No active keyboard in onMouseButton??");
+ return;
+ }
+
switch (e->state) {
case WLR_BUTTON_PRESSED:
if (!g_pCompositor->m_sSeat.mouse->currentConstraint)
@@ -280,22 +297,34 @@ void CInputManager::newKeyboard(wlr_input_device* keyboard) {
}
void CInputManager::setKeyboardLayout() {
+ for (auto& k : m_lKeyboards)
+ applyConfigToKeyboard(&k);
+}
- const auto RULES = g_pConfigManager->getString("input:kb_rules");
- const auto MODEL = g_pConfigManager->getString("input:kb_model");
- const auto LAYOUT = g_pConfigManager->getString("input:kb_layout");
- const auto VARIANT = g_pConfigManager->getString("input:kb_variant");
- const auto OPTIONS = g_pConfigManager->getString("input:kb_options");
+void CInputManager::applyConfigToKeyboard(SKeyboard* pKeyboard) {
+
+ ASSERT(pKeyboard);
+
+ const auto RULES = g_pConfigManager->getString("input:kb_rules");
+ const auto MODEL = g_pConfigManager->getString("input:kb_model");
+ const auto LAYOUT = g_pConfigManager->getString("input:kb_layout");
+ const auto VARIANT = g_pConfigManager->getString("input:kb_variant");
+ const auto OPTIONS = g_pConfigManager->getString("input:kb_options");
xkb_rule_names rules = {
.rules = RULES.c_str(),
.model = MODEL.c_str(),
.layout = LAYOUT.c_str(),
.variant = VARIANT.c_str(),
- .options = OPTIONS.c_str()
- };
+ .options = OPTIONS.c_str()};
const auto CONTEXT = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
+
+ if (!CONTEXT) {
+ Debug::log(ERR, "applyConfigToKeyboard: CONTEXT null??");
+ return;
+ }
+
const auto KEYMAP = xkb_keymap_new_from_names(CONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
if (!KEYMAP) {
@@ -304,17 +333,7 @@ void CInputManager::setKeyboardLayout() {
return;
}
- const auto PLASTKEEB = m_pActiveKeyboard->keyboard->keyboard;
-
- if (!PLASTKEEB) {
- xkb_keymap_unref(KEYMAP);
- xkb_context_unref(CONTEXT);
-
- Debug::log(ERR, "No Seat Keyboard???");
- return;
- }
-
- wlr_keyboard_set_keymap(PLASTKEEB, KEYMAP);
+ wlr_keyboard_set_keymap(pKeyboard->keyboard->keyboard, KEYMAP);
wlr_keyboard_modifiers wlrMods = {0};
@@ -327,14 +346,14 @@ void CInputManager::setKeyboardLayout() {
}
if (wlrMods.locked != 0) {
- wlr_keyboard_notify_modifiers(g_pInputManager->m_pActiveKeyboard->keyboard->keyboard, 0, 0, wlrMods.locked, 0);
+ wlr_keyboard_notify_modifiers(pKeyboard->keyboard->keyboard, 0, 0, wlrMods.locked, 0);
}
xkb_keymap_unref(KEYMAP);
xkb_context_unref(CONTEXT);
- Debug::log(LOG, "Set the keyboard layout to %s and variant to %s", rules.layout, rules.variant);
-}
+ Debug::log(LOG, "Set the keyboard layout to %s and variant to %s for keyboard \"%s\"", rules.layout, rules.variant, pKeyboard->keyboard->name);
+}
void CInputManager::newMouse(wlr_input_device* mouse) {
m_lMice.emplace_back();
@@ -559,4 +578,4 @@ void CInputManager::updateCapabilities(wlr_input_device* pDev) {
}
wlr_seat_set_capabilities(g_pCompositor->m_sSeat.seat, m_uiCapabilities);
-}
+}
\ No newline at end of file
diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp
index 7a3601bc..ef3a4eb4 100644
--- a/src/managers/input/InputManager.hpp
+++ b/src/managers/input/InputManager.hpp
@@ -53,13 +53,15 @@ public:
SKeyboard* m_pActiveKeyboard = nullptr;
- private:
+private:
uint32_t m_uiCapabilities = 0;
void mouseMoveUnified(uint32_t, bool refocus = false);
STabletTool* ensureTabletToolPresent(wlr_tablet_tool*);
+
+ void applyConfigToKeyboard(SKeyboard*);
};
inline std::unique_ptr g_pInputManager;
\ No newline at end of file
diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp
index 6a82cb83..85dd29be 100644
--- a/src/render/OpenGL.cpp
+++ b/src/render/OpenGL.cpp
@@ -240,6 +240,10 @@ void CHyprOpenGLImpl::scissor(const int x, const int y, const int w, const int h
}
void CHyprOpenGLImpl::renderRect(wlr_box* box, const CColor& col, int round) {
+ renderRectWithDamage(box, col, m_RenderData.pDamage, round);
+}
+
+void CHyprOpenGLImpl::renderRectWithDamage(wlr_box* box, const CColor& col, pixman_region32_t* damage, int round) {
RASSERT((box->width > 0 && box->height > 0), "Tried to render rect with width/height < 0!");
RASSERT(m_RenderData.pMonitor, "Tried to render rect without begin()!");
@@ -279,8 +283,8 @@ void CHyprOpenGLImpl::renderRect(wlr_box* box, const CColor& col, int round) {
glEnableVertexAttribArray(m_shQUAD.posAttrib);
glEnableVertexAttribArray(m_shQUAD.texAttrib);
- if (pixman_region32_not_empty(m_RenderData.pDamage)) {
- PIXMAN_DAMAGE_FOREACH(m_RenderData.pDamage) {
+ if (pixman_region32_not_empty(damage)) {
+ PIXMAN_DAMAGE_FOREACH(damage) {
const auto RECT = RECTSARR[i];
scissor(&RECT);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
@@ -299,15 +303,15 @@ void CHyprOpenGLImpl::renderTexture(wlr_texture* tex, wlr_box* pBox, float alpha
renderTexture(CTexture(tex), pBox, alpha, round);
}
-void CHyprOpenGLImpl::renderTexture(const CTexture& tex, wlr_box* pBox, float alpha, int round, bool discardopaque, bool border) {
+void CHyprOpenGLImpl::renderTexture(const CTexture& tex, wlr_box* pBox, float alpha, int round, bool discardopaque, bool border, bool allowPrimary) {
RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!");
- renderTextureInternalWithDamage(tex, pBox, alpha, m_RenderData.pDamage, round, discardopaque, border);
+ renderTextureInternalWithDamage(tex, pBox, alpha, m_RenderData.pDamage, round, discardopaque, border, false, allowPrimary);
scissor((wlr_box*)nullptr);
}
-void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_box* pBox, float alpha, pixman_region32_t* damage, int round, bool discardOpaque, bool border, bool noAA) {
+void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_box* pBox, float alpha, pixman_region32_t* damage, int round, bool discardOpaque, bool border, bool noAA, bool allowPrimary) {
RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!");
RASSERT((tex.m_iTexID > 0), "Attempted to draw NULL texture!");
@@ -341,6 +345,23 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b
RASSERT(false, "tex.m_iTarget unsupported!");
}
+ // stencil for when we want a border
+ if (border) {
+ glClearStencil(0);
+ glClear(GL_STENCIL_BUFFER_BIT);
+
+ glEnable(GL_STENCIL_TEST);
+
+ glStencilFunc(GL_ALWAYS, 1, -1);
+ glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
+
+ // hacky fix to fix broken borders.
+ // TODO: this is kinda slow... question mark?
+ renderRect(pBox, CColor(0, 0, 0, 0), round);
+
+ glDisable(GL_STENCIL_TEST);
+ }
+
glActiveTexture(GL_TEXTURE0);
glBindTexture(tex.m_iTarget, tex.m_iTexID);
@@ -357,8 +378,8 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b
// so we need to do some maf
const auto TOPLEFT = Vector2D(round, round);
- const auto BOTTOMRIGHT = Vector2D(tex.m_vSize.x - round, tex.m_vSize.y - round);
- const auto FULLSIZE = tex.m_vSize;
+ const auto BOTTOMRIGHT = Vector2D(pBox->width - round, pBox->height - round);
+ const auto FULLSIZE = Vector2D(pBox->width, pBox->height);
static auto *const PMULTISAMPLEEDGES = &g_pConfigManager->getConfigValuePtr("decoration:multisample_edges")->intValue;
// Rounded corners
@@ -369,22 +390,23 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b
glUniform1i(glGetUniformLocation(shader->program, "primitiveMultisample"), (int)(*PMULTISAMPLEEDGES == 1 && round != 0 && !border && !noAA));
glVertexAttribPointer(shader->posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
- glVertexAttribPointer(shader->texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
+
+ if (allowPrimary && m_RenderData.renderingPrimarySurface && m_RenderData.primarySurfaceUVTopLeft != Vector2D(-1, -1)) {
+ const float verts[] = {
+ m_RenderData.primarySurfaceUVBottomRight.x, m_RenderData.primarySurfaceUVTopLeft.y, // top right
+ m_RenderData.primarySurfaceUVTopLeft.x, m_RenderData.primarySurfaceUVTopLeft.y, // top left
+ m_RenderData.primarySurfaceUVBottomRight.x, m_RenderData.primarySurfaceUVBottomRight.y, // bottom right
+ m_RenderData.primarySurfaceUVTopLeft.x, m_RenderData.primarySurfaceUVBottomRight.y, // bottom left
+ };
+
+ glVertexAttribPointer(shader->texAttrib, 2, GL_FLOAT, GL_FALSE, 0, verts);
+ } else {
+ glVertexAttribPointer(shader->texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
+ }
glEnableVertexAttribArray(shader->posAttrib);
glEnableVertexAttribArray(shader->texAttrib);
- // stencil for when we want a border
- if (border) {
- glClearStencil(0);
- glClear(GL_STENCIL_BUFFER_BIT);
-
- glEnable(GL_STENCIL_TEST);
-
- glStencilFunc(GL_ALWAYS, 1, -1);
- glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
- }
-
if (pixman_region32_not_empty(m_RenderData.pDamage)) {
PIXMAN_DAMAGE_FOREACH(m_RenderData.pDamage) {
const auto RECT = RECTSARR[i];
@@ -394,6 +416,8 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b
}
if (border) {
+ glEnable(GL_STENCIL_TEST);
+
glStencilFunc(GL_EQUAL, 1, -1);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
}
@@ -540,9 +564,10 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox,
RASSERT(m_RenderData.pMonitor, "Tried to render texture with blur without begin()!");
static auto *const PBLURENABLED = &g_pConfigManager->getConfigValuePtr("decoration:blur")->intValue;
+ static auto* const PNOBLUROVERSIZED = &g_pConfigManager->getConfigValuePtr("decoration:no_blur_on_oversized")->intValue;
- if (*PBLURENABLED == 0) {
- renderTexture(tex, pBox, a, round, false, border);
+ if (*PBLURENABLED == 0 || (*PNOBLUROVERSIZED && m_RenderData.primarySurfaceUVTopLeft != Vector2D(-1, -1))) {
+ renderTexture(tex, pBox, a, round, false, border, true);
return;
}
@@ -599,17 +624,26 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox,
if (pixman_region32_not_empty(&damage)) {
// render our great blurred FB
static auto *const PBLURIGNOREOPACITY = &g_pConfigManager->getConfigValuePtr("decoration:blur_ignore_opacity")->intValue;
- renderTextureInternalWithDamage(POUTFB->m_cTex, &MONITORBOX, *PBLURIGNOREOPACITY ? 255.f : a, &damage);
+ renderTextureInternalWithDamage(POUTFB->m_cTex, &MONITORBOX, *PBLURIGNOREOPACITY ? 255.f : a, &damage, 0, false, false, false, true);
// render the window, but clear stencil
glClearStencil(0);
glClear(GL_STENCIL_BUFFER_BIT);
- // and write to it
+ // draw window
+ glDisable(GL_STENCIL_TEST);
+ renderTextureInternalWithDamage(tex, pBox, a, &damage, round, false, false, true, true);
+ glEnable(GL_STENCIL_TEST);
+
+ // prep stencil for border
glStencilFunc(GL_ALWAYS, 1, -1);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
- renderTextureInternalWithDamage(tex, pBox, a, &damage, round, false, false, true);
+ if (border) {
+ // hacky fix to fix broken borders.
+ // TODO: this is kinda slow... question mark?
+ renderRectWithDamage(pBox, CColor(0,0,0,0), &damage, round);
+ }
// then stop
glStencilFunc(GL_EQUAL, 1, -1);
@@ -649,7 +683,7 @@ void CHyprOpenGLImpl::renderBorder(wlr_box* box, const CColor& col, int thick, i
box->width += 2 * thick;
box->height += 2 * thick;
- round += thick * m_RenderData.pMonitor->scale; // cuz yeah
+ round += thick; // cuz yeah
// only draw on non-stencild.
glStencilFunc(GL_NOTEQUAL, 1, -1);
diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp
index 9a8084db..0648e73a 100644
--- a/src/render/OpenGL.hpp
+++ b/src/render/OpenGL.hpp
@@ -34,6 +34,10 @@ struct SCurrentRenderData {
float projection[9];
pixman_region32_t* pDamage = nullptr;
+
+ bool renderingPrimarySurface = false;
+ Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1);
+ Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1);
};
struct SMonitorRenderData {
@@ -53,8 +57,9 @@ public:
void end();
void renderRect(wlr_box*, const CColor&, int round = 0);
+ void renderRectWithDamage(wlr_box*, const CColor&, pixman_region32_t* damage, int round = 0);
void renderTexture(wlr_texture*, wlr_box*, float a, int round = 0);
- void renderTexture(const CTexture&, wlr_box*, float a, int round = 0, bool discardOpaque = false, bool border = false);
+ void renderTexture(const CTexture&, wlr_box*, float a, int round = 0, bool discardOpaque = false, bool border = false, bool allowPrimary = false);
void renderTextureWithBlur(const CTexture&, wlr_box*, float a, wlr_surface* pSurface, int round = 0, bool border = false);
void makeWindowSnapshot(CWindow*);
@@ -110,7 +115,7 @@ private:
// returns the out FB, can be either Mirror or MirrorSwap
CFramebuffer* blurMainFramebufferWithDamage(float a, wlr_box* pBox, pixman_region32_t* damage);
- void renderTextureInternalWithDamage(const CTexture&, wlr_box* pBox, float a, pixman_region32_t* damage, int round = 0, bool discardOpaque = false, bool border = false, bool noAA = false);
+ void renderTextureInternalWithDamage(const CTexture&, wlr_box* pBox, float a, pixman_region32_t* damage, int round = 0, bool discardOpaque = false, bool border = false, bool noAA = false, bool allowPrimary = false);
void renderBorder(wlr_box*, const CColor&, int thick = 1, int round = 0);
};
diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp
index eb29a65d..8118af48 100644
--- a/src/render/Renderer.cpp
+++ b/src/render/Renderer.cpp
@@ -23,8 +23,12 @@ void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
float rounding = RDATA->dontRound ? 0 : RDATA->rounding == -1 ? *PROUNDING : RDATA->rounding;
- if (RDATA->surface && surface == RDATA->surface)
+ g_pHyprOpenGL->m_RenderData.renderingPrimarySurface = false;
+
+ if (RDATA->surface && surface == RDATA->surface) {
+ g_pHyprOpenGL->m_RenderData.renderingPrimarySurface = true;
g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, surface, rounding, RDATA->decorate);
+ }
else
g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, rounding, false, false);
@@ -142,6 +146,8 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, SMonitor* pMonitor, timespec*
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID);
const auto REALPOS = pWindow->m_vRealPosition.vec() + PWORKSPACE->m_vRenderOffset.vec();
+ static const auto PNOFLOATINGBORDERS = &g_pConfigManager->getConfigValuePtr("general:no_border_on_floating")->intValue;
+
SRenderData renderdata = {pMonitor->output, time, REALPOS.x, REALPOS.y};
renderdata.surface = g_pXWaylandManager->getWindowSurface(pWindow);
renderdata.w = std::clamp(pWindow->m_vRealSize.vec().x, (double)5, (double)1337420); // clamp the size to min 5,
@@ -149,7 +155,7 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, SMonitor* pMonitor, timespec*
renderdata.dontRound = pWindow->m_bIsFullscreen && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL;
renderdata.fadeAlpha = pWindow->m_fAlpha.fl() * (PWORKSPACE->m_fAlpha.fl() / 255.f);
renderdata.alpha = pWindow->m_bIsFullscreen ? g_pConfigManager->getFloat("decoration:fullscreen_opacity") : pWindow == g_pCompositor->m_pLastWindow ? g_pConfigManager->getFloat("decoration:active_opacity") : g_pConfigManager->getFloat("decoration:inactive_opacity");
- renderdata.decorate = decorate && !pWindow->m_bX11DoesntWantBorders;
+ renderdata.decorate = decorate && !pWindow->m_bX11DoesntWantBorders && (pWindow->m_bIsFloating ? *PNOFLOATINGBORDERS == 0 : true);
renderdata.rounding = pWindow->m_sAdditionalConfigData.rounding;
// apply window special data
@@ -164,8 +170,30 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, SMonitor* pMonitor, timespec*
for (auto& wd : pWindow->m_dWindowDecorations)
wd->draw(pMonitor);
+ if (!pWindow->m_bIsX11) {
+
+ // To everyone who makes apps with improperly aligned surfaces,
+ // For example chromium, or GTK devs who allow shadows on windows,
+ // a sincere FUCK YOU.
+
+ wlr_box geom;
+ wlr_xdg_surface_get_geometry(pWindow->m_uSurface.xdg, &geom);
+
+ g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D((double)geom.x / (double)pWindow->m_uSurface.xdg->surface->current.width, (double)geom.y / (double)pWindow->m_uSurface.xdg->surface->current.height);
+ g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D((double)(geom.width + geom.x) / (double)pWindow->m_uSurface.xdg->surface->current.width, (double)(geom.y + geom.height) / (double)pWindow->m_uSurface.xdg->surface->current.height);
+
+ if (g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft == Vector2D() && g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight == Vector2D(1, 1)) {
+ // No special UV mods needed
+ g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(-1, -1);
+ g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(-1, -1);
+ }
+ }
+
wlr_surface_for_each_surface(g_pXWaylandManager->getWindowSurface(pWindow), renderSurface, &renderdata);
+ g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(-1, -1);
+ g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(-1, -1);
+
if (pWindow->m_bIsX11) {
if (pWindow->m_uSurface.xwayland->surface) {
wlr_surface_for_each_surface(pWindow->m_uSurface.xwayland->surface, renderSurface, &renderdata);