Compare commits
102 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
84ab8d11e8 | ||
|
60bda7ee3d | ||
|
939696f97e | ||
|
cbadf3e3f3 | ||
|
1ed4f1cb25 | ||
|
5d4ff60f53 | ||
|
504ebe1b37 | ||
|
cf1886ca44 | ||
|
341e04a36c | ||
|
d7514412d8 | ||
|
7447be8220 | ||
|
4644de2269 | ||
|
3656045ad8 | ||
|
15316aaa31 | ||
|
cfd68af5b6 | ||
|
4f804d5f96 | ||
|
e6f7724ab0 | ||
|
e65f52bf2d | ||
|
c51b3fb06f | ||
|
3ff59e7e1d | ||
|
3d0d3b6343 | ||
|
2e3f0d5991 | ||
|
91e8c42843 | ||
|
4b4bd90b14 | ||
|
7009dc9184 | ||
|
b7840c6461 | ||
|
5a90911b70 | ||
|
0e5f14d8d2 | ||
|
df990c80e2 | ||
|
352574d862 | ||
|
bfcc2adbda | ||
|
9002657bcc | ||
|
3e93fdf779 | ||
|
bc7e488a4c | ||
|
8b1069b330 | ||
|
61fd75b55e | ||
|
7b3d039388 | ||
|
12d79d6342 | ||
|
08e3519747 | ||
|
5cd7e4587e | ||
|
72987dee88 | ||
|
754eaf5b8b | ||
|
df17991b1c | ||
|
791e1b96b3 | ||
|
02b4a9bded | ||
|
4d403dac32 | ||
|
f40e382fc6 | ||
|
b86ed02d8a | ||
|
17339e0ae9 | ||
|
5eeec8860e | ||
|
9f20a15955 | ||
|
c4365f20ed | ||
|
307dd8f511 | ||
|
8342bac697 | ||
|
3c964a9fdc | ||
|
f14c5ea5c5 | ||
|
dcd7a92b01 | ||
|
b6516bad02 | ||
|
13d9a637d6 | ||
|
4cee94b91c | ||
|
c4da4b026d | ||
|
babb9c07b0 | ||
|
6b92144f15 | ||
|
8d31c84483 | ||
|
d484506600 | ||
|
b240704bee | ||
|
71166ef40b | ||
|
252aaaecfa | ||
|
f92a86af53 | ||
|
2ba2c8aeee | ||
|
955009655d | ||
|
d7d333d162 | ||
|
f5b2fd2bc3 | ||
|
44ee9915e3 | ||
|
9f2bde925b | ||
|
7904188de9 | ||
|
666ee61c13 | ||
|
7e033e48ac | ||
|
d8dbdc4a01 | ||
|
d3acf8da3b | ||
|
aeeeace102 | ||
|
880996b053 | ||
|
4d6d662c67 | ||
|
1512b81126 | ||
|
4f26c4e1eb | ||
|
3c33d4b9dd | ||
|
bd3ea8dcb5 | ||
|
813af393f1 | ||
|
583b05a8c6 | ||
|
1607e96704 | ||
|
1a4f23eb2f | ||
|
42ab06e7c8 | ||
|
46753b1f22 | ||
|
d4e68ab602 | ||
|
37b76cd1ca | ||
|
0be36cd02d | ||
|
4e0e8d933e | ||
|
c7ba460687 | ||
|
3a189c265d | ||
|
069880e374 | ||
|
fa5e812304 | ||
|
33444e1e5e |
17
.github/ISSUE_TEMPLATE/bug.yml
vendored
@@ -9,12 +9,23 @@ body:
|
||||
|
||||
---
|
||||
|
||||
- type: input
|
||||
- type: textarea
|
||||
id: ver
|
||||
attributes:
|
||||
label: Hyprland Version
|
||||
description: "Paste here the output of `hyprctl version`."
|
||||
placeholder: Hyprland, built from branch main at commit...
|
||||
description: "Paste here the output of `hyprctl version`. For hyprland after 0.34.0, paste `hyprctl systeminfo` instead."
|
||||
value: "<details>
|
||||
<summary>System/Version info</summary>
|
||||
|
||||
|
||||
```sh
|
||||
|
||||
<Paste the output of the command here>
|
||||
|
||||
```
|
||||
|
||||
|
||||
</details>"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
|
28
.github/workflows/stale.yml
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
# This workflow warns and then closes issues and PRs that have had no activity for a specified amount of time.
|
||||
#
|
||||
# You can adjust the behavior by modifying this file.
|
||||
# For more information, see:
|
||||
# https://github.com/actions/stale
|
||||
name: Mark stale issues and pull requests
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '7 */4 * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
steps:
|
||||
- uses: actions/stale@v5
|
||||
with:
|
||||
repo-token: ${{ secrets.STALEBOT_PAT }}
|
||||
stale-issue-label: 'stale'
|
||||
stale-pr-label: 'stale'
|
||||
operations-per-run: 40
|
||||
days-before-close: -1
|
@@ -57,8 +57,8 @@ ExternalProject_Add(
|
||||
wlroots
|
||||
PREFIX ${CMAKE_SOURCE_DIR}/subprojects/wlroots
|
||||
SOURCE_DIR ${CMAKE_SOURCE_DIR}/subprojects/wlroots
|
||||
PATCH_COMMAND sed -E -i -e "s/(soversion = 13)([^032]|$$)/soversion = 13032/g" meson.build
|
||||
CONFIGURE_COMMAND meson setup build --buildtype=${BUILDTYPE_LOWER} -Dwerror=false -Dexamples=false -Drenderers=gles2 $<IF:$<BOOL:${WITH_ASAN}>,-Db_sanitize=address,-Db_sanitize=none> && meson setup build --buildtype=${BUILDTYPE_LOWER} -Dwerror=false -Dexamples=false -Drenderers=gles2 $<IF:$<BOOL:${WITH_ASAN}>,-Db_sanitize=address,-Db_sanitize=none> --reconfigure
|
||||
PATCH_COMMAND sed -E -i -e "s/(soversion = .*$)/soversion = 13032/g" meson.build
|
||||
CONFIGURE_COMMAND meson setup --reconfigure build --buildtype=${BUILDTYPE_LOWER} -Dwerror=false -Dxwayland=$<IF:$<BOOL:${NO_XWAYLAND}>,disabled,enabled> -Dexamples=false -Drenderers=gles2 $<IF:$<BOOL:${WITH_ASAN}>,-Db_sanitize=address,-Db_sanitize=none>
|
||||
BUILD_COMMAND ninja -C build
|
||||
BUILD_ALWAYS true
|
||||
BUILD_IN_SOURCE true
|
||||
|
13
Makefile
@@ -1,22 +1,22 @@
|
||||
PREFIX = /usr/local
|
||||
|
||||
legacyrenderer:
|
||||
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja
|
||||
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja
|
||||
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
||||
chmod -R 777 ./build
|
||||
|
||||
legacyrendererdebug:
|
||||
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja
|
||||
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja
|
||||
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
||||
chmod -R 777 ./build
|
||||
|
||||
release:
|
||||
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -S . -B ./build -G Ninja
|
||||
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build -G Ninja
|
||||
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
||||
chmod -R 777 ./build
|
||||
|
||||
debug:
|
||||
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -S . -B ./build -G Ninja
|
||||
cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build -G Ninja
|
||||
cmake --build ./build --config Debug --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
||||
chmod -R 777 ./build
|
||||
|
||||
@@ -42,10 +42,10 @@ install:
|
||||
chmod 755 ${PREFIX}/bin/Hyprland
|
||||
chmod 755 ${PREFIX}/bin/hyprctl
|
||||
chmod 755 ${PREFIX}/bin/hyprpm
|
||||
ln -s -r ${PREFIX}/bin/Hyprland ${PREFIX}/bin/hyprland
|
||||
cd ${PREFIX}/bin && ln -sf Hyprland hyprland
|
||||
if [ ! -f ${PREFIX}/share/wayland-sessions/hyprland.desktop ]; then cp ./example/hyprland.desktop ${PREFIX}/share/wayland-sessions; fi
|
||||
mkdir -p ${PREFIX}/share/hyprland
|
||||
cp ./assets/wall_* ${PREFIX}/share/hyprland
|
||||
cp ./assets/wall* ${PREFIX}/share/hyprland
|
||||
mkdir -p ${PREFIX}/share/xdg-desktop-portal
|
||||
cp ./assets/hyprland-portals.conf ${PREFIX}/share/xdg-desktop-portal
|
||||
|
||||
@@ -60,6 +60,7 @@ install:
|
||||
uninstall:
|
||||
rm -f ${PREFIX}/share/wayland-sessions/hyprland.desktop
|
||||
rm -f ${PREFIX}/bin/Hyprland
|
||||
rm -f ${PREFIX}/bin/hyprland
|
||||
rm -f ${PREFIX}/bin/hyprctl
|
||||
rm -f ${PREFIX}/bin/hyprpm
|
||||
rm -f ${PREFIX}/lib/libwlroots.so.13032
|
||||
|
@@ -1,9 +1,7 @@
|
||||
wallpaper_types = ['', 'anime_', 'anime2_']
|
||||
wallpapers = ['0', '1', '2']
|
||||
|
||||
foreach type : wallpaper_types
|
||||
foreach size : [2, 4, 8]
|
||||
install_data(f'wall_@type@@size@K.png', install_dir: join_paths(get_option('datadir'), 'hyprland'), install_tag: 'runtime')
|
||||
endforeach
|
||||
foreach type : wallpapers
|
||||
install_data(f'wall@type@.png', install_dir: join_paths(get_option('datadir'), 'hyprland'), install_tag: 'runtime')
|
||||
endforeach
|
||||
|
||||
install_data('hyprland-portals.conf', install_dir: join_paths(get_option('datadir'), 'xdg-desktop-portal'), install_tag: 'runtime')
|
||||
|
BIN
assets/wall0.png
Normal file
After Width: | Height: | Size: 14 MiB |
BIN
assets/wall1.png
Normal file
After Width: | Height: | Size: 5.4 MiB |
BIN
assets/wall2.png
Normal file
After Width: | Height: | Size: 27 MiB |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 146 KiB |
Before Width: | Height: | Size: 511 KiB |
Before Width: | Height: | Size: 1.3 MiB |
Before Width: | Height: | Size: 1.3 MiB |
Before Width: | Height: | Size: 502 KiB |
Before Width: | Height: | Size: 1.4 MiB |
Before Width: | Height: | Size: 1.6 MiB |
@@ -1,8 +0,0 @@
|
||||
# compile with HYPRLAND_HEADERS=<path_to_hl> make all
|
||||
# make sure that the path above is to the root hl repo directory, NOT src/
|
||||
# and that you have ran `make protocols` in the hl dir.
|
||||
|
||||
all:
|
||||
$(CXX) -shared -fPIC --no-gnu-unique main.cpp customLayout.cpp customDecoration.cpp -o examplePlugin.so -g `pkg-config --cflags pixman-1 libdrm hyprland` -std=c++2b
|
||||
clean:
|
||||
rm ./examplePlugin.so
|
@@ -1,74 +0,0 @@
|
||||
#include "customDecoration.hpp"
|
||||
#include <hyprland/src/Window.hpp>
|
||||
#include <hyprland/src/Compositor.hpp>
|
||||
#include "globals.hpp"
|
||||
|
||||
CCustomDecoration::CCustomDecoration(CWindow* pWindow) {
|
||||
m_pWindow = pWindow;
|
||||
m_vLastWindowPos = pWindow->m_vRealPosition.vec();
|
||||
m_vLastWindowSize = pWindow->m_vRealSize.vec();
|
||||
}
|
||||
|
||||
CCustomDecoration::~CCustomDecoration() {
|
||||
damageEntire();
|
||||
}
|
||||
|
||||
SWindowDecorationExtents CCustomDecoration::getWindowDecorationExtents() {
|
||||
return m_seExtents;
|
||||
}
|
||||
|
||||
void CCustomDecoration::draw(CMonitor* pMonitor, float a, const Vector2D& offset) {
|
||||
if (!g_pCompositor->windowValidMapped(m_pWindow))
|
||||
return;
|
||||
|
||||
if (!m_pWindow->m_sSpecialRenderData.decorate)
|
||||
return;
|
||||
|
||||
static auto* const PCOLOR = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:example:border_color")->intValue;
|
||||
static auto* const PROUNDING = &HyprlandAPI::getConfigValue(PHANDLE, "decoration:rounding")->intValue;
|
||||
static auto* const PBORDERSIZE = &HyprlandAPI::getConfigValue(PHANDLE, "general:border_size")->intValue;
|
||||
|
||||
const auto ROUNDING = !m_pWindow->m_sSpecialRenderData.rounding ?
|
||||
0 :
|
||||
(m_pWindow->m_sAdditionalConfigData.rounding.toUnderlying() == -1 ? *PROUNDING : m_pWindow->m_sAdditionalConfigData.rounding.toUnderlying());
|
||||
|
||||
// draw the border
|
||||
CBox fullBox = {(int)(m_vLastWindowPos.x - *PBORDERSIZE), (int)(m_vLastWindowPos.y - *PBORDERSIZE), (int)(m_vLastWindowSize.x + 2.0 * *PBORDERSIZE),
|
||||
(int)(m_vLastWindowSize.y + 2.0 * *PBORDERSIZE)};
|
||||
|
||||
fullBox.x -= pMonitor->vecPosition.x;
|
||||
fullBox.y -= pMonitor->vecPosition.y;
|
||||
|
||||
m_seExtents = {{m_vLastWindowPos.x - fullBox.x - pMonitor->vecPosition.x + 2, m_vLastWindowPos.y - fullBox.y - pMonitor->vecPosition.y + 2},
|
||||
{fullBox.x + fullBox.width + pMonitor->vecPosition.x - m_vLastWindowPos.x - m_vLastWindowSize.x + 2,
|
||||
fullBox.y + fullBox.height + pMonitor->vecPosition.y - m_vLastWindowPos.y - m_vLastWindowSize.y + 2}};
|
||||
|
||||
fullBox.x += offset.x;
|
||||
fullBox.y += offset.y;
|
||||
|
||||
if (fullBox.width < 1 || fullBox.height < 1)
|
||||
return; // don't draw invisible shadows
|
||||
|
||||
g_pHyprOpenGL->scissor((CBox*)nullptr);
|
||||
|
||||
fullBox.scale(pMonitor->scale);
|
||||
g_pHyprOpenGL->renderBorder(&fullBox, CColor(*PCOLOR), *PROUNDING * pMonitor->scale + *PBORDERSIZE * 2, a);
|
||||
}
|
||||
|
||||
eDecorationType CCustomDecoration::getDecorationType() {
|
||||
return DECORATION_CUSTOM;
|
||||
}
|
||||
|
||||
void CCustomDecoration::updateWindow(CWindow* pWindow) {
|
||||
|
||||
m_vLastWindowPos = pWindow->m_vRealPosition.vec();
|
||||
m_vLastWindowSize = pWindow->m_vRealSize.vec();
|
||||
|
||||
damageEntire();
|
||||
}
|
||||
|
||||
void CCustomDecoration::damageEntire() {
|
||||
CBox dm = {(int)(m_vLastWindowPos.x - m_seExtents.topLeft.x), (int)(m_vLastWindowPos.y - m_seExtents.topLeft.y),
|
||||
(int)(m_vLastWindowSize.x + m_seExtents.topLeft.x + m_seExtents.bottomRight.x), (int)m_seExtents.topLeft.y};
|
||||
g_pHyprRenderer->damageBox(&dm);
|
||||
}
|
@@ -1,29 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#define WLR_USE_UNSTABLE
|
||||
|
||||
#include <hyprland/src/render/decorations/IHyprWindowDecoration.hpp>
|
||||
|
||||
class CCustomDecoration : public IHyprWindowDecoration {
|
||||
public:
|
||||
CCustomDecoration(CWindow*);
|
||||
virtual ~CCustomDecoration();
|
||||
|
||||
virtual SWindowDecorationExtents getWindowDecorationExtents();
|
||||
|
||||
virtual void draw(CMonitor*, float a, const Vector2D& offset);
|
||||
|
||||
virtual eDecorationType getDecorationType();
|
||||
|
||||
virtual void updateWindow(CWindow*);
|
||||
|
||||
virtual void damageEntire();
|
||||
|
||||
private:
|
||||
SWindowDecorationExtents m_seExtents;
|
||||
|
||||
CWindow* m_pWindow = nullptr;
|
||||
|
||||
Vector2D m_vLastWindowPos;
|
||||
Vector2D m_vLastWindowSize;
|
||||
};
|
@@ -1,80 +0,0 @@
|
||||
#include "customLayout.hpp"
|
||||
#include <hyprland/src/Compositor.hpp>
|
||||
#include "globals.hpp"
|
||||
|
||||
void CHyprCustomLayout::onWindowCreatedTiling(CWindow* pWindow) {
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
|
||||
const auto SIZE = PMONITOR->vecSize;
|
||||
|
||||
// these are used for focus and move calculations, and are *required* to touch for moving focus to work properly.
|
||||
pWindow->m_vPosition = Vector2D{(SIZE.x / 2.0) * (m_vWindowData.size() % 2), (SIZE.y / 2.0) * (int)(m_vWindowData.size() > 1)};
|
||||
pWindow->m_vSize = SIZE / 2.0;
|
||||
|
||||
// this is the actual pos and size of the window (where it's rendered)
|
||||
pWindow->m_vRealPosition = pWindow->m_vPosition + Vector2D{10, 10};
|
||||
pWindow->m_vRealSize = pWindow->m_vSize - Vector2D{20, 20};
|
||||
|
||||
const auto PDATA = &m_vWindowData.emplace_back();
|
||||
PDATA->pWindow = pWindow;
|
||||
}
|
||||
|
||||
void CHyprCustomLayout::onWindowRemovedTiling(CWindow* pWindow) {
|
||||
std::erase_if(m_vWindowData, [&](const auto& other) { return other.pWindow == pWindow; });
|
||||
}
|
||||
|
||||
bool CHyprCustomLayout::isWindowTiled(CWindow* pWindow) {
|
||||
return std::find_if(m_vWindowData.begin(), m_vWindowData.end(), [&](const auto& other) { return other.pWindow == pWindow; }) != m_vWindowData.end();
|
||||
}
|
||||
|
||||
void CHyprCustomLayout::recalculateMonitor(const int& eIdleInhibitMode) {
|
||||
; // empty
|
||||
}
|
||||
|
||||
void CHyprCustomLayout::recalculateWindow(CWindow* pWindow) {
|
||||
; // empty
|
||||
}
|
||||
|
||||
void CHyprCustomLayout::resizeActiveWindow(const Vector2D& delta, CWindow* pWindow) {
|
||||
; // empty
|
||||
}
|
||||
|
||||
void CHyprCustomLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreenMode mode, bool on) {
|
||||
; // empty
|
||||
}
|
||||
|
||||
std::any CHyprCustomLayout::layoutMessage(SLayoutMessageHeader header, std::string content) {
|
||||
return "";
|
||||
}
|
||||
|
||||
SWindowRenderLayoutHints CHyprCustomLayout::requestRenderHints(CWindow* pWindow) {
|
||||
return {};
|
||||
}
|
||||
|
||||
void CHyprCustomLayout::switchWindows(CWindow* pWindowA, CWindow* pWindowB) {
|
||||
; // empty
|
||||
}
|
||||
|
||||
void CHyprCustomLayout::alterSplitRatio(CWindow* pWindow, float delta, bool exact) {
|
||||
; // empty
|
||||
}
|
||||
|
||||
std::string CHyprCustomLayout::getLayoutName() {
|
||||
return "custom";
|
||||
}
|
||||
|
||||
void CHyprCustomLayout::replaceWindowDataWith(CWindow* from, CWindow* to) {
|
||||
; // empty
|
||||
}
|
||||
|
||||
void CHyprCustomLayout::onEnable() {
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (w->isHidden() || !w->m_bIsMapped || w->m_bFadingOut || w->m_bIsFloating)
|
||||
continue;
|
||||
|
||||
onWindowCreatedTiling(w.get());
|
||||
}
|
||||
}
|
||||
|
||||
void CHyprCustomLayout::onDisable() {
|
||||
m_vWindowData.clear();
|
||||
}
|
@@ -1,32 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#define WLR_USE_UNSTABLE
|
||||
|
||||
#include <hyprland/src/layout/IHyprLayout.hpp>
|
||||
|
||||
struct SWindowData {
|
||||
CWindow* pWindow = nullptr;
|
||||
};
|
||||
|
||||
class CHyprCustomLayout : public IHyprLayout {
|
||||
public:
|
||||
virtual void onWindowCreatedTiling(CWindow*);
|
||||
virtual void onWindowRemovedTiling(CWindow*);
|
||||
virtual bool isWindowTiled(CWindow*);
|
||||
virtual void recalculateMonitor(const int&);
|
||||
virtual void recalculateWindow(CWindow*);
|
||||
virtual void resizeActiveWindow(const Vector2D&, CWindow* pWindow = nullptr);
|
||||
virtual void fullscreenRequestForWindow(CWindow*, eFullscreenMode, bool);
|
||||
virtual std::any layoutMessage(SLayoutMessageHeader, std::string);
|
||||
virtual SWindowRenderLayoutHints requestRenderHints(CWindow*);
|
||||
virtual void switchWindows(CWindow*, CWindow*);
|
||||
virtual void alterSplitRatio(CWindow*, float, bool);
|
||||
virtual std::string getLayoutName();
|
||||
virtual void replaceWindowDataWith(CWindow* from, CWindow* to);
|
||||
|
||||
virtual void onEnable();
|
||||
virtual void onDisable();
|
||||
|
||||
private:
|
||||
std::vector<SWindowData> m_vWindowData;
|
||||
};
|
@@ -1,5 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hyprland/src/plugins/PluginAPI.hpp>
|
||||
|
||||
inline HANDLE PHANDLE = nullptr;
|
@@ -1,99 +0,0 @@
|
||||
#define WLR_USE_UNSTABLE
|
||||
|
||||
#include "globals.hpp"
|
||||
|
||||
#include <hyprland/src/Window.hpp>
|
||||
#include <hyprland/src/Compositor.hpp>
|
||||
#include "customLayout.hpp"
|
||||
#include "customDecoration.hpp"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <thread>
|
||||
|
||||
// Methods
|
||||
inline std::unique_ptr<CHyprCustomLayout> g_pCustomLayout;
|
||||
inline CFunctionHook* g_pFocusHook = nullptr;
|
||||
inline CFunctionHook* g_pMotionHook = nullptr;
|
||||
inline CFunctionHook* g_pMouseDownHook = nullptr;
|
||||
typedef void (*origFocusWindow)(void*, CWindow*, wlr_surface*);
|
||||
typedef void (*origMotion)(wlr_seat*, uint32_t, double, double);
|
||||
typedef void (*origMouseDownNormal)(void*, wlr_pointer_button_event*);
|
||||
|
||||
// Do NOT change this function.
|
||||
APICALL EXPORT std::string PLUGIN_API_VERSION() {
|
||||
return HYPRLAND_API_VERSION;
|
||||
}
|
||||
|
||||
static void onActiveWindowChange(void* self, std::any data) {
|
||||
try {
|
||||
auto* const PWINDOW = std::any_cast<CWindow*>(data);
|
||||
|
||||
HyprlandAPI::addNotification(PHANDLE, "[ExamplePlugin] Active window: " + (PWINDOW ? PWINDOW->m_szTitle : "None"), CColor{0.f, 0.5f, 1.f, 1.f}, 5000);
|
||||
} catch (std::bad_any_cast& e) { HyprlandAPI::addNotification(PHANDLE, "[ExamplePlugin] Active window: None", CColor{0.f, 0.5f, 1.f, 1.f}, 5000); }
|
||||
}
|
||||
|
||||
static void onNewWindow(void* self, std::any data) {
|
||||
auto* const PWINDOW = std::any_cast<CWindow*>(data);
|
||||
|
||||
HyprlandAPI::addWindowDecoration(PHANDLE, PWINDOW, new CCustomDecoration(PWINDOW));
|
||||
}
|
||||
|
||||
void hkFocusWindow(void* thisptr, CWindow* pWindow, wlr_surface* pSurface) {
|
||||
// HyprlandAPI::addNotification(PHANDLE, getFormat("FocusWindow with %lx %lx", pWindow, pSurface), CColor{0.f, 1.f, 1.f, 1.f}, 5000);
|
||||
(*(origFocusWindow)g_pFocusHook->m_pOriginal)(thisptr, pWindow, pSurface);
|
||||
}
|
||||
|
||||
void hkNotifyMotion(wlr_seat* wlr_seat, uint32_t time_msec, double sx, double sy) {
|
||||
// HyprlandAPI::addNotification(PHANDLE, getFormat("NotifyMotion with %lf %lf", sx, sy), CColor{0.f, 1.f, 1.f, 1.f}, 5000);
|
||||
(*(origMotion)g_pMotionHook->m_pOriginal)(wlr_seat, time_msec, sx, sy);
|
||||
}
|
||||
|
||||
void hkProcessMouseDownNormal(void* thisptr, wlr_pointer_button_event* e) {
|
||||
// HyprlandAPI::addNotification(PHANDLE, "Mouse down normal!", CColor{0.8f, 0.2f, 0.5f, 1.0f}, 5000);
|
||||
(*(origMouseDownNormal)g_pMouseDownHook->m_pOriginal)(thisptr, e);
|
||||
}
|
||||
|
||||
APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
||||
PHANDLE = handle;
|
||||
|
||||
HyprlandAPI::addNotification(PHANDLE, "Hello World from an example plugin!", CColor{0.f, 1.f, 1.f, 1.f}, 5000);
|
||||
|
||||
HyprlandAPI::registerCallbackDynamic(PHANDLE, "activeWindow", [&](void* self, SCallbackInfo& info, std::any data) { onActiveWindowChange(self, data); });
|
||||
HyprlandAPI::registerCallbackDynamic(PHANDLE, "openWindow", [&](void* self, SCallbackInfo& info, std::any data) { onNewWindow(self, data); });
|
||||
|
||||
g_pCustomLayout = std::make_unique<CHyprCustomLayout>();
|
||||
|
||||
HyprlandAPI::addLayout(PHANDLE, "custom", g_pCustomLayout.get());
|
||||
|
||||
HyprlandAPI::addConfigValue(PHANDLE, "plugin:example:border_color", SConfigValue{.intValue = configStringToInt("rgb(44ee44)")});
|
||||
|
||||
HyprlandAPI::addDispatcher(PHANDLE, "example", [](std::string arg) { HyprlandAPI::addNotification(PHANDLE, "Arg passed: " + arg, CColor{0.5f, 0.5f, 0.7f, 1.0f}, 5000); });
|
||||
|
||||
// Hook a public member
|
||||
g_pFocusHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&CCompositor::focusWindow, (void*)&hkFocusWindow);
|
||||
// Hook a public non-member
|
||||
g_pMotionHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&wlr_seat_pointer_notify_motion, (void*)&hkNotifyMotion);
|
||||
// Hook a private member
|
||||
static const auto METHODS = HyprlandAPI::findFunctionsByName(PHANDLE, "processMouseDownNormal");
|
||||
g_pMouseDownHook = HyprlandAPI::createFunctionHook(PHANDLE, METHODS[0].address, (void*)&hkProcessMouseDownNormal);
|
||||
|
||||
static auto* const PBORDERCOLOR = HyprlandAPI::getConfigValue(PHANDLE, "plugin:example:border_color");
|
||||
|
||||
// fancy notifications
|
||||
HyprlandAPI::addNotificationV2(
|
||||
PHANDLE,
|
||||
{{"text", "Example hint, color " + std::to_string(PBORDERCOLOR->intValue)}, {"time", (uint64_t)10000}, {"color", CColor{PBORDERCOLOR->intValue}}, {"icon", ICON_HINT}});
|
||||
|
||||
// Enable our hooks
|
||||
g_pFocusHook->hook();
|
||||
g_pMotionHook->hook();
|
||||
g_pMouseDownHook->hook();
|
||||
|
||||
HyprlandAPI::reloadConfig();
|
||||
|
||||
return {"ExamplePlugin", "An example plugin", "Vaxry", "1.0"};
|
||||
}
|
||||
|
||||
APICALL EXPORT void PLUGIN_EXIT() {
|
||||
HyprlandAPI::invokeHyprctlCommand("seterror", "disable");
|
||||
}
|
@@ -112,7 +112,7 @@ gestures {
|
||||
|
||||
misc {
|
||||
# See https://wiki.hyprland.org/Configuring/Variables/ for more
|
||||
force_default_wallpaper = -1 # Set to 0 to disable the anime mascot wallpapers
|
||||
force_default_wallpaper = -1 # Set to 0 or 1 to disable the anime mascot wallpapers
|
||||
}
|
||||
|
||||
# Example per-device config
|
||||
|
42
flake.lock
generated
@@ -23,13 +23,34 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hyprlang": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"xdph",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1704287638,
|
||||
"narHash": "sha256-TuRXJGwtK440AXQNl5eiqmQqY4LZ/9+z/R7xC0ie3iA=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprlang",
|
||||
"rev": "6624f2bb66d4d27975766e81f77174adbe58ec97",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprlang",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1703438236,
|
||||
"narHash": "sha256-aqVBq1u09yFhL7bj1/xyUeJjzr92fXVvQSSEx6AdB1M=",
|
||||
"lastModified": 1706191920,
|
||||
"narHash": "sha256-eLihrZAPZX0R6RyM5fYAWeKVNuQPYjAkCUBr+JNvtdE=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "5f64a12a728902226210bf01d25ec6cbb9d9265b",
|
||||
"rev": "ae5c332cbb5827f6b1f02572496b141021de335f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -67,18 +88,18 @@
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"host": "gitlab.freedesktop.org",
|
||||
"lastModified": 1701368958,
|
||||
"narHash": "sha256-7kvyoA91etzVEl9mkA/EJfB6z/PltxX7Xc4gcr7/xlo=",
|
||||
"lastModified": 1706359063,
|
||||
"narHash": "sha256-5HUTG0p+nCJv3cn73AmFHRZdfRV5AD5N43g8xAePSKM=",
|
||||
"owner": "wlroots",
|
||||
"repo": "wlroots",
|
||||
"rev": "5d639394f3e83b01596dcd166a44a9a1a2583350",
|
||||
"rev": "00b869c1a96f300a8f25da95d624524895e0ddf2",
|
||||
"type": "gitlab"
|
||||
},
|
||||
"original": {
|
||||
"host": "gitlab.freedesktop.org",
|
||||
"owner": "wlroots",
|
||||
"repo": "wlroots",
|
||||
"rev": "5d639394f3e83b01596dcd166a44a9a1a2583350",
|
||||
"rev": "00b869c1a96f300a8f25da95d624524895e0ddf2",
|
||||
"type": "gitlab"
|
||||
}
|
||||
},
|
||||
@@ -87,6 +108,7 @@
|
||||
"hyprland-protocols": [
|
||||
"hyprland-protocols"
|
||||
],
|
||||
"hyprlang": "hyprlang",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
@@ -95,11 +117,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1703514399,
|
||||
"narHash": "sha256-VRr5Xc4S/VPr/gU3fiOD3vSIL2+GJ+LUrmFTWTwnTz4=",
|
||||
"lastModified": 1706145785,
|
||||
"narHash": "sha256-j9MP4fv2U/vdRKAXXc2gyMTmYwVnHP6kHx1/y6jprrU=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "xdg-desktop-portal-hyprland",
|
||||
"rev": "0a318a7a217a6402b0b705837cd5b50b0e94b31b",
|
||||
"rev": "5a592647587cd20b9692a347df6939b6d371b3bb",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@@ -12,7 +12,7 @@
|
||||
host = "gitlab.freedesktop.org";
|
||||
owner = "wlroots";
|
||||
repo = "wlroots";
|
||||
rev = "5d639394f3e83b01596dcd166a44a9a1a2583350";
|
||||
rev = "00b869c1a96f300a8f25da95d624524895e0ddf2";
|
||||
flake = false;
|
||||
};
|
||||
|
||||
@@ -86,6 +86,7 @@
|
||||
name = "hyprland-shell";
|
||||
nativeBuildInputs = with pkgsFor.${system}; [cmake python3];
|
||||
buildInputs = [self.packages.${system}.wlroots-hyprland];
|
||||
hardeningDisable = [ "fortify" ];
|
||||
inputsFrom = [
|
||||
self.packages.${system}.wlroots-hyprland
|
||||
self.packages.${system}.hyprland
|
||||
|
@@ -51,6 +51,7 @@ commands:
|
||||
setprop
|
||||
splash
|
||||
switchxkblayout
|
||||
systeminfo
|
||||
version
|
||||
workspacerules
|
||||
workspaces
|
||||
@@ -388,6 +389,8 @@ int main(int argc, char** argv) {
|
||||
request(fullRequest);
|
||||
else if (fullRequest.contains("/kill"))
|
||||
request(fullRequest);
|
||||
else if (fullRequest.contains("/systeminfo"))
|
||||
request(fullRequest);
|
||||
else if (fullRequest.contains("/splash"))
|
||||
request(fullRequest);
|
||||
else if (fullRequest.contains("/devices"))
|
||||
|
@@ -20,11 +20,18 @@ std::string DataState::getDataStatePath() {
|
||||
return std::string{HOME} + "/.local/share/hyprpm";
|
||||
}
|
||||
|
||||
std::string DataState::getHeadersPath() {
|
||||
return getDataStatePath() + "/headersRoot";
|
||||
}
|
||||
|
||||
void DataState::ensureStateStoreExists() {
|
||||
const auto PATH = getDataStatePath();
|
||||
|
||||
if (!std::filesystem::exists(PATH))
|
||||
std::filesystem::create_directories(PATH);
|
||||
|
||||
if (!std::filesystem::exists(getHeadersPath()))
|
||||
std::filesystem::create_directories(getHeadersPath());
|
||||
}
|
||||
|
||||
void DataState::addNewPluginRepo(const SPluginRepository& repo) {
|
||||
@@ -47,7 +54,8 @@ void DataState::addNewPluginRepo(const SPluginRepository& repo) {
|
||||
|
||||
DATA.emplace(p.name, toml::table{
|
||||
{"filename", p.name + ".so"},
|
||||
{"enabled", p.enabled}
|
||||
{"enabled", p.enabled},
|
||||
{"failed", p.failed}
|
||||
});
|
||||
}
|
||||
// clang-format on
|
||||
@@ -63,7 +71,10 @@ bool DataState::pluginRepoExists(const std::string& urlOrName) {
|
||||
const auto PATH = getDataStatePath();
|
||||
|
||||
for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
|
||||
if (!entry.is_directory())
|
||||
if (!entry.is_directory() || entry.path().stem() == "headersRoot")
|
||||
continue;
|
||||
|
||||
if (!std::filesystem::exists(entry.path().string() + "/state.toml"))
|
||||
continue;
|
||||
|
||||
auto STATE = toml::parse_file(entry.path().string() + "/state.toml");
|
||||
@@ -84,7 +95,10 @@ void DataState::removePluginRepo(const std::string& urlOrName) {
|
||||
const auto PATH = getDataStatePath();
|
||||
|
||||
for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
|
||||
if (!entry.is_directory())
|
||||
if (!entry.is_directory() || entry.path().stem() == "headersRoot")
|
||||
continue;
|
||||
|
||||
if (!std::filesystem::exists(entry.path().string() + "/state.toml"))
|
||||
continue;
|
||||
|
||||
auto STATE = toml::parse_file(entry.path().string() + "/state.toml");
|
||||
@@ -153,7 +167,10 @@ std::vector<SPluginRepository> DataState::getAllRepositories() {
|
||||
std::vector<SPluginRepository> repos;
|
||||
|
||||
for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
|
||||
if (!entry.is_directory())
|
||||
if (!entry.is_directory() || entry.path().stem() == "headersRoot")
|
||||
continue;
|
||||
|
||||
if (!std::filesystem::exists(entry.path().string() + "/state.toml"))
|
||||
continue;
|
||||
|
||||
auto STATE = toml::parse_file(entry.path().string() + "/state.toml");
|
||||
@@ -172,9 +189,10 @@ std::vector<SPluginRepository> DataState::getAllRepositories() {
|
||||
continue;
|
||||
|
||||
const auto ENABLED = STATE[key]["enabled"].value_or(false);
|
||||
const auto FAILED = STATE[key]["failed"].value_or(false);
|
||||
const auto FILENAME = STATE[key]["filename"].value_or("");
|
||||
|
||||
repo.plugins.push_back(SPlugin{std::string{key.str()}, FILENAME, ENABLED});
|
||||
repo.plugins.push_back(SPlugin{std::string{key.str()}, FILENAME, ENABLED, FAILED});
|
||||
}
|
||||
|
||||
repos.push_back(repo);
|
||||
@@ -189,7 +207,10 @@ bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
|
||||
const auto PATH = getDataStatePath();
|
||||
|
||||
for (const auto& entry : std::filesystem::directory_iterator(PATH)) {
|
||||
if (!entry.is_directory())
|
||||
if (!entry.is_directory() || entry.path().stem() == "headersRoot")
|
||||
continue;
|
||||
|
||||
if (!std::filesystem::exists(entry.path().string() + "/state.toml"))
|
||||
continue;
|
||||
|
||||
auto STATE = toml::parse_file(entry.path().string() + "/state.toml");
|
||||
@@ -201,6 +222,11 @@ bool DataState::setPluginEnabled(const std::string& name, bool enabled) {
|
||||
if (key.str() != name)
|
||||
continue;
|
||||
|
||||
const auto FAILED = STATE[key]["failed"].value_or(false);
|
||||
|
||||
if (FAILED)
|
||||
return false;
|
||||
|
||||
(*STATE[key].as_table()).insert_or_assign("enabled", enabled);
|
||||
|
||||
std::ofstream state(entry.path().string() + "/state.toml", std::ios::trunc);
|
||||
|
@@ -10,6 +10,7 @@ struct SGlobalState {
|
||||
|
||||
namespace DataState {
|
||||
std::string getDataStatePath();
|
||||
std::string getHeadersPath();
|
||||
void ensureStateStoreExists();
|
||||
void addNewPluginRepo(const SPluginRepository& repo);
|
||||
void removePluginRepo(const std::string& urlOrName);
|
||||
|
@@ -19,6 +19,7 @@ class CManifest {
|
||||
std::vector<std::string> authors;
|
||||
std::vector<std::string> buildSteps;
|
||||
std::string output;
|
||||
bool failed = false;
|
||||
};
|
||||
|
||||
struct {
|
||||
|
@@ -6,7 +6,8 @@
|
||||
struct SPlugin {
|
||||
std::string name;
|
||||
std::string filename;
|
||||
bool enabled;
|
||||
bool enabled = false;
|
||||
bool failed = false;
|
||||
};
|
||||
|
||||
struct SPluginRepository {
|
||||
|
@@ -10,6 +10,7 @@
|
||||
#include <thread>
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include <format>
|
||||
|
||||
#include <toml++/toml.hpp>
|
||||
|
||||
@@ -78,6 +79,8 @@ SHyprlandVersion CPluginManager::getHyprlandVersion() {
|
||||
|
||||
bool CPluginManager::addNewPluginRepo(const std::string& url) {
|
||||
|
||||
const auto HLVER = getHyprlandVersion();
|
||||
|
||||
if (DataState::pluginRepoExists(url)) {
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not clone the plugin repository. Repository already installed.\n";
|
||||
return false;
|
||||
@@ -170,6 +173,22 @@ bool CPluginManager::addNewPluginRepo(const std::string& url) {
|
||||
message += " version " + pl.version;
|
||||
progress.printMessageAbove(message);
|
||||
}
|
||||
|
||||
if (!pManifest->m_sRepository.commitPins.empty()) {
|
||||
// check commit pins
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::RESET} + " → Manifest has " + std::to_string(pManifest->m_sRepository.commitPins.size()) + " pins, checking");
|
||||
|
||||
for (auto& [hl, plugin] : pManifest->m_sRepository.commitPins) {
|
||||
if (hl != HLVER.hash)
|
||||
continue;
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " commit pin " + plugin + " matched hl, resetting");
|
||||
|
||||
execAndGet("cd /tmp/hyprpm/new/ && git reset --hard --recurse-submodules " + plugin);
|
||||
}
|
||||
}
|
||||
|
||||
progress.m_szCurrentMessage = "Verifying headers";
|
||||
progress.print();
|
||||
|
||||
@@ -191,16 +210,19 @@ bool CPluginManager::addNewPluginRepo(const std::string& url) {
|
||||
progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + p.name);
|
||||
|
||||
for (auto& bs : p.buildSteps) {
|
||||
out += execAndGet("cd /tmp/hyprpm/new && " + bs) + "\n";
|
||||
std::string cmd = std::format("cd /tmp/hyprpm/new && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", DataState::getHeadersPath(), bs);
|
||||
out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n";
|
||||
}
|
||||
|
||||
if (!std::filesystem::exists("/tmp/hyprpm/new/" + p.output)) {
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Plugin " << p.name << " failed to build.\n";
|
||||
progress.printMessageAbove(std::string{Colors::RED} + "✖" + Colors::RESET + " Plugin " + p.name + " failed to build.\n");
|
||||
|
||||
if (m_bVerbose)
|
||||
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "shell returned: " << out << "\n";
|
||||
|
||||
return false;
|
||||
p.failed = true;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " built " + p.name + " into " + p.output);
|
||||
@@ -220,7 +242,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url) {
|
||||
repo.url = url;
|
||||
repo.hash = repohash;
|
||||
for (auto& p : pManifest->m_vPlugins) {
|
||||
repo.plugins.push_back(SPlugin{p.name, "/tmp/hyprpm/new/" + p.output, false});
|
||||
repo.plugins.push_back(SPlugin{p.name, "/tmp/hyprpm/new/" + p.output, false, p.failed});
|
||||
}
|
||||
DataState::addNewPluginRepo(repo);
|
||||
|
||||
@@ -263,8 +285,12 @@ bool CPluginManager::removePluginRepo(const std::string& urlOrName) {
|
||||
eHeadersErrors CPluginManager::headersValid() {
|
||||
const auto HLVER = getHyprlandVersion();
|
||||
|
||||
if (!std::filesystem::exists(DataState::getHeadersPath() + "/share/pkgconfig/hyprland.pc"))
|
||||
return HEADERS_MISSING;
|
||||
|
||||
// find headers commit
|
||||
auto headers = execAndGet("pkg-config --cflags --keep-system-cflags hyprland");
|
||||
std::string cmd = std::format("PKG_CONFIG_PATH=\"{}/share/pkgconfig\" pkg-config --cflags --keep-system-cflags hyprland", DataState::getHeadersPath());
|
||||
auto headers = execAndGet(cmd.c_str());
|
||||
|
||||
if (!headers.contains("-I/"))
|
||||
return HEADERS_MISSING;
|
||||
@@ -296,10 +322,6 @@ eHeadersErrors CPluginManager::headersValid() {
|
||||
if (!ifs.good())
|
||||
return HEADERS_CORRUPTED;
|
||||
|
||||
if ((std::filesystem::exists("/usr/include/hyprland/src/version.h") && verHeader != "/usr/include/hyprland/src/version.h") ||
|
||||
(std::filesystem::exists("/usr/local/include/hyprland/src/version.h") && verHeader != "/usr/local/include/hyprland/src/version.h"))
|
||||
return HEADERS_DUPLICATED;
|
||||
|
||||
std::string verHeaderContent((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
|
||||
ifs.close();
|
||||
|
||||
@@ -314,7 +336,9 @@ eHeadersErrors CPluginManager::headersValid() {
|
||||
return HEADERS_OK;
|
||||
}
|
||||
|
||||
bool CPluginManager::updateHeaders() {
|
||||
bool CPluginManager::updateHeaders(bool force) {
|
||||
|
||||
DataState::ensureStateStoreExists();
|
||||
|
||||
const auto HLVER = getHyprlandVersion();
|
||||
|
||||
@@ -323,11 +347,8 @@ bool CPluginManager::updateHeaders() {
|
||||
std::filesystem::permissions("/tmp/hyprpm", std::filesystem::perms::all, std::filesystem::perm_options::replace);
|
||||
}
|
||||
|
||||
if (headersValid() == HEADERS_OK) {
|
||||
std::cout << "\n" << std::string{Colors::GREEN} + "✔" + Colors::RESET + " Your headers are already up-to-date.\n";
|
||||
auto GLOBALSTATE = DataState::getGlobalState();
|
||||
GLOBALSTATE.headersHashCompiled = HLVER.hash;
|
||||
DataState::updateGlobalState(GLOBALSTATE);
|
||||
if (!force && headersValid() == HEADERS_OK) {
|
||||
std::cout << "\n" << std::string{Colors::GREEN} + "✔" + Colors::RESET + " Headers up to date.\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -369,23 +390,38 @@ bool CPluginManager::updateHeaders() {
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::YELLOW} + "!" + Colors::RESET + " configuring Hyprland");
|
||||
|
||||
ret = execAndGet("cd /tmp/hyprpm/hyprland && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -S . -B ./build -G Ninja");
|
||||
if (m_bVerbose)
|
||||
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "setting PREFIX for cmake to " + DataState::getHeadersPath());
|
||||
|
||||
ret = execAndGet(
|
||||
std::format("cd /tmp/hyprpm/hyprland && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=\"{}\" -S . -B ./build -G Ninja",
|
||||
DataState::getHeadersPath()));
|
||||
if (m_bVerbose)
|
||||
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "cmake returned: " + ret);
|
||||
|
||||
// le hack. Wlroots has to generate its build/include
|
||||
ret = execAndGet("cd /tmp/hyprpm/hyprland/subprojects/wlroots && meson setup -Drenderers=gles2 -Dexamples=false build");
|
||||
if (m_bVerbose)
|
||||
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "meson returned: " + ret);
|
||||
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " configured Hyprland");
|
||||
progress.m_iSteps = 4;
|
||||
progress.m_szCurrentMessage = "Installing sources";
|
||||
progress.print();
|
||||
|
||||
progress.printMessageAbove(
|
||||
std::string{Colors::YELLOW} + "!" + Colors::RESET +
|
||||
" in order to install the sources, you will need to input your password.\n If nothing pops up, make sure you have polkit and an authentication daemon running.");
|
||||
// progress.printMessageAbove(
|
||||
// std::string{Colors::YELLOW} + "!" + Colors::RESET +
|
||||
// " in order to install the sources, you will need to input your password.\n If nothing pops up, make sure you have polkit and an authentication daemon running.");
|
||||
|
||||
ret = execAndGet("pkexec sh \"-c\" \"cd /tmp/hyprpm/hyprland && make installheaders\"");
|
||||
std::string cmd = std::format("sed -i -e \"s#PREFIX = /usr/local#PREFIX = {}#\" /tmp/hyprpm/hyprland/Makefile && cd /tmp/hyprpm/hyprland && make installheaders",
|
||||
DataState::getHeadersPath());
|
||||
if (m_bVerbose)
|
||||
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "installation will run: " + cmd);
|
||||
|
||||
ret = execAndGet(cmd);
|
||||
|
||||
if (m_bVerbose)
|
||||
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "pkexec returned: " << ret << "\n";
|
||||
std::cout << Colors::BLUE << "[v] " << Colors::RESET << "installer returned: " << ret << "\n";
|
||||
|
||||
// remove build files
|
||||
std::filesystem::remove_all("/tmp/hyprpm/hyprland");
|
||||
@@ -397,10 +433,6 @@ bool CPluginManager::updateHeaders() {
|
||||
progress.m_szCurrentMessage = "Done!";
|
||||
progress.print();
|
||||
|
||||
auto GLOBALSTATE = DataState::getGlobalState();
|
||||
GLOBALSTATE.headersHashCompiled = HLVER.hash;
|
||||
DataState::updateGlobalState(GLOBALSTATE);
|
||||
|
||||
std::cout << "\n";
|
||||
} else {
|
||||
progress.printMessageAbove(std::string{Colors::RED} + "✖" + Colors::RESET + " failed to install headers with error code " + std::to_string((int)HEADERSVALID));
|
||||
@@ -434,7 +466,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
|
||||
const auto HLVER = getHyprlandVersion();
|
||||
|
||||
CProgressBar progress;
|
||||
progress.m_iMaxSteps = REPOS.size() * 2 + 1;
|
||||
progress.m_iMaxSteps = REPOS.size() * 2 + 2;
|
||||
progress.m_iSteps = 0;
|
||||
progress.m_szCurrentMessage = "Updating repositories";
|
||||
progress.print();
|
||||
@@ -528,7 +560,8 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
|
||||
progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + p.name);
|
||||
|
||||
for (auto& bs : p.buildSteps) {
|
||||
out += execAndGet("cd /tmp/hyprpm/update && " + bs) + "\n";
|
||||
std::string cmd = std::format("cd /tmp/hyprpm/update && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", DataState::getHeadersPath(), bs);
|
||||
out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n";
|
||||
}
|
||||
|
||||
if (!std::filesystem::exists("/tmp/hyprpm/update/" + p.output)) {
|
||||
@@ -566,6 +599,14 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) {
|
||||
progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " updated " + repo.name);
|
||||
}
|
||||
|
||||
progress.m_iSteps++;
|
||||
progress.m_szCurrentMessage = "Updating global state...";
|
||||
progress.print();
|
||||
|
||||
auto GLOBALSTATE = DataState::getGlobalState();
|
||||
GLOBALSTATE.headersHashCompiled = HLVER.hash;
|
||||
DataState::updateGlobalState(GLOBALSTATE);
|
||||
|
||||
progress.m_iSteps++;
|
||||
progress.m_szCurrentMessage = "Done!";
|
||||
progress.print();
|
||||
@@ -696,8 +737,13 @@ void CPluginManager::listAllPlugins() {
|
||||
std::cout << std::string{Colors::RESET} + " → Repository " + r.name + ":\n";
|
||||
|
||||
for (auto& p : r.plugins) {
|
||||
std::cout << std::string{Colors::RESET} + " │ Plugin " + p.name + "\n └─ enabled: " << (p.enabled ? Colors::GREEN : Colors::RED) << (p.enabled ? "true" : "false")
|
||||
<< Colors::RESET << "\n";
|
||||
|
||||
std::cout << std::string{Colors::RESET} + " │ Plugin " + p.name;
|
||||
|
||||
if (!p.failed)
|
||||
std::cout << "\n └─ enabled: " << (p.enabled ? Colors::GREEN : Colors::RED) << (p.enabled ? "true" : "false") << Colors::RESET << "\n";
|
||||
else
|
||||
std::cout << "\n └─ enabled: " << Colors::RED << "Plugin failed to build" << Colors::RESET << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -40,7 +40,7 @@ class CPluginManager {
|
||||
bool removePluginRepo(const std::string& urlOrName);
|
||||
|
||||
eHeadersErrors headersValid();
|
||||
bool updateHeaders();
|
||||
bool updateHeaders(bool force = false);
|
||||
bool updatePlugins(bool forceUpdateAll);
|
||||
|
||||
void listAllPlugins();
|
||||
|
@@ -1,6 +1,7 @@
|
||||
#include "progress/CProgressBar.hpp"
|
||||
#include "helpers/Colors.hpp"
|
||||
#include "core/PluginManager.hpp"
|
||||
#include "core/DataState.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
@@ -23,6 +24,7 @@ const std::string HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager
|
||||
┣ --notify | -n → Send a hyprland notification for important events (e.g. load fail)
|
||||
┣ --help | -h → Show this menu
|
||||
┣ --verbose | -v → Enable too much logging
|
||||
┣ --force | -f → Force an operation ignoring checks (e.g. update -f)
|
||||
┗
|
||||
)#";
|
||||
|
||||
@@ -38,7 +40,7 @@ int main(int argc, char** argv, char** envp) {
|
||||
}
|
||||
|
||||
std::vector<std::string> command;
|
||||
bool notify = false, verbose = false;
|
||||
bool notify = false, verbose = false, force = false;
|
||||
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
if (ARGS[i].starts_with("-")) {
|
||||
@@ -49,6 +51,9 @@ int main(int argc, char** argv, char** envp) {
|
||||
notify = true;
|
||||
} else if (ARGS[i] == "--verbose" || ARGS[i] == "-v") {
|
||||
verbose = true;
|
||||
} else if (ARGS[i] == "--force" || ARGS[i] == "-f") {
|
||||
force = true;
|
||||
std::cout << Colors::RED << "!" << Colors::RESET << " Using --force, I hope you know what you are doing.\n";
|
||||
} else {
|
||||
std::cerr << "Unrecognized option " << ARGS[i];
|
||||
return 1;
|
||||
@@ -82,9 +87,13 @@ int main(int argc, char** argv, char** envp) {
|
||||
return g_pPluginManager->removePluginRepo(command[1]) ? 0 : 1;
|
||||
} else if (command[0] == "update") {
|
||||
bool headersValid = g_pPluginManager->headersValid() == HEADERS_OK;
|
||||
bool headers = g_pPluginManager->updateHeaders();
|
||||
bool headers = g_pPluginManager->updateHeaders(force);
|
||||
if (headers) {
|
||||
bool ret1 = g_pPluginManager->updatePlugins(!headersValid);
|
||||
const auto HLVER = g_pPluginManager->getHyprlandVersion();
|
||||
auto GLOBALSTATE = DataState::getGlobalState();
|
||||
const auto COMPILEDOUTDATED = HLVER.hash != GLOBALSTATE.headersHashCompiled;
|
||||
|
||||
bool ret1 = g_pPluginManager->updatePlugins(!headersValid || force || COMPILEDOUTDATED);
|
||||
|
||||
if (!ret1)
|
||||
return 1;
|
||||
|
@@ -10,19 +10,16 @@
|
||||
(builtins.substring 4 2 longDate)
|
||||
(builtins.substring 6 2 longDate)
|
||||
]);
|
||||
|
||||
mkJoinedOverlays = overlays: final: prev:
|
||||
lib.foldl' (attrs: overlay: attrs // (overlay final prev)) {} overlays;
|
||||
in {
|
||||
# Contains what a user is most likely to care about:
|
||||
# Hyprland itself, XDPH and the Share Picker.
|
||||
default = mkJoinedOverlays (with self.overlays; [
|
||||
default = lib.composeManyExtensions (with self.overlays; [
|
||||
hyprland-packages
|
||||
hyprland-extras
|
||||
]);
|
||||
|
||||
# Packages for variations of Hyprland, dependencies included.
|
||||
hyprland-packages = mkJoinedOverlays [
|
||||
hyprland-packages = lib.composeManyExtensions [
|
||||
# Dependencies
|
||||
inputs.hyprland-protocols.overlays.default
|
||||
self.overlays.wlroots-hyprland
|
||||
@@ -34,7 +31,7 @@ in {
|
||||
hyprland = final.callPackage ./default.nix {
|
||||
stdenv = final.gcc13Stdenv;
|
||||
version = "${props.version}+date=${date}_${self.shortRev or "dirty"}";
|
||||
wlroots = final.wlroots-hyprland;
|
||||
wlroots = prev.wlroots-hyprland;
|
||||
commit = self.rev or "";
|
||||
inherit (final) udis86 hyprland-protocols;
|
||||
inherit date;
|
||||
@@ -59,7 +56,7 @@ in {
|
||||
|
||||
# Packages for extra software recommended for usage with Hyprland,
|
||||
# including forked or patched packages for compatibility.
|
||||
hyprland-extras = mkJoinedOverlays [
|
||||
hyprland-extras = lib.composeManyExtensions [
|
||||
inputs.xdph.overlays.xdg-desktop-portal-hyprland
|
||||
];
|
||||
|
||||
|
@@ -8,7 +8,7 @@ CRT_REV=$(rg rev flake.nix | awk '{ print substr($3, 2, 40) }')
|
||||
if [ "$SUB_REV" != "$CRT_REV" ]; then
|
||||
echo "Updating wlroots..."
|
||||
# update wlroots to submodule revision
|
||||
sed -Ei "s/\w{40}/$SUB_REV/g" flake.nix subprojects/wlroots.wrap
|
||||
sed -Ei "s/\w{40}/$SUB_REV/g" flake.nix
|
||||
nix flake lock
|
||||
|
||||
echo "wlroots: $CRT_REV -> $SUB_REV"
|
||||
|
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"version": "0.34.0"
|
||||
"version": "0.35.0"
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
wayland_protos = dependency('wayland-protocols',
|
||||
version: '>=1.25',
|
||||
version: '>=1.32',
|
||||
fallback: 'wayland-protocols',
|
||||
default_options: ['tests=false'],
|
||||
)
|
||||
|
@@ -81,26 +81,6 @@ CCompositor::CCompositor() {
|
||||
|
||||
CCompositor::~CCompositor() {
|
||||
cleanup();
|
||||
g_pDecorationPositioner.reset();
|
||||
g_pPluginSystem.reset();
|
||||
g_pHyprNotificationOverlay.reset();
|
||||
g_pDebugOverlay.reset();
|
||||
g_pEventManager.reset();
|
||||
g_pSessionLockManager.reset();
|
||||
g_pProtocolManager.reset();
|
||||
g_pXWaylandManager.reset();
|
||||
g_pHyprRenderer.reset();
|
||||
g_pHyprOpenGL.reset();
|
||||
g_pInputManager.reset();
|
||||
g_pThreadManager.reset();
|
||||
g_pConfigManager.reset();
|
||||
g_pLayoutManager.reset();
|
||||
g_pHyprError.reset();
|
||||
g_pConfigManager.reset();
|
||||
g_pAnimationManager.reset();
|
||||
g_pKeybindManager.reset();
|
||||
g_pHookSystem.reset();
|
||||
g_pWatchdog.reset();
|
||||
}
|
||||
|
||||
void CCompositor::setRandomSplash() {
|
||||
@@ -135,10 +115,10 @@ void CCompositor::initServer() {
|
||||
else
|
||||
wlr_log_init(WLR_ERROR, Debug::wlrLog);
|
||||
|
||||
m_sWLRBackend = wlr_backend_autocreate(m_sWLDisplay, &m_sWLRSession);
|
||||
m_sWLRBackend = wlr_backend_autocreate(m_sWLEventLoop, &m_sWLRSession);
|
||||
|
||||
if (!m_sWLRBackend) {
|
||||
Debug::log(CRIT, "m_sWLRBackend was NULL!");
|
||||
Debug::log(CRIT, "m_sWLRBackend was NULL! This usually means wlroots could not find a GPU or enountered some issues.");
|
||||
throwError("wlr_backend_autocreate() failed!");
|
||||
}
|
||||
|
||||
@@ -151,7 +131,7 @@ void CCompositor::initServer() {
|
||||
m_sWLRRenderer = wlr_gles2_renderer_create_with_drm_fd(m_iDRMFD);
|
||||
|
||||
if (!m_sWLRRenderer) {
|
||||
Debug::log(CRIT, "m_sWLRRenderer was NULL!");
|
||||
Debug::log(CRIT, "m_sWLRRenderer was NULL! This usually means wlroots could not find a GPU or enountered some issues.");
|
||||
throwError("wlr_gles2_renderer_create_with_drm_fd() failed!");
|
||||
}
|
||||
|
||||
@@ -259,7 +239,7 @@ void CCompositor::initServer() {
|
||||
|
||||
m_sWLRActivation = wlr_xdg_activation_v1_create(m_sWLDisplay);
|
||||
|
||||
m_sWLRHeadlessBackend = wlr_headless_backend_create(m_sWLDisplay);
|
||||
m_sWLRHeadlessBackend = wlr_headless_backend_create(m_sWLEventLoop);
|
||||
|
||||
m_sWLRSessionLockMgr = wlr_session_lock_manager_v1_create(m_sWLDisplay);
|
||||
|
||||
@@ -332,6 +312,59 @@ void CCompositor::initAllSignals() {
|
||||
addWLSignal(&m_sWLRSession->events.active, &Events::listen_sessionActive, m_sWLRSession, "Session");
|
||||
}
|
||||
|
||||
void CCompositor::removeAllSignals() {
|
||||
removeWLSignal(&Events::listen_newOutput);
|
||||
removeWLSignal(&Events::listen_newXDGToplevel);
|
||||
removeWLSignal(&Events::listen_mouseMove);
|
||||
removeWLSignal(&Events::listen_mouseMoveAbsolute);
|
||||
removeWLSignal(&Events::listen_mouseButton);
|
||||
removeWLSignal(&Events::listen_mouseAxis);
|
||||
removeWLSignal(&Events::listen_mouseFrame);
|
||||
removeWLSignal(&Events::listen_swipeBegin);
|
||||
removeWLSignal(&Events::listen_swipeUpdate);
|
||||
removeWLSignal(&Events::listen_swipeEnd);
|
||||
removeWLSignal(&Events::listen_pinchBegin);
|
||||
removeWLSignal(&Events::listen_pinchUpdate);
|
||||
removeWLSignal(&Events::listen_pinchEnd);
|
||||
removeWLSignal(&Events::listen_touchBegin);
|
||||
removeWLSignal(&Events::listen_touchEnd);
|
||||
removeWLSignal(&Events::listen_touchUpdate);
|
||||
removeWLSignal(&Events::listen_touchFrame);
|
||||
removeWLSignal(&Events::listen_holdBegin);
|
||||
removeWLSignal(&Events::listen_holdEnd);
|
||||
removeWLSignal(&Events::listen_newInput);
|
||||
removeWLSignal(&Events::listen_requestMouse);
|
||||
removeWLSignal(&Events::listen_requestSetSel);
|
||||
removeWLSignal(&Events::listen_requestDrag);
|
||||
removeWLSignal(&Events::listen_startDrag);
|
||||
removeWLSignal(&Events::listen_requestSetSel);
|
||||
removeWLSignal(&Events::listen_requestSetPrimarySel);
|
||||
removeWLSignal(&Events::listen_newLayerSurface);
|
||||
removeWLSignal(&Events::listen_change);
|
||||
removeWLSignal(&Events::listen_outputMgrApply);
|
||||
removeWLSignal(&Events::listen_outputMgrTest);
|
||||
removeWLSignal(&Events::listen_newConstraint);
|
||||
removeWLSignal(&Events::listen_NewXDGDeco);
|
||||
removeWLSignal(&Events::listen_newVirtPtr);
|
||||
removeWLSignal(&Events::listen_newVirtualKeyboard);
|
||||
removeWLSignal(&Events::listen_RendererDestroy);
|
||||
removeWLSignal(&Events::listen_newIdleInhibitor);
|
||||
removeWLSignal(&Events::listen_powerMgrSetMode);
|
||||
removeWLSignal(&Events::listen_newIME);
|
||||
removeWLSignal(&Events::listen_newTextInput);
|
||||
removeWLSignal(&Events::listen_activateXDG);
|
||||
removeWLSignal(&Events::listen_newSessionLock);
|
||||
removeWLSignal(&Events::listen_setGamma);
|
||||
removeWLSignal(&Events::listen_setCursorShape);
|
||||
removeWLSignal(&Events::listen_newTearingHint);
|
||||
|
||||
if (m_sWRLDRMLeaseMgr)
|
||||
removeWLSignal(&Events::listen_leaseRequest);
|
||||
|
||||
if (m_sWLRSession)
|
||||
removeWLSignal(&Events::listen_sessionActive);
|
||||
}
|
||||
|
||||
void CCompositor::cleanup() {
|
||||
if (!m_sWLDisplay || m_bIsShuttingDown)
|
||||
return;
|
||||
@@ -362,8 +395,8 @@ void CCompositor::cleanup() {
|
||||
for (auto& m : m_vMonitors) {
|
||||
g_pHyprOpenGL->destroyMonitorResources(m.get());
|
||||
|
||||
wlr_output_enable(m->output, false);
|
||||
wlr_output_commit(m->output);
|
||||
wlr_output_state_set_enabled(m->state.wlr(), false);
|
||||
m->state.commit();
|
||||
}
|
||||
|
||||
m_vMonitors.clear();
|
||||
@@ -373,8 +406,31 @@ void CCompositor::cleanup() {
|
||||
g_pXWaylandManager->m_sWLRXWayland = nullptr;
|
||||
}
|
||||
|
||||
removeAllSignals();
|
||||
|
||||
wl_display_destroy_clients(g_pCompositor->m_sWLDisplay);
|
||||
|
||||
g_pDecorationPositioner.reset();
|
||||
g_pPluginSystem.reset();
|
||||
g_pHyprNotificationOverlay.reset();
|
||||
g_pDebugOverlay.reset();
|
||||
g_pEventManager.reset();
|
||||
g_pSessionLockManager.reset();
|
||||
g_pProtocolManager.reset();
|
||||
g_pHyprRenderer.reset();
|
||||
g_pHyprOpenGL.reset();
|
||||
g_pInputManager.reset();
|
||||
g_pThreadManager.reset();
|
||||
g_pConfigManager.reset();
|
||||
g_pLayoutManager.reset();
|
||||
g_pHyprError.reset();
|
||||
g_pConfigManager.reset();
|
||||
g_pAnimationManager.reset();
|
||||
g_pKeybindManager.reset();
|
||||
g_pHookSystem.reset();
|
||||
g_pWatchdog.reset();
|
||||
g_pXWaylandManager.reset();
|
||||
|
||||
wl_display_terminate(m_sWLDisplay);
|
||||
|
||||
m_sWLDisplay = nullptr;
|
||||
@@ -408,6 +464,9 @@ void CCompositor::initManagers(eManagersInitStage stage) {
|
||||
Debug::log(LOG, "Creating the ThreadManager!");
|
||||
g_pThreadManager = std::make_unique<CThreadManager>();
|
||||
|
||||
Debug::log(LOG, "Creating CHyprCtl");
|
||||
g_pHyprCtl = std::make_unique<CHyprCtl>();
|
||||
|
||||
Debug::log(LOG, "Creating the InputManager!");
|
||||
g_pInputManager = std::make_unique<CInputManager>();
|
||||
|
||||
@@ -629,72 +688,22 @@ bool CCompositor::windowExists(CWindow* pWindow) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CWindow* CCompositor::vectorToWindowTiled(const Vector2D& pos) {
|
||||
const auto PMONITOR = getMonitorFromVector(pos);
|
||||
|
||||
if (PMONITOR->specialWorkspaceID) {
|
||||
for (auto& w : m_vWindows) {
|
||||
CBox box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
|
||||
if (w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && box.containsPoint(pos) && !w->m_bIsFloating && !w->isHidden() && !w->m_bNoFocus)
|
||||
return w.get();
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& w : m_vWindows) {
|
||||
CBox box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
|
||||
if (w->m_bIsMapped && box.containsPoint(pos) && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->m_bIsFloating && !w->isHidden() && !w->m_bNoFocus)
|
||||
return w.get();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos, CWindow* pIgnoreWindow) {
|
||||
CWindow* CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t properties, CWindow* pIgnoreWindow) {
|
||||
const auto PMONITOR = getMonitorFromVector(pos);
|
||||
static auto* const PRESIZEONBORDER = &g_pConfigManager->getConfigValuePtr("general:resize_on_border")->intValue;
|
||||
static auto* const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
|
||||
static auto* const PBORDERGRABEXTEND = &g_pConfigManager->getConfigValuePtr("general:extend_border_grab_area")->intValue;
|
||||
static auto* const PSPECIALFALLTHRU = &g_pConfigManager->getConfigValuePtr("input:special_fallthrough")->intValue;
|
||||
const auto BORDER_GRAB_AREA = *PRESIZEONBORDER ? *PBORDERSIZE + *PBORDERGRABEXTEND : 0;
|
||||
|
||||
// pinned windows on top of floating regardless
|
||||
for (auto& w : m_vWindows | std::views::reverse) {
|
||||
const auto BB = w->getWindowInputBox();
|
||||
CBox box = {BB.x - BORDER_GRAB_AREA, BB.y - BORDER_GRAB_AREA, BB.width + 2 * BORDER_GRAB_AREA, BB.height + 2 * BORDER_GRAB_AREA};
|
||||
if (w->m_bIsFloating && w->m_bIsMapped && !w->isHidden() && !w->m_bX11ShouldntFocus && w->m_bPinned && !w->m_bNoFocus && w.get() != pIgnoreWindow) {
|
||||
if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}))
|
||||
return w.get();
|
||||
|
||||
if (!w->m_bIsX11) {
|
||||
if (w->hasPopupAt(pos))
|
||||
return w.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto windowForWorkspace = [&](bool special) -> CWindow* {
|
||||
// first loop over floating cuz they're above, m_lWindows should be sorted bottom->top, for tiled it doesn't matter.
|
||||
if (properties & ALLOW_FLOATING) {
|
||||
for (auto& w : m_vWindows | std::views::reverse) {
|
||||
|
||||
if (special && !isWorkspaceSpecial(w->m_iWorkspaceID)) // because special floating may creep up into regular
|
||||
continue;
|
||||
|
||||
const auto BB = w->getWindowInputBox();
|
||||
const auto BB = w->getWindowBoxUnified(properties);
|
||||
CBox box = {BB.x - BORDER_GRAB_AREA, BB.y - BORDER_GRAB_AREA, BB.width + 2 * BORDER_GRAB_AREA, BB.height + 2 * BORDER_GRAB_AREA};
|
||||
if (w->m_bIsFloating && w->m_bIsMapped && isWorkspaceVisible(w->m_iWorkspaceID) && !w->isHidden() && !w->m_bPinned && !w->m_bNoFocus && w.get() != pIgnoreWindow) {
|
||||
// OR windows should add focus to parent
|
||||
if (w->m_bX11ShouldntFocus && w->m_iX11Type != 2)
|
||||
continue;
|
||||
|
||||
if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y})) {
|
||||
|
||||
if (w->m_bIsX11 && w->m_iX11Type == 2 && !wlr_xwayland_or_surface_wants_focus(w->m_uSurface.xwayland)) {
|
||||
// Override Redirect
|
||||
return g_pCompositor->m_pLastWindow; // we kinda trick everything here.
|
||||
// TODO: this is wrong, we should focus the parent, but idk how to get it considering it's nullptr in most cases.
|
||||
}
|
||||
|
||||
if (w->m_bIsFloating && w->m_bIsMapped && !w->isHidden() && !w->m_bX11ShouldntFocus && w->m_bPinned && !w->m_bNoFocus && w.get() != pIgnoreWindow) {
|
||||
if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}))
|
||||
return w.get();
|
||||
}
|
||||
|
||||
if (!w->m_bIsX11) {
|
||||
if (w->hasPopupAt(pos))
|
||||
@@ -702,6 +711,44 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos, CWindow* pIgnoreW
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto windowForWorkspace = [&](bool special) -> CWindow* {
|
||||
if (properties & ALLOW_FLOATING) {
|
||||
// first loop over floating cuz they're above, m_lWindows should be sorted bottom->top, for tiled it doesn't matter.
|
||||
for (auto& w : m_vWindows | std::views::reverse) {
|
||||
|
||||
if (special && !isWorkspaceSpecial(w->m_iWorkspaceID)) // because special floating may creep up into regular
|
||||
continue;
|
||||
|
||||
const auto BB = w->getWindowBoxUnified(properties);
|
||||
CBox box = {BB.x - BORDER_GRAB_AREA, BB.y - BORDER_GRAB_AREA, BB.width + 2 * BORDER_GRAB_AREA, BB.height + 2 * BORDER_GRAB_AREA};
|
||||
if (w->m_bIsFloating && w->m_bIsMapped && isWorkspaceVisible(w->m_iWorkspaceID) && !w->isHidden() && !w->m_bPinned && !w->m_bNoFocus && w.get() != pIgnoreWindow) {
|
||||
// OR windows should add focus to parent
|
||||
if (w->m_bX11ShouldntFocus && w->m_iX11Type != 2)
|
||||
continue;
|
||||
|
||||
if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y})) {
|
||||
|
||||
if (w->m_bIsX11 && w->m_iX11Type == 2 && !wlr_xwayland_or_surface_wants_focus(w->m_uSurface.xwayland)) {
|
||||
// Override Redirect
|
||||
return g_pCompositor->m_pLastWindow; // we kinda trick everything here.
|
||||
// TODO: this is wrong, we should focus the parent, but idk how to get it considering it's nullptr in most cases.
|
||||
}
|
||||
|
||||
return w.get();
|
||||
}
|
||||
|
||||
if (!w->m_bIsX11) {
|
||||
if (w->hasPopupAt(pos))
|
||||
return w.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (properties & FLOATING_ONLY)
|
||||
return nullptr;
|
||||
|
||||
const int64_t WORKSPACEID = special ? PMONITOR->specialWorkspaceID : PMONITOR->activeWorkspace;
|
||||
const auto PWORKSPACE = getWorkspaceByID(WORKSPACEID);
|
||||
@@ -725,7 +772,7 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos, CWindow* pIgnoreW
|
||||
if (special != isWorkspaceSpecial(w->m_iWorkspaceID))
|
||||
continue;
|
||||
|
||||
CBox box = {w->m_vPosition, w->m_vSize};
|
||||
CBox box = (properties & USE_PROP_TILED) ? w->getWindowBoxUnified(properties) : CBox{w->m_vPosition, w->m_vSize};
|
||||
if (!w->m_bIsFloating && w->m_bIsMapped && box.containsPoint(pos) && w->m_iWorkspaceID == WORKSPACEID && !w->isHidden() && !w->m_bX11ShouldntFocus && !w->m_bNoFocus &&
|
||||
w.get() != pIgnoreWindow)
|
||||
return w.get();
|
||||
@@ -735,68 +782,17 @@ CWindow* CCompositor::vectorToWindowIdeal(const Vector2D& pos, CWindow* pIgnoreW
|
||||
};
|
||||
|
||||
// special workspace
|
||||
if (PMONITOR->specialWorkspaceID)
|
||||
if (PMONITOR->specialWorkspaceID && !*PSPECIALFALLTHRU)
|
||||
return windowForWorkspace(true);
|
||||
|
||||
return windowForWorkspace(false);
|
||||
}
|
||||
|
||||
CWindow* CCompositor::windowFromCursor() {
|
||||
const auto PMONITOR = getMonitorFromCursor();
|
||||
|
||||
if (PMONITOR->specialWorkspaceID) {
|
||||
for (auto& w : m_vWindows | std::views::reverse) {
|
||||
CBox 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_iWorkspaceID == PMONITOR->specialWorkspaceID && w->m_bIsMapped && box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}) &&
|
||||
!w->isHidden() && !w->m_bNoFocus)
|
||||
return w.get();
|
||||
}
|
||||
const auto PWINDOW = windowForWorkspace(true);
|
||||
|
||||
for (auto& w : m_vWindows) {
|
||||
CBox box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
|
||||
if (w->m_iWorkspaceID == PMONITOR->specialWorkspaceID && box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}) && w->m_bIsMapped && !w->m_bNoFocus)
|
||||
return w.get();
|
||||
}
|
||||
if (PWINDOW)
|
||||
return PWINDOW;
|
||||
}
|
||||
|
||||
// pinned
|
||||
for (auto& w : m_vWindows | std::views::reverse) {
|
||||
CBox box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
|
||||
if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}) && w->m_bIsMapped && w->m_bIsFloating && w->m_bPinned && !w->m_bNoFocus)
|
||||
return w.get();
|
||||
}
|
||||
|
||||
// first loop over floating cuz they're above, m_lWindows should be sorted bottom->top, for tiled it doesn't matter.
|
||||
for (auto& w : m_vWindows | std::views::reverse) {
|
||||
CBox box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
|
||||
if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}) && w->m_bIsMapped && w->m_bIsFloating && isWorkspaceVisible(w->m_iWorkspaceID) && !w->m_bPinned && !w->m_bNoFocus)
|
||||
return w.get();
|
||||
}
|
||||
|
||||
for (auto& w : m_vWindows) {
|
||||
CBox box = {w->m_vPosition.x, w->m_vPosition.y, w->m_vSize.x, w->m_vSize.y};
|
||||
if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}) && w->m_bIsMapped && w->m_iWorkspaceID == PMONITOR->activeWorkspace && !w->m_bNoFocus)
|
||||
return w.get();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CWindow* CCompositor::windowFloatingFromCursor() {
|
||||
for (auto& w : m_vWindows | std::views::reverse) {
|
||||
CBox box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
|
||||
if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}) && w->m_bIsMapped && w->m_bIsFloating && !w->isHidden() && w->m_bPinned && !w->m_bNoFocus)
|
||||
return w.get();
|
||||
}
|
||||
|
||||
for (auto& w : m_vWindows | std::views::reverse) {
|
||||
CBox box = {w->m_vRealPosition.vec().x, w->m_vRealPosition.vec().y, w->m_vRealSize.vec().x, w->m_vRealSize.vec().y};
|
||||
if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}) && w->m_bIsMapped && w->m_bIsFloating && isWorkspaceVisible(w->m_iWorkspaceID) && !w->isHidden() &&
|
||||
!w->m_bPinned && !w->m_bNoFocus)
|
||||
return w.get();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return windowForWorkspace(false);
|
||||
}
|
||||
|
||||
wlr_surface* CCompositor::vectorWindowToSurface(const Vector2D& pos, CWindow* pWindow, Vector2D& sl) {
|
||||
@@ -876,13 +872,19 @@ CMonitor* CCompositor::getMonitorFromOutput(wlr_output* out) {
|
||||
|
||||
void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
|
||||
|
||||
static auto* const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
|
||||
static auto* const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
|
||||
static auto* const PSPECIALFALLTHROUGH = &g_pConfigManager->getConfigValuePtr("input:special_fallthrough")->intValue;
|
||||
|
||||
if (g_pCompositor->m_sSeat.exclusiveClient) {
|
||||
Debug::log(LOG, "Disallowing setting focus to a window due to there being an active input inhibitor layer.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!g_pInputManager->m_dExclusiveLSes.empty()) {
|
||||
Debug::log(LOG, "Refusing a keyboard focus to a window because of an exclusive ls");
|
||||
return;
|
||||
}
|
||||
|
||||
g_pLayoutManager->getCurrentLayout()->bringWindowToTop(pWindow);
|
||||
|
||||
if (!pWindow || !windowValidMapped(pWindow)) {
|
||||
@@ -928,12 +930,13 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
|
||||
if (pWindow->m_bPinned)
|
||||
pWindow->m_iWorkspaceID = m_pLastMonitor->activeWorkspace;
|
||||
|
||||
const auto PMONITOR = getMonitorFromID(pWindow->m_iMonitorID);
|
||||
|
||||
if (!isWorkspaceVisible(pWindow->m_iWorkspaceID)) {
|
||||
const auto PWORKSPACE = getWorkspaceByID(pWindow->m_iWorkspaceID);
|
||||
// This is to fix incorrect feedback on the focus history.
|
||||
const auto PWORKSPACE = getWorkspaceByID(pWindow->m_iWorkspaceID);
|
||||
PWORKSPACE->m_pLastFocusedWindow = pWindow;
|
||||
PWORKSPACE->rememberPrevWorkspace(getWorkspaceByID(m_pLastMonitor->activeWorkspace));
|
||||
const auto PMONITOR = getMonitorFromID(PWORKSPACE->m_iMonitorID);
|
||||
PMONITOR->changeWorkspace(PWORKSPACE, false, true);
|
||||
// changeworkspace already calls focusWindow
|
||||
return;
|
||||
@@ -942,6 +945,11 @@ void CCompositor::focusWindow(CWindow* pWindow, wlr_surface* pSurface) {
|
||||
const auto PLASTWINDOW = m_pLastWindow;
|
||||
m_pLastWindow = pWindow;
|
||||
|
||||
/* If special fallthrough is enabled, this behavior will be disabled, as I have no better idea of nicely tracking which
|
||||
window focuses are "via keybinds" and which ones aren't. */
|
||||
if (PMONITOR->specialWorkspaceID && PMONITOR->specialWorkspaceID != pWindow->m_iWorkspaceID && !pWindow->m_bPinned && !*PSPECIALFALLTHROUGH)
|
||||
PMONITOR->setSpecialWorkspace(nullptr);
|
||||
|
||||
// we need to make the PLASTWINDOW not equal to m_pLastWindow so that RENDERDATA is correct for an unfocused window
|
||||
if (windowValidMapped(PLASTWINDOW)) {
|
||||
PLASTWINDOW->updateDynamicRules();
|
||||
@@ -1015,10 +1023,8 @@ void CCompositor::focusSurface(wlr_surface* pSurface, CWindow* pWindowOwner) {
|
||||
if (m_sSeat.seat->keyboard_state.focused_surface == pSurface || (pWindowOwner && m_sSeat.seat->keyboard_state.focused_surface == pWindowOwner->m_pWLSurface.wlr()))
|
||||
return; // Don't focus when already focused on this.
|
||||
|
||||
if (g_pSessionLockManager->isSessionLocked()) {
|
||||
wlr_seat_keyboard_clear_focus(m_sSeat.seat);
|
||||
m_pLastFocus = nullptr;
|
||||
}
|
||||
if (g_pSessionLockManager->isSessionLocked() && !g_pSessionLockManager->isSurfaceSessionLock(pSurface))
|
||||
return;
|
||||
|
||||
// Unfocus last surface if should
|
||||
if (m_pLastFocus && !pWindowOwner)
|
||||
@@ -1089,14 +1095,6 @@ wlr_surface* CCompositor::vectorToLayerSurface(const Vector2D& pos, std::vector<
|
||||
|
||||
auto SURFACEAT = wlr_layer_surface_v1_surface_at(ls->layerSurface, pos.x - ls->geometry.x, pos.y - ls->geometry.y, &sCoords->x, &sCoords->y);
|
||||
|
||||
if (ls->layerSurface->current.keyboard_interactive && ls->layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) {
|
||||
if (!SURFACEAT)
|
||||
SURFACEAT = ls->layerSurface->surface;
|
||||
|
||||
*ppLayerSurfaceFound = ls.get();
|
||||
return SURFACEAT;
|
||||
}
|
||||
|
||||
if (SURFACEAT) {
|
||||
if (!pixman_region32_not_empty(&SURFACEAT->input_region))
|
||||
continue;
|
||||
@@ -1879,15 +1877,13 @@ void CCompositor::updateWindowAnimatedDecorationValues(CWindow* pWindow) {
|
||||
if (pWindow == m_pLastWindow) {
|
||||
const auto* const ACTIVECOLOR =
|
||||
!pWindow->m_sGroupData.pNextWindow ? (!pWindow->m_sGroupData.deny ? ACTIVECOL : NOGROUPACTIVECOL) : (GROUPLOCKED ? GROUPACTIVELOCKEDCOL : GROUPACTIVECOL);
|
||||
setBorderColor(pWindow->m_sSpecialRenderData.activeBorderColor.toUnderlying() >= 0 ?
|
||||
CGradientValueData(CColor(pWindow->m_sSpecialRenderData.activeBorderColor.toUnderlying())) :
|
||||
*ACTIVECOLOR);
|
||||
setBorderColor(pWindow->m_sSpecialRenderData.activeBorderColor.toUnderlying().m_vColors.empty() ? *ACTIVECOLOR :
|
||||
pWindow->m_sSpecialRenderData.activeBorderColor.toUnderlying());
|
||||
} else {
|
||||
const auto* const INACTIVECOLOR =
|
||||
!pWindow->m_sGroupData.pNextWindow ? (!pWindow->m_sGroupData.deny ? INACTIVECOL : NOGROUPINACTIVECOL) : (GROUPLOCKED ? GROUPINACTIVELOCKEDCOL : GROUPINACTIVECOL);
|
||||
setBorderColor(pWindow->m_sSpecialRenderData.inactiveBorderColor.toUnderlying() >= 0 ?
|
||||
CGradientValueData(CColor(pWindow->m_sSpecialRenderData.inactiveBorderColor.toUnderlying())) :
|
||||
*INACTIVECOLOR);
|
||||
setBorderColor(pWindow->m_sSpecialRenderData.inactiveBorderColor.toUnderlying().m_vColors.empty() ? *INACTIVECOLOR :
|
||||
pWindow->m_sSpecialRenderData.inactiveBorderColor.toUnderlying());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2111,7 +2107,7 @@ CMonitor* CCompositor::getMonitorFromString(const std::string& name) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, CMonitor* pMonitor) {
|
||||
void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, CMonitor* pMonitor, bool noWarpCursor) {
|
||||
|
||||
// We trust the workspace and monitor to be correct.
|
||||
|
||||
@@ -2197,7 +2193,8 @@ void CCompositor::moveWorkspaceToMonitor(CWorkspace* pWorkspace, CMonitor* pMoni
|
||||
|
||||
pWorkspace->startAnim(true, true, true);
|
||||
|
||||
wlr_cursor_warp(m_sWLRCursor, nullptr, pMonitor->vecPosition.x + pMonitor->vecTransformedSize.x / 2, pMonitor->vecPosition.y + pMonitor->vecTransformedSize.y / 2);
|
||||
if (!noWarpCursor)
|
||||
wlr_cursor_warp(m_sWLRCursor, nullptr, pMonitor->vecPosition.x + pMonitor->vecTransformedSize.x / 2, pMonitor->vecPosition.y + pMonitor->vecTransformedSize.y / 2);
|
||||
|
||||
g_pInputManager->sendMotionEventsToFocused();
|
||||
}
|
||||
@@ -2284,7 +2281,6 @@ void CCompositor::setWindowFullscreen(CWindow* pWindow, bool on, eFullscreenMode
|
||||
|
||||
g_pXWaylandManager->setWindowFullscreen(pWindow, pWindow->shouldSendFullscreenState());
|
||||
|
||||
pWindow->updateDynamicRules();
|
||||
updateWindowAnimatedDecorationValues(pWindow);
|
||||
|
||||
// make all windows on the same workspace under the fullscreen window
|
||||
@@ -2606,11 +2602,7 @@ int CCompositor::getNewSpecialID() {
|
||||
}
|
||||
|
||||
void CCompositor::performUserChecks() {
|
||||
if (g_pConfigManager->getInt("general:allow_tearing") == 1 && !envEnabled("WLR_DRM_NO_ATOMIC")) {
|
||||
g_pHyprNotificationOverlay->addNotification("You have enabled tearing, but immediate presentations are not available on your configuration. Try adding "
|
||||
"env = WLR_DRM_NO_ATOMIC,1 to your config.",
|
||||
CColor(0), 15000, ICON_WARNING);
|
||||
}
|
||||
; // intentional
|
||||
}
|
||||
|
||||
void CCompositor::moveWindowToWorkspaceSafe(CWindow* pWindow, CWorkspace* pWorkspace) {
|
||||
@@ -2785,10 +2777,27 @@ void CCompositor::leaveUnsafeState() {
|
||||
void CCompositor::setPreferredScaleForSurface(wlr_surface* pSurface, double scale) {
|
||||
g_pProtocolManager->m_pFractionalScaleProtocolManager->setPreferredScaleForSurface(pSurface, scale);
|
||||
wlr_surface_set_preferred_buffer_scale(pSurface, static_cast<int32_t>(std::ceil(scale)));
|
||||
|
||||
const auto PSURFACE = CWLSurface::surfaceFromWlr(pSurface);
|
||||
if (!PSURFACE) {
|
||||
Debug::log(WARN, "Orphaned wlr_surface {:x} in setPreferredScaleForSurface", (uintptr_t)pSurface);
|
||||
return;
|
||||
}
|
||||
|
||||
PSURFACE->m_fLastScale = scale;
|
||||
PSURFACE->m_iLastScale = static_cast<int32_t>(std::ceil(scale));
|
||||
}
|
||||
|
||||
void CCompositor::setPreferredTransformForSurface(wlr_surface* pSurface, wl_output_transform transform) {
|
||||
wlr_surface_set_preferred_buffer_transform(pSurface, transform);
|
||||
|
||||
const auto PSURFACE = CWLSurface::surfaceFromWlr(pSurface);
|
||||
if (!PSURFACE) {
|
||||
Debug::log(WARN, "Orphaned wlr_surface {:x} in setPreferredTransformForSurface", (uintptr_t)pSurface);
|
||||
return;
|
||||
}
|
||||
|
||||
PSURFACE->m_eLastTransform = transform;
|
||||
}
|
||||
|
||||
void CCompositor::updateSuspendedStates() {
|
||||
|
@@ -135,14 +135,11 @@ class CCompositor {
|
||||
void focusSurface(wlr_surface*, CWindow* pWindowOwner = nullptr);
|
||||
bool windowExists(CWindow*);
|
||||
bool windowValidMapped(CWindow*);
|
||||
CWindow* vectorToWindowIdeal(const Vector2D&, CWindow* pIgnoreWindow = nullptr); // used only for finding a window to focus on, basically a "findFocusableWindow"
|
||||
CWindow* vectorToWindowTiled(const Vector2D&);
|
||||
CWindow* vectorToWindowUnified(const Vector2D&, uint8_t properties, CWindow* pIgnoreWindow = nullptr);
|
||||
wlr_surface* vectorToLayerSurface(const Vector2D&, std::vector<std::unique_ptr<SLayerSurface>>*, Vector2D*, SLayerSurface**);
|
||||
SIMEPopup* vectorToIMEPopup(const Vector2D& pos, std::list<SIMEPopup>& popups);
|
||||
wlr_surface* vectorWindowToSurface(const Vector2D&, CWindow*, Vector2D& sl);
|
||||
Vector2D vectorToSurfaceLocal(const Vector2D&, CWindow*, wlr_surface*);
|
||||
CWindow* windowFromCursor();
|
||||
CWindow* windowFloatingFromCursor();
|
||||
CMonitor* getMonitorFromOutput(wlr_output*);
|
||||
CWindow* getWindowForPopup(wlr_xdg_popup*);
|
||||
CWindow* getWindowFromSurface(wlr_surface*);
|
||||
@@ -176,7 +173,7 @@ class CCompositor {
|
||||
void updateWorkspaceWindows(const int64_t& id);
|
||||
void updateWindowAnimatedDecorationValues(CWindow*);
|
||||
int getNextAvailableMonitorID(std::string const& name);
|
||||
void moveWorkspaceToMonitor(CWorkspace*, CMonitor*);
|
||||
void moveWorkspaceToMonitor(CWorkspace*, CMonitor*, bool noWarpCursor = false);
|
||||
void swapActiveWorkspaces(CMonitor*, CMonitor*);
|
||||
CMonitor* getMonitorFromString(const std::string&);
|
||||
bool workspaceIDOutOfBounds(const int64_t&);
|
||||
@@ -214,6 +211,7 @@ class CCompositor {
|
||||
|
||||
private:
|
||||
void initAllSignals();
|
||||
void removeAllSignals();
|
||||
void setRandomSplash();
|
||||
void initManagers(eManagersInitStage stage);
|
||||
void prepareFallbackOutput();
|
||||
|
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "helpers/Vector2D.hpp"
|
||||
#include <functional>
|
||||
|
||||
enum eIcons {
|
||||
ICON_WARNING = 0,
|
||||
@@ -52,4 +53,20 @@ struct SWindowDecorationExtents {
|
||||
bool operator==(const SWindowDecorationExtents& other) const {
|
||||
return topLeft == other.topLeft && bottomRight == other.bottomRight;
|
||||
}
|
||||
};
|
||||
|
||||
void addExtents(const SWindowDecorationExtents& other) {
|
||||
topLeft = topLeft.getComponentMax(other.topLeft);
|
||||
bottomRight = bottomRight.getComponentMax(other.bottomRight);
|
||||
}
|
||||
};
|
||||
|
||||
enum eHyprCtlOutputFormat {
|
||||
FORMAT_NORMAL = 0,
|
||||
FORMAT_JSON
|
||||
};
|
||||
|
||||
struct SHyprCtlCommand {
|
||||
std::string name = "";
|
||||
bool exact = true;
|
||||
std::function<std::string(eHyprCtlOutputFormat, std::string)> fn;
|
||||
};
|
||||
|
109
src/Window.cpp
@@ -139,35 +139,25 @@ CBox CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
|
||||
return CBox{(int)POS.x, (int)POS.y, (int)SIZE.x, (int)SIZE.y};
|
||||
}
|
||||
|
||||
CBox CWindow::getWindowInputBox() {
|
||||
const int BORDERSIZE = getRealBorderSize();
|
||||
CBox CWindow::getWindowBoxUnified(uint64_t properties) {
|
||||
|
||||
if (m_sAdditionalConfigData.dimAround) {
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
||||
return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y};
|
||||
}
|
||||
|
||||
SWindowDecorationExtents maxExtents = {{BORDERSIZE + 2, BORDERSIZE + 2}, {BORDERSIZE + 2, BORDERSIZE + 2}};
|
||||
SWindowDecorationExtents EXTENTS = {{0, 0}, {0, 0}};
|
||||
if (properties & RESERVED_EXTENTS)
|
||||
EXTENTS.addExtents(g_pDecorationPositioner->getWindowDecorationReserved(this));
|
||||
if (properties & INPUT_EXTENTS)
|
||||
EXTENTS.addExtents(g_pDecorationPositioner->getWindowDecorationExtents(this, true));
|
||||
if (properties & FULL_EXTENTS)
|
||||
EXTENTS.addExtents(g_pDecorationPositioner->getWindowDecorationExtents(this, false));
|
||||
|
||||
const auto EXTENTS = g_pDecorationPositioner->getWindowDecorationExtents(this, true);
|
||||
CBox box = {m_vRealPosition.vec().x, m_vRealPosition.vec().y, m_vRealSize.vec().x, m_vRealSize.vec().y};
|
||||
box.addExtents(EXTENTS);
|
||||
|
||||
if (EXTENTS.topLeft.x > maxExtents.topLeft.x)
|
||||
maxExtents.topLeft.x = EXTENTS.topLeft.x;
|
||||
|
||||
if (EXTENTS.topLeft.y > maxExtents.topLeft.y)
|
||||
maxExtents.topLeft.y = EXTENTS.topLeft.y;
|
||||
|
||||
if (EXTENTS.bottomRight.x > maxExtents.bottomRight.x)
|
||||
maxExtents.bottomRight.x = EXTENTS.bottomRight.x;
|
||||
|
||||
if (EXTENTS.bottomRight.y > maxExtents.bottomRight.y)
|
||||
maxExtents.bottomRight.y = EXTENTS.bottomRight.y;
|
||||
|
||||
// Add extents to the real base BB and return
|
||||
CBox finalBox = {m_vRealPosition.vec().x - maxExtents.topLeft.x, m_vRealPosition.vec().y - maxExtents.topLeft.y,
|
||||
m_vRealSize.vec().x + maxExtents.topLeft.x + maxExtents.bottomRight.x, m_vRealSize.vec().y + maxExtents.topLeft.y + maxExtents.bottomRight.y};
|
||||
|
||||
return finalBox;
|
||||
return box;
|
||||
}
|
||||
|
||||
CBox CWindow::getWindowMainSurfaceBox() {
|
||||
@@ -318,7 +308,7 @@ void CWindow::destroyToplevelHandle() {
|
||||
}
|
||||
|
||||
void CWindow::updateToplevel() {
|
||||
updateSurfaceOutputs();
|
||||
updateSurfaceScaleTransformDetails();
|
||||
|
||||
if (!m_phForeignToplevel)
|
||||
return;
|
||||
@@ -345,8 +335,8 @@ void sendLeaveIter(wlr_surface* pSurface, int x, int y, void* data) {
|
||||
wlr_surface_send_leave(pSurface, OUTPUT);
|
||||
}
|
||||
|
||||
void CWindow::updateSurfaceOutputs() {
|
||||
if (m_iLastSurfaceMonitorID == m_iMonitorID || !m_bIsMapped || m_bHidden)
|
||||
void CWindow::updateSurfaceScaleTransformDetails() {
|
||||
if (!m_bIsMapped || m_bHidden)
|
||||
return;
|
||||
|
||||
const auto PLASTMONITOR = g_pCompositor->getMonitorFromID(m_iLastSurfaceMonitorID);
|
||||
@@ -355,16 +345,23 @@ void CWindow::updateSurfaceOutputs() {
|
||||
|
||||
const auto PNEWMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
||||
|
||||
if (PLASTMONITOR && PLASTMONITOR->m_bEnabled)
|
||||
wlr_surface_for_each_surface(m_pWLSurface.wlr(), sendLeaveIter, PLASTMONITOR->output);
|
||||
if (PNEWMONITOR != PLASTMONITOR) {
|
||||
if (PLASTMONITOR && PLASTMONITOR->m_bEnabled)
|
||||
wlr_surface_for_each_surface(m_pWLSurface.wlr(), sendLeaveIter, PLASTMONITOR->output);
|
||||
|
||||
wlr_surface_for_each_surface(m_pWLSurface.wlr(), sendEnterIter, PNEWMONITOR->output);
|
||||
wlr_surface_for_each_surface(m_pWLSurface.wlr(), sendEnterIter, PNEWMONITOR->output);
|
||||
}
|
||||
|
||||
wlr_surface_for_each_surface(
|
||||
m_pWLSurface.wlr(),
|
||||
[](wlr_surface* surf, int x, int y, void* data) {
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(((CWindow*)data)->m_iMonitorID);
|
||||
g_pCompositor->setPreferredScaleForSurface(surf, PMONITOR ? PMONITOR->scale : 1.f);
|
||||
|
||||
const auto PSURFACE = CWLSurface::surfaceFromWlr(surf);
|
||||
if (PSURFACE && PSURFACE->m_fLastScale == PMONITOR->scale)
|
||||
return;
|
||||
|
||||
g_pCompositor->setPreferredScaleForSurface(surf, PMONITOR->scale);
|
||||
g_pCompositor->setPreferredTransformForSurface(surf, PMONITOR->transform);
|
||||
},
|
||||
this);
|
||||
@@ -511,6 +508,14 @@ void CWindow::onMap() {
|
||||
"CWindow");
|
||||
|
||||
m_vReportedSize = m_vPendingReportedSize;
|
||||
|
||||
for (const auto& ctrl : g_pHyprRenderer->m_vTearingControllers) {
|
||||
if (ctrl->pWlrHint->surface != m_pWLSurface.wlr())
|
||||
continue;
|
||||
|
||||
m_bTearingHint = ctrl->pWlrHint->current;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CWindow::onBorderAngleAnimEnd(void* ptr) {
|
||||
@@ -607,14 +612,42 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
|
||||
m_sAdditionalConfigData.animationStyle = STYLE;
|
||||
} else if (r.szRule.starts_with("bordercolor")) {
|
||||
try {
|
||||
std::string colorPart = removeBeginEndSpacesTabs(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
|
||||
// Each vector will only get used if it has at least one color
|
||||
CGradientValueData activeBorderGradient = {};
|
||||
CGradientValueData inactiveBorderGradient = {};
|
||||
bool active = true;
|
||||
CVarList colorsAndAngles = CVarList(removeBeginEndSpacesTabs(r.szRule.substr(r.szRule.find_first_of(' ') + 1)), 0, 's', true);
|
||||
|
||||
if (colorPart.contains(' ')) {
|
||||
// we have a space, 2 values
|
||||
m_sSpecialRenderData.activeBorderColor = configStringToInt(colorPart.substr(0, colorPart.find_first_of(' ')));
|
||||
m_sSpecialRenderData.inactiveBorderColor = configStringToInt(colorPart.substr(colorPart.find_first_of(' ') + 1));
|
||||
} else {
|
||||
m_sSpecialRenderData.activeBorderColor = configStringToInt(colorPart);
|
||||
// Basic form has only two colors, everything else can be parsed as a gradient
|
||||
if (colorsAndAngles.size() == 2 && !colorsAndAngles[1].contains("deg")) {
|
||||
m_sSpecialRenderData.activeBorderColor = CGradientValueData(CColor(configStringToInt(colorsAndAngles[0])));
|
||||
m_sSpecialRenderData.inactiveBorderColor = CGradientValueData(CColor(configStringToInt(colorsAndAngles[1])));
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& token : colorsAndAngles) {
|
||||
// The first angle, or an explicit "0deg", splits the two gradients
|
||||
if (active && token.contains("deg")) {
|
||||
activeBorderGradient.m_fAngle = std::stoi(token.substr(0, token.size() - 3)) * (PI / 180.0);
|
||||
active = false;
|
||||
} else if (token.contains("deg"))
|
||||
inactiveBorderGradient.m_fAngle = std::stoi(token.substr(0, token.size() - 3)) * (PI / 180.0);
|
||||
else if (active)
|
||||
activeBorderGradient.m_vColors.push_back(configStringToInt(token));
|
||||
else
|
||||
inactiveBorderGradient.m_vColors.push_back(configStringToInt(token));
|
||||
}
|
||||
|
||||
// Includes sanity checks for the number of colors in each gradient
|
||||
if (activeBorderGradient.m_vColors.size() > 10 || inactiveBorderGradient.m_vColors.size() > 10)
|
||||
Debug::log(WARN, "Bordercolor rule \"{}\" has more than 10 colors in one gradient, ignoring", r.szRule);
|
||||
else if (activeBorderGradient.m_vColors.empty())
|
||||
Debug::log(WARN, "Bordercolor rule \"{}\" has no colors, ignoring", r.szRule);
|
||||
else if (inactiveBorderGradient.m_vColors.empty())
|
||||
m_sSpecialRenderData.activeBorderColor = activeBorderGradient;
|
||||
else {
|
||||
m_sSpecialRenderData.activeBorderColor = activeBorderGradient;
|
||||
m_sSpecialRenderData.inactiveBorderColor = inactiveBorderGradient;
|
||||
}
|
||||
} catch (std::exception& e) { Debug::log(ERR, "BorderColor rule \"{}\" failed with: {}", r.szRule, e.what()); }
|
||||
} else if (r.szRule == "dimaround") {
|
||||
@@ -644,8 +677,8 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
|
||||
}
|
||||
|
||||
void CWindow::updateDynamicRules() {
|
||||
m_sSpecialRenderData.activeBorderColor = -1;
|
||||
m_sSpecialRenderData.inactiveBorderColor = -1;
|
||||
m_sSpecialRenderData.activeBorderColor = CGradientValueData();
|
||||
m_sSpecialRenderData.inactiveBorderColor = CGradientValueData();
|
||||
m_sSpecialRenderData.alpha = 1.f;
|
||||
m_sSpecialRenderData.alphaInactive = -1.f;
|
||||
m_sAdditionalConfigData.forceNoBlur = false;
|
||||
@@ -1026,7 +1059,7 @@ int CWindow::getRealBorderSize() {
|
||||
}
|
||||
|
||||
bool CWindow::canBeTorn() {
|
||||
return (m_sAdditionalConfigData.forceTearing.toUnderlying() || m_bTearingHint) && g_pHyprRenderer->m_bTearingEnvSatisfied;
|
||||
return (m_sAdditionalConfigData.forceTearing.toUnderlying() || m_bTearingHint);
|
||||
}
|
||||
|
||||
bool CWindow::shouldSendFullscreenState() {
|
||||
|
@@ -30,6 +30,16 @@ enum eGroupRules {
|
||||
GROUP_OVERRIDE = 1 << 6, // Override other rules
|
||||
};
|
||||
|
||||
enum eGetWindowProperties {
|
||||
WINDOW_ONLY = 0,
|
||||
RESERVED_EXTENTS = 1 << 0,
|
||||
INPUT_EXTENTS = 1 << 1,
|
||||
FULL_EXTENTS = 1 << 2,
|
||||
FLOATING_ONLY = 1 << 3,
|
||||
ALLOW_FLOATING = 1 << 4,
|
||||
USE_PROP_TILED = 1 << 5
|
||||
};
|
||||
|
||||
class IWindowTransformer;
|
||||
|
||||
template <typename T>
|
||||
@@ -106,13 +116,13 @@ class CWindowOverridableVar {
|
||||
};
|
||||
|
||||
struct SWindowSpecialRenderData {
|
||||
CWindowOverridableVar<bool> alphaOverride = false;
|
||||
CWindowOverridableVar<float> alpha = 1.f;
|
||||
CWindowOverridableVar<bool> alphaInactiveOverride = false;
|
||||
CWindowOverridableVar<float> alphaInactive = -1.f; // -1 means unset
|
||||
CWindowOverridableVar<bool> alphaOverride = false;
|
||||
CWindowOverridableVar<float> alpha = 1.f;
|
||||
CWindowOverridableVar<bool> alphaInactiveOverride = false;
|
||||
CWindowOverridableVar<float> alphaInactive = -1.f; // -1 means unset
|
||||
|
||||
CWindowOverridableVar<int64_t> activeBorderColor = -1; // -1 means unset
|
||||
CWindowOverridableVar<int64_t> inactiveBorderColor = -1; // -1 means unset
|
||||
CWindowOverridableVar<CGradientValueData> activeBorderColor = CGradientValueData(); // empty color vector means unset
|
||||
CWindowOverridableVar<CGradientValueData> inactiveBorderColor = CGradientValueData(); // empty color vector means unset
|
||||
|
||||
// set by the layout
|
||||
CWindowOverridableVar<int> borderSize = -1; // -1 means unset
|
||||
@@ -342,7 +352,7 @@ class CWindow {
|
||||
// methods
|
||||
CBox getFullWindowBoundingBox();
|
||||
SWindowDecorationExtents getFullWindowExtents();
|
||||
CBox getWindowInputBox();
|
||||
CBox getWindowBoxUnified(uint64_t props);
|
||||
CBox getWindowMainSurfaceBox();
|
||||
CBox getWindowIdealBoundingBoxIgnoreReserved();
|
||||
void addWindowDeco(std::unique_ptr<IHyprWindowDecoration> deco);
|
||||
@@ -356,7 +366,7 @@ class CWindow {
|
||||
void createToplevelHandle();
|
||||
void destroyToplevelHandle();
|
||||
void updateToplevel();
|
||||
void updateSurfaceOutputs();
|
||||
void updateSurfaceScaleTransformDetails();
|
||||
void moveToWorkspace(int);
|
||||
CWindow* X11TransientFor();
|
||||
void onUnmap();
|
||||
|
@@ -16,6 +16,7 @@ class ICustomConfigValueData {
|
||||
|
||||
class CGradientValueData : public ICustomConfigValueData {
|
||||
public:
|
||||
CGradientValueData(){};
|
||||
CGradientValueData(CColor col) {
|
||||
m_vColors.push_back(col);
|
||||
};
|
||||
|
@@ -99,7 +99,6 @@ void CConfigManager::setDefaultVars() {
|
||||
|
||||
configValues["misc:disable_hyprland_logo"].intValue = 0;
|
||||
configValues["misc:disable_splash_rendering"].intValue = 0;
|
||||
configValues["misc:force_hypr_chan"].intValue = 0;
|
||||
configValues["misc:force_default_wallpaper"].intValue = -1;
|
||||
configValues["misc:vfr"].intValue = 1;
|
||||
configValues["misc:vrr"].intValue = 0;
|
||||
@@ -138,6 +137,7 @@ void CConfigManager::setDefaultVars() {
|
||||
configValues["group:groupbar:font_family"].strValue = "Sans";
|
||||
configValues["group:groupbar:font_size"].intValue = 8;
|
||||
configValues["group:groupbar:gradients"].intValue = 1;
|
||||
configValues["group:groupbar:height"].intValue = 14;
|
||||
configValues["group:groupbar:priority"].intValue = 3;
|
||||
configValues["group:groupbar:render_titles"].intValue = 1;
|
||||
configValues["group:groupbar:scrolling"].intValue = 1;
|
||||
@@ -223,6 +223,7 @@ void CConfigManager::setDefaultVars() {
|
||||
|
||||
configValues["input:follow_mouse"].intValue = 1;
|
||||
configValues["input:mouse_refocus"].intValue = 1;
|
||||
configValues["input:special_fallthrough"].intValue = 0;
|
||||
configValues["input:sensitivity"].floatValue = 0.f;
|
||||
configValues["input:accel_profile"].strValue = STRVAL_EMPTY;
|
||||
configValues["input:kb_file"].strValue = STRVAL_EMPTY;
|
||||
@@ -253,6 +254,7 @@ void CConfigManager::setDefaultVars() {
|
||||
configValues["input:touchpad:scroll_factor"].floatValue = 1.f;
|
||||
configValues["input:touchdevice:transform"].intValue = 0;
|
||||
configValues["input:touchdevice:output"].strValue = STRVAL_EMPTY;
|
||||
configValues["input:touchdevice:enabled"].intValue = 1;
|
||||
configValues["input:tablet:transform"].intValue = 0;
|
||||
configValues["input:tablet:output"].strValue = STRVAL_EMPTY;
|
||||
configValues["input:tablet:region_position"].vecValue = Vector2D();
|
||||
@@ -318,7 +320,7 @@ void CConfigManager::setDeviceDefaultVars(const std::string& dev) {
|
||||
cfgValues["scroll_points"].strValue = STRVAL_EMPTY;
|
||||
cfgValues["transform"].intValue = 0;
|
||||
cfgValues["output"].strValue = STRVAL_EMPTY;
|
||||
cfgValues["enabled"].intValue = 1; // only for mice / touchpads
|
||||
cfgValues["enabled"].intValue = 1; // only for mice, touchpads, and touchdevices
|
||||
cfgValues["region_position"].vecValue = Vector2D(); // only for tablets
|
||||
cfgValues["region_size"].vecValue = Vector2D(); // only for tablets
|
||||
cfgValues["relative_input"].intValue = 0; // only for tablets
|
||||
@@ -395,10 +397,20 @@ void CConfigManager::configSetValueSafe(const std::string& COMMAND, const std::s
|
||||
if (!COMMAND.starts_with("device:") /* devices parsed later */ && !COMMAND.starts_with("plugin:") /* plugins parsed later */) {
|
||||
if (COMMAND[0] == '$') {
|
||||
// register a dynamic var
|
||||
Debug::log(LOG, "Registered dynamic var \"{}\" -> {}", COMMAND, VALUE);
|
||||
configDynamicVars.emplace_back(std::make_pair<>(COMMAND.substr(1), VALUE));
|
||||
bool found = false;
|
||||
for (auto& [var, val] : configDynamicVars) {
|
||||
if (var == COMMAND.substr(1)) {
|
||||
Debug::log(LOG, "Registered new value for dynamic var \"{}\" -> {}", COMMAND, VALUE);
|
||||
val = VALUE;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(configDynamicVars.begin(), configDynamicVars.end(), [&](const auto& a, const auto& b) { return a.first.length() > b.first.length(); });
|
||||
if (!found) {
|
||||
Debug::log(LOG, "Registered dynamic var \"{}\" -> {}", COMMAND, VALUE);
|
||||
configDynamicVars.emplace_back(std::make_pair<>(COMMAND.substr(1), VALUE));
|
||||
std::sort(configDynamicVars.begin(), configDynamicVars.end(), [&](const auto& a, const auto& b) { return a.first.length() > b.first.length(); });
|
||||
}
|
||||
} else {
|
||||
parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">: No such field.";
|
||||
}
|
||||
@@ -539,7 +551,7 @@ void CConfigManager::configSetValueSafe(const std::string& COMMAND, const std::s
|
||||
}
|
||||
}
|
||||
|
||||
if (COMMAND == "decoration:screen_shader") {
|
||||
if (COMMAND == "decoration:screen_shader" && VALUE != STRVAL_EMPTY) {
|
||||
const auto PATH = absolutePath(VALUE, configCurrentPath);
|
||||
|
||||
configPaths.push_back(PATH);
|
||||
@@ -588,12 +600,15 @@ static bool parseModeLine(const std::string& modeline, drmModeModeInfo& mode) {
|
||||
mode.vtotal = std::stoi(args[argno++]);
|
||||
mode.vrefresh = mode.clock * 1000.0 * 1000.0 / mode.htotal / mode.vtotal;
|
||||
|
||||
// clang-format off
|
||||
static std::unordered_map<std::string, uint32_t> flagsmap = {
|
||||
{"+hsync", DRM_MODE_FLAG_PHSYNC},
|
||||
{"-hsync", DRM_MODE_FLAG_NHSYNC},
|
||||
{"+vsync", DRM_MODE_FLAG_PVSYNC},
|
||||
{"-vsync", DRM_MODE_FLAG_NVSYNC},
|
||||
{"Interlace", DRM_MODE_FLAG_INTERLACE},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
for (; argno < static_cast<int>(args.size()); argno++) {
|
||||
auto key = args[argno];
|
||||
@@ -935,7 +950,7 @@ void CConfigManager::handleBind(const std::string& command, const std::string& v
|
||||
g_pKeybindManager->addKeybind(
|
||||
SKeybind{"", std::stoi(KEY.substr(5)), MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse, nonConsuming, transparent, ignoreMods});
|
||||
else
|
||||
g_pKeybindManager->addKeybind(SKeybind{KEY, -1, MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse, nonConsuming, transparent, ignoreMods});
|
||||
g_pKeybindManager->addKeybind(SKeybind{KEY, 0, MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse, nonConsuming, transparent, ignoreMods});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2297,30 +2312,30 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) {
|
||||
static auto* const PVRR = &getConfigValuePtr("misc:vrr")->intValue;
|
||||
|
||||
static auto ensureVRRForDisplay = [&](CMonitor* m) -> void {
|
||||
if (!m->output)
|
||||
if (!m->output || m->createdByUser)
|
||||
return;
|
||||
|
||||
const auto USEVRR = m->activeMonitorRule.vrr.has_value() ? m->activeMonitorRule.vrr.value() : *PVRR;
|
||||
|
||||
if (USEVRR == 0) {
|
||||
if (m->vrrActive) {
|
||||
wlr_output_enable_adaptive_sync(m->output, 0);
|
||||
wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 0);
|
||||
|
||||
if (!wlr_output_commit(m->output))
|
||||
if (!m->state.commit())
|
||||
Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> false", m->output->name);
|
||||
}
|
||||
m->vrrActive = false;
|
||||
return;
|
||||
} else if (USEVRR == 1) {
|
||||
if (!m->vrrActive) {
|
||||
wlr_output_enable_adaptive_sync(m->output, 1);
|
||||
wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 1);
|
||||
|
||||
if (!wlr_output_test(m->output)) {
|
||||
if (!m->state.test()) {
|
||||
Debug::log(LOG, "Pending output {} does not accept VRR.", m->output->name);
|
||||
wlr_output_enable_adaptive_sync(m->output, 0);
|
||||
wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 0);
|
||||
}
|
||||
|
||||
if (!wlr_output_commit(m->output))
|
||||
if (!m->state.commit())
|
||||
Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> true", m->output->name);
|
||||
}
|
||||
m->vrrActive = true;
|
||||
@@ -2337,20 +2352,20 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) {
|
||||
const auto WORKSPACEFULL = PWORKSPACE->m_bHasFullscreenWindow && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL;
|
||||
|
||||
if (WORKSPACEFULL && m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_DISABLED) {
|
||||
wlr_output_enable_adaptive_sync(m->output, 1);
|
||||
wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 1);
|
||||
|
||||
if (!wlr_output_test(m->output)) {
|
||||
if (!m->state.test()) {
|
||||
Debug::log(LOG, "Pending output {} does not accept VRR.", m->output->name);
|
||||
wlr_output_enable_adaptive_sync(m->output, 0);
|
||||
wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 0);
|
||||
}
|
||||
|
||||
if (!wlr_output_commit(m->output))
|
||||
if (!m->state.commit())
|
||||
Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> true", m->output->name);
|
||||
|
||||
} else if (!WORKSPACEFULL && m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED) {
|
||||
wlr_output_enable_adaptive_sync(m->output, 0);
|
||||
wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 0);
|
||||
|
||||
if (!wlr_output_commit(m->output))
|
||||
if (!m->state.commit())
|
||||
Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> false", m->output->name);
|
||||
}
|
||||
}
|
||||
|
@@ -119,7 +119,7 @@ gestures {
|
||||
|
||||
misc {
|
||||
# See https://wiki.hyprland.org/Configuring/Variables/ for more
|
||||
force_default_wallpaper = -1 # Set to 0 to disable the anime mascot wallpapers
|
||||
force_default_wallpaper = -1 # Set to 0 or 1 to disable the anime mascot wallpapers
|
||||
}
|
||||
|
||||
# Example per-device config
|
||||
|
@@ -119,7 +119,7 @@ void CrashReporter::createAndSaveCrash(int sig) {
|
||||
|
||||
finalCrashReport += "\n\nLog tail:\n";
|
||||
|
||||
finalCrashReport += Debug::rollingLog;
|
||||
finalCrashReport += Debug::rollingLog.substr(Debug::rollingLog.find("\n") + 1);
|
||||
|
||||
const auto HOME = getenv("HOME");
|
||||
const auto CACHE_HOME = getenv("XDG_CACHE_HOME");
|
||||
|
@@ -7,6 +7,7 @@
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
@@ -28,7 +29,7 @@ static std::string getWorkspaceNameFromSpecialID(const int workspaceID) {
|
||||
return workspace->m_szName;
|
||||
}
|
||||
|
||||
std::string monitorsRequest(std::string request, HyprCtl::eHyprCtlOutputFormat format) {
|
||||
std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
CVarList vars(request, 0, ' ');
|
||||
auto allMonitors = false;
|
||||
|
||||
@@ -39,7 +40,7 @@ std::string monitorsRequest(std::string request, HyprCtl::eHyprCtlOutputFormat f
|
||||
allMonitors = true;
|
||||
|
||||
std::string result = "";
|
||||
if (format == HyprCtl::FORMAT_JSON) {
|
||||
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
|
||||
result += "[";
|
||||
|
||||
for (auto& m : allMonitors ? g_pCompositor->m_vRealMonitors : g_pCompositor->m_vMonitors) {
|
||||
@@ -109,8 +110,8 @@ std::string monitorsRequest(std::string request, HyprCtl::eHyprCtlOutputFormat f
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::string getGroupedData(CWindow* w, HyprCtl::eHyprCtlOutputFormat format) {
|
||||
const bool isJson = format == HyprCtl::FORMAT_JSON;
|
||||
static std::string getGroupedData(CWindow* w, eHyprCtlOutputFormat format) {
|
||||
const bool isJson = format == eHyprCtlOutputFormat::FORMAT_JSON;
|
||||
if (!w->m_sGroupData.pNextWindow)
|
||||
return isJson ? "" : "0";
|
||||
|
||||
@@ -133,7 +134,7 @@ static std::string getGroupedData(CWindow* w, HyprCtl::eHyprCtlOutputFormat form
|
||||
return result.str();
|
||||
}
|
||||
|
||||
static std::string getWindowData(CWindow* w, HyprCtl::eHyprCtlOutputFormat format) {
|
||||
static std::string getWindowData(CWindow* w, eHyprCtlOutputFormat format) {
|
||||
auto getFocusHistoryID = [](CWindow* wnd) -> int {
|
||||
for (size_t i = 0; i < g_pCompositor->m_vWindowFocusHistory.size(); ++i) {
|
||||
if (g_pCompositor->m_vWindowFocusHistory[i] == wnd)
|
||||
@@ -142,7 +143,7 @@ static std::string getWindowData(CWindow* w, HyprCtl::eHyprCtlOutputFormat forma
|
||||
return -1;
|
||||
};
|
||||
|
||||
if (format == HyprCtl::FORMAT_JSON) {
|
||||
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
|
||||
return std::format(
|
||||
R"#({{
|
||||
"address": "0x{:x}",
|
||||
@@ -198,9 +199,9 @@ static std::string getWindowData(CWindow* w, HyprCtl::eHyprCtlOutputFormat forma
|
||||
}
|
||||
}
|
||||
|
||||
std::string clientsRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
std::string clientsRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
std::string result = "";
|
||||
if (format == HyprCtl::FORMAT_JSON) {
|
||||
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
|
||||
result += "[";
|
||||
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
@@ -218,10 +219,10 @@ std::string clientsRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::string getWorkspaceData(CWorkspace* w, HyprCtl::eHyprCtlOutputFormat format) {
|
||||
static std::string getWorkspaceData(CWorkspace* w, eHyprCtlOutputFormat format) {
|
||||
const auto PLASTW = w->getLastFocusedWindow();
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(w->m_iMonitorID);
|
||||
if (format == HyprCtl::FORMAT_JSON) {
|
||||
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
|
||||
return std::format(R"#({{
|
||||
"id": {},
|
||||
"name": "{}",
|
||||
@@ -242,9 +243,9 @@ static std::string getWorkspaceData(CWorkspace* w, HyprCtl::eHyprCtlOutputFormat
|
||||
}
|
||||
}
|
||||
|
||||
static std::string getWorkspaceRuleData(const SWorkspaceRule& r, HyprCtl::eHyprCtlOutputFormat format) {
|
||||
static std::string getWorkspaceRuleData(const SWorkspaceRule& r, eHyprCtlOutputFormat format) {
|
||||
const auto boolToString = [](const bool b) -> std::string { return b ? "true" : "false"; };
|
||||
if (format == HyprCtl::FORMAT_JSON) {
|
||||
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
|
||||
const std::string monitor = r.monitor.empty() ? "" : std::format(",\n \"monitor\": \"{}\"", escapeJSONStrings(r.monitor));
|
||||
const std::string default_ = (bool)(r.isDefault) ? std::format(",\n \"default\": {}", boolToString(r.isDefault)) : "";
|
||||
const std::string persistent = (bool)(r.isPersistent) ? std::format(",\n \"persistent\": {}", boolToString(r.isPersistent)) : "";
|
||||
@@ -280,7 +281,7 @@ static std::string getWorkspaceRuleData(const SWorkspaceRule& r, HyprCtl::eHyprC
|
||||
return result;
|
||||
}
|
||||
}
|
||||
std::string activeWorkspaceRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
std::string activeWorkspaceRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
if (!g_pCompositor->m_pLastMonitor)
|
||||
return "unsafe state";
|
||||
|
||||
@@ -293,10 +294,10 @@ std::string activeWorkspaceRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
return getWorkspaceData(w, format);
|
||||
}
|
||||
|
||||
std::string workspacesRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
std::string workspacesRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
std::string result = "";
|
||||
|
||||
if (format == HyprCtl::FORMAT_JSON) {
|
||||
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
|
||||
result += "[";
|
||||
for (auto& w : g_pCompositor->m_vWorkspaces) {
|
||||
result += getWorkspaceData(w.get(), format);
|
||||
@@ -314,9 +315,9 @@ std::string workspacesRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string workspaceRulesRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
std::string workspaceRulesRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
std::string result = "";
|
||||
if (format == HyprCtl::FORMAT_JSON) {
|
||||
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
|
||||
result += "[";
|
||||
for (auto& r : g_pConfigManager->getAllWorkspaceRules()) {
|
||||
result += getWorkspaceRuleData(r, format);
|
||||
@@ -334,24 +335,24 @@ std::string workspaceRulesRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string activeWindowRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
std::string activeWindowRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
const auto PWINDOW = g_pCompositor->m_pLastWindow;
|
||||
|
||||
if (!g_pCompositor->windowValidMapped(PWINDOW))
|
||||
return format == HyprCtl::FORMAT_JSON ? "{}" : "Invalid";
|
||||
return format == eHyprCtlOutputFormat::FORMAT_JSON ? "{}" : "Invalid";
|
||||
|
||||
auto result = getWindowData(PWINDOW, format);
|
||||
|
||||
if (format == HyprCtl::FORMAT_JSON)
|
||||
if (format == eHyprCtlOutputFormat::FORMAT_JSON)
|
||||
result.pop_back();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string layersRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
std::string layersRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
std::string result = "";
|
||||
|
||||
if (format == HyprCtl::FORMAT_JSON) {
|
||||
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
|
||||
result += "{\n";
|
||||
|
||||
for (auto& mon : g_pCompositor->m_vMonitors) {
|
||||
@@ -422,9 +423,9 @@ std::string layersRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string layoutsRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
std::string layoutsRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
std::string result = "";
|
||||
if (format == HyprCtl::FORMAT_JSON) {
|
||||
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
|
||||
result += "[";
|
||||
|
||||
for (auto& m : g_pLayoutManager->getAllLayoutNames()) {
|
||||
@@ -444,10 +445,10 @@ std::string layoutsRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string devicesRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
std::string result = "";
|
||||
|
||||
if (format == HyprCtl::FORMAT_JSON) {
|
||||
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
|
||||
result += "{\n";
|
||||
result += "\"mice\": [\n";
|
||||
|
||||
@@ -603,9 +604,9 @@ std::string devicesRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string animationsRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
std::string animationsRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
std::string ret = "";
|
||||
if (format == HyprCtl::eHyprCtlOutputFormat::FORMAT_NORMAL) {
|
||||
if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
|
||||
ret += "animations:\n";
|
||||
|
||||
for (auto& ac : g_pConfigManager->getAnimationConfig()) {
|
||||
@@ -656,10 +657,10 @@ std::string animationsRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string rollinglogRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
std::string rollinglogRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
std::string result = "";
|
||||
|
||||
if (format == HyprCtl::FORMAT_JSON) {
|
||||
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
|
||||
result += "[\n\"log\":\"";
|
||||
result += escapeJSONStrings(Debug::rollingLog);
|
||||
result += "\"]";
|
||||
@@ -670,10 +671,10 @@ std::string rollinglogRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string globalShortcutsRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
std::string globalShortcutsRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
std::string ret = "";
|
||||
const auto SHORTCUTS = g_pProtocolManager->m_pGlobalShortcutsProtocolManager->getAllShortcuts();
|
||||
if (format == HyprCtl::eHyprCtlOutputFormat::FORMAT_NORMAL) {
|
||||
if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
|
||||
for (auto& sh : SHORTCUTS)
|
||||
ret += std::format("{}:{} -> {}\n", sh.appid, sh.id, sh.description);
|
||||
} else {
|
||||
@@ -693,9 +694,9 @@ std::string globalShortcutsRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string bindsRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
std::string ret = "";
|
||||
if (format == HyprCtl::eHyprCtlOutputFormat::FORMAT_NORMAL) {
|
||||
if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
|
||||
for (auto& kb : g_pKeybindManager->m_lKeybinds) {
|
||||
ret += "bind";
|
||||
if (kb.locked)
|
||||
@@ -741,12 +742,12 @@ std::string bindsRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string versionRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
std::string versionRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
|
||||
auto commitMsg = removeBeginEndSpacesTabs(GIT_COMMIT_MESSAGE);
|
||||
std::replace(commitMsg.begin(), commitMsg.end(), '#', ' ');
|
||||
|
||||
if (format == HyprCtl::eHyprCtlOutputFormat::FORMAT_NORMAL) {
|
||||
if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
|
||||
std::string result = "Hyprland, built from branch " + std::string(GIT_BRANCH) + " at commit " + GIT_COMMIT_HASH + " " + GIT_DIRTY + " (" + commitMsg +
|
||||
").\nDate: " + GIT_COMMIT_DATE + "\nTag: " + GIT_TAG + "\n\nflags: (if any)\n";
|
||||
|
||||
@@ -793,7 +794,40 @@ std::string versionRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
return ""; // make the compiler happy
|
||||
}
|
||||
|
||||
std::string dispatchRequest(std::string in) {
|
||||
std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
std::string result = versionRequest(eHyprCtlOutputFormat::FORMAT_NORMAL, "");
|
||||
|
||||
result += "\n\nSystem Information:\n";
|
||||
|
||||
struct utsname unameInfo;
|
||||
|
||||
uname(&unameInfo);
|
||||
|
||||
result += "System name: " + std::string{unameInfo.sysname} + "\n";
|
||||
result += "Node name: " + std::string{unameInfo.nodename} + "\n";
|
||||
result += "Release: " + std::string{unameInfo.release} + "\n";
|
||||
result += "Version: " + std::string{unameInfo.version} + "\n";
|
||||
|
||||
result += "\n\n";
|
||||
|
||||
#if defined(__DragonFly__) || defined(__FreeBSD__)
|
||||
const std::string GPUINFO = execAndGet("pciconf -lv | fgrep -A4 vga");
|
||||
#else
|
||||
const std::string GPUINFO = execAndGet("lspci -vnn | grep VGA");
|
||||
#endif
|
||||
result += "GPU information: \n" + GPUINFO + "\n\n";
|
||||
|
||||
result += "os-release: " + execAndGet("cat /etc/os-release") + "\n\n";
|
||||
|
||||
result += "plugins:\n";
|
||||
for (auto& pl : g_pPluginSystem->getAllPlugins()) {
|
||||
result += std::format(" {} by {} ver {}\n", pl->name, pl->author, pl->version);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string dispatchRequest(eHyprCtlOutputFormat format, std::string in) {
|
||||
// get rid of the dispatch keyword
|
||||
in = in.substr(in.find_first_of(' ') + 1);
|
||||
|
||||
@@ -814,7 +848,7 @@ std::string dispatchRequest(std::string in) {
|
||||
return "ok";
|
||||
}
|
||||
|
||||
std::string dispatchKeyword(std::string in) {
|
||||
std::string dispatchKeyword(eHyprCtlOutputFormat format, std::string in) {
|
||||
// get rid of the keyword keyword
|
||||
in = in.substr(in.find_first_of(' ') + 1);
|
||||
|
||||
@@ -862,7 +896,7 @@ std::string dispatchKeyword(std::string in) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
std::string reloadRequest(const std::string& request) {
|
||||
std::string reloadRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
|
||||
const auto REQMODE = request.substr(request.find_last_of(' ') + 1);
|
||||
|
||||
@@ -877,20 +911,20 @@ std::string reloadRequest(const std::string& request) {
|
||||
return "ok";
|
||||
}
|
||||
|
||||
std::string killRequest() {
|
||||
std::string killRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
g_pInputManager->setClickMode(CLICKMODE_KILL);
|
||||
|
||||
return "ok";
|
||||
}
|
||||
|
||||
std::string splashRequest() {
|
||||
std::string splashRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
return g_pCompositor->m_szCurrentSplash;
|
||||
}
|
||||
|
||||
std::string cursorPosRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
std::string cursorPosRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
const auto CURSORPOS = g_pInputManager->getMouseCoordsInternal().floor();
|
||||
|
||||
if (format == HyprCtl::FORMAT_NORMAL) {
|
||||
if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
|
||||
return std::format("{}, {}", (int)CURSORPOS.x, (int)CURSORPOS.y);
|
||||
} else {
|
||||
return std::format(R"#(
|
||||
@@ -905,9 +939,7 @@ std::string cursorPosRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||
return "error";
|
||||
}
|
||||
|
||||
std::string getReply(std::string);
|
||||
|
||||
std::string dispatchBatch(std::string request) {
|
||||
std::string dispatchBatch(eHyprCtlOutputFormat format, std::string request) {
|
||||
// split by ;
|
||||
|
||||
request = request.substr(9);
|
||||
@@ -931,7 +963,7 @@ std::string dispatchBatch(std::string request) {
|
||||
nextItem();
|
||||
|
||||
while (curitem != "") {
|
||||
reply += getReply(curitem);
|
||||
reply += g_pHyprCtl->getReply(curitem);
|
||||
|
||||
nextItem();
|
||||
}
|
||||
@@ -939,7 +971,7 @@ std::string dispatchBatch(std::string request) {
|
||||
return reply;
|
||||
}
|
||||
|
||||
std::string dispatchSetCursor(std::string request) {
|
||||
std::string dispatchSetCursor(eHyprCtlOutputFormat format, std::string request) {
|
||||
CVarList vars(request, 0, ' ');
|
||||
|
||||
const auto SIZESTR = vars[vars.size() - 1];
|
||||
@@ -971,7 +1003,7 @@ std::string dispatchSetCursor(std::string request) {
|
||||
return "ok";
|
||||
}
|
||||
|
||||
std::string switchXKBLayoutRequest(const std::string& request) {
|
||||
std::string switchXKBLayoutRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
CVarList vars(request, 0, ' ');
|
||||
|
||||
const auto KB = vars[1];
|
||||
@@ -1017,7 +1049,7 @@ std::string switchXKBLayoutRequest(const std::string& request) {
|
||||
return "ok";
|
||||
}
|
||||
|
||||
std::string dispatchSeterror(std::string request) {
|
||||
std::string dispatchSeterror(eHyprCtlOutputFormat format, std::string request) {
|
||||
CVarList vars(request, 0, ' ');
|
||||
|
||||
std::string errorMessage = "";
|
||||
@@ -1046,7 +1078,7 @@ std::string dispatchSeterror(std::string request) {
|
||||
return "ok";
|
||||
}
|
||||
|
||||
std::string dispatchSetProp(std::string request) {
|
||||
std::string dispatchSetProp(eHyprCtlOutputFormat format, std::string request) {
|
||||
CVarList vars(request, 0, ' ');
|
||||
|
||||
if (vars.size() < 4)
|
||||
@@ -1104,9 +1136,9 @@ std::string dispatchSetProp(std::string request) {
|
||||
} else if (PROP == "alphainactive") {
|
||||
PWINDOW->m_sSpecialRenderData.alphaInactive.forceSetIgnoreLocked(std::stof(VAL), lock);
|
||||
} else if (PROP == "activebordercolor") {
|
||||
PWINDOW->m_sSpecialRenderData.activeBorderColor.forceSetIgnoreLocked(configStringToInt(VAL), lock);
|
||||
PWINDOW->m_sSpecialRenderData.activeBorderColor.forceSetIgnoreLocked(CGradientValueData(CColor(configStringToInt(VAL))), lock);
|
||||
} else if (PROP == "inactivebordercolor") {
|
||||
PWINDOW->m_sSpecialRenderData.inactiveBorderColor.forceSetIgnoreLocked(configStringToInt(VAL), lock);
|
||||
PWINDOW->m_sSpecialRenderData.inactiveBorderColor.forceSetIgnoreLocked(CGradientValueData(CColor(configStringToInt(VAL))), lock);
|
||||
} else if (PROP == "forcergbx") {
|
||||
PWINDOW->m_sAdditionalConfigData.forceRGBX.forceSetIgnoreLocked(configStringToInt(VAL), lock);
|
||||
} else if (PROP == "bordersize") {
|
||||
@@ -1130,7 +1162,7 @@ std::string dispatchSetProp(std::string request) {
|
||||
return "ok";
|
||||
}
|
||||
|
||||
std::string dispatchGetOption(std::string request, HyprCtl::eHyprCtlOutputFormat format) {
|
||||
std::string dispatchGetOption(eHyprCtlOutputFormat format, std::string request) {
|
||||
std::string curitem = "";
|
||||
|
||||
auto nextItem = [&]() {
|
||||
@@ -1155,7 +1187,7 @@ std::string dispatchGetOption(std::string request, HyprCtl::eHyprCtlOutputFormat
|
||||
if (!PCFGOPT)
|
||||
return "no such option";
|
||||
|
||||
if (format == HyprCtl::eHyprCtlOutputFormat::FORMAT_NORMAL)
|
||||
if (format == eHyprCtlOutputFormat::FORMAT_NORMAL)
|
||||
return std::format("option {}\n\tint: {}\n\tfloat: {:.5f}\n\tstr: \"{}\"\n\tdata: {:x}\n\tset: {}", curitem, PCFGOPT->intValue, PCFGOPT->floatValue, PCFGOPT->strValue,
|
||||
(uintptr_t)PCFGOPT->data.get(), PCFGOPT->set);
|
||||
else {
|
||||
@@ -1174,7 +1206,7 @@ std::string dispatchGetOption(std::string request, HyprCtl::eHyprCtlOutputFormat
|
||||
}
|
||||
}
|
||||
|
||||
std::string decorationRequest(std::string request, HyprCtl::eHyprCtlOutputFormat format) {
|
||||
std::string decorationRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
CVarList vars(request, 0, ' ');
|
||||
const auto PWINDOW = g_pCompositor->getWindowByRegex(vars[1]);
|
||||
|
||||
@@ -1182,7 +1214,7 @@ std::string decorationRequest(std::string request, HyprCtl::eHyprCtlOutputFormat
|
||||
return "none";
|
||||
|
||||
std::string result = "";
|
||||
if (format == HyprCtl::FORMAT_JSON) {
|
||||
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
|
||||
result += "[";
|
||||
for (auto& wd : PWINDOW->m_dWindowDecorations) {
|
||||
result += "{\n\"decorationName\": \"" + wd->getDisplayName() + "\",\n\"priority\": " + std::to_string(wd->getPositioningInfo().priority) + "\n},";
|
||||
@@ -1231,7 +1263,7 @@ void createOutputIter(wlr_backend* backend, void* data) {
|
||||
}
|
||||
}
|
||||
|
||||
std::string dispatchOutput(std::string request) {
|
||||
std::string dispatchOutput(eHyprCtlOutputFormat format, std::string request) {
|
||||
std::string curitem = "";
|
||||
|
||||
auto nextItem = [&]() {
|
||||
@@ -1280,7 +1312,7 @@ std::string dispatchOutput(std::string request) {
|
||||
return "ok";
|
||||
}
|
||||
|
||||
std::string dispatchPlugin(std::string request) {
|
||||
std::string dispatchPlugin(eHyprCtlOutputFormat format, std::string request) {
|
||||
CVarList vars(request, 0, ' ');
|
||||
|
||||
if (vars.size() < 2)
|
||||
@@ -1323,7 +1355,7 @@ std::string dispatchPlugin(std::string request) {
|
||||
return "ok";
|
||||
}
|
||||
|
||||
std::string dispatchNotify(std::string request) {
|
||||
std::string dispatchNotify(eHyprCtlOutputFormat format, std::string request) {
|
||||
CVarList vars(request, 0, ' ');
|
||||
|
||||
if (vars.size() < 5)
|
||||
@@ -1364,92 +1396,100 @@ std::string dispatchNotify(std::string request) {
|
||||
return "ok";
|
||||
}
|
||||
|
||||
std::string getReply(std::string request) {
|
||||
auto format = HyprCtl::FORMAT_NORMAL;
|
||||
CHyprCtl::CHyprCtl() {
|
||||
registerCommand(SHyprCtlCommand{"workspaces", true, workspacesRequest});
|
||||
registerCommand(SHyprCtlCommand{"workspacerules", true, workspaceRulesRequest});
|
||||
registerCommand(SHyprCtlCommand{"activeworkspace", true, activeWorkspaceRequest});
|
||||
registerCommand(SHyprCtlCommand{"clients", true, clientsRequest});
|
||||
registerCommand(SHyprCtlCommand{"kill", true, killRequest});
|
||||
registerCommand(SHyprCtlCommand{"activewindow", true, activeWindowRequest});
|
||||
registerCommand(SHyprCtlCommand{"layers", true, layersRequest});
|
||||
registerCommand(SHyprCtlCommand{"version", true, versionRequest});
|
||||
registerCommand(SHyprCtlCommand{"devices", true, devicesRequest});
|
||||
registerCommand(SHyprCtlCommand{"splash", true, splashRequest});
|
||||
registerCommand(SHyprCtlCommand{"cursorpos", true, cursorPosRequest});
|
||||
registerCommand(SHyprCtlCommand{"binds", true, bindsRequest});
|
||||
registerCommand(SHyprCtlCommand{"globalshortcuts", true, globalShortcutsRequest});
|
||||
registerCommand(SHyprCtlCommand{"systeminfo", true, systemInfoRequest});
|
||||
registerCommand(SHyprCtlCommand{"animations", true, animationsRequest});
|
||||
registerCommand(SHyprCtlCommand{"rollinglog", true, rollinglogRequest});
|
||||
registerCommand(SHyprCtlCommand{"layouts", true, layoutsRequest});
|
||||
|
||||
registerCommand(SHyprCtlCommand{"monitors", false, monitorsRequest});
|
||||
registerCommand(SHyprCtlCommand{"reload", false, reloadRequest});
|
||||
registerCommand(SHyprCtlCommand{"plugin", false, dispatchPlugin});
|
||||
registerCommand(SHyprCtlCommand{"notify", false, dispatchNotify});
|
||||
registerCommand(SHyprCtlCommand{"setprop", false, dispatchSetProp});
|
||||
registerCommand(SHyprCtlCommand{"seterror", false, dispatchSeterror});
|
||||
registerCommand(SHyprCtlCommand{"switchxkblayout", false, switchXKBLayoutRequest});
|
||||
registerCommand(SHyprCtlCommand{"output", false, dispatchOutput});
|
||||
registerCommand(SHyprCtlCommand{"dispatch", false, dispatchRequest});
|
||||
registerCommand(SHyprCtlCommand{"keyword", false, dispatchKeyword});
|
||||
registerCommand(SHyprCtlCommand{"setcursor", false, dispatchSetCursor});
|
||||
registerCommand(SHyprCtlCommand{"getoption", false, dispatchGetOption});
|
||||
registerCommand(SHyprCtlCommand{"decorations", false, decorationRequest});
|
||||
registerCommand(SHyprCtlCommand{"[[BATCH]]", false, dispatchBatch});
|
||||
|
||||
startHyprCtlSocket();
|
||||
}
|
||||
|
||||
std::shared_ptr<SHyprCtlCommand> CHyprCtl::registerCommand(SHyprCtlCommand cmd) {
|
||||
return m_vCommands.emplace_back(std::make_shared<SHyprCtlCommand>(cmd));
|
||||
}
|
||||
|
||||
void CHyprCtl::unregisterCommand(const std::shared_ptr<SHyprCtlCommand>& cmd) {
|
||||
std::erase(m_vCommands, cmd);
|
||||
}
|
||||
|
||||
std::string CHyprCtl::getReply(std::string request) {
|
||||
auto format = eHyprCtlOutputFormat::FORMAT_NORMAL;
|
||||
|
||||
// process flags for non-batch requests
|
||||
if (!request.contains("[[BATCH]]") && request.contains("/")) {
|
||||
if (!request.starts_with("[[BATCH]]") && request.contains("/")) {
|
||||
long unsigned int sepIndex = 0;
|
||||
for (const auto& c : request) {
|
||||
if (c == '/') { // stop at separator
|
||||
break;
|
||||
}
|
||||
|
||||
// after whitespace assume the first word as a keyword,
|
||||
// so its value can have slashes (e.g., a path)
|
||||
if (c == ' ') {
|
||||
sepIndex = request.size();
|
||||
break;
|
||||
}
|
||||
|
||||
sepIndex++;
|
||||
|
||||
if (c == 'j')
|
||||
format = HyprCtl::FORMAT_JSON;
|
||||
format = eHyprCtlOutputFormat::FORMAT_JSON;
|
||||
}
|
||||
|
||||
if (sepIndex < request.size())
|
||||
request = request.substr(sepIndex + 1); // remove flags and separator so we can compare the rest of the string
|
||||
}
|
||||
|
||||
if (request.starts_with("monitors"))
|
||||
return monitorsRequest(request, format);
|
||||
else if (request == "workspaces")
|
||||
return workspacesRequest(format);
|
||||
else if (request == "workspacerules")
|
||||
return workspaceRulesRequest(format);
|
||||
else if (request == "activeworkspace")
|
||||
return activeWorkspaceRequest(format);
|
||||
else if (request == "clients")
|
||||
return clientsRequest(format);
|
||||
else if (request == "kill")
|
||||
return killRequest();
|
||||
else if (request == "activewindow")
|
||||
return activeWindowRequest(format);
|
||||
else if (request == "layers")
|
||||
return layersRequest(format);
|
||||
else if (request == "version")
|
||||
return versionRequest(format);
|
||||
else if (request.starts_with("reload"))
|
||||
return reloadRequest(request);
|
||||
else if (request == "devices")
|
||||
return devicesRequest(format);
|
||||
else if (request == "splash")
|
||||
return splashRequest();
|
||||
else if (request == "cursorpos")
|
||||
return cursorPosRequest(format);
|
||||
else if (request == "binds")
|
||||
return bindsRequest(format);
|
||||
else if (request == "globalshortcuts")
|
||||
return globalShortcutsRequest(format);
|
||||
else if (request == "animations")
|
||||
return animationsRequest(format);
|
||||
else if (request == "rollinglog")
|
||||
return rollinglogRequest(format);
|
||||
else if (request == "layouts")
|
||||
return layoutsRequest(format);
|
||||
else if (request.starts_with("plugin"))
|
||||
return dispatchPlugin(request);
|
||||
else if (request.starts_with("notify"))
|
||||
return dispatchNotify(request);
|
||||
else if (request.starts_with("setprop"))
|
||||
return dispatchSetProp(request);
|
||||
else if (request.starts_with("seterror"))
|
||||
return dispatchSeterror(request);
|
||||
else if (request.starts_with("switchxkblayout"))
|
||||
return switchXKBLayoutRequest(request);
|
||||
else if (request.starts_with("output"))
|
||||
return dispatchOutput(request);
|
||||
else if (request.starts_with("dispatch"))
|
||||
return dispatchRequest(request);
|
||||
else if (request.starts_with("keyword"))
|
||||
return dispatchKeyword(request);
|
||||
else if (request.starts_with("setcursor"))
|
||||
return dispatchSetCursor(request);
|
||||
else if (request.starts_with("getoption"))
|
||||
return dispatchGetOption(request, format);
|
||||
else if (request.starts_with("decorations"))
|
||||
return decorationRequest(request, format);
|
||||
else if (request.starts_with("[[BATCH]]"))
|
||||
return dispatchBatch(request);
|
||||
// parse exact cmds first, then non-exact.
|
||||
for (auto& cmd : m_vCommands) {
|
||||
if (!cmd->exact)
|
||||
continue;
|
||||
|
||||
if (cmd->name == request)
|
||||
return cmd->fn(format, request);
|
||||
}
|
||||
|
||||
for (auto& cmd : m_vCommands) {
|
||||
if (cmd->exact)
|
||||
continue;
|
||||
|
||||
if (request.starts_with(cmd->name))
|
||||
return cmd->fn(format, request);
|
||||
}
|
||||
|
||||
return "unknown request";
|
||||
}
|
||||
|
||||
std::string HyprCtl::makeDynamicCall(const std::string& input) {
|
||||
std::string CHyprCtl::makeDynamicCall(const std::string& input) {
|
||||
return getReply(input);
|
||||
}
|
||||
|
||||
@@ -1460,7 +1500,7 @@ int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
|
||||
sockaddr_in clientAddress;
|
||||
socklen_t clientSize = sizeof(clientAddress);
|
||||
|
||||
const auto ACCEPTEDCONNECTION = accept4(HyprCtl::iSocketFD, (sockaddr*)&clientAddress, &clientSize, SOCK_CLOEXEC);
|
||||
const auto ACCEPTEDCONNECTION = accept4(g_pHyprCtl->m_iSocketFD, (sockaddr*)&clientAddress, &clientSize, SOCK_CLOEXEC);
|
||||
|
||||
std::array<char, 1024> readBuffer;
|
||||
|
||||
@@ -1490,7 +1530,7 @@ int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
|
||||
std::string reply = "";
|
||||
|
||||
try {
|
||||
reply = getReply(request);
|
||||
reply = g_pHyprCtl->getReply(request);
|
||||
} catch (std::exception& e) {
|
||||
Debug::log(ERR, "Error in request: {}", e.what());
|
||||
reply = "Err: " + std::string(e.what());
|
||||
@@ -1500,18 +1540,17 @@ int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
|
||||
|
||||
close(ACCEPTEDCONNECTION);
|
||||
|
||||
if (g_pConfigManager->m_bWantsMonitorReload) {
|
||||
if (g_pConfigManager->m_bWantsMonitorReload)
|
||||
g_pConfigManager->ensureMonitorStatus();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void HyprCtl::startHyprCtlSocket() {
|
||||
void CHyprCtl::startHyprCtlSocket() {
|
||||
|
||||
iSocketFD = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||
m_iSocketFD = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||
|
||||
if (iSocketFD < 0) {
|
||||
if (m_iSocketFD < 0) {
|
||||
Debug::log(ERR, "Couldn't start the Hyprland Socket. (1) IPC will not work.");
|
||||
return;
|
||||
}
|
||||
@@ -1522,15 +1561,15 @@ void HyprCtl::startHyprCtlSocket() {
|
||||
|
||||
strcpy(SERVERADDRESS.sun_path, socketPath.c_str());
|
||||
|
||||
if (bind(iSocketFD, (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)) < 0) {
|
||||
if (bind(m_iSocketFD, (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)) < 0) {
|
||||
Debug::log(ERR, "Couldn't start the Hyprland Socket. (2) IPC will not work.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 10 max queued.
|
||||
listen(iSocketFD, 10);
|
||||
listen(m_iSocketFD, 10);
|
||||
|
||||
Debug::log(LOG, "Hypr socket started at {}", socketPath);
|
||||
|
||||
wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, iSocketFD, WL_EVENT_READABLE, hyprCtlFDTick, nullptr);
|
||||
wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD, WL_EVENT_READABLE, hyprCtlFDTick, nullptr);
|
||||
}
|
||||
|
@@ -3,24 +3,23 @@
|
||||
#include "../Compositor.hpp"
|
||||
#include <fstream>
|
||||
#include "../helpers/MiscFunctions.hpp"
|
||||
#include <functional>
|
||||
|
||||
namespace HyprCtl {
|
||||
void startHyprCtlSocket();
|
||||
std::string makeDynamicCall(const std::string& input);
|
||||
class CHyprCtl {
|
||||
public:
|
||||
CHyprCtl();
|
||||
|
||||
// very simple thread-safe request method
|
||||
inline bool requestMade = false;
|
||||
inline bool requestReady = false;
|
||||
inline std::string request = "";
|
||||
std::string makeDynamicCall(const std::string& input);
|
||||
std::shared_ptr<SHyprCtlCommand> registerCommand(SHyprCtlCommand cmd);
|
||||
void unregisterCommand(const std::shared_ptr<SHyprCtlCommand>& cmd);
|
||||
std::string getReply(std::string);
|
||||
|
||||
inline std::ifstream requestStream;
|
||||
int m_iSocketFD = -1;
|
||||
|
||||
inline wl_event_source* hyprCtlTickSource = nullptr;
|
||||
private:
|
||||
void startHyprCtlSocket();
|
||||
|
||||
inline int iSocketFD = -1;
|
||||
std::vector<std::shared_ptr<SHyprCtlCommand>> m_vCommands;
|
||||
};
|
||||
|
||||
enum eHyprCtlOutputFormat {
|
||||
FORMAT_NORMAL = 0,
|
||||
FORMAT_JSON
|
||||
};
|
||||
};
|
||||
inline std::unique_ptr<CHyprCtl> g_pHyprCtl;
|
@@ -142,6 +142,9 @@ void Events::listener_mapLayerSurface(void* owner, void* data) {
|
||||
|
||||
wlr_surface_send_enter(layersurface->layerSurface->surface, layersurface->layerSurface->output);
|
||||
|
||||
if (layersurface->layerSurface->current.keyboard_interactive == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE)
|
||||
g_pInputManager->m_dExclusiveLSes.push_back(layersurface);
|
||||
|
||||
const bool GRABSFOCUS = layersurface->layerSurface->current.keyboard_interactive != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE &&
|
||||
// don't focus if constrained
|
||||
(!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->currentConstraint);
|
||||
@@ -183,6 +186,11 @@ void Events::listener_unmapLayerSurface(void* owner, void* data) {
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"closelayer", std::string(layersurface->layerSurface->_namespace ? layersurface->layerSurface->_namespace : "")});
|
||||
EMIT_HOOK_EVENT("closeLayer", layersurface);
|
||||
|
||||
std::erase(g_pInputManager->m_dExclusiveLSes, layersurface);
|
||||
|
||||
if (!g_pInputManager->m_dExclusiveLSes.empty())
|
||||
g_pCompositor->focusSurface(g_pInputManager->m_dExclusiveLSes[0]->layerSurface->surface);
|
||||
|
||||
if (!g_pCompositor->getMonitorFromID(layersurface->monitorID) || g_pCompositor->m_bUnsafeState) {
|
||||
Debug::log(WARN, "Layersurface unmapping on invalid monitor (removed?) ignoring.");
|
||||
|
||||
|
@@ -175,11 +175,17 @@ void Events::listener_sessionActive(wl_listener* listener, void* data) {
|
||||
void Events::listener_powerMgrSetMode(wl_listener* listener, void* data) {
|
||||
Debug::log(LOG, "PowerMgr set mode!");
|
||||
|
||||
const auto EVENT = (wlr_output_power_v1_set_mode_event*)data;
|
||||
const auto EVENT = (wlr_output_power_v1_set_mode_event*)data;
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromOutput(EVENT->output);
|
||||
|
||||
wlr_output_enable(EVENT->output, EVENT->mode == 1);
|
||||
if (!PMONITOR) {
|
||||
Debug::log(ERR, "Invalid powerMgrSetMode output");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!wlr_output_commit(EVENT->output))
|
||||
wlr_output_state_set_enabled(PMONITOR->state.wlr(), EVENT->mode == 1);
|
||||
|
||||
if (!PMONITOR->state.commit())
|
||||
Debug::log(ERR, "Couldn't set power mode");
|
||||
}
|
||||
|
||||
@@ -227,14 +233,7 @@ void Events::listener_setCursorShape(wl_listener* listener, void* data) {
|
||||
void Events::listener_newTearingHint(wl_listener* listener, void* data) {
|
||||
const auto TCTL = (wlr_tearing_control_v1*)data;
|
||||
|
||||
const auto PWINDOW = g_pCompositor->getWindowFromSurface(TCTL->surface);
|
||||
|
||||
if (!PWINDOW) {
|
||||
Debug::log(ERR, "Tearing hint {} was attached to an unknown surface", (uintptr_t)data);
|
||||
return;
|
||||
}
|
||||
|
||||
Debug::log(LOG, "New tearing hint for window {} at {}", PWINDOW, (uintptr_t)data);
|
||||
Debug::log(LOG, "New tearing hint at {:x}", (uintptr_t)data);
|
||||
|
||||
const auto NEWCTRL = g_pHyprRenderer->m_vTearingControllers.emplace_back(std::make_unique<STearingController>()).get();
|
||||
NEWCTRL->pWlrHint = (wlr_tearing_control_v1*)data;
|
||||
@@ -242,7 +241,7 @@ void Events::listener_newTearingHint(wl_listener* listener, void* data) {
|
||||
NEWCTRL->hyprListener_destroy.initCallback(
|
||||
&NEWCTRL->pWlrHint->events.destroy,
|
||||
[&](void* owner, void* data) {
|
||||
Debug::log(LOG, "Destroyed {} tearing hint", (uintptr_t)((STearingController*)owner)->pWlrHint);
|
||||
Debug::log(LOG, "Destroyed {:x} tearing hint", (uintptr_t)((STearingController*)owner)->pWlrHint);
|
||||
|
||||
std::erase_if(g_pHyprRenderer->m_vTearingControllers, [&](const auto& other) { return other.get() == owner; });
|
||||
},
|
||||
@@ -256,9 +255,9 @@ void Events::listener_newTearingHint(wl_listener* listener, void* data) {
|
||||
const auto PWINDOW = g_pCompositor->getWindowFromSurface(TEARINGHINT->pWlrHint->surface);
|
||||
|
||||
if (PWINDOW) {
|
||||
PWINDOW->m_bTearingHint = TEARINGHINT->pWlrHint->hint;
|
||||
PWINDOW->m_bTearingHint = (bool)TEARINGHINT->pWlrHint->current;
|
||||
|
||||
Debug::log(LOG, "Hint {} (window {}) set tearing hint to {}", (uintptr_t)TEARINGHINT->pWlrHint, PWINDOW, (uint32_t)TEARINGHINT->pWlrHint->hint);
|
||||
Debug::log(LOG, "Hint {:x} (window {}) set tearing hint to {}", (uintptr_t)TEARINGHINT->pWlrHint, PWINDOW, (uint32_t)TEARINGHINT->pWlrHint->current);
|
||||
}
|
||||
},
|
||||
NEWCTRL, "TearingController");
|
||||
|
@@ -109,7 +109,7 @@ void Events::listener_newOutput(wl_listener* listener, void* data) {
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (w->m_iMonitorID == PNEWMONITOR->ID) {
|
||||
w->m_iLastSurfaceMonitorID = -1;
|
||||
w->updateSurfaceOutputs();
|
||||
w->updateSurfaceScaleTransformDetails();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -209,10 +209,10 @@ void Events::listener_monitorDestroy(void* owner, void* data) {
|
||||
}
|
||||
|
||||
void Events::listener_monitorStateRequest(void* owner, void* data) {
|
||||
const auto PMONITOR = (CMonitor*)owner;
|
||||
const auto E = (wlr_output_event_request_state*)data;
|
||||
//const auto PMONITOR = (CMonitor*)owner;
|
||||
//const auto E = (wlr_output_event_request_state*)data;
|
||||
|
||||
wlr_output_commit_state(PMONITOR->output, E->state);
|
||||
// TODO: maybe don't ignore?
|
||||
}
|
||||
|
||||
void Events::listener_monitorDamage(void* owner, void* data) {
|
||||
|
@@ -639,7 +639,8 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
||||
g_pCompositor->setPreferredScaleForSurface(PWINDOW->m_pWLSurface.wlr(), PMONITOR->scale);
|
||||
g_pCompositor->setPreferredTransformForSurface(PWINDOW->m_pWLSurface.wlr(), PMONITOR->transform);
|
||||
|
||||
g_pInputManager->sendMotionEventsToFocused();
|
||||
if (!g_pCompositor->m_sSeat.mouse || !g_pCompositor->m_sSeat.mouse->constraintActive)
|
||||
g_pInputManager->sendMotionEventsToFocused();
|
||||
|
||||
// fix some xwayland apps that don't behave nicely
|
||||
PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize;
|
||||
@@ -803,8 +804,6 @@ void Events::listener_commitWindow(void* owner, void* data) {
|
||||
PWINDOW->m_pPendingSizeAck.reset();
|
||||
}
|
||||
|
||||
PWINDOW->updateSurfaceOutputs();
|
||||
|
||||
g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface.wlr(), PWINDOW->m_vRealPosition.goalv().x, PWINDOW->m_vRealPosition.goalv().y,
|
||||
PWINDOW->m_bIsX11 ? 1.0 / PWINDOW->m_fX11SurfaceScaledBy : 1.0);
|
||||
|
||||
@@ -1054,11 +1053,8 @@ void Events::listener_configureX11(void* owner, void* data) {
|
||||
|
||||
static auto* const PXWLFORCESCALEZERO = &g_pConfigManager->getConfigValuePtr("xwayland:force_zero_scaling")->intValue;
|
||||
if (*PXWLFORCESCALEZERO) {
|
||||
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR) {
|
||||
const Vector2D DELTA = PWINDOW->m_vRealSize.goalv() - PWINDOW->m_vRealSize.goalv() / PMONITOR->scale;
|
||||
if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR)
|
||||
PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goalv() / PMONITOR->scale);
|
||||
PWINDOW->m_vRealPosition.setValueAndWarp(PWINDOW->m_vRealPosition.goalv() + DELTA / 2.0);
|
||||
}
|
||||
}
|
||||
|
||||
PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.vec();
|
||||
@@ -1139,8 +1135,7 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) {
|
||||
g_pHyprRenderer->damageWindow(PWINDOW);
|
||||
|
||||
PWINDOW->m_vReportedPosition = PWINDOW->m_vRealPosition.goalv();
|
||||
PWINDOW->m_vReportedSize = PWINDOW->m_vRealSize.goalv();
|
||||
PWINDOW->m_vPendingReportedSize = PWINDOW->m_vReportedSize;
|
||||
PWINDOW->m_vPendingReportedSize = PWINDOW->m_vRealSize.goalv();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,4 +1,8 @@
|
||||
#include "Box.hpp"
|
||||
|
||||
#include <limits>
|
||||
#include <algorithm>
|
||||
|
||||
wlr_box CBox::wlr() {
|
||||
CBox rounded = roundInternal();
|
||||
m_bWlrBox = wlr_box{(int)rounded.x, (int)rounded.y, (int)rounded.w, (int)rounded.h};
|
||||
@@ -105,6 +109,13 @@ CBox& CBox::expand(const double& value) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
CBox& CBox::noNegativeSize() {
|
||||
std::clamp(w, 0.0, std::numeric_limits<double>::infinity());
|
||||
std::clamp(h, 0.0, std::numeric_limits<double>::infinity());
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
CBox CBox::roundInternal() {
|
||||
float newW = x + w - std::floor(x);
|
||||
float newH = y + h - std::floor(y);
|
||||
|
@@ -51,6 +51,7 @@ class CBox {
|
||||
CBox& transform(const wl_output_transform t, double w, double h);
|
||||
CBox& addExtents(const SWindowDecorationExtents& e);
|
||||
CBox& expand(const double& value);
|
||||
CBox& noNegativeSize();
|
||||
|
||||
CBox copy() const;
|
||||
|
||||
@@ -73,6 +74,8 @@ class CBox {
|
||||
double height;
|
||||
};
|
||||
|
||||
double rot = 0; /* rad, ccw */
|
||||
|
||||
//
|
||||
bool operator==(const CBox& rhs) const {
|
||||
return x == rhs.x && y == rhs.y && w == rhs.w && h == rhs.h;
|
||||
|
@@ -159,6 +159,13 @@ void addWLSignal(wl_signal* pSignal, wl_listener* pListener, void* pOwner, const
|
||||
Debug::log(LOG, "Registered signal for owner {:x}: {:x} -> {:x} (owner: {})", (uintptr_t)pOwner, (uintptr_t)pSignal, (uintptr_t)pListener, ownerString);
|
||||
}
|
||||
|
||||
void removeWLSignal(wl_listener* pListener) {
|
||||
wl_list_remove(&pListener->link);
|
||||
wl_list_init(&pListener->link);
|
||||
|
||||
Debug::log(LOG, "Removed listener {:x}", (uintptr_t)pListener);
|
||||
}
|
||||
|
||||
void handleNoop(struct wl_listener* listener, void* data) {
|
||||
// Do nothing
|
||||
}
|
||||
|
@@ -15,6 +15,7 @@ struct SCallstackFrameInfo {
|
||||
|
||||
std::string absolutePath(const std::string&, const std::string&);
|
||||
void addWLSignal(wl_signal*, wl_listener*, void* pOwner, const std::string& ownerString);
|
||||
void removeWLSignal(wl_listener*);
|
||||
std::string escapeJSONStrings(const std::string& str);
|
||||
std::string removeBeginEndSpacesTabs(std::string);
|
||||
bool isNumber(const std::string&, bool allowfloat = false);
|
||||
|
@@ -8,7 +8,7 @@ int ratHandler(void* data) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
CMonitor::CMonitor() {
|
||||
CMonitor::CMonitor() : state(this) {
|
||||
wlr_damage_ring_init(&damage);
|
||||
}
|
||||
|
||||
@@ -43,8 +43,8 @@ void CMonitor::onConnect(bool noRule) {
|
||||
tearingState.canTear = wlr_backend_is_drm(output->backend); // tearing only works on drm
|
||||
|
||||
if (m_bEnabled) {
|
||||
wlr_output_enable(output, 1);
|
||||
wlr_output_commit(output);
|
||||
wlr_output_state_set_enabled(state.wlr(), true);
|
||||
state.commit();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -63,8 +63,8 @@ void CMonitor::onConnect(bool noRule) {
|
||||
// if it's disabled, disable and ignore
|
||||
if (monitorRule.disabled) {
|
||||
|
||||
wlr_output_set_scale(output, 1);
|
||||
wlr_output_set_transform(output, WL_OUTPUT_TRANSFORM_NORMAL);
|
||||
wlr_output_state_set_scale(state.wlr(), 1);
|
||||
wlr_output_state_set_transform(state.wlr(), WL_OUTPUT_TRANSFORM_NORMAL);
|
||||
|
||||
auto PREFSTATE = wlr_output_preferred_mode(output);
|
||||
|
||||
@@ -72,9 +72,9 @@ void CMonitor::onConnect(bool noRule) {
|
||||
wlr_output_mode* mode;
|
||||
|
||||
wl_list_for_each(mode, &output->modes, link) {
|
||||
wlr_output_set_mode(output, PREFSTATE);
|
||||
wlr_output_state_set_mode(state.wlr(), mode);
|
||||
|
||||
if (!wlr_output_test(output))
|
||||
if (!wlr_output_test_state(output, state.wlr()))
|
||||
continue;
|
||||
|
||||
PREFSTATE = mode;
|
||||
@@ -83,13 +83,13 @@ void CMonitor::onConnect(bool noRule) {
|
||||
}
|
||||
|
||||
if (PREFSTATE)
|
||||
wlr_output_set_mode(output, PREFSTATE);
|
||||
wlr_output_state_set_mode(state.wlr(), PREFSTATE);
|
||||
else
|
||||
Debug::log(WARN, "No mode found for disabled output {}", output->name);
|
||||
|
||||
wlr_output_enable(output, 0);
|
||||
wlr_output_state_set_enabled(state.wlr(), 0);
|
||||
|
||||
if (!wlr_output_commit(output))
|
||||
if (!state.commit())
|
||||
Debug::log(ERR, "Couldn't commit disabled state on output {}", output->name);
|
||||
|
||||
m_bEnabled = false;
|
||||
@@ -130,13 +130,14 @@ void CMonitor::onConnect(bool noRule) {
|
||||
|
||||
m_bEnabled = true;
|
||||
|
||||
wlr_output_enable(output, 1);
|
||||
wlr_output_state_set_enabled(state.wlr(), 1);
|
||||
|
||||
// set mode, also applies
|
||||
if (!noRule)
|
||||
g_pHyprRenderer->applyMonitorRule(this, &monitorRule, true);
|
||||
|
||||
wlr_output_commit(output);
|
||||
if (!state.commit())
|
||||
Debug::log(WARN, "wlr_output_commit_state failed in CMonitor::onCommit");
|
||||
|
||||
wlr_damage_ring_set_bounds(&damage, vecTransformedSize.x, vecTransformedSize.y);
|
||||
|
||||
@@ -283,9 +284,10 @@ void CMonitor::onDisconnect(bool destroy) {
|
||||
if (!destroy)
|
||||
wlr_output_layout_remove(g_pCompositor->m_sWLROutputLayout, output);
|
||||
|
||||
wlr_output_enable(output, false);
|
||||
wlr_output_state_set_enabled(state.wlr(), false);
|
||||
|
||||
wlr_output_commit(output);
|
||||
if (!state.commit())
|
||||
Debug::log(WARN, "wlr_output_commit_state failed in CMonitor::onDisconnect");
|
||||
|
||||
if (g_pCompositor->m_pLastMonitor == this)
|
||||
g_pCompositor->setActiveMonitor(BACKUPMON);
|
||||
@@ -502,7 +504,7 @@ float CMonitor::getDefaultScale() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool noMouseMove) {
|
||||
void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool noMouseMove, bool noFocus) {
|
||||
if (!pWorkspace)
|
||||
return;
|
||||
|
||||
@@ -533,13 +535,13 @@ void CMonitor::changeWorkspace(CWorkspace* const pWorkspace, bool internal, bool
|
||||
}
|
||||
}
|
||||
|
||||
if (!g_pCompositor->m_pLastMonitor->specialWorkspaceID) {
|
||||
if (!noFocus && !g_pCompositor->m_pLastMonitor->specialWorkspaceID) {
|
||||
static auto* const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
|
||||
CWindow* pWindow = pWorkspace->getLastFocusedWindow();
|
||||
|
||||
if (!pWindow) {
|
||||
if (*PFOLLOWMOUSE == 1)
|
||||
pWindow = g_pCompositor->vectorToWindowIdeal(g_pInputManager->getMouseCoordsInternal());
|
||||
pWindow = g_pCompositor->vectorToWindowUnified(g_pInputManager->getMouseCoordsInternal(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
|
||||
|
||||
if (!pWindow)
|
||||
pWindow = g_pCompositor->getTopLeftWindowOnWorkspace(pWorkspace->m_iID);
|
||||
@@ -621,7 +623,7 @@ void CMonitor::setSpecialWorkspace(CWorkspace* const pWorkspace) {
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (w->m_iWorkspaceID == pWorkspace->m_iID) {
|
||||
w->m_iMonitorID = ID;
|
||||
w->updateSurfaceOutputs();
|
||||
w->updateSurfaceScaleTransformDetails();
|
||||
|
||||
const auto MIDDLE = w->middle();
|
||||
if (w->m_bIsFloating && !VECINRECT(MIDDLE, vecPosition.x, vecPosition.y, vecPosition.x + vecSize.x, vecPosition.y + vecSize.y) && w->m_iX11Type != 2) {
|
||||
@@ -678,3 +680,32 @@ void CMonitor::updateMatrix() {
|
||||
wlr_matrix_translate(projMatrix.data(), -vecTransformedSize.x / 2.0, -vecTransformedSize.y / 2.0);
|
||||
}
|
||||
}
|
||||
|
||||
CMonitorState::CMonitorState(CMonitor* owner) {
|
||||
m_pOwner = owner;
|
||||
wlr_output_state_init(&m_state);
|
||||
}
|
||||
|
||||
CMonitorState::~CMonitorState() {
|
||||
wlr_output_state_finish(&m_state);
|
||||
}
|
||||
|
||||
wlr_output_state* CMonitorState::wlr() {
|
||||
return &m_state;
|
||||
}
|
||||
|
||||
void CMonitorState::clear() {
|
||||
wlr_output_state_finish(&m_state);
|
||||
m_state = {0};
|
||||
wlr_output_state_init(&m_state);
|
||||
}
|
||||
|
||||
bool CMonitorState::commit() {
|
||||
bool ret = wlr_output_commit_state(m_pOwner->output, &m_state);
|
||||
clear();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CMonitorState::test() {
|
||||
return wlr_output_test_state(m_pOwner->output, &m_state);
|
||||
}
|
||||
|
@@ -25,6 +25,25 @@ struct SMonitorRule {
|
||||
std::optional<int> vrr;
|
||||
};
|
||||
|
||||
class CMonitor;
|
||||
|
||||
// Class for wrapping the wlr state
|
||||
class CMonitorState {
|
||||
public:
|
||||
CMonitorState(CMonitor* owner);
|
||||
~CMonitorState();
|
||||
|
||||
wlr_output_state* wlr();
|
||||
void clear();
|
||||
// commit() will also clear()
|
||||
bool commit();
|
||||
bool test();
|
||||
|
||||
private:
|
||||
wlr_output_state m_state = {0};
|
||||
CMonitor* m_pOwner;
|
||||
};
|
||||
|
||||
class CMonitor {
|
||||
public:
|
||||
CMonitor();
|
||||
@@ -51,6 +70,8 @@ class CMonitor {
|
||||
|
||||
drmModeModeInfo customDrmMode = {};
|
||||
|
||||
CMonitorState state;
|
||||
|
||||
// WLR stuff
|
||||
wlr_damage_ring damage;
|
||||
wlr_output* output = nullptr;
|
||||
@@ -120,7 +141,7 @@ class CMonitor {
|
||||
void setMirror(const std::string&);
|
||||
bool isMirror();
|
||||
float getDefaultScale();
|
||||
void changeWorkspace(CWorkspace* const pWorkspace, bool internal = false, bool noMouseMove = false);
|
||||
void changeWorkspace(CWorkspace* const pWorkspace, bool internal = false, bool noMouseMove = false, bool noFocus = false);
|
||||
void changeWorkspace(const int& id, bool internal = false);
|
||||
void setSpecialWorkspace(CWorkspace* const pWorkspace);
|
||||
void setSpecialWorkspace(const int& id);
|
||||
|
@@ -19,6 +19,21 @@ inline const std::vector<std::string> SPLASHES = {
|
||||
"Compile, wait for 20 minutes, notice a new commit, compile again.",
|
||||
"To rice, or not to rice, that is the question.",
|
||||
"Now available on Fedora!",
|
||||
"\"Hyprland is so good it starts with a capital letter\" - Hazel",
|
||||
"\"please make this message a splash\" - eriedaberrie",
|
||||
"\"the only wayland compositor powered by fried chicken\" - raf",
|
||||
"\"This will never get into Hyprland\" - Flafy",
|
||||
"\"Hyprland only gives you up on -git\" - fazzi",
|
||||
"Segmentation fault (core dumped)",
|
||||
"\"disabling hyprland logo is a war crime\" - vaxry",
|
||||
"some basic startup code",
|
||||
"\"I think I am addicted to hyprland\" - mathisbuilder",
|
||||
"\"hyprland is the most important package in the arch repos\" - jacekpoz",
|
||||
"Thanks Brodie!",
|
||||
"Thanks fufexan!",
|
||||
"Thanks raf!",
|
||||
"You can't use --splash to change this message :)",
|
||||
"Hyprland will overtake Gnome in popularity by [insert year]",
|
||||
// music reference / quote section
|
||||
"J'remue le ciel, le jour, la nuit.",
|
||||
"aezakmi, aezakmi, aezakmi, aezakmi, aezakmi, aezakmi, aezakmi!",
|
||||
|
@@ -178,6 +178,9 @@ void Events::listener_mapSubsurface(void* owner, void* data) {
|
||||
Debug::log(LOG, "Subsurface {:x} mapped", (uintptr_t)subsurface->pSubsurface);
|
||||
|
||||
subsurface->pChild = createSubsurfaceNode(subsurface->pParent, subsurface, subsurface->pSubsurface->surface, subsurface->pWindowOwner);
|
||||
|
||||
if (subsurface->pWindowOwner)
|
||||
subsurface->pWindowOwner->updateSurfaceScaleTransformDetails();
|
||||
}
|
||||
|
||||
void Events::listener_unmapSubsurface(void* owner, void* data) {
|
||||
@@ -259,13 +262,11 @@ void Events::listener_commitSubsurface(void* owner, void* data) {
|
||||
|
||||
// tearing: if solitary, redraw it. This still might be a single surface window
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(pNode->pWindowOwner->m_iMonitorID);
|
||||
if (PMONITOR->solitaryClient == pNode->pWindowOwner && pNode->pWindowOwner->canBeTorn() && PMONITOR->tearingState.canTear &&
|
||||
if (PMONITOR && PMONITOR->solitaryClient == pNode->pWindowOwner && pNode->pWindowOwner->canBeTorn() && PMONITOR->tearingState.canTear &&
|
||||
pNode->pSurface->wlr()->current.committed & WLR_SURFACE_STATE_BUFFER) {
|
||||
CRegion damageBox;
|
||||
wlr_surface_get_effective_damage(pNode->pSurface->wlr(), damageBox.pixman());
|
||||
CRegion damageBox{&pNode->pSurface->wlr()->buffer_damage};
|
||||
|
||||
if (!damageBox.empty()) {
|
||||
|
||||
if (PMONITOR->tearingState.busy) {
|
||||
PMONITOR->tearingState.frameScheduledWhileBusy = true;
|
||||
} else {
|
||||
|
@@ -42,14 +42,10 @@ double Vector2D::distance(const Vector2D& other) const {
|
||||
return std::sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
bool Vector2D::inTriangle(const Vector2D& p1, const Vector2D& p2, const Vector2D& p3) const {
|
||||
const auto a = ((p2.y - p3.y) * (x - p3.x) + (p3.x - p2.x) * (y - p3.y)) / ((p2.y - p3.y) * (p1.x - p3.x) + (p3.x - p2.x) * (p1.y - p3.y));
|
||||
const auto b = ((p3.y - p1.y) * (x - p3.x) + (p1.x - p3.x) * (y - p3.y)) / ((p2.y - p3.y) * (p1.x - p3.x) + (p3.x - p2.x) * (p1.y - p3.y));
|
||||
const auto c = 1 - a - b;
|
||||
|
||||
return 0 <= a && a <= 1 && 0 <= b && b <= 1 && 0 <= c && c <= 1;
|
||||
}
|
||||
|
||||
double Vector2D::size() const {
|
||||
return std::sqrt(x * x + y * y);
|
||||
}
|
||||
|
||||
Vector2D Vector2D::getComponentMax(const Vector2D& other) const {
|
||||
return Vector2D(std::max(this->x, other.x), std::max(this->y, other.y));
|
||||
}
|
||||
|
@@ -93,7 +93,7 @@ class Vector2D {
|
||||
Vector2D floor() const;
|
||||
Vector2D round() const;
|
||||
|
||||
bool inTriangle(const Vector2D& p1, const Vector2D& p2, const Vector2D& p3) const;
|
||||
Vector2D getComponentMax(const Vector2D& other) const;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@@ -7,13 +7,15 @@
|
||||
void handleWrapped(wl_listener* listener, void* data) {
|
||||
CHyprWLListener::SWrapper* pWrap = wl_container_of(listener, pWrap, m_sListener);
|
||||
|
||||
g_pWatchdog->startWatching();
|
||||
if (g_pWatchdog)
|
||||
g_pWatchdog->startWatching();
|
||||
|
||||
try {
|
||||
pWrap->m_pSelf->emit(data);
|
||||
} catch (std::exception& e) { Debug::log(ERR, "Listener {} timed out and was killed by Watchdog!!!", (uintptr_t)listener); }
|
||||
|
||||
g_pWatchdog->endWatching();
|
||||
if (g_pWatchdog)
|
||||
g_pWatchdog->endWatching();
|
||||
}
|
||||
|
||||
CHyprWLListener::CHyprWLListener(wl_signal* pSignal, std::function<void(void*, void*)> callback, void* pOwner) {
|
||||
|
@@ -28,8 +28,14 @@ class CWLSurface {
|
||||
bool m_bFillIgnoreSmall = false;
|
||||
|
||||
// if present, means this is a base surface of a window. Cleaned on unassign()
|
||||
CWindow* m_pOwner = nullptr;
|
||||
CWindow* m_pOwner = nullptr;
|
||||
|
||||
// track surface data and avoid dupes
|
||||
float m_fLastScale = 0;
|
||||
int m_iLastScale = 0;
|
||||
wl_output_transform m_eLastTransform = (wl_output_transform)-1;
|
||||
|
||||
//
|
||||
CWLSurface& operator=(wlr_surface* pSurface) {
|
||||
destroy();
|
||||
m_pWLRSurface = pSurface;
|
||||
|
@@ -22,13 +22,13 @@ void SDwindleNodeData::recalcSizePosRecursive(bool force, bool horizontalOverrid
|
||||
if (SPLITSIDE) {
|
||||
// split left/right
|
||||
const float FIRSTSIZE = box.w / 2.0 * splitRatio;
|
||||
children[0]->box = CBox{box.x, box.y, FIRSTSIZE, box.h};
|
||||
children[1]->box = CBox{box.x + FIRSTSIZE, box.y, box.w - FIRSTSIZE, box.h};
|
||||
children[0]->box = CBox{box.x, box.y, FIRSTSIZE, box.h}.noNegativeSize();
|
||||
children[1]->box = CBox{box.x + FIRSTSIZE, box.y, box.w - FIRSTSIZE, box.h}.noNegativeSize();
|
||||
} else {
|
||||
// split top/bottom
|
||||
const float FIRSTSIZE = box.h / 2.0 * splitRatio;
|
||||
children[0]->box = CBox{box.x, box.y, box.w, FIRSTSIZE};
|
||||
children[1]->box = CBox{box.x, box.y + FIRSTSIZE, box.w, box.h - FIRSTSIZE};
|
||||
children[0]->box = CBox{box.x, box.y, box.w, FIRSTSIZE}.noNegativeSize();
|
||||
children[1]->box = CBox{box.x, box.y + FIRSTSIZE, box.w, box.h - FIRSTSIZE}.noNegativeSize();
|
||||
}
|
||||
|
||||
children[0]->recalcSizePosRecursive(force);
|
||||
@@ -64,6 +64,21 @@ SDwindleNodeData* CHyprDwindleLayout::getFirstNodeOnWorkspace(const int& id) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SDwindleNodeData* CHyprDwindleLayout::getClosestNodeOnWorkspace(const int& id, const Vector2D& point) {
|
||||
SDwindleNodeData* res = nullptr;
|
||||
double distClosest = -1;
|
||||
for (auto& n : m_lDwindleNodesData) {
|
||||
if (n.workspaceID == id && n.pWindow && g_pCompositor->windowValidMapped(n.pWindow)) {
|
||||
auto distAnother = vecToRectDistanceSquared(point, n.box.pos(), n.box.pos() + n.box.size());
|
||||
if (!res || distAnother < distClosest) {
|
||||
res = &n;
|
||||
distClosest = distAnother;
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
SDwindleNodeData* CHyprDwindleLayout::getNodeFromWindow(CWindow* pWindow) {
|
||||
for (auto& n : m_lDwindleNodesData) {
|
||||
if (n.pWindow == pWindow && !n.isNode)
|
||||
@@ -254,26 +269,25 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
|
||||
|
||||
const auto MOUSECOORDS = m_vOverrideFocalPoint.value_or(g_pInputManager->getMouseCoordsInternal());
|
||||
const auto MONFROMCURSOR = g_pCompositor->getMonitorFromVector(MOUSECOORDS);
|
||||
const auto TARGETCOORDS = PMONITOR->ID == MONFROMCURSOR->ID && g_pCompositor->isPointOnReservedArea(MOUSECOORDS, PMONITOR) ? pWindow->middle() : MOUSECOORDS;
|
||||
|
||||
if (PMONITOR->ID == MONFROMCURSOR->ID &&
|
||||
(PNODE->workspaceID == PMONITOR->activeWorkspace || (g_pCompositor->isWorkspaceSpecial(PNODE->workspaceID) && PMONITOR->specialWorkspaceID)) && !*PUSEACTIVE) {
|
||||
OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowTiled(TARGETCOORDS));
|
||||
OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowUnified(MOUSECOORDS, RESERVED_EXTENTS | INPUT_EXTENTS));
|
||||
|
||||
// happens on reserved area
|
||||
if (!OPENINGON && g_pCompositor->getWindowsOnWorkspace(PNODE->workspaceID) > 0)
|
||||
OPENINGON = getFirstNodeOnWorkspace(PMONITOR->activeWorkspace);
|
||||
if (!OPENINGON && g_pCompositor->isPointOnReservedArea(MOUSECOORDS, PMONITOR))
|
||||
OPENINGON = getClosestNodeOnWorkspace(PNODE->workspaceID, MOUSECOORDS);
|
||||
|
||||
} else if (*PUSEACTIVE) {
|
||||
if (g_pCompositor->m_pLastWindow && !g_pCompositor->m_pLastWindow->m_bIsFloating && g_pCompositor->m_pLastWindow != pWindow &&
|
||||
g_pCompositor->m_pLastWindow->m_iWorkspaceID == pWindow->m_iWorkspaceID && g_pCompositor->m_pLastWindow->m_bIsMapped) {
|
||||
OPENINGON = getNodeFromWindow(g_pCompositor->m_pLastWindow);
|
||||
} else {
|
||||
OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowTiled(TARGETCOORDS));
|
||||
OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowUnified(MOUSECOORDS, RESERVED_EXTENTS | INPUT_EXTENTS));
|
||||
}
|
||||
|
||||
if (!OPENINGON && g_pCompositor->getWindowsOnWorkspace(PNODE->workspaceID) > 0)
|
||||
OPENINGON = getFirstNodeOnWorkspace(PMONITOR->activeWorkspace);
|
||||
if (!OPENINGON && g_pCompositor->isPointOnReservedArea(MOUSECOORDS, PMONITOR))
|
||||
OPENINGON = getClosestNodeOnWorkspace(PNODE->workspaceID, MOUSECOORDS);
|
||||
|
||||
} else
|
||||
OPENINGON = getFirstNodeOnWorkspace(pWindow->m_iWorkspaceID);
|
||||
|
||||
@@ -386,34 +400,41 @@ void CHyprDwindleLayout::onWindowCreatedTiling(CWindow* pWindow, eDirection dire
|
||||
if (*PERMANENTDIRECTIONOVERRIDE == 0)
|
||||
overrideDirection = DIRECTION_DEFAULT;
|
||||
} else if (*PSMARTSPLIT == 1) {
|
||||
const auto tl = NEWPARENT->box.pos();
|
||||
const auto tr = NEWPARENT->box.pos() + Vector2D(NEWPARENT->box.w, 0);
|
||||
const auto bl = NEWPARENT->box.pos() + Vector2D(0, NEWPARENT->box.h);
|
||||
const auto br = NEWPARENT->box.pos() + NEWPARENT->box.size();
|
||||
const auto cc = NEWPARENT->box.pos() + NEWPARENT->box.size() / 2;
|
||||
const auto PARENT_CENTER = NEWPARENT->box.pos() + NEWPARENT->box.size() / 2;
|
||||
const auto PARENT_PROPORTIONS = NEWPARENT->box.h / NEWPARENT->box.w;
|
||||
const auto DELTA = MOUSECOORDS - PARENT_CENTER;
|
||||
const auto DELTA_SLOPE = DELTA.y / DELTA.x;
|
||||
|
||||
if (TARGETCOORDS.inTriangle(tl, tr, cc)) {
|
||||
NEWPARENT->splitTop = true;
|
||||
NEWPARENT->children[0] = PNODE;
|
||||
NEWPARENT->children[1] = OPENINGON;
|
||||
} else if (TARGETCOORDS.inTriangle(tr, cc, br)) {
|
||||
NEWPARENT->splitTop = false;
|
||||
NEWPARENT->children[0] = OPENINGON;
|
||||
NEWPARENT->children[1] = PNODE;
|
||||
} else if (TARGETCOORDS.inTriangle(br, bl, cc)) {
|
||||
NEWPARENT->splitTop = true;
|
||||
NEWPARENT->children[0] = OPENINGON;
|
||||
NEWPARENT->children[1] = PNODE;
|
||||
if (abs(DELTA_SLOPE) < PARENT_PROPORTIONS) {
|
||||
if (DELTA.x > 0) {
|
||||
// right
|
||||
NEWPARENT->splitTop = false;
|
||||
NEWPARENT->children[0] = OPENINGON;
|
||||
NEWPARENT->children[1] = PNODE;
|
||||
} else {
|
||||
// left
|
||||
NEWPARENT->splitTop = false;
|
||||
NEWPARENT->children[0] = PNODE;
|
||||
NEWPARENT->children[1] = OPENINGON;
|
||||
}
|
||||
} else {
|
||||
NEWPARENT->splitTop = false;
|
||||
NEWPARENT->children[0] = PNODE;
|
||||
NEWPARENT->children[1] = OPENINGON;
|
||||
if (DELTA.y > 0) {
|
||||
// bottom
|
||||
NEWPARENT->splitTop = true;
|
||||
NEWPARENT->children[0] = OPENINGON;
|
||||
NEWPARENT->children[1] = PNODE;
|
||||
} else {
|
||||
// top
|
||||
NEWPARENT->splitTop = true;
|
||||
NEWPARENT->children[0] = PNODE;
|
||||
NEWPARENT->children[1] = OPENINGON;
|
||||
}
|
||||
}
|
||||
} else if (*PFORCESPLIT == 0 || !pWindow->m_bFirstMap) {
|
||||
if ((SIDEBYSIDE &&
|
||||
VECINRECT(TARGETCOORDS, NEWPARENT->box.x, NEWPARENT->box.y / *PWIDTHMULTIPLIER, NEWPARENT->box.x + NEWPARENT->box.w / 2.f, NEWPARENT->box.y + NEWPARENT->box.h)) ||
|
||||
VECINRECT(MOUSECOORDS, NEWPARENT->box.x, NEWPARENT->box.y / *PWIDTHMULTIPLIER, NEWPARENT->box.x + NEWPARENT->box.w / 2.f, NEWPARENT->box.y + NEWPARENT->box.h)) ||
|
||||
(!SIDEBYSIDE &&
|
||||
VECINRECT(TARGETCOORDS, NEWPARENT->box.x, NEWPARENT->box.y / *PWIDTHMULTIPLIER, NEWPARENT->box.x + NEWPARENT->box.w, NEWPARENT->box.y + NEWPARENT->box.h / 2.f))) {
|
||||
VECINRECT(MOUSECOORDS, NEWPARENT->box.x, NEWPARENT->box.y / *PWIDTHMULTIPLIER, NEWPARENT->box.x + NEWPARENT->box.w, NEWPARENT->box.y + NEWPARENT->box.h / 2.f))) {
|
||||
// we are hovering over the first node, make PNODE first.
|
||||
NEWPARENT->children[1] = OPENINGON;
|
||||
NEWPARENT->children[0] = PNODE;
|
||||
@@ -776,10 +797,21 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscree
|
||||
return;
|
||||
}
|
||||
|
||||
// save position and size if floating
|
||||
if (pWindow->m_bIsFloating && on) {
|
||||
pWindow->m_vLastFloatingSize = pWindow->m_vRealSize.goalv();
|
||||
pWindow->m_vLastFloatingPosition = pWindow->m_vRealPosition.goalv();
|
||||
pWindow->m_vPosition = pWindow->m_vRealPosition.goalv();
|
||||
pWindow->m_vSize = pWindow->m_vRealSize.goalv();
|
||||
}
|
||||
|
||||
// otherwise, accept it.
|
||||
pWindow->m_bIsFullscreen = on;
|
||||
PWORKSPACE->m_bHasFullscreenWindow = !PWORKSPACE->m_bHasFullscreenWindow;
|
||||
|
||||
pWindow->updateDynamicRules();
|
||||
pWindow->updateWindowDecos();
|
||||
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"fullscreen", std::to_string((int)on)});
|
||||
EMIT_HOOK_EVENT("fullscreen", pWindow);
|
||||
|
||||
@@ -800,14 +832,6 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscree
|
||||
|
||||
PWORKSPACE->m_efFullscreenMode = fullscreenMode;
|
||||
|
||||
// save position and size if floating
|
||||
if (pWindow->m_bIsFloating) {
|
||||
pWindow->m_vLastFloatingSize = pWindow->m_vRealSize.goalv();
|
||||
pWindow->m_vLastFloatingPosition = pWindow->m_vRealPosition.goalv();
|
||||
pWindow->m_vPosition = pWindow->m_vRealPosition.goalv();
|
||||
pWindow->m_vSize = pWindow->m_vRealSize.goalv();
|
||||
}
|
||||
|
||||
// apply new pos and size being monitors' box
|
||||
if (fullscreenMode == FULLSCREEN_FULL) {
|
||||
pWindow->m_vRealPosition = PMONITOR->vecPosition;
|
||||
@@ -824,7 +848,7 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscree
|
||||
pWindow->m_vPosition = fakeNode.box.pos();
|
||||
pWindow->m_vSize = fakeNode.box.size();
|
||||
|
||||
applyNodeDataToWindow(&fakeNode);
|
||||
applyNodeDataToWindow(&fakeNode, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -79,6 +79,7 @@ class CHyprDwindleLayout : public IHyprLayout {
|
||||
void applyNodeDataToWindow(SDwindleNodeData*, bool force = false);
|
||||
SDwindleNodeData* getNodeFromWindow(CWindow*);
|
||||
SDwindleNodeData* getFirstNodeOnWorkspace(const int&);
|
||||
SDwindleNodeData* getClosestNodeOnWorkspace(const int&, const Vector2D&);
|
||||
SDwindleNodeData* getMasterNodeOnWorkspace(const int&);
|
||||
|
||||
void toggleSplit(CWindow*);
|
||||
|
@@ -268,9 +268,9 @@ void IHyprLayout::onEndDragWindow() {
|
||||
} else if (g_pInputManager->dragMode == MBIND_MOVE) {
|
||||
g_pHyprRenderer->damageWindow(DRAGGINGWINDOW);
|
||||
const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal();
|
||||
CWindow* pWindow = g_pCompositor->vectorToWindowIdeal(MOUSECOORDS, DRAGGINGWINDOW);
|
||||
CWindow* pWindow = g_pCompositor->vectorToWindowUnified(MOUSECOORDS, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING | FLOATING_ONLY, DRAGGINGWINDOW);
|
||||
|
||||
if (pWindow && pWindow->m_bIsFloating) {
|
||||
if (pWindow) {
|
||||
if (pWindow->checkInputOnDecos(INPUT_TYPE_DRAG_END, MOUSECOORDS, DRAGGINGWINDOW))
|
||||
return;
|
||||
|
||||
@@ -314,8 +314,7 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) {
|
||||
|
||||
if ((abs(TICKDELTA.x) < 1.f && abs(TICKDELTA.y) < 1.f) ||
|
||||
(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - TIMER).count() <
|
||||
1000.0 / g_pHyprRenderer->m_pMostHzMonitor->refreshRate &&
|
||||
(*PANIMATEMOUSE || *PANIMATE)))
|
||||
1000.0 / g_pHyprRenderer->m_pMostHzMonitor->refreshRate))
|
||||
return;
|
||||
|
||||
TIMER = std::chrono::high_resolution_clock::now();
|
||||
@@ -469,16 +468,18 @@ void IHyprLayout::changeWindowFloatingMode(CWindow* pWindow) {
|
||||
|
||||
g_pCompositor->changeWindowZOrder(pWindow, true);
|
||||
|
||||
CBox wb = {pWindow->m_vRealPosition.goalv() + (pWindow->m_vRealSize.goalv() - pWindow->m_vLastFloatingSize) / 2.f, pWindow->m_vLastFloatingSize};
|
||||
wb.round();
|
||||
|
||||
if (DELTALESSTHAN(pWindow->m_vRealSize.vec().x, pWindow->m_vLastFloatingSize.x, 10) && DELTALESSTHAN(pWindow->m_vRealSize.vec().y, pWindow->m_vLastFloatingSize.y, 10)) {
|
||||
pWindow->m_vRealPosition = pWindow->m_vRealPosition.goalv() + (pWindow->m_vRealSize.goalv() - pWindow->m_vLastFloatingSize) / 2.f + Vector2D{10, 10};
|
||||
pWindow->m_vRealSize = pWindow->m_vLastFloatingSize - Vector2D{20, 20};
|
||||
wb = {wb.pos() + Vector2D{10, 10}, wb.size() - Vector2D{20, 20}};
|
||||
}
|
||||
|
||||
pWindow->m_vRealPosition = pWindow->m_vRealPosition.goalv() + (pWindow->m_vRealSize.goalv() - pWindow->m_vLastFloatingSize) / 2.f;
|
||||
pWindow->m_vRealSize = pWindow->m_vLastFloatingSize;
|
||||
pWindow->m_vRealPosition = wb.pos();
|
||||
pWindow->m_vRealSize = wb.size();
|
||||
|
||||
pWindow->m_vSize = pWindow->m_vRealSize.goalv();
|
||||
pWindow->m_vPosition = pWindow->m_vRealPosition.goalv();
|
||||
pWindow->m_vSize = wb.pos();
|
||||
pWindow->m_vPosition = wb.size();
|
||||
|
||||
g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID));
|
||||
|
||||
@@ -542,7 +543,8 @@ CWindow* IHyprLayout::getNextWindowCandidate(CWindow* pWindow) {
|
||||
return m_pLastTiledWindow;
|
||||
|
||||
// if we don't, let's try to find any window that is in the middle
|
||||
if (const auto PWINDOWCANDIDATE = g_pCompositor->vectorToWindowIdeal(pWindow->middle()); PWINDOWCANDIDATE && PWINDOWCANDIDATE != pWindow)
|
||||
if (const auto PWINDOWCANDIDATE = g_pCompositor->vectorToWindowUnified(pWindow->middle(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
|
||||
PWINDOWCANDIDATE && PWINDOWCANDIDATE != pWindow)
|
||||
return PWINDOWCANDIDATE;
|
||||
|
||||
// if not, floating window
|
||||
@@ -557,7 +559,7 @@ CWindow* IHyprLayout::getNextWindowCandidate(CWindow* pWindow) {
|
||||
}
|
||||
|
||||
// if it was a tiled window, we first try to find the window that will replace it.
|
||||
auto pWindowCandidate = g_pCompositor->vectorToWindowIdeal(pWindow->middle());
|
||||
auto pWindowCandidate = g_pCompositor->vectorToWindowUnified(pWindow->middle(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
|
||||
|
||||
if (!pWindowCandidate)
|
||||
pWindowCandidate = g_pCompositor->getTopLeftWindowOnWorkspace(pWindow->m_iWorkspaceID);
|
||||
|
@@ -879,10 +879,21 @@ void CHyprMasterLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreen
|
||||
return;
|
||||
}
|
||||
|
||||
// save position and size if floating
|
||||
if (pWindow->m_bIsFloating && on) {
|
||||
pWindow->m_vLastFloatingSize = pWindow->m_vRealSize.goalv();
|
||||
pWindow->m_vLastFloatingPosition = pWindow->m_vRealPosition.goalv();
|
||||
pWindow->m_vPosition = pWindow->m_vRealPosition.goalv();
|
||||
pWindow->m_vSize = pWindow->m_vRealSize.goalv();
|
||||
}
|
||||
|
||||
// otherwise, accept it.
|
||||
pWindow->m_bIsFullscreen = on;
|
||||
PWORKSPACE->m_bHasFullscreenWindow = !PWORKSPACE->m_bHasFullscreenWindow;
|
||||
|
||||
pWindow->updateDynamicRules();
|
||||
pWindow->updateWindowDecos();
|
||||
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"fullscreen", std::to_string((int)on)});
|
||||
EMIT_HOOK_EVENT("fullscreen", pWindow);
|
||||
|
||||
@@ -903,14 +914,6 @@ void CHyprMasterLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreen
|
||||
|
||||
PWORKSPACE->m_efFullscreenMode = fullscreenMode;
|
||||
|
||||
// save position and size if floating
|
||||
if (pWindow->m_bIsFloating) {
|
||||
pWindow->m_vLastFloatingSize = pWindow->m_vRealSize.goalv();
|
||||
pWindow->m_vLastFloatingPosition = pWindow->m_vRealPosition.goalv();
|
||||
pWindow->m_vPosition = pWindow->m_vRealPosition.goalv();
|
||||
pWindow->m_vSize = pWindow->m_vRealSize.goalv();
|
||||
}
|
||||
|
||||
// apply new pos and size being monitors' box
|
||||
if (fullscreenMode == FULLSCREEN_FULL) {
|
||||
pWindow->m_vRealPosition = PMONITOR->vecPosition;
|
||||
@@ -1328,7 +1331,13 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
|
||||
const auto PWINDOW = header.pWindow;
|
||||
const auto PNODE = getNodeFromWindow(PWINDOW);
|
||||
|
||||
const auto OLDMASTER = PNODE->isMaster ? PNODE : getMasterNodeOnWorkspace(PNODE->workspaceID);
|
||||
if (!PNODE)
|
||||
return 0;
|
||||
|
||||
const auto OLDMASTER = PNODE->isMaster ? PNODE : getMasterNodeOnWorkspace(PNODE->workspaceID);
|
||||
if (!OLDMASTER)
|
||||
return 0;
|
||||
|
||||
const auto OLDMASTERIT = std::find(m_lMasterNodesData.begin(), m_lMasterNodesData.end(), *OLDMASTER);
|
||||
|
||||
for (auto& nd : m_lMasterNodesData) {
|
||||
@@ -1350,7 +1359,13 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri
|
||||
const auto PWINDOW = header.pWindow;
|
||||
const auto PNODE = getNodeFromWindow(PWINDOW);
|
||||
|
||||
const auto OLDMASTER = PNODE->isMaster ? PNODE : getMasterNodeOnWorkspace(PNODE->workspaceID);
|
||||
if (!PNODE)
|
||||
return 0;
|
||||
|
||||
const auto OLDMASTER = PNODE->isMaster ? PNODE : getMasterNodeOnWorkspace(PNODE->workspaceID);
|
||||
if (!OLDMASTER)
|
||||
return 0;
|
||||
|
||||
const auto OLDMASTERIT = std::find(m_lMasterNodesData.begin(), m_lMasterNodesData.end(), *OLDMASTER);
|
||||
|
||||
for (auto& nd : m_lMasterNodesData | std::views::reverse) {
|
||||
|
@@ -85,7 +85,7 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
if (!ignoreSudo && Init::isSudo()) {
|
||||
std::cerr << "[ ERROR ] Hyprland was launched with superuser priveleges, but the privileges check is not omitted.\n";
|
||||
std::cerr << "[ ERROR ] Hyprland was launched with superuser privileges, but the privileges check is not omitted.\n";
|
||||
std::cerr << " Hint: Use the --i-am-really-stupid flag to omit that check.\n";
|
||||
|
||||
return 1;
|
||||
|
@@ -7,6 +7,7 @@
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <vector>
|
||||
#if defined(__linux__)
|
||||
#include <linux/vt.h>
|
||||
#elif defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
@@ -18,64 +19,65 @@
|
||||
CKeybindManager::CKeybindManager() {
|
||||
// initialize all dispatchers
|
||||
|
||||
m_mDispatchers["exec"] = spawn;
|
||||
m_mDispatchers["execr"] = spawnRaw;
|
||||
m_mDispatchers["killactive"] = killActive;
|
||||
m_mDispatchers["closewindow"] = kill;
|
||||
m_mDispatchers["togglefloating"] = toggleActiveFloating;
|
||||
m_mDispatchers["workspace"] = changeworkspace;
|
||||
m_mDispatchers["renameworkspace"] = renameWorkspace;
|
||||
m_mDispatchers["fullscreen"] = fullscreenActive;
|
||||
m_mDispatchers["fakefullscreen"] = fakeFullscreenActive;
|
||||
m_mDispatchers["movetoworkspace"] = moveActiveToWorkspace;
|
||||
m_mDispatchers["movetoworkspacesilent"] = moveActiveToWorkspaceSilent;
|
||||
m_mDispatchers["pseudo"] = toggleActivePseudo;
|
||||
m_mDispatchers["movefocus"] = moveFocusTo;
|
||||
m_mDispatchers["movewindow"] = moveActiveTo;
|
||||
m_mDispatchers["swapwindow"] = swapActive;
|
||||
m_mDispatchers["centerwindow"] = centerWindow;
|
||||
m_mDispatchers["togglegroup"] = toggleGroup;
|
||||
m_mDispatchers["changegroupactive"] = changeGroupActive;
|
||||
m_mDispatchers["movegroupwindow"] = moveGroupWindow;
|
||||
m_mDispatchers["togglesplit"] = toggleSplit;
|
||||
m_mDispatchers["splitratio"] = alterSplitRatio;
|
||||
m_mDispatchers["focusmonitor"] = focusMonitor;
|
||||
m_mDispatchers["movecursortocorner"] = moveCursorToCorner;
|
||||
m_mDispatchers["movecursor"] = moveCursor;
|
||||
m_mDispatchers["workspaceopt"] = workspaceOpt;
|
||||
m_mDispatchers["exit"] = exitHyprland;
|
||||
m_mDispatchers["movecurrentworkspacetomonitor"] = moveCurrentWorkspaceToMonitor;
|
||||
m_mDispatchers["moveworkspacetomonitor"] = moveWorkspaceToMonitor;
|
||||
m_mDispatchers["togglespecialworkspace"] = toggleSpecialWorkspace;
|
||||
m_mDispatchers["forcerendererreload"] = forceRendererReload;
|
||||
m_mDispatchers["resizeactive"] = resizeActive;
|
||||
m_mDispatchers["moveactive"] = moveActive;
|
||||
m_mDispatchers["cyclenext"] = circleNext;
|
||||
m_mDispatchers["focuswindowbyclass"] = focusWindow;
|
||||
m_mDispatchers["focuswindow"] = focusWindow;
|
||||
m_mDispatchers["submap"] = setSubmap;
|
||||
m_mDispatchers["pass"] = pass;
|
||||
m_mDispatchers["layoutmsg"] = layoutmsg;
|
||||
m_mDispatchers["toggleopaque"] = toggleOpaque;
|
||||
m_mDispatchers["dpms"] = dpms;
|
||||
m_mDispatchers["movewindowpixel"] = moveWindow;
|
||||
m_mDispatchers["resizewindowpixel"] = resizeWindow;
|
||||
m_mDispatchers["swapnext"] = swapnext;
|
||||
m_mDispatchers["swapactiveworkspaces"] = swapActiveWorkspaces;
|
||||
m_mDispatchers["pin"] = pinActive;
|
||||
m_mDispatchers["mouse"] = mouse;
|
||||
m_mDispatchers["bringactivetotop"] = bringActiveToTop;
|
||||
m_mDispatchers["alterzorder"] = alterZOrder;
|
||||
m_mDispatchers["focusurgentorlast"] = focusUrgentOrLast;
|
||||
m_mDispatchers["focuscurrentorlast"] = focusCurrentOrLast;
|
||||
m_mDispatchers["lockgroups"] = lockGroups;
|
||||
m_mDispatchers["lockactivegroup"] = lockActiveGroup;
|
||||
m_mDispatchers["moveintogroup"] = moveIntoGroup;
|
||||
m_mDispatchers["moveoutofgroup"] = moveOutOfGroup;
|
||||
m_mDispatchers["movewindoworgroup"] = moveWindowOrGroup;
|
||||
m_mDispatchers["setignoregrouplock"] = setIgnoreGroupLock;
|
||||
m_mDispatchers["denywindowfromgroup"] = denyWindowFromGroup;
|
||||
m_mDispatchers["global"] = global;
|
||||
m_mDispatchers["exec"] = spawn;
|
||||
m_mDispatchers["execr"] = spawnRaw;
|
||||
m_mDispatchers["killactive"] = killActive;
|
||||
m_mDispatchers["closewindow"] = kill;
|
||||
m_mDispatchers["togglefloating"] = toggleActiveFloating;
|
||||
m_mDispatchers["workspace"] = changeworkspace;
|
||||
m_mDispatchers["renameworkspace"] = renameWorkspace;
|
||||
m_mDispatchers["fullscreen"] = fullscreenActive;
|
||||
m_mDispatchers["fakefullscreen"] = fakeFullscreenActive;
|
||||
m_mDispatchers["movetoworkspace"] = moveActiveToWorkspace;
|
||||
m_mDispatchers["movetoworkspacesilent"] = moveActiveToWorkspaceSilent;
|
||||
m_mDispatchers["pseudo"] = toggleActivePseudo;
|
||||
m_mDispatchers["movefocus"] = moveFocusTo;
|
||||
m_mDispatchers["movewindow"] = moveActiveTo;
|
||||
m_mDispatchers["swapwindow"] = swapActive;
|
||||
m_mDispatchers["centerwindow"] = centerWindow;
|
||||
m_mDispatchers["togglegroup"] = toggleGroup;
|
||||
m_mDispatchers["changegroupactive"] = changeGroupActive;
|
||||
m_mDispatchers["movegroupwindow"] = moveGroupWindow;
|
||||
m_mDispatchers["togglesplit"] = toggleSplit;
|
||||
m_mDispatchers["splitratio"] = alterSplitRatio;
|
||||
m_mDispatchers["focusmonitor"] = focusMonitor;
|
||||
m_mDispatchers["movecursortocorner"] = moveCursorToCorner;
|
||||
m_mDispatchers["movecursor"] = moveCursor;
|
||||
m_mDispatchers["workspaceopt"] = workspaceOpt;
|
||||
m_mDispatchers["exit"] = exitHyprland;
|
||||
m_mDispatchers["movecurrentworkspacetomonitor"] = moveCurrentWorkspaceToMonitor;
|
||||
m_mDispatchers["focusworkspaceoncurrentmonitor"] = focusWorkspaceOnCurrentMonitor;
|
||||
m_mDispatchers["moveworkspacetomonitor"] = moveWorkspaceToMonitor;
|
||||
m_mDispatchers["togglespecialworkspace"] = toggleSpecialWorkspace;
|
||||
m_mDispatchers["forcerendererreload"] = forceRendererReload;
|
||||
m_mDispatchers["resizeactive"] = resizeActive;
|
||||
m_mDispatchers["moveactive"] = moveActive;
|
||||
m_mDispatchers["cyclenext"] = circleNext;
|
||||
m_mDispatchers["focuswindowbyclass"] = focusWindow;
|
||||
m_mDispatchers["focuswindow"] = focusWindow;
|
||||
m_mDispatchers["submap"] = setSubmap;
|
||||
m_mDispatchers["pass"] = pass;
|
||||
m_mDispatchers["layoutmsg"] = layoutmsg;
|
||||
m_mDispatchers["toggleopaque"] = toggleOpaque;
|
||||
m_mDispatchers["dpms"] = dpms;
|
||||
m_mDispatchers["movewindowpixel"] = moveWindow;
|
||||
m_mDispatchers["resizewindowpixel"] = resizeWindow;
|
||||
m_mDispatchers["swapnext"] = swapnext;
|
||||
m_mDispatchers["swapactiveworkspaces"] = swapActiveWorkspaces;
|
||||
m_mDispatchers["pin"] = pinActive;
|
||||
m_mDispatchers["mouse"] = mouse;
|
||||
m_mDispatchers["bringactivetotop"] = bringActiveToTop;
|
||||
m_mDispatchers["alterzorder"] = alterZOrder;
|
||||
m_mDispatchers["focusurgentorlast"] = focusUrgentOrLast;
|
||||
m_mDispatchers["focuscurrentorlast"] = focusCurrentOrLast;
|
||||
m_mDispatchers["lockgroups"] = lockGroups;
|
||||
m_mDispatchers["lockactivegroup"] = lockActiveGroup;
|
||||
m_mDispatchers["moveintogroup"] = moveIntoGroup;
|
||||
m_mDispatchers["moveoutofgroup"] = moveOutOfGroup;
|
||||
m_mDispatchers["movewindoworgroup"] = moveWindowOrGroup;
|
||||
m_mDispatchers["setignoregrouplock"] = setIgnoreGroupLock;
|
||||
m_mDispatchers["denywindowfromgroup"] = denyWindowFromGroup;
|
||||
m_mDispatchers["global"] = global;
|
||||
|
||||
m_tScrollTimer.reset();
|
||||
|
||||
@@ -95,7 +97,7 @@ void CKeybindManager::addKeybind(SKeybind kb) {
|
||||
void CKeybindManager::removeKeybind(uint32_t mod, const std::string& key) {
|
||||
for (auto it = m_lKeybinds.begin(); it != m_lKeybinds.end(); ++it) {
|
||||
if (isNumber(key) && std::stoi(key) > 9) {
|
||||
const auto KEYNUM = std::stoi(key);
|
||||
const uint32_t KEYNUM = std::stoi(key);
|
||||
|
||||
if (it->modmask == mod && it->keycode == KEYNUM) {
|
||||
it = m_lKeybinds.erase(it);
|
||||
@@ -137,6 +139,22 @@ uint32_t CKeybindManager::stringToModMask(std::string mods) {
|
||||
return modMask;
|
||||
}
|
||||
|
||||
uint32_t CKeybindManager::keycodeToModifier(xkb_keycode_t keycode) {
|
||||
switch (keycode - 8) {
|
||||
case KEY_LEFTMETA: return WLR_MODIFIER_LOGO;
|
||||
case KEY_RIGHTMETA: return WLR_MODIFIER_LOGO;
|
||||
case KEY_LEFTSHIFT: return WLR_MODIFIER_SHIFT;
|
||||
case KEY_RIGHTSHIFT: return WLR_MODIFIER_SHIFT;
|
||||
case KEY_LEFTCTRL: return WLR_MODIFIER_CTRL;
|
||||
case KEY_RIGHTCTRL: return WLR_MODIFIER_CTRL;
|
||||
case KEY_LEFTALT: return WLR_MODIFIER_ALT;
|
||||
case KEY_RIGHTALT: return WLR_MODIFIER_ALT;
|
||||
case KEY_CAPSLOCK: return WLR_MODIFIER_CAPS;
|
||||
case KEY_NUMLOCK: return WLR_MODIFIER_MOD2;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void CKeybindManager::updateXKBTranslationState() {
|
||||
if (m_pXKBTranslationState) {
|
||||
xkb_keymap_unref(xkb_state_get_keymap(m_pXKBTranslationState));
|
||||
@@ -261,8 +279,7 @@ void CKeybindManager::switchToWindow(CWindow* PWINDOWTOCHANGETO) {
|
||||
|
||||
bool CKeybindManager::onKeyEvent(wlr_keyboard_key_event* e, SKeyboard* pKeyboard) {
|
||||
if (!g_pCompositor->m_bSessionActive || g_pCompositor->m_bUnsafeState) {
|
||||
m_dPressedKeycodes.clear();
|
||||
m_dPressedKeysyms.clear();
|
||||
m_dPressedKeys.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -291,9 +308,16 @@ bool CKeybindManager::onKeyEvent(wlr_keyboard_key_event* e, SKeyboard* pKeyboard
|
||||
m_uLastCode = KEYCODE;
|
||||
m_uLastMouseCode = 0;
|
||||
|
||||
bool mouseBindWasActive = ensureMouseBindState();
|
||||
bool mouseBindWasActive = ensureMouseBindState();
|
||||
|
||||
bool found = false;
|
||||
const auto KEY = SPressedKeyWithMods{
|
||||
.keysym = keysym,
|
||||
.keycode = KEYCODE,
|
||||
.modmaskAtPressTime = MODS,
|
||||
.sent = true,
|
||||
};
|
||||
|
||||
bool suppressEvent = false;
|
||||
if (e->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
||||
// clean repeat
|
||||
if (m_pActiveKeybindEventSource) {
|
||||
@@ -302,16 +326,15 @@ bool CKeybindManager::onKeyEvent(wlr_keyboard_key_event* e, SKeyboard* pKeyboard
|
||||
m_pActiveKeybind = nullptr;
|
||||
}
|
||||
|
||||
m_dPressedKeycodes.push_back(KEYCODE);
|
||||
m_dPressedKeysyms.push_back(keysym);
|
||||
m_dPressedKeys.push_back(KEY);
|
||||
|
||||
found = handleKeybinds(MODS, "", keysym, 0, true, e->time_msec) || found;
|
||||
suppressEvent = handleKeybinds(MODS, KEY, true);
|
||||
|
||||
found = handleKeybinds(MODS, "", 0, KEYCODE, true, e->time_msec) || found;
|
||||
|
||||
if (found)
|
||||
if (suppressEvent)
|
||||
shadowKeybinds(keysym, KEYCODE);
|
||||
} else if (e->state == WL_KEYBOARD_KEY_STATE_RELEASED) {
|
||||
|
||||
m_dPressedKeys.back().sent = !suppressEvent;
|
||||
} else { // key release
|
||||
// clean repeat
|
||||
if (m_pActiveKeybindEventSource) {
|
||||
wl_event_source_remove(m_pActiveKeybindEventSource);
|
||||
@@ -319,17 +342,27 @@ bool CKeybindManager::onKeyEvent(wlr_keyboard_key_event* e, SKeyboard* pKeyboard
|
||||
m_pActiveKeybind = nullptr;
|
||||
}
|
||||
|
||||
m_dPressedKeycodes.erase(std::remove(m_dPressedKeycodes.begin(), m_dPressedKeycodes.end(), KEYCODE), m_dPressedKeycodes.end());
|
||||
m_dPressedKeysyms.erase(std::remove(m_dPressedKeysyms.begin(), m_dPressedKeysyms.end(), keysym), m_dPressedKeysyms.end());
|
||||
|
||||
found = handleKeybinds(MODS, "", keysym, 0, false, e->time_msec) || found;
|
||||
|
||||
found = handleKeybinds(MODS, "", 0, KEYCODE, false, e->time_msec) || found;
|
||||
bool foundInPressedKeys = false;
|
||||
for (auto it = m_dPressedKeys.begin(); it != m_dPressedKeys.end();) {
|
||||
if (it->keycode == KEYCODE) {
|
||||
suppressEvent = handleKeybinds(MODS, *it, false);
|
||||
foundInPressedKeys = true;
|
||||
suppressEvent = !it->sent;
|
||||
it = m_dPressedKeys.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
if (!foundInPressedKeys) {
|
||||
Debug::log(ERR, "BUG THIS: key not found in m_dPressedKeys");
|
||||
// fallback with wrong `KEY.modmaskAtPressTime`, this can be buggy
|
||||
suppressEvent = handleKeybinds(MODS, KEY, false);
|
||||
}
|
||||
|
||||
shadowKeybinds();
|
||||
}
|
||||
|
||||
return !found && !mouseBindWasActive;
|
||||
return !suppressEvent && !mouseBindWasActive;
|
||||
}
|
||||
|
||||
bool CKeybindManager::onAxisEvent(wlr_pointer_axis_event* e) {
|
||||
@@ -347,14 +380,14 @@ bool CKeybindManager::onAxisEvent(wlr_pointer_axis_event* e) {
|
||||
bool found = false;
|
||||
if (e->source == WLR_AXIS_SOURCE_WHEEL && e->orientation == WLR_AXIS_ORIENTATION_VERTICAL) {
|
||||
if (e->delta < 0)
|
||||
found = handleKeybinds(MODS, "mouse_down", 0, 0, true, 0);
|
||||
found = handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_down"}, true);
|
||||
else
|
||||
found = handleKeybinds(MODS, "mouse_up", 0, 0, true, 0);
|
||||
found = handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_up"}, true);
|
||||
} else if (e->source == WLR_AXIS_SOURCE_WHEEL && e->orientation == WLR_AXIS_ORIENTATION_HORIZONTAL) {
|
||||
if (e->delta < 0)
|
||||
found = handleKeybinds(MODS, "mouse_left", 0, 0, true, 0);
|
||||
found = handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_left"}, true);
|
||||
else
|
||||
found = handleKeybinds(MODS, "mouse_right", 0, 0, true, 0);
|
||||
found = handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_right"}, true);
|
||||
}
|
||||
|
||||
if (found)
|
||||
@@ -366,26 +399,52 @@ bool CKeybindManager::onAxisEvent(wlr_pointer_axis_event* e) {
|
||||
bool CKeybindManager::onMouseEvent(wlr_pointer_button_event* e) {
|
||||
const auto MODS = g_pInputManager->accumulateModsFromAllKBs();
|
||||
|
||||
bool found = false;
|
||||
bool suppressEvent = false;
|
||||
|
||||
m_uLastMouseCode = e->button;
|
||||
m_uLastCode = 0;
|
||||
m_uTimeLastMs = e->time_msec;
|
||||
|
||||
bool mouseBindWasActive = ensureMouseBindState();
|
||||
bool mouseBindWasActive = ensureMouseBindState();
|
||||
|
||||
const auto KEY_NAME = "mouse:" + std::to_string(e->button);
|
||||
|
||||
const auto KEY = SPressedKeyWithMods{
|
||||
.keyName = KEY_NAME,
|
||||
.modmaskAtPressTime = MODS,
|
||||
};
|
||||
|
||||
if (e->state == WLR_BUTTON_PRESSED) {
|
||||
found = handleKeybinds(MODS, "mouse:" + std::to_string(e->button), 0, 0, true, 0);
|
||||
m_dPressedKeys.push_back(KEY);
|
||||
|
||||
if (found)
|
||||
suppressEvent = handleKeybinds(MODS, KEY, true);
|
||||
|
||||
if (suppressEvent)
|
||||
shadowKeybinds();
|
||||
|
||||
m_dPressedKeys.back().sent = !suppressEvent;
|
||||
} else {
|
||||
found = handleKeybinds(MODS, "mouse:" + std::to_string(e->button), 0, 0, false, 0);
|
||||
bool foundInPressedKeys = false;
|
||||
for (auto it = m_dPressedKeys.begin(); it != m_dPressedKeys.end();) {
|
||||
if (it->keyName == KEY_NAME) {
|
||||
suppressEvent = handleKeybinds(MODS, *it, false);
|
||||
foundInPressedKeys = true;
|
||||
suppressEvent = !it->sent;
|
||||
it = m_dPressedKeys.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
if (!foundInPressedKeys) {
|
||||
Debug::log(ERR, "BUG THIS: key not found in m_dPressedKeys (2)");
|
||||
// fallback with wrong `KEY.modmaskAtPressTime`, this can be buggy
|
||||
suppressEvent = handleKeybinds(MODS, KEY, false);
|
||||
}
|
||||
|
||||
shadowKeybinds();
|
||||
}
|
||||
|
||||
return !found && !mouseBindWasActive;
|
||||
return !suppressEvent && !mouseBindWasActive;
|
||||
}
|
||||
|
||||
void CKeybindManager::resizeWithBorder(wlr_pointer_button_event* e) {
|
||||
@@ -397,15 +456,15 @@ void CKeybindManager::resizeWithBorder(wlr_pointer_button_event* e) {
|
||||
}
|
||||
|
||||
void CKeybindManager::onSwitchEvent(const std::string& switchName) {
|
||||
handleKeybinds(0, "switch:" + switchName, 0, 0, true, 0);
|
||||
handleKeybinds(0, SPressedKeyWithMods{.keyName = "switch:" + switchName}, true);
|
||||
}
|
||||
|
||||
void CKeybindManager::onSwitchOnEvent(const std::string& switchName) {
|
||||
handleKeybinds(0, "switch:on:" + switchName, 0, 0, true, 0);
|
||||
handleKeybinds(0, SPressedKeyWithMods{.keyName = "switch:on:" + switchName}, true);
|
||||
}
|
||||
|
||||
void CKeybindManager::onSwitchOffEvent(const std::string& switchName) {
|
||||
handleKeybinds(0, "switch:off:" + switchName, 0, 0, true, 0);
|
||||
handleKeybinds(0, SPressedKeyWithMods{.keyName = "switch:off:" + switchName}, true);
|
||||
}
|
||||
|
||||
int repeatKeyHandler(void* data) {
|
||||
@@ -424,7 +483,7 @@ int repeatKeyHandler(void* data) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool CKeybindManager::handleKeybinds(const uint32_t& modmask, const std::string& key, const xkb_keysym_t& keysym, const int& keycode, bool pressed, uint32_t time) {
|
||||
bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWithMods& key, bool pressed) {
|
||||
bool found = false;
|
||||
|
||||
if (g_pCompositor->m_sSeat.exclusiveClient)
|
||||
@@ -441,22 +500,19 @@ bool CKeybindManager::handleKeybinds(const uint32_t& modmask, const std::string&
|
||||
((modmask != k.modmask && !k.ignoreMods) || (g_pCompositor->m_sSeat.exclusiveClient && !k.locked) || k.submap != m_szCurrentSelectedSubmap || k.shadowed))
|
||||
continue;
|
||||
|
||||
if (!key.empty()) {
|
||||
if (key != k.key)
|
||||
if (!key.keyName.empty()) {
|
||||
if (key.keyName != k.key)
|
||||
continue;
|
||||
} else if (k.keycode != -1) {
|
||||
if (keycode != k.keycode)
|
||||
} else if (k.keycode != 0) {
|
||||
if (key.keycode != k.keycode)
|
||||
continue;
|
||||
} else {
|
||||
if (keysym == 0)
|
||||
continue; // this is a keycode check run
|
||||
|
||||
// oMg such performance hit!!11!
|
||||
// this little maneouver is gonna cost us 4µs
|
||||
const auto KBKEY = xkb_keysym_from_name(k.key.c_str(), XKB_KEYSYM_CASE_INSENSITIVE);
|
||||
const auto KBKEYUPPER = xkb_keysym_to_upper(KBKEY);
|
||||
|
||||
if (keysym != KBKEY && keysym != KBKEYUPPER)
|
||||
if (key.keysym != KBKEY && key.keysym != KBKEYUPPER)
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -468,12 +524,24 @@ bool CKeybindManager::handleKeybinds(const uint32_t& modmask, const std::string&
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!pressed && !k.release && !SPECIALDISPATCHER) {
|
||||
if (k.nonConsuming)
|
||||
continue;
|
||||
if (!pressed) {
|
||||
// Require mods to be matching when the key was first pressed.
|
||||
if (key.modmaskAtPressTime != modmask && !k.ignoreMods) {
|
||||
// Handle properly `bindr` where a key is itself a bind mod for example:
|
||||
// "bindr = SUPER, SUPER_L, exec, $launcher".
|
||||
// This needs to be handled separately for the above case, because `key.modmaskAtPressTime` is set
|
||||
// from currently pressed keys as programs see them, but it doesn't yet include the currently
|
||||
// pressed mod key, which is still being handled internally.
|
||||
if (keycodeToModifier(key.keycode) == key.modmaskAtPressTime)
|
||||
continue;
|
||||
|
||||
found = true; // suppress the event
|
||||
continue;
|
||||
} else if (!k.release && !SPECIALDISPATCHER) {
|
||||
if (k.nonConsuming)
|
||||
continue;
|
||||
|
||||
found = true; // suppress the event
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
const auto DISPATCHER = m_mDispatchers.find(k.mouse ? "mouse" : k.handler);
|
||||
@@ -488,7 +556,7 @@ bool CKeybindManager::handleKeybinds(const uint32_t& modmask, const std::string&
|
||||
Debug::log(ERR, "Invalid handler in a keybind! (handler {} does not exist)", k.handler);
|
||||
} else {
|
||||
// call the dispatcher
|
||||
Debug::log(LOG, "Keybind triggered, calling dispatcher ({}, {}, {})", modmask, key, keysym);
|
||||
Debug::log(LOG, "Keybind triggered, calling dispatcher ({}, {}, {})", modmask, key.keyName, key.keysym);
|
||||
|
||||
m_iPassPressed = (int)pressed;
|
||||
|
||||
@@ -521,7 +589,7 @@ bool CKeybindManager::handleKeybinds(const uint32_t& modmask, const std::string&
|
||||
return found;
|
||||
}
|
||||
|
||||
void CKeybindManager::shadowKeybinds(const xkb_keysym_t& doesntHave, const int& doesntHaveCode) {
|
||||
void CKeybindManager::shadowKeybinds(const xkb_keysym_t& doesntHave, const uint32_t doesntHaveCode) {
|
||||
// shadow disables keybinds after one has been triggered
|
||||
|
||||
for (auto& k : m_lKeybinds) {
|
||||
@@ -534,22 +602,20 @@ void CKeybindManager::shadowKeybinds(const xkb_keysym_t& doesntHave, const int&
|
||||
const auto KBKEY = xkb_keysym_from_name(k.key.c_str(), XKB_KEYSYM_CASE_INSENSITIVE);
|
||||
const auto KBKEYUPPER = xkb_keysym_to_upper(KBKEY);
|
||||
|
||||
for (auto& pk : m_dPressedKeysyms) {
|
||||
if ((pk == KBKEY || pk == KBKEYUPPER)) {
|
||||
for (auto& pk : m_dPressedKeys) {
|
||||
if ((pk.keysym != 0 && (pk.keysym == KBKEY || pk.keysym == KBKEYUPPER))) {
|
||||
shadow = true;
|
||||
|
||||
if (pk == doesntHave && doesntHave != 0) {
|
||||
if (pk.keysym == doesntHave && doesntHave != 0) {
|
||||
shadow = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& pk : m_dPressedKeycodes) {
|
||||
if (pk == k.keycode) {
|
||||
if (pk.keycode != 0 && pk.keycode == k.keycode) {
|
||||
shadow = true;
|
||||
|
||||
if (pk == doesntHaveCode && doesntHaveCode != 0 && doesntHaveCode != -1) {
|
||||
if (pk.keycode == doesntHaveCode && doesntHaveCode != 0) {
|
||||
shadow = false;
|
||||
break;
|
||||
}
|
||||
@@ -1000,10 +1066,12 @@ void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) {
|
||||
g_pCompositor->moveWindowToWorkspaceSafe(PWINDOW, pWorkspace);
|
||||
}
|
||||
|
||||
if (const auto PATCOORDS = g_pCompositor->vectorToWindowIdeal(OLDMIDDLE); PATCOORDS && PATCOORDS != PWINDOW)
|
||||
g_pCompositor->focusWindow(PATCOORDS);
|
||||
else
|
||||
g_pInputManager->refocus();
|
||||
if (PWINDOW == g_pCompositor->m_pLastWindow) {
|
||||
if (const auto PATCOORDS = g_pCompositor->vectorToWindowUnified(OLDMIDDLE, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING, PWINDOW); PATCOORDS)
|
||||
g_pCompositor->focusWindow(PATCOORDS);
|
||||
else
|
||||
g_pInputManager->refocus();
|
||||
}
|
||||
}
|
||||
|
||||
void CKeybindManager::moveFocusTo(std::string args) {
|
||||
@@ -1385,7 +1453,7 @@ void CKeybindManager::renameWorkspace(std::string args) {
|
||||
}
|
||||
|
||||
void CKeybindManager::exitHyprland(std::string argz) {
|
||||
g_pCompositor->cleanup();
|
||||
g_pInputManager->m_bExitTriggered = true;
|
||||
}
|
||||
|
||||
void CKeybindManager::moveCurrentWorkspaceToMonitor(std::string args) {
|
||||
@@ -1435,6 +1503,48 @@ void CKeybindManager::moveWorkspaceToMonitor(std::string args) {
|
||||
g_pCompositor->moveWorkspaceToMonitor(PWORKSPACE, PMONITOR);
|
||||
}
|
||||
|
||||
void CKeybindManager::focusWorkspaceOnCurrentMonitor(std::string args) {
|
||||
std::string workspaceName;
|
||||
const int WORKSPACEID = getWorkspaceIDFromString(args, workspaceName);
|
||||
|
||||
if (WORKSPACEID == WORKSPACE_INVALID) {
|
||||
Debug::log(ERR, "focusWorkspaceOnCurrentMonitor invalid workspace!");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto PCURRMONITOR = g_pCompositor->getMonitorFromCursor();
|
||||
|
||||
if (!PCURRMONITOR) {
|
||||
Debug::log(ERR, "focusWorkspaceOnCurrentMonitor monitor doesn't exist!");
|
||||
return;
|
||||
}
|
||||
|
||||
auto PWORKSPACE = g_pCompositor->getWorkspaceByID(WORKSPACEID);
|
||||
|
||||
if (!PWORKSPACE) {
|
||||
PWORKSPACE = g_pCompositor->createNewWorkspace(WORKSPACEID, PCURRMONITOR->ID);
|
||||
// we can skip the moving, since it's already on the current monitor
|
||||
changeworkspace(PWORKSPACE->getConfigName());
|
||||
return;
|
||||
}
|
||||
|
||||
if (PWORKSPACE->m_iMonitorID != PCURRMONITOR->ID) {
|
||||
const auto POLDMONITOR = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID);
|
||||
if (!POLDMONITOR) { // wat
|
||||
Debug::log(ERR, "focusWorkspaceOnCurrentMonitor old monitor doesn't exist!");
|
||||
return;
|
||||
}
|
||||
if (POLDMONITOR->activeWorkspace == WORKSPACEID) {
|
||||
g_pCompositor->swapActiveWorkspaces(POLDMONITOR, PCURRMONITOR);
|
||||
return;
|
||||
} else {
|
||||
g_pCompositor->moveWorkspaceToMonitor(PWORKSPACE, PCURRMONITOR, true);
|
||||
}
|
||||
}
|
||||
|
||||
changeworkspace(PWORKSPACE->getConfigName());
|
||||
}
|
||||
|
||||
void CKeybindManager::toggleSpecialWorkspace(std::string args) {
|
||||
|
||||
static auto* const PFOLLOWMOUSE = &g_pConfigManager->getConfigValuePtr("input:follow_mouse")->intValue;
|
||||
@@ -1742,11 +1852,11 @@ void CKeybindManager::dpms(std::string arg) {
|
||||
if (!port.empty() && m->szName != port)
|
||||
continue;
|
||||
|
||||
wlr_output_enable(m->output, enable);
|
||||
wlr_output_state_set_enabled(m->state.wlr(), enable);
|
||||
|
||||
m->dpmsStatus = enable;
|
||||
|
||||
if (!wlr_output_commit(m->output)) {
|
||||
if (!m->state.commit()) {
|
||||
Debug::log(ERR, "Couldn't commit output {}", m->szName);
|
||||
}
|
||||
|
||||
@@ -1829,7 +1939,7 @@ void CKeybindManager::pinActive(std::string args) {
|
||||
|
||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(PWINDOW->m_iWorkspaceID);
|
||||
|
||||
PWORKSPACE->m_pLastFocusedWindow = g_pCompositor->vectorToWindowTiled(g_pInputManager->getMouseCoordsInternal());
|
||||
PWORKSPACE->m_pLastFocusedWindow = g_pCompositor->vectorToWindowUnified(g_pInputManager->getMouseCoordsInternal(), RESERVED_EXTENTS | INPUT_EXTENTS);
|
||||
}
|
||||
|
||||
void CKeybindManager::mouse(std::string args) {
|
||||
@@ -1841,7 +1951,7 @@ void CKeybindManager::mouse(std::string args) {
|
||||
g_pKeybindManager->m_bIsMouseBindActive = true;
|
||||
|
||||
const auto mouseCoords = g_pInputManager->getMouseCoordsInternal();
|
||||
CWindow* pWindow = g_pCompositor->vectorToWindowIdeal(mouseCoords);
|
||||
CWindow* pWindow = g_pCompositor->vectorToWindowUnified(mouseCoords, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
|
||||
|
||||
if (pWindow && !pWindow->m_bIsFullscreen)
|
||||
pWindow->checkInputOnDecos(INPUT_TYPE_DRAG_START, mouseCoords);
|
||||
@@ -1864,7 +1974,8 @@ void CKeybindManager::mouse(std::string args) {
|
||||
if (PRESSED) {
|
||||
g_pKeybindManager->m_bIsMouseBindActive = true;
|
||||
|
||||
g_pInputManager->currentlyDraggedWindow = g_pCompositor->vectorToWindowIdeal(g_pInputManager->getMouseCoordsInternal());
|
||||
g_pInputManager->currentlyDraggedWindow =
|
||||
g_pCompositor->vectorToWindowUnified(g_pInputManager->getMouseCoordsInternal(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
|
||||
|
||||
try {
|
||||
switch (std::stoi(ARGS[1])) {
|
||||
|
@@ -12,7 +12,7 @@ class CPluginSystem;
|
||||
|
||||
struct SKeybind {
|
||||
std::string key = "";
|
||||
int keycode = -1;
|
||||
uint32_t keycode = 0;
|
||||
uint32_t modmask = 0;
|
||||
std::string handler = "";
|
||||
std::string arg = "";
|
||||
@@ -36,6 +36,14 @@ enum eFocusWindowMode {
|
||||
MODE_PID
|
||||
};
|
||||
|
||||
struct SPressedKeyWithMods {
|
||||
std::string keyName = "";
|
||||
xkb_keysym_t keysym = 0;
|
||||
uint32_t keycode = 0;
|
||||
uint32_t modmaskAtPressTime = 0;
|
||||
bool sent = false;
|
||||
};
|
||||
|
||||
class CKeybindManager {
|
||||
public:
|
||||
CKeybindManager();
|
||||
@@ -51,8 +59,9 @@ class CKeybindManager {
|
||||
void addKeybind(SKeybind);
|
||||
void removeKeybind(uint32_t, const std::string&);
|
||||
uint32_t stringToModMask(std::string);
|
||||
uint32_t keycodeToModifier(xkb_keycode_t);
|
||||
void clearKeybinds();
|
||||
void shadowKeybinds(const xkb_keysym_t& doesntHave = 0, const int& doesntHaveCode = 0);
|
||||
void shadowKeybinds(const xkb_keysym_t& doesntHave = 0, const uint32_t doesntHaveCode = 0);
|
||||
|
||||
std::unordered_map<std::string, std::function<void(std::string)>> m_mDispatchers;
|
||||
|
||||
@@ -63,38 +72,37 @@ class CKeybindManager {
|
||||
std::list<SKeybind> m_lKeybinds;
|
||||
|
||||
private:
|
||||
std::deque<xkb_keysym_t> m_dPressedKeysyms;
|
||||
std::deque<int> m_dPressedKeycodes;
|
||||
std::deque<SPressedKeyWithMods> m_dPressedKeys;
|
||||
|
||||
inline static std::string m_szCurrentSelectedSubmap = "";
|
||||
inline static std::string m_szCurrentSelectedSubmap = "";
|
||||
|
||||
SKeybind* m_pActiveKeybind = nullptr;
|
||||
SKeybind* m_pActiveKeybind = nullptr;
|
||||
|
||||
uint32_t m_uTimeLastMs = 0;
|
||||
uint32_t m_uLastCode = 0;
|
||||
uint32_t m_uLastMouseCode = 0;
|
||||
uint32_t m_uTimeLastMs = 0;
|
||||
uint32_t m_uLastCode = 0;
|
||||
uint32_t m_uLastMouseCode = 0;
|
||||
|
||||
bool m_bIsMouseBindActive = false;
|
||||
std::vector<SKeybind*> m_vPressedSpecialBinds;
|
||||
bool m_bIsMouseBindActive = false;
|
||||
std::vector<SKeybind*> m_vPressedSpecialBinds;
|
||||
|
||||
int m_iPassPressed = -1; // used for pass
|
||||
int m_iPassPressed = -1; // used for pass
|
||||
|
||||
CTimer m_tScrollTimer;
|
||||
CTimer m_tScrollTimer;
|
||||
|
||||
bool handleKeybinds(const uint32_t&, const std::string&, const xkb_keysym_t&, const int&, bool, uint32_t);
|
||||
bool handleKeybinds(const uint32_t, const SPressedKeyWithMods&, bool);
|
||||
|
||||
bool handleInternalKeybinds(xkb_keysym_t);
|
||||
bool handleVT(xkb_keysym_t);
|
||||
bool handleInternalKeybinds(xkb_keysym_t);
|
||||
bool handleVT(xkb_keysym_t);
|
||||
|
||||
xkb_state* m_pXKBTranslationState = nullptr;
|
||||
xkb_state* m_pXKBTranslationState = nullptr;
|
||||
|
||||
void updateXKBTranslationState();
|
||||
bool ensureMouseBindState();
|
||||
void updateXKBTranslationState();
|
||||
bool ensureMouseBindState();
|
||||
|
||||
static bool tryMoveFocusToMonitor(CMonitor* monitor);
|
||||
static void moveWindowOutOfGroup(CWindow* pWindow, const std::string& dir = "");
|
||||
static void moveWindowIntoGroup(CWindow* pWindow, CWindow* pWindowInDirection);
|
||||
static void switchToWindow(CWindow* PWINDOWTOCHANGETO);
|
||||
static bool tryMoveFocusToMonitor(CMonitor* monitor);
|
||||
static void moveWindowOutOfGroup(CWindow* pWindow, const std::string& dir = "");
|
||||
static void moveWindowIntoGroup(CWindow* pWindow, CWindow* pWindowInDirection);
|
||||
static void switchToWindow(CWindow* PWINDOWTOCHANGETO);
|
||||
|
||||
// -------------- Dispatchers -------------- //
|
||||
static void killActive(std::string);
|
||||
@@ -126,6 +134,7 @@ class CKeybindManager {
|
||||
static void exitHyprland(std::string);
|
||||
static void moveCurrentWorkspaceToMonitor(std::string);
|
||||
static void moveWorkspaceToMonitor(std::string);
|
||||
static void focusWorkspaceOnCurrentMonitor(std::string);
|
||||
static void toggleSpecialWorkspace(std::string);
|
||||
static void forceRendererReload(std::string);
|
||||
static void resizeActive(std::string);
|
||||
|
@@ -18,8 +18,6 @@ int handleTimer(void* data) {
|
||||
}
|
||||
|
||||
CThreadManager::CThreadManager() {
|
||||
HyprCtl::startHyprCtlSocket();
|
||||
|
||||
m_esConfigTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, handleTimer, this);
|
||||
|
||||
wl_event_source_timer_update(m_esConfigTimer, 1000);
|
||||
|
@@ -261,7 +261,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto PWINDOWIDEAL = g_pCompositor->vectorToWindowIdeal(mouseCoords);
|
||||
const auto PWINDOWIDEAL = g_pCompositor->vectorToWindowUnified(mouseCoords, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
|
||||
|
||||
if (PWINDOWIDEAL &&
|
||||
((PWINDOWIDEAL->m_bIsFloating && PWINDOWIDEAL->m_bCreatedOverFullscreen) /* floating over fullscreen */
|
||||
@@ -282,19 +282,19 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
||||
if (PWORKSPACE->m_bHasFullscreenWindow && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_MAXIMIZED) {
|
||||
|
||||
if (PMONITOR->specialWorkspaceID) {
|
||||
pFoundWindow = g_pCompositor->vectorToWindowIdeal(mouseCoords);
|
||||
pFoundWindow = g_pCompositor->vectorToWindowUnified(mouseCoords, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
|
||||
|
||||
if (pFoundWindow && !g_pCompositor->isWorkspaceSpecial(pFoundWindow->m_iWorkspaceID)) {
|
||||
pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
|
||||
}
|
||||
} else {
|
||||
pFoundWindow = g_pCompositor->vectorToWindowIdeal(mouseCoords);
|
||||
pFoundWindow = g_pCompositor->vectorToWindowUnified(mouseCoords, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
|
||||
|
||||
if (!(pFoundWindow && pFoundWindow->m_bIsFloating && pFoundWindow->m_bCreatedOverFullscreen))
|
||||
pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
|
||||
}
|
||||
} else {
|
||||
pFoundWindow = g_pCompositor->vectorToWindowIdeal(mouseCoords);
|
||||
pFoundWindow = g_pCompositor->vectorToWindowUnified(mouseCoords, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
|
||||
}
|
||||
|
||||
if (pFoundWindow) {
|
||||
@@ -421,7 +421,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
||||
m_bLastFocusOnLS = false;
|
||||
return; // don't enter any new surfaces
|
||||
} else {
|
||||
if (((FOLLOWMOUSE != 3 && allowKeyboardRefocus) && (*PMOUSEREFOCUS || m_pLastMouseFocus != pFoundWindow)) || refocus) {
|
||||
if (allowKeyboardRefocus && ((FOLLOWMOUSE != 3 && (*PMOUSEREFOCUS || m_pLastMouseFocus != pFoundWindow)) || refocus)) {
|
||||
m_pLastMouseFocus = pFoundWindow;
|
||||
g_pCompositor->focusWindow(pFoundWindow, foundSurface);
|
||||
}
|
||||
@@ -599,10 +599,14 @@ void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) {
|
||||
return;
|
||||
|
||||
const auto mouseCoords = g_pInputManager->getMouseCoordsInternal();
|
||||
const auto w = g_pCompositor->vectorToWindowIdeal(mouseCoords);
|
||||
const auto w = g_pCompositor->vectorToWindowUnified(mouseCoords, ALLOW_FLOATING | RESERVED_EXTENTS | INPUT_EXTENTS);
|
||||
|
||||
if (w && !m_bLastFocusOnLS && w->checkInputOnDecos(INPUT_TYPE_BUTTON, mouseCoords, e))
|
||||
return;
|
||||
if (w && !m_bLastFocusOnLS) {
|
||||
if (g_pCompositor->m_pLastWindow != w && *PFOLLOWMOUSE != 3)
|
||||
g_pCompositor->focusWindow(w);
|
||||
if (w->checkInputOnDecos(INPUT_TYPE_BUTTON, mouseCoords, e))
|
||||
return;
|
||||
}
|
||||
|
||||
// clicking on border triggers resize
|
||||
// TODO detect click on LS properly
|
||||
@@ -653,7 +657,7 @@ void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) {
|
||||
void CInputManager::processMouseDownKill(wlr_pointer_button_event* e) {
|
||||
switch (e->state) {
|
||||
case WLR_BUTTON_PRESSED: {
|
||||
const auto PWINDOW = g_pCompositor->vectorToWindowIdeal(getMouseCoordsInternal());
|
||||
const auto PWINDOW = g_pCompositor->vectorToWindowUnified(getMouseCoordsInternal(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
|
||||
|
||||
if (!PWINDOW) {
|
||||
Debug::log(ERR, "Cannot kill invalid window!");
|
||||
@@ -689,13 +693,14 @@ void CInputManager::onMouseWheel(wlr_pointer_axis_event* e) {
|
||||
|
||||
if (!m_bLastFocusOnLS) {
|
||||
const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal();
|
||||
const auto PWINDOW = g_pCompositor->vectorToWindowIdeal(MOUSECOORDS);
|
||||
const auto PWINDOW = g_pCompositor->vectorToWindowUnified(MOUSECOORDS, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
|
||||
|
||||
if (PWINDOW && PWINDOW->checkInputOnDecos(INPUT_TYPE_AXIS, MOUSECOORDS, e))
|
||||
return;
|
||||
}
|
||||
|
||||
wlr_seat_pointer_notify_axis(g_pCompositor->m_sSeat.seat, e->time_msec, e->orientation, factor * e->delta, std::round(factor * e->delta_discrete), e->source);
|
||||
wlr_seat_pointer_notify_axis(g_pCompositor->m_sSeat.seat, e->time_msec, e->orientation, factor * e->delta, std::round(factor * e->delta_discrete), e->source,
|
||||
WLR_AXIS_RELATIVE_DIRECTION_IDENTICAL);
|
||||
}
|
||||
|
||||
Vector2D CInputManager::getMouseCoordsInternal() {
|
||||
@@ -1185,6 +1190,9 @@ void CInputManager::onKeyboardKey(wlr_keyboard_key_event* e, SKeyboard* pKeyboar
|
||||
|
||||
updateKeyboardsLeds(pKeyboard->keyboard);
|
||||
}
|
||||
|
||||
if (m_bExitTriggered)
|
||||
g_pCompositor->cleanup();
|
||||
}
|
||||
|
||||
void CInputManager::onKeyboardMod(void* data, SKeyboard* pKeyboard) {
|
||||
@@ -1457,12 +1465,16 @@ void CInputManager::newTouchDevice(wlr_input_device* pDevice) {
|
||||
}
|
||||
|
||||
void CInputManager::setTouchDeviceConfigs(STouchDevice* dev) {
|
||||
|
||||
auto setConfig = [&](STouchDevice* const PTOUCHDEV) -> void {
|
||||
if (wlr_input_device_is_libinput(PTOUCHDEV->pWlrDevice)) {
|
||||
const auto LIBINPUTDEV = (libinput_device*)wlr_libinput_get_device_handle(PTOUCHDEV->pWlrDevice);
|
||||
|
||||
const int ROTATION = std::clamp(g_pConfigManager->getDeviceInt(PTOUCHDEV->name, "transform", "input:touchdevice:transform"), 0, 7);
|
||||
const auto ENABLED = g_pConfigManager->getDeviceInt(PTOUCHDEV->name, "enabled", "input:touchdevice:enabled");
|
||||
const auto mode = ENABLED ? LIBINPUT_CONFIG_SEND_EVENTS_ENABLED : LIBINPUT_CONFIG_SEND_EVENTS_DISABLED;
|
||||
if (libinput_device_config_send_events_get_mode(LIBINPUTDEV) != mode)
|
||||
libinput_device_config_send_events_set_mode(LIBINPUTDEV, mode);
|
||||
|
||||
const int ROTATION = std::clamp(g_pConfigManager->getDeviceInt(PTOUCHDEV->name, "transform", "input:touchdevice:transform"), 0, 7);
|
||||
if (libinput_device_config_calibration_has_matrix(LIBINPUTDEV))
|
||||
libinput_device_config_calibration_set_matrix(LIBINPUTDEV, MATRICES[ROTATION]);
|
||||
|
||||
|
@@ -142,25 +142,28 @@ class CInputManager {
|
||||
// Switches
|
||||
std::list<SSwitchDevice> m_lSwitches;
|
||||
|
||||
void newTabletTool(wlr_input_device*);
|
||||
void newTabletPad(wlr_input_device*);
|
||||
void focusTablet(STablet*, wlr_tablet_tool*, bool motion = false);
|
||||
void newIdleInhibitor(wlr_idle_inhibitor_v1*);
|
||||
void recheckIdleInhibitorStatus();
|
||||
// Exclusive layer surfaces
|
||||
std::deque<SLayerSurface*> m_dExclusiveLSes;
|
||||
|
||||
void onSwipeBegin(wlr_pointer_swipe_begin_event*);
|
||||
void onSwipeEnd(wlr_pointer_swipe_end_event*);
|
||||
void onSwipeUpdate(wlr_pointer_swipe_update_event*);
|
||||
void newTabletTool(wlr_input_device*);
|
||||
void newTabletPad(wlr_input_device*);
|
||||
void focusTablet(STablet*, wlr_tablet_tool*, bool motion = false);
|
||||
void newIdleInhibitor(wlr_idle_inhibitor_v1*);
|
||||
void recheckIdleInhibitorStatus();
|
||||
|
||||
SSwipeGesture m_sActiveSwipe;
|
||||
void onSwipeBegin(wlr_pointer_swipe_begin_event*);
|
||||
void onSwipeEnd(wlr_pointer_swipe_end_event*);
|
||||
void onSwipeUpdate(wlr_pointer_swipe_update_event*);
|
||||
|
||||
SKeyboard* m_pActiveKeyboard = nullptr;
|
||||
SSwipeGesture m_sActiveSwipe;
|
||||
|
||||
CTimer m_tmrLastCursorMovement;
|
||||
SKeyboard* m_pActiveKeyboard = nullptr;
|
||||
|
||||
CInputMethodRelay m_sIMERelay;
|
||||
CTimer m_tmrLastCursorMovement;
|
||||
|
||||
void updateKeyboardsLeds(wlr_input_device* pKeyboard);
|
||||
CInputMethodRelay m_sIMERelay;
|
||||
|
||||
void updateKeyboardsLeds(wlr_input_device* pKeyboard);
|
||||
|
||||
// for shared mods
|
||||
uint32_t accumulateModsFromAllKBs();
|
||||
@@ -243,6 +246,8 @@ class CInputManager {
|
||||
|
||||
void restoreCursorIconToApp(); // no-op if restored
|
||||
|
||||
bool m_bExitTriggered = false; // for exit dispatcher
|
||||
|
||||
friend class CKeybindManager;
|
||||
friend class CWLSurface;
|
||||
};
|
||||
|
@@ -265,7 +265,7 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
|
||||
PWORKSPACE->m_bForceRendering = true;
|
||||
PWORKSPACE->m_fAlpha.setValueAndWarp(1.f);
|
||||
|
||||
if (workspaceIDLeft != workspaceIDRight) {
|
||||
if (workspaceIDLeft != workspaceIDRight && workspaceIDRight != m_sActiveSwipe.pWorkspaceBegin->m_iID) {
|
||||
const auto PWORKSPACER = g_pCompositor->getWorkspaceByID(workspaceIDRight);
|
||||
|
||||
if (PWORKSPACER) {
|
||||
@@ -305,7 +305,7 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
|
||||
PWORKSPACE->m_bForceRendering = true;
|
||||
PWORKSPACE->m_fAlpha.setValueAndWarp(1.f);
|
||||
|
||||
if (workspaceIDLeft != workspaceIDRight) {
|
||||
if (workspaceIDLeft != workspaceIDRight && workspaceIDLeft != m_sActiveSwipe.pWorkspaceBegin->m_iID) {
|
||||
const auto PWORKSPACEL = g_pCompositor->getWorkspaceByID(workspaceIDLeft);
|
||||
|
||||
if (PWORKSPACEL) {
|
||||
|
@@ -74,9 +74,10 @@ CFunctionHook::SAssembly CFunctionHook::fixInstructionProbeRIPCalls(const SInstr
|
||||
std::string code = probe.assembly.substr(lastAsmNewline, probe.assembly.find("\n", lastAsmNewline) - lastAsmNewline);
|
||||
if (code.contains("%rip")) {
|
||||
CVarList tokens{code, 0, 's'};
|
||||
size_t plusPresent = tokens[1][0] == '+' ? 1 : 0;
|
||||
std::string addr = tokens[1].substr(plusPresent, tokens[1].find("(%rip)") - plusPresent);
|
||||
const uint64_t OFFSET = configStringToInt(addr);
|
||||
size_t plusPresent = tokens[1][0] == '+' ? 1 : 0;
|
||||
size_t minusPresent = tokens[1][0] == '-' ? 1 : 0;
|
||||
std::string addr = tokens[1].substr((plusPresent || minusPresent), tokens[1].find("(%rip)") - (plusPresent || minusPresent));
|
||||
const uint64_t OFFSET = (minusPresent ? -1 : 1) * configStringToInt(addr);
|
||||
if (OFFSET == 0)
|
||||
return {};
|
||||
const uint64_t DESTINATION = currentAddress + OFFSET + len;
|
||||
@@ -190,9 +191,9 @@ bool CFunctionHook::hook() {
|
||||
(uint64_t)((uint8_t*)m_pSource + sizeof(ABSOLUTE_JMP_ADDRESS));
|
||||
|
||||
// make jump to hk
|
||||
const auto PAGESIZE = sysconf(_SC_PAGE_SIZE);
|
||||
const uint8_t* PROTSTART = (uint8_t*)m_pSource - ((uint64_t)m_pSource % PAGESIZE);
|
||||
const size_t PROTLEN = std::ceil((float)(ORIGSIZE + ((uint64_t)m_pSource - (uint64_t)PROTSTART)) / (float)PAGESIZE) * PAGESIZE;
|
||||
const auto PAGESIZE_VAR = sysconf(_SC_PAGE_SIZE);
|
||||
const uint8_t* PROTSTART = (uint8_t*)m_pSource - ((uint64_t)m_pSource % PAGESIZE_VAR);
|
||||
const size_t PROTLEN = std::ceil((float)(ORIGSIZE + ((uint64_t)m_pSource - (uint64_t)PROTSTART)) / (float)PAGESIZE_VAR) * PAGESIZE_VAR;
|
||||
mprotect((uint8_t*)PROTSTART, PROTLEN, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
memcpy((uint8_t*)m_pSource, ABSOLUTE_JMP_ADDRESS, sizeof(ABSOLUTE_JMP_ADDRESS));
|
||||
|
||||
|
@@ -50,9 +50,9 @@ APICALL bool HyprlandAPI::unregisterCallback(HANDLE handle, HOOK_CALLBACK_FN* fn
|
||||
|
||||
APICALL std::string HyprlandAPI::invokeHyprctlCommand(const std::string& call, const std::string& args, const std::string& format) {
|
||||
if (args.empty())
|
||||
return HyprCtl::makeDynamicCall(format + "/" + call);
|
||||
return g_pHyprCtl->makeDynamicCall(format + "/" + call);
|
||||
else
|
||||
return HyprCtl::makeDynamicCall(format + "/" + call + " " + args);
|
||||
return g_pHyprCtl->makeDynamicCall(format + "/" + call + " " + args);
|
||||
}
|
||||
|
||||
APICALL bool HyprlandAPI::addLayout(HANDLE handle, const std::string& name, IHyprLayout* layout) {
|
||||
@@ -362,4 +362,28 @@ APICALL SVersionInfo HyprlandAPI::getHyprlandVersion(HANDLE handle) {
|
||||
return {};
|
||||
|
||||
return {GIT_COMMIT_HASH, GIT_TAG, GIT_DIRTY != std::string(""), GIT_BRANCH, GIT_COMMIT_MESSAGE};
|
||||
}
|
||||
|
||||
APICALL std::shared_ptr<SHyprCtlCommand> HyprlandAPI::registerHyprCtlCommand(HANDLE handle, SHyprCtlCommand cmd) {
|
||||
auto* const PLUGIN = g_pPluginSystem->getPluginByHandle(handle);
|
||||
|
||||
if (!PLUGIN)
|
||||
return nullptr;
|
||||
|
||||
auto PTR = g_pHyprCtl->registerCommand(cmd);
|
||||
PLUGIN->registeredHyprctlCommands.push_back(PTR);
|
||||
return PTR;
|
||||
}
|
||||
|
||||
APICALL bool HyprlandAPI::unregisterHyprCtlCommand(HANDLE handle, std::shared_ptr<SHyprCtlCommand> cmd) {
|
||||
|
||||
auto* const PLUGIN = g_pPluginSystem->getPluginByHandle(handle);
|
||||
|
||||
if (!PLUGIN)
|
||||
return false;
|
||||
|
||||
std::erase(PLUGIN->registeredHyprctlCommands, cmd);
|
||||
g_pHyprCtl->unregisterCommand(cmd);
|
||||
|
||||
return true;
|
||||
}
|
@@ -273,6 +273,20 @@ namespace HyprlandAPI {
|
||||
for a different hash.
|
||||
*/
|
||||
APICALL SVersionInfo getHyprlandVersion(HANDLE handle);
|
||||
|
||||
/*
|
||||
Registers a hyprctl command
|
||||
|
||||
returns: Pointer. Nullptr on fail.
|
||||
*/
|
||||
APICALL std::shared_ptr<SHyprCtlCommand> registerHyprCtlCommand(HANDLE handle, SHyprCtlCommand cmd);
|
||||
|
||||
/*
|
||||
Unregisters a hyprctl command
|
||||
|
||||
returns: true on success. False otherwise.
|
||||
*/
|
||||
APICALL bool unregisterHyprCtlCommand(HANDLE handle, std::shared_ptr<SHyprCtlCommand> cmd);
|
||||
};
|
||||
|
||||
/*
|
||||
|
@@ -113,6 +113,10 @@ void CPluginSystem::unloadPlugin(const CPlugin* plugin, bool eject) {
|
||||
for (auto& d : rdi)
|
||||
HyprlandAPI::removeDispatcher(plugin->m_pHandle, d);
|
||||
|
||||
const auto rhc = plugin->registeredHyprctlCommands;
|
||||
for (auto& c : rhc)
|
||||
HyprlandAPI::unregisterHyprCtlCommand(plugin->m_pHandle, c);
|
||||
|
||||
g_pConfigManager->removePluginConfig(plugin->m_pHandle);
|
||||
|
||||
dlclose(plugin->m_pHandle);
|
||||
|
@@ -23,6 +23,7 @@ class CPlugin {
|
||||
std::vector<IHyprWindowDecoration*> registeredDecorations;
|
||||
std::vector<std::pair<std::string, HOOK_CALLBACK_FN*>> registeredCallbacks;
|
||||
std::vector<std::string> registeredDispatchers;
|
||||
std::vector<std::shared_ptr<SHyprCtlCommand>> registeredHyprctlCommands;
|
||||
};
|
||||
|
||||
class CPluginSystem {
|
||||
|
@@ -189,16 +189,39 @@ bool CHyprOpenGLImpl::passRequiresIntrospection(CMonitor* pMonitor) {
|
||||
void CHyprOpenGLImpl::begin(CMonitor* pMonitor, CRegion* pDamage, CFramebuffer* fb) {
|
||||
m_RenderData.pMonitor = pMonitor;
|
||||
|
||||
#ifndef GLES2
|
||||
|
||||
const GLenum RESETSTATUS = glGetGraphicsResetStatus();
|
||||
if (RESETSTATUS != GL_NO_ERROR) {
|
||||
std::string errStr = "";
|
||||
switch (RESETSTATUS) {
|
||||
case GL_GUILTY_CONTEXT_RESET: errStr = "GL_GUILTY_CONTEXT_RESET"; break;
|
||||
case GL_INNOCENT_CONTEXT_RESET: errStr = "GL_INNOCENT_CONTEXT_RESET"; break;
|
||||
case GL_UNKNOWN_CONTEXT_RESET: errStr = "GL_UNKNOWN_CONTEXT_RESET"; break;
|
||||
default: errStr = "UNKNOWN??"; break;
|
||||
}
|
||||
RASSERT(false, "Aborting, glGetGraphicsResetStatus returned {}. Cannot continue until proper GPU reset handling is implemented.", errStr);
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
TRACY_GPU_ZONE("RenderBegin");
|
||||
|
||||
glViewport(0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y);
|
||||
|
||||
matrixProjection(m_RenderData.projection, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, WL_OUTPUT_TRANSFORM_NORMAL);
|
||||
|
||||
if (m_mMonitorRenderResources.contains(pMonitor) && m_mMonitorRenderResources.at(pMonitor).offloadFB.m_vSize != pMonitor->vecPixelSize)
|
||||
destroyMonitorResources(pMonitor);
|
||||
|
||||
m_RenderData.pCurrentMonData = &m_mMonitorRenderResources[pMonitor];
|
||||
|
||||
if (!m_RenderData.pCurrentMonData->m_bShadersInitialized)
|
||||
initShaders();
|
||||
|
||||
// ensure a framebuffer for the monitor exists
|
||||
if (!m_mMonitorRenderResources.contains(pMonitor) || m_RenderData.pCurrentMonData->offloadFB.m_vSize != pMonitor->vecPixelSize) {
|
||||
if (m_RenderData.pCurrentMonData->offloadFB.m_vSize != pMonitor->vecPixelSize) {
|
||||
m_RenderData.pCurrentMonData->stencilTex.allocate();
|
||||
|
||||
m_RenderData.pCurrentMonData->offloadFB.m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex;
|
||||
@@ -210,16 +233,11 @@ void CHyprOpenGLImpl::begin(CMonitor* pMonitor, CRegion* pDamage, CFramebuffer*
|
||||
m_RenderData.pCurrentMonData->mirrorFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat);
|
||||
m_RenderData.pCurrentMonData->mirrorSwapFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat);
|
||||
m_RenderData.pCurrentMonData->offMainFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat);
|
||||
|
||||
createBGTextureForMonitor(pMonitor);
|
||||
}
|
||||
|
||||
if (m_RenderData.pCurrentMonData->monitorMirrorFB.isAllocated() && m_RenderData.pMonitor->mirrors.empty())
|
||||
m_RenderData.pCurrentMonData->monitorMirrorFB.release();
|
||||
|
||||
if (!m_RenderData.pCurrentMonData->m_bShadersInitialized)
|
||||
initShaders();
|
||||
|
||||
m_RenderData.damage.set(*pDamage);
|
||||
|
||||
m_bFakeFrame = fb;
|
||||
@@ -232,7 +250,8 @@ void CHyprOpenGLImpl::begin(CMonitor* pMonitor, CRegion* pDamage, CFramebuffer*
|
||||
const auto PRBO = g_pHyprRenderer->getCurrentRBO();
|
||||
const bool FBPROPERSIZE = fb && fb->m_vSize == pMonitor->vecPixelSize;
|
||||
|
||||
if (!FBPROPERSIZE || m_sFinalScreenShader.program > 0 || (PRBO && pMonitor->vecPixelSize != PRBO->getFB()->m_vSize) || passRequiresIntrospection(pMonitor)) {
|
||||
if (m_RenderData.forceIntrospection || !FBPROPERSIZE || m_sFinalScreenShader.program > 0 || (PRBO && pMonitor->vecPixelSize != PRBO->getFB()->m_vSize) ||
|
||||
passRequiresIntrospection(pMonitor)) {
|
||||
// we have to offload
|
||||
// bind the offload Hypr Framebuffer
|
||||
m_RenderData.pCurrentMonData->offloadFB.bind();
|
||||
@@ -307,9 +326,19 @@ void CHyprOpenGLImpl::end() {
|
||||
}
|
||||
|
||||
// reset our data
|
||||
m_RenderData.pMonitor = nullptr;
|
||||
m_RenderData.mouseZoomFactor = 1.f;
|
||||
m_RenderData.mouseZoomUseMouse = true;
|
||||
m_RenderData.pMonitor = nullptr;
|
||||
m_RenderData.mouseZoomFactor = 1.f;
|
||||
m_RenderData.mouseZoomUseMouse = true;
|
||||
m_RenderData.forceIntrospection = false;
|
||||
m_RenderData.currentFB = nullptr;
|
||||
m_RenderData.mainFB = nullptr;
|
||||
m_RenderData.outFB = nullptr;
|
||||
|
||||
// check for gl errors
|
||||
const GLenum ERR = glGetError();
|
||||
|
||||
if (ERR == GL_CONTEXT_LOST) /* We don't have infra to recover from this */
|
||||
RASSERT(false, "glGetError at Opengl::end() returned GL_CONTEXT_LOST. Cannot continue until proper GPU reset handling is implemented.");
|
||||
}
|
||||
|
||||
void CHyprOpenGLImpl::initShaders() {
|
||||
@@ -497,10 +526,10 @@ void CHyprOpenGLImpl::applyScreenShader(const std::string& path) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_sFinalScreenShader.proj = glGetUniformLocation(m_sFinalScreenShader.program, "proj");
|
||||
m_sFinalScreenShader.tex = glGetUniformLocation(m_sFinalScreenShader.program, "tex");
|
||||
m_sFinalScreenShader.time = glGetUniformLocation(m_sFinalScreenShader.program, "time");
|
||||
m_sFinalScreenShader.output = glGetUniformLocation(m_sFinalScreenShader.program, "output");
|
||||
m_sFinalScreenShader.proj = glGetUniformLocation(m_sFinalScreenShader.program, "proj");
|
||||
m_sFinalScreenShader.tex = glGetUniformLocation(m_sFinalScreenShader.program, "tex");
|
||||
m_sFinalScreenShader.time = glGetUniformLocation(m_sFinalScreenShader.program, "time");
|
||||
m_sFinalScreenShader.wl_output = glGetUniformLocation(m_sFinalScreenShader.program, "wl_output");
|
||||
if (m_sFinalScreenShader.time != -1 && g_pConfigManager->getInt("debug:damage_tracking") != 0 && !g_pHyprRenderer->m_bCrashingInProgress) {
|
||||
// The screen shader uses the "time" uniform
|
||||
// Since the screen shader could change every frame, damage tracking *needs* to be disabled
|
||||
@@ -637,12 +666,12 @@ void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CColor& col, CRegion
|
||||
TRACY_GPU_ZONE("RenderRectWithDamage");
|
||||
|
||||
CBox newBox = *box;
|
||||
newBox.scale(m_RenderData.renderModif.scale).translate(m_RenderData.renderModif.translate);
|
||||
m_RenderData.renderModif.applyToBox(newBox);
|
||||
|
||||
box = &newBox;
|
||||
|
||||
float matrix[9];
|
||||
wlr_matrix_project_box(matrix, box->pWlr(), wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform), 0,
|
||||
wlr_matrix_project_box(matrix, box->pWlr(), wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform), newBox.rot,
|
||||
m_RenderData.pMonitor->projMatrix.data()); // TODO: write own, don't use WLR here
|
||||
|
||||
float glMatrix[9];
|
||||
@@ -719,18 +748,18 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, CBox*
|
||||
|
||||
alpha = std::clamp(alpha, 0.f, 1.f);
|
||||
|
||||
if (m_RenderData.damage.empty())
|
||||
if (damage->empty())
|
||||
return;
|
||||
|
||||
CBox newBox = *pBox;
|
||||
newBox.scale(m_RenderData.renderModif.scale).translate(m_RenderData.renderModif.translate);
|
||||
m_RenderData.renderModif.applyToBox(newBox);
|
||||
|
||||
static auto* const PDIMINACTIVE = &g_pConfigManager->getConfigValuePtr("decoration:dim_inactive")->intValue;
|
||||
|
||||
// get transform
|
||||
const auto TRANSFORM = wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform);
|
||||
float matrix[9];
|
||||
wlr_matrix_project_box(matrix, newBox.pWlr(), TRANSFORM, 0, m_RenderData.pMonitor->projMatrix.data());
|
||||
wlr_matrix_project_box(matrix, newBox.pWlr(), TRANSFORM, newBox.rot, m_RenderData.pMonitor->projMatrix.data());
|
||||
|
||||
float glMatrix[9];
|
||||
wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);
|
||||
@@ -792,8 +821,8 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, CBox*
|
||||
glUniform1f(shader->time, 0.f);
|
||||
}
|
||||
|
||||
if (usingFinalShader && shader->output != -1)
|
||||
glUniform1i(shader->output, m_RenderData.pMonitor->ID);
|
||||
if (usingFinalShader && shader->wl_output != -1)
|
||||
glUniform1i(shader->wl_output, m_RenderData.pMonitor->ID);
|
||||
|
||||
if (CRASHING) {
|
||||
glUniform1f(shader->distort, g_pHyprRenderer->m_fCrashingDistort);
|
||||
@@ -886,12 +915,12 @@ void CHyprOpenGLImpl::renderTexturePrimitive(const CTexture& tex, CBox* pBox) {
|
||||
return;
|
||||
|
||||
CBox newBox = *pBox;
|
||||
newBox.scale(m_RenderData.renderModif.scale).translate(m_RenderData.renderModif.translate);
|
||||
m_RenderData.renderModif.applyToBox(newBox);
|
||||
|
||||
// get transform
|
||||
const auto TRANSFORM = wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform);
|
||||
float matrix[9];
|
||||
wlr_matrix_project_box(matrix, newBox.pWlr(), TRANSFORM, 0, m_RenderData.pMonitor->projMatrix.data());
|
||||
wlr_matrix_project_box(matrix, newBox.pWlr(), TRANSFORM, newBox.rot, m_RenderData.pMonitor->projMatrix.data());
|
||||
|
||||
float glMatrix[9];
|
||||
wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);
|
||||
@@ -940,12 +969,12 @@ void CHyprOpenGLImpl::renderTextureMatte(const CTexture& tex, CBox* pBox, CFrame
|
||||
return;
|
||||
|
||||
CBox newBox = *pBox;
|
||||
newBox.scale(m_RenderData.renderModif.scale).translate(m_RenderData.renderModif.translate);
|
||||
m_RenderData.renderModif.applyToBox(newBox);
|
||||
|
||||
// get transform
|
||||
const auto TRANSFORM = wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform);
|
||||
float matrix[9];
|
||||
wlr_matrix_project_box(matrix, newBox.pWlr(), TRANSFORM, 0, m_RenderData.pMonitor->projMatrix.data());
|
||||
wlr_matrix_project_box(matrix, newBox.pWlr(), TRANSFORM, newBox.rot, m_RenderData.pMonitor->projMatrix.data());
|
||||
|
||||
float glMatrix[9];
|
||||
wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);
|
||||
@@ -1475,14 +1504,14 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in
|
||||
return;
|
||||
|
||||
CBox newBox = *box;
|
||||
newBox.scale(m_RenderData.renderModif.scale).translate(m_RenderData.renderModif.translate);
|
||||
m_RenderData.renderModif.applyToBox(newBox);
|
||||
|
||||
box = &newBox;
|
||||
|
||||
if (borderSize < 1)
|
||||
return;
|
||||
|
||||
int scaledBorderSize = std::round(borderSize * m_RenderData.pMonitor->scale * m_RenderData.renderModif.scale);
|
||||
int scaledBorderSize = std::round(borderSize * m_RenderData.pMonitor->scale);
|
||||
|
||||
// adjust box
|
||||
box->x -= scaledBorderSize;
|
||||
@@ -1493,7 +1522,7 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in
|
||||
round += round == 0 ? 0 : scaledBorderSize;
|
||||
|
||||
float matrix[9];
|
||||
wlr_matrix_project_box(matrix, box->pWlr(), wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform), 0,
|
||||
wlr_matrix_project_box(matrix, box->pWlr(), wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform), newBox.rot,
|
||||
m_RenderData.pMonitor->projMatrix.data()); // TODO: write own, don't use WLR here
|
||||
|
||||
float glMatrix[9];
|
||||
@@ -1779,7 +1808,7 @@ void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const
|
||||
TRACY_GPU_ZONE("RenderShadow");
|
||||
|
||||
CBox newBox = *box;
|
||||
newBox.scale(m_RenderData.renderModif.scale).translate(m_RenderData.renderModif.translate);
|
||||
m_RenderData.renderModif.applyToBox(newBox);
|
||||
|
||||
box = &newBox;
|
||||
|
||||
@@ -1790,7 +1819,7 @@ void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const
|
||||
const auto col = color;
|
||||
|
||||
float matrix[9];
|
||||
wlr_matrix_project_box(matrix, box->pWlr(), wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform), 0,
|
||||
wlr_matrix_project_box(matrix, box->pWlr(), wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform), newBox.rot,
|
||||
m_RenderData.pMonitor->projMatrix.data()); // TODO: write own, don't use WLR here
|
||||
|
||||
float glMatrix[9];
|
||||
@@ -1876,10 +1905,10 @@ void CHyprOpenGLImpl::renderMirrored() {
|
||||
renderTexture(PFB->m_cTex, &monbox, 1.f, 0, false, false);
|
||||
}
|
||||
|
||||
void CHyprOpenGLImpl::renderSplash(cairo_t* const CAIRO, cairo_surface_t* const CAIROSURFACE, double offsetY) {
|
||||
void CHyprOpenGLImpl::renderSplash(cairo_t* const CAIRO, cairo_surface_t* const CAIROSURFACE, double offsetY, const Vector2D& size) {
|
||||
cairo_select_font_face(CAIRO, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
|
||||
|
||||
const auto FONTSIZE = (int)(m_RenderData.pMonitor->vecPixelSize.y / 76);
|
||||
const auto FONTSIZE = (int)(size.y / 76);
|
||||
cairo_set_font_size(CAIRO, FONTSIZE);
|
||||
|
||||
cairo_set_source_rgba(CAIRO, 1.0, 1.0, 1.0, 0.32);
|
||||
@@ -1887,7 +1916,7 @@ void CHyprOpenGLImpl::renderSplash(cairo_t* const CAIRO, cairo_surface_t* const
|
||||
cairo_text_extents_t textExtents;
|
||||
cairo_text_extents(CAIRO, g_pCompositor->m_szCurrentSplash.c_str(), &textExtents);
|
||||
|
||||
cairo_move_to(CAIRO, (m_RenderData.pMonitor->vecPixelSize.x - textExtents.width) / 2.0, m_RenderData.pMonitor->vecPixelSize.y - textExtents.height + offsetY);
|
||||
cairo_move_to(CAIRO, (size.x - textExtents.width) / 2.0, size.y - textExtents.height + offsetY);
|
||||
|
||||
cairo_show_text(CAIRO, g_pCompositor->m_szCurrentSplash.c_str());
|
||||
|
||||
@@ -1899,109 +1928,123 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) {
|
||||
|
||||
static auto* const PRENDERTEX = &g_pConfigManager->getConfigValuePtr("misc:disable_hyprland_logo")->intValue;
|
||||
static auto* const PNOSPLASH = &g_pConfigManager->getConfigValuePtr("misc:disable_splash_rendering")->intValue;
|
||||
static auto* const PFORCEHYPRCHAN = &g_pConfigManager->getConfigValuePtr("misc:force_hypr_chan")->intValue;
|
||||
static auto* const PFORCEWALLPAPER = &g_pConfigManager->getConfigValuePtr("misc:force_default_wallpaper")->intValue;
|
||||
|
||||
const auto FORCEWALLPAPER = std::clamp(*PFORCEWALLPAPER, static_cast<int64_t>(-1L), static_cast<int64_t>(2L));
|
||||
|
||||
static std::string texPath = "";
|
||||
|
||||
if (*PRENDERTEX)
|
||||
return;
|
||||
|
||||
// release the last tex if exists
|
||||
const auto PTEX = &m_mMonitorBGTextures[pMonitor];
|
||||
PTEX->destroyTexture();
|
||||
const auto PFB = &m_mMonitorBGFBs[pMonitor];
|
||||
PFB->release();
|
||||
|
||||
PTEX->allocate();
|
||||
PFB->alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat);
|
||||
Debug::log(LOG, "Allocated texture for BGTex");
|
||||
|
||||
// TODO: use relative paths to the installation
|
||||
// or configure the paths at build time
|
||||
std::string texPath = "/usr/share/hyprland/wall_";
|
||||
std::string prefixes[] = {"", "anime_", "anime2_"};
|
||||
if (texPath.empty()) {
|
||||
texPath = "/usr/share/hyprland/wall";
|
||||
|
||||
// get the adequate tex
|
||||
if (FORCEWALLPAPER == -1) {
|
||||
std::random_device dev;
|
||||
std::mt19937 engine(dev());
|
||||
std::uniform_int_distribution<> distribution(0, 2);
|
||||
std::uniform_int_distribution<> distribution_anime(1, 2);
|
||||
// get the adequate tex
|
||||
if (FORCEWALLPAPER == -1) {
|
||||
std::mt19937_64 engine(time(nullptr));
|
||||
std::uniform_int_distribution<> distribution(0, 2);
|
||||
|
||||
if (PFORCEHYPRCHAN)
|
||||
texPath += prefixes[distribution_anime(engine)];
|
||||
else
|
||||
texPath += prefixes[distribution(engine)];
|
||||
} else
|
||||
texPath += prefixes[FORCEWALLPAPER];
|
||||
texPath += std::to_string(distribution(engine));
|
||||
} else
|
||||
texPath += std::to_string(std::clamp(*PFORCEWALLPAPER, (int64_t)0, (int64_t)2));
|
||||
|
||||
Vector2D textureSize;
|
||||
if (pMonitor->vecTransformedSize.x > 3850) {
|
||||
textureSize = Vector2D(7680, 4320);
|
||||
texPath += "8K.png";
|
||||
} else if (pMonitor->vecTransformedSize.x > 1930) {
|
||||
textureSize = Vector2D(3840, 2160);
|
||||
texPath += "4K.png";
|
||||
} else {
|
||||
textureSize = Vector2D(1920, 1080);
|
||||
texPath += "2K.png";
|
||||
texPath += ".png";
|
||||
|
||||
// check if wallpapers exist
|
||||
if (!std::filesystem::exists(texPath)) {
|
||||
// try local
|
||||
texPath = texPath.substr(0, 5) + "local/" + texPath.substr(5);
|
||||
|
||||
if (!std::filesystem::exists(texPath))
|
||||
return; // the texture will be empty, oh well. We'll clear with a solid color anyways.
|
||||
}
|
||||
}
|
||||
|
||||
// check if wallpapers exist
|
||||
if (!std::filesystem::exists(texPath)) {
|
||||
// try local
|
||||
texPath = texPath.substr(0, 5) + "local/" + texPath.substr(5);
|
||||
// create a new one with cairo
|
||||
CTexture tex;
|
||||
|
||||
if (!std::filesystem::exists(texPath))
|
||||
return; // the texture will be empty, oh well. We'll clear with a solid color anyways.
|
||||
}
|
||||
const auto CAIROISURFACE = cairo_image_surface_create_from_png(texPath.c_str());
|
||||
const auto CAIROFORMAT = cairo_image_surface_get_format(CAIROISURFACE);
|
||||
|
||||
PTEX->m_vSize = textureSize;
|
||||
tex.allocate();
|
||||
const Vector2D IMAGESIZE = {cairo_image_surface_get_width(CAIROISURFACE), cairo_image_surface_get_height(CAIROISURFACE)};
|
||||
|
||||
// calc the target box
|
||||
const double MONRATIO = m_RenderData.pMonitor->vecTransformedSize.x / m_RenderData.pMonitor->vecTransformedSize.y;
|
||||
const double WPRATIO = 1.77;
|
||||
const double WPRATIO = IMAGESIZE.x / IMAGESIZE.y;
|
||||
|
||||
Vector2D origin;
|
||||
double scale;
|
||||
|
||||
if (MONRATIO > WPRATIO) {
|
||||
scale = m_RenderData.pMonitor->vecTransformedSize.x / PTEX->m_vSize.x;
|
||||
scale = m_RenderData.pMonitor->vecTransformedSize.x / IMAGESIZE.x;
|
||||
|
||||
origin.y = (m_RenderData.pMonitor->vecTransformedSize.y - PTEX->m_vSize.y * scale) / 2.0;
|
||||
origin.y = (m_RenderData.pMonitor->vecTransformedSize.y - IMAGESIZE.y * scale) / 2.0;
|
||||
} else {
|
||||
scale = m_RenderData.pMonitor->vecTransformedSize.y / PTEX->m_vSize.y;
|
||||
scale = m_RenderData.pMonitor->vecTransformedSize.y / IMAGESIZE.y;
|
||||
|
||||
origin.x = (m_RenderData.pMonitor->vecTransformedSize.x - PTEX->m_vSize.x * scale) / 2.0;
|
||||
origin.x = (m_RenderData.pMonitor->vecTransformedSize.x - IMAGESIZE.x * scale) / 2.0;
|
||||
}
|
||||
|
||||
CBox box = {origin.x, origin.y, PTEX->m_vSize.x * scale, PTEX->m_vSize.y * scale};
|
||||
const Vector2D scaledSize = IMAGESIZE * scale;
|
||||
|
||||
m_mMonitorRenderResources[pMonitor].backgroundTexBox = box;
|
||||
const auto CAIROSURFACE = cairo_image_surface_create(CAIROFORMAT, scaledSize.x, scaledSize.y);
|
||||
const auto CAIRO = cairo_create(CAIROSURFACE);
|
||||
|
||||
// create a new one with cairo
|
||||
const auto CAIROSURFACE = cairo_image_surface_create_from_png(texPath.c_str());
|
||||
const auto CAIRO = cairo_create(CAIROSURFACE);
|
||||
cairo_set_antialias(CAIRO, CAIRO_ANTIALIAS_GOOD);
|
||||
cairo_scale(CAIRO, scale, scale);
|
||||
cairo_rectangle(CAIRO, 0, 0, 100, 100);
|
||||
cairo_set_source_surface(CAIRO, CAIROISURFACE, 0, 0);
|
||||
cairo_paint(CAIRO);
|
||||
|
||||
// scale it to fit the current monitor
|
||||
cairo_scale(CAIRO, textureSize.x / pMonitor->vecTransformedSize.x, textureSize.y / pMonitor->vecTransformedSize.y);
|
||||
|
||||
// render splash on wallpaper
|
||||
if (!*PNOSPLASH)
|
||||
renderSplash(CAIRO, CAIROSURFACE, origin.y * WPRATIO / MONRATIO);
|
||||
renderSplash(CAIRO, CAIROSURFACE, origin.y * WPRATIO / MONRATIO * scale, IMAGESIZE);
|
||||
|
||||
cairo_surface_flush(CAIROSURFACE);
|
||||
|
||||
CBox box = {origin.x, origin.y, IMAGESIZE.x * scale, IMAGESIZE.y * scale};
|
||||
tex.m_vSize = IMAGESIZE * scale;
|
||||
|
||||
// copy the data to an OpenGL texture we have
|
||||
const auto DATA = cairo_image_surface_get_data(CAIROSURFACE);
|
||||
glBindTexture(GL_TEXTURE_2D, PTEX->m_iTexID);
|
||||
const GLint glIFormat = CAIROFORMAT == CAIRO_FORMAT_RGB96F ? GL_RGB32F : GL_RGBA;
|
||||
const GLint glFormat = CAIROFORMAT == CAIRO_FORMAT_RGB96F ? GL_RGB : GL_RGBA;
|
||||
const GLint glType = CAIROFORMAT == CAIRO_FORMAT_RGB96F ? GL_FLOAT : GL_UNSIGNED_BYTE;
|
||||
|
||||
const auto DATA = cairo_image_surface_get_data(CAIROSURFACE);
|
||||
glBindTexture(GL_TEXTURE_2D, tex.m_iTexID);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
#ifndef GLES2
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
|
||||
if (CAIROFORMAT != CAIRO_FORMAT_RGB96F) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
|
||||
}
|
||||
#endif
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, textureSize.x, textureSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, glIFormat, tex.m_vSize.x, tex.m_vSize.y, 0, glFormat, glType, DATA);
|
||||
|
||||
cairo_surface_destroy(CAIROSURFACE);
|
||||
cairo_surface_destroy(CAIROISURFACE);
|
||||
cairo_destroy(CAIRO);
|
||||
|
||||
// render the texture to our fb
|
||||
PFB->bind();
|
||||
CRegion fakeDamage{0, 0, INT16_MAX, INT16_MAX};
|
||||
renderTextureInternalWithDamage(tex, &box, 1.0, &fakeDamage);
|
||||
|
||||
// bind back
|
||||
if (m_RenderData.currentFB)
|
||||
m_RenderData.currentFB->bind();
|
||||
|
||||
Debug::log(LOG, "Background created for monitor {}", pMonitor->szName);
|
||||
}
|
||||
|
||||
@@ -2010,15 +2053,19 @@ void CHyprOpenGLImpl::clearWithTex() {
|
||||
|
||||
TRACY_GPU_ZONE("RenderClearWithTex");
|
||||
|
||||
auto TEXIT = m_mMonitorBGTextures.find(m_RenderData.pMonitor);
|
||||
auto TEXIT = m_mMonitorBGFBs.find(m_RenderData.pMonitor);
|
||||
|
||||
if (TEXIT == m_mMonitorBGTextures.end()) {
|
||||
if (TEXIT == m_mMonitorBGFBs.end()) {
|
||||
createBGTextureForMonitor(m_RenderData.pMonitor);
|
||||
TEXIT = m_mMonitorBGTextures.find(m_RenderData.pMonitor);
|
||||
TEXIT = m_mMonitorBGFBs.find(m_RenderData.pMonitor);
|
||||
}
|
||||
|
||||
if (TEXIT != m_mMonitorBGTextures.end())
|
||||
renderTexturePrimitive(TEXIT->second, &m_mMonitorRenderResources[m_RenderData.pMonitor].backgroundTexBox);
|
||||
if (TEXIT != m_mMonitorBGFBs.end()) {
|
||||
CBox monbox = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y};
|
||||
m_bEndFrame = true;
|
||||
renderTexture(TEXIT->second.m_cTex, &monbox, 1);
|
||||
m_bEndFrame = false;
|
||||
}
|
||||
}
|
||||
|
||||
void CHyprOpenGLImpl::destroyMonitorResources(CMonitor* pMonitor) {
|
||||
@@ -2036,10 +2083,10 @@ void CHyprOpenGLImpl::destroyMonitorResources(CMonitor* pMonitor) {
|
||||
g_pHyprOpenGL->m_mMonitorRenderResources.erase(RESIT);
|
||||
}
|
||||
|
||||
auto TEXIT = g_pHyprOpenGL->m_mMonitorBGTextures.find(pMonitor);
|
||||
if (TEXIT != g_pHyprOpenGL->m_mMonitorBGTextures.end()) {
|
||||
TEXIT->second.destroyTexture();
|
||||
g_pHyprOpenGL->m_mMonitorBGTextures.erase(TEXIT);
|
||||
auto TEXIT = g_pHyprOpenGL->m_mMonitorBGFBs.find(pMonitor);
|
||||
if (TEXIT != g_pHyprOpenGL->m_mMonitorBGFBs.end()) {
|
||||
TEXIT->second.release();
|
||||
g_pHyprOpenGL->m_mMonitorBGFBs.erase(TEXIT);
|
||||
}
|
||||
|
||||
Debug::log(LOG, "Monitor {} -> destroyed all render data", pMonitor->szName);
|
||||
@@ -2210,4 +2257,26 @@ const SGLPixelFormat* CHyprOpenGLImpl::getPixelFormatFromDRM(uint32_t drmFormat)
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void SRenderModifData::applyToBox(CBox& box) {
|
||||
for (auto& [type, val] : modifs) {
|
||||
try {
|
||||
switch (type) {
|
||||
case RMOD_TYPE_SCALE: box.scale(std::any_cast<float>(val)); break;
|
||||
case RMOD_TYPE_SCALECENTER: box.scaleFromCenter(std::any_cast<float>(val)); break;
|
||||
case RMOD_TYPE_TRANSLATE: box.translate(std::any_cast<Vector2D>(val)); break;
|
||||
case RMOD_TYPE_ROTATE: box.rot += std::any_cast<float>(val); break;
|
||||
case RMOD_TYPE_ROTATECENTER: {
|
||||
const auto THETA = std::any_cast<float>(val);
|
||||
const double COS = std::cos(THETA);
|
||||
const double SIN = std::sin(THETA);
|
||||
box.rot += THETA;
|
||||
const auto OLDPOS = box.pos();
|
||||
box.x = OLDPOS.x * COS - OLDPOS.y * SIN;
|
||||
box.y = OLDPOS.y * COS + OLDPOS.x * SIN;
|
||||
}
|
||||
}
|
||||
} catch (std::bad_any_cast& e) { Debug::log(ERR, "BUG THIS OR PLUGIN ERROR: caught a bad_any_cast in SRenderModifData::applyToBox!"); }
|
||||
}
|
||||
}
|
||||
|
@@ -36,8 +36,17 @@ enum eDiscardMode {
|
||||
};
|
||||
|
||||
struct SRenderModifData {
|
||||
Vector2D translate = {};
|
||||
float scale = 1.f;
|
||||
enum eRenderModifType {
|
||||
RMOD_TYPE_SCALE, /* scale by a float */
|
||||
RMOD_TYPE_SCALECENTER, /* scale by a float from the center */
|
||||
RMOD_TYPE_TRANSLATE, /* translate by a Vector2D */
|
||||
RMOD_TYPE_ROTATE, /* rotate by a float in rad from top left */
|
||||
RMOD_TYPE_ROTATECENTER, /* rotate by a float in rad from center */
|
||||
};
|
||||
|
||||
std::vector<std::pair<eRenderModifType, std::any>> modifs;
|
||||
|
||||
void applyToBox(CBox& box);
|
||||
};
|
||||
|
||||
struct SGLPixelFormat {
|
||||
@@ -62,8 +71,6 @@ struct SMonitorRenderData {
|
||||
bool blurFBDirty = true;
|
||||
bool blurFBShouldRender = false;
|
||||
|
||||
CBox backgroundTexBox;
|
||||
|
||||
// Shaders
|
||||
bool m_bShadersInitialized = false;
|
||||
CShader m_shQUAD;
|
||||
@@ -99,6 +106,7 @@ struct SCurrentRenderData {
|
||||
float mouseZoomFactor = 1.f;
|
||||
bool mouseZoomUseMouse = true; // true by default
|
||||
bool useNearestNeighbor = false;
|
||||
bool forceIntrospection = false; // cleaned in ::end()
|
||||
|
||||
Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1);
|
||||
Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1);
|
||||
@@ -181,7 +189,7 @@ class CHyprOpenGLImpl {
|
||||
std::unordered_map<CWindow*, CFramebuffer> m_mWindowFramebuffers;
|
||||
std::unordered_map<SLayerSurface*, CFramebuffer> m_mLayerFramebuffers;
|
||||
std::unordered_map<CMonitor*, SMonitorRenderData> m_mMonitorRenderResources;
|
||||
std::unordered_map<CMonitor*, CTexture> m_mMonitorBGTextures;
|
||||
std::unordered_map<CMonitor*, CFramebuffer> m_mMonitorBGFBs;
|
||||
|
||||
struct {
|
||||
PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES = nullptr;
|
||||
@@ -219,7 +227,7 @@ class CHyprOpenGLImpl {
|
||||
void renderTextureInternalWithDamage(const CTexture&, CBox* pBox, float a, CRegion* damage, int round = 0, bool discardOpaque = false, bool noAA = false,
|
||||
bool allowCustomUV = false, bool allowDim = false);
|
||||
void renderTexturePrimitive(const CTexture& tex, CBox* pBox);
|
||||
void renderSplash(cairo_t* const, cairo_surface_t* const, double);
|
||||
void renderSplash(cairo_t* const, cairo_surface_t* const, double offset, const Vector2D& size);
|
||||
|
||||
void preBlurForCurrentMonitor();
|
||||
|
||||
|
@@ -9,8 +9,6 @@ extern "C" {
|
||||
}
|
||||
|
||||
CHyprRenderer::CHyprRenderer() {
|
||||
if (envEnabled("WLR_DRM_NO_ATOMIC"))
|
||||
m_bTearingEnvSatisfied = true;
|
||||
|
||||
if (g_pCompositor->m_sWLRSession) {
|
||||
wlr_device* dev;
|
||||
@@ -107,18 +105,22 @@ static void renderSurface(struct wlr_surface* surface, int x, int y, void* data)
|
||||
if (windowBox.width <= 1 || windowBox.height <= 1)
|
||||
return; // invisible
|
||||
|
||||
g_pHyprRenderer->calculateUVForSurface(RDATA->pWindow, surface, RDATA->surface == surface);
|
||||
|
||||
windowBox.scale(RDATA->pMonitor->scale);
|
||||
windowBox.round();
|
||||
|
||||
const bool MISALIGNEDFSV1 = std::floor(RDATA->pMonitor->scale) != RDATA->pMonitor->scale /* Fractional */ && surface->current.scale == 1 /* fs protocol */ &&
|
||||
windowBox.size() != Vector2D{surface->current.buffer_width, surface->current.buffer_height} /* misaligned */ &&
|
||||
DELTALESSTHAN(windowBox.width, surface->current.buffer_width, 3) && DELTALESSTHAN(windowBox.height, surface->current.buffer_height, 3) /* off by one-or-two */ &&
|
||||
(!RDATA->pWindow || (!RDATA->pWindow->m_vRealSize.isBeingAnimated() && !INTERACTIVERESIZEINPROGRESS)) /* not window or not animated/resizing */;
|
||||
|
||||
g_pHyprRenderer->calculateUVForSurface(RDATA->pWindow, surface, RDATA->surface == surface, windowBox.size(), MISALIGNEDFSV1);
|
||||
|
||||
// check for fractional scale surfaces misaligning the buffer size
|
||||
// in those cases it's better to just force nearest neighbor
|
||||
// as long as the window is not animated. During those it'd look weird
|
||||
// as long as the window is not animated. During those it'd look weird.
|
||||
// UV will fixup it as well
|
||||
const auto NEARESTNEIGHBORSET = g_pHyprOpenGL->m_RenderData.useNearestNeighbor;
|
||||
if (std::floor(RDATA->pMonitor->scale) != RDATA->pMonitor->scale /* Fractional */ && surface->current.scale == 1 /* fs protocol */ &&
|
||||
windowBox.size() != Vector2D{surface->current.buffer_width, surface->current.buffer_height} /* misaligned */ &&
|
||||
(!RDATA->pWindow || (!RDATA->pWindow->m_vRealSize.isBeingAnimated() && !INTERACTIVERESIZEINPROGRESS)) /* not window or not animated/resizing */)
|
||||
if (MISALIGNEDFSV1)
|
||||
g_pHyprOpenGL->m_RenderData.useNearestNeighbor = true;
|
||||
|
||||
float rounding = RDATA->rounding;
|
||||
@@ -161,7 +163,7 @@ static void renderSurface(struct wlr_surface* surface, int x, int y, void* data)
|
||||
|
||||
if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) {
|
||||
wlr_surface_send_frame_done(surface, RDATA->when);
|
||||
wlr_presentation_surface_textured_on_output(g_pCompositor->m_sWLRPresentation, surface, RDATA->pMonitor->output);
|
||||
wlr_presentation_surface_textured_on_output(surface, RDATA->pMonitor->output);
|
||||
}
|
||||
|
||||
g_pHyprOpenGL->blend(true);
|
||||
@@ -289,11 +291,14 @@ void CHyprRenderer::renderWorkspaceWindowsFullscreen(CMonitor* pMonitor, CWorksp
|
||||
continue;
|
||||
}
|
||||
|
||||
if (w->m_iWorkspaceID != pMonitor->activeWorkspace || !w->m_bIsFullscreen)
|
||||
if (!w->m_bIsFullscreen)
|
||||
continue;
|
||||
|
||||
renderWindow(w.get(), pMonitor, time, pWorkspace->m_efFullscreenMode != FULLSCREEN_FULL, RENDER_PASS_ALL);
|
||||
|
||||
if (w->m_iWorkspaceID != pWorkspace->m_iID)
|
||||
continue;
|
||||
|
||||
pWorkspaceWindow = w.get();
|
||||
}
|
||||
|
||||
@@ -452,7 +457,7 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, CMonitor* pMonitor, timespec*
|
||||
|
||||
// clip box for animated offsets
|
||||
const Vector2D PREOFFSETPOS = {renderdata.x, renderdata.y};
|
||||
if (!ignorePosition && pWindow->m_bIsFloating && !pWindow->m_bPinned) {
|
||||
if (!ignorePosition && pWindow->m_bIsFloating && !pWindow->m_bPinned && !pWindow->m_bIsFullscreen) {
|
||||
Vector2D offset;
|
||||
|
||||
if (PWORKSPACE->m_vRenderOffset.vec().x != 0) {
|
||||
@@ -652,13 +657,17 @@ void CHyprRenderer::renderSessionLockSurface(SSessionLockSurface* pSurface, CMon
|
||||
}
|
||||
|
||||
void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, CWorkspace* pWorkspace, timespec* time, const Vector2D& translate, const float& scale) {
|
||||
static auto* const PDIMSPECIAL = &g_pConfigManager->getConfigValuePtr("decoration:dim_special")->floatValue;
|
||||
static auto* const PBLURSPECIAL = &g_pConfigManager->getConfigValuePtr("decoration:blur:special")->intValue;
|
||||
static auto* const PBLUR = &g_pConfigManager->getConfigValuePtr("decoration:blur:enabled")->intValue;
|
||||
static auto* const PRENDERTEX = &g_pConfigManager->getConfigValuePtr("misc:disable_hyprland_logo")->intValue;
|
||||
static auto* const PBACKGROUNDCOLOR = &g_pConfigManager->getConfigValuePtr("misc:background_color")->intValue;
|
||||
static auto* const PDIMSPECIAL = &g_pConfigManager->getConfigValuePtr("decoration:dim_special")->floatValue;
|
||||
static auto* const PBLURSPECIAL = &g_pConfigManager->getConfigValuePtr("decoration:blur:special")->intValue;
|
||||
static auto* const PBLUR = &g_pConfigManager->getConfigValuePtr("decoration:blur:enabled")->intValue;
|
||||
static auto* const PRENDERTEX = &g_pConfigManager->getConfigValuePtr("misc:disable_hyprland_logo")->intValue;
|
||||
static auto* const PBACKGROUNDCOLOR = &g_pConfigManager->getConfigValuePtr("misc:background_color")->intValue;
|
||||
|
||||
const SRenderModifData RENDERMODIFDATA = {translate, scale};
|
||||
SRenderModifData RENDERMODIFDATA;
|
||||
if (translate != Vector2D{0, 0})
|
||||
RENDERMODIFDATA.modifs.push_back({SRenderModifData::eRenderModifType::RMOD_TYPE_TRANSLATE, translate});
|
||||
if (scale != 1.f)
|
||||
RENDERMODIFDATA.modifs.push_back({SRenderModifData::eRenderModifType::RMOD_TYPE_SCALE, scale});
|
||||
|
||||
if (!pMonitor)
|
||||
return;
|
||||
@@ -800,7 +809,7 @@ void CHyprRenderer::renderLockscreen(CMonitor* pMonitor, timespec* now) {
|
||||
}
|
||||
}
|
||||
|
||||
void CHyprRenderer::calculateUVForSurface(CWindow* pWindow, wlr_surface* pSurface, bool main) {
|
||||
void CHyprRenderer::calculateUVForSurface(CWindow* pWindow, wlr_surface* pSurface, bool main, const Vector2D& projSize, bool fixMisalignedFSV1) {
|
||||
if (!pWindow || !pWindow->m_bIsX11) {
|
||||
Vector2D uvTL;
|
||||
Vector2D uvBR = Vector2D(1, 1);
|
||||
@@ -822,6 +831,15 @@ void CHyprRenderer::calculateUVForSurface(CWindow* pWindow, wlr_surface* pSurfac
|
||||
}
|
||||
}
|
||||
|
||||
if (projSize != Vector2D{} && fixMisalignedFSV1) {
|
||||
// instead of nearest_neighbor (we will repeat / skip)
|
||||
// just cut off / expand surface
|
||||
const Vector2D PIXELASUV = Vector2D{1, 1} / Vector2D{pSurface->buffer->texture->width, pSurface->buffer->texture->height};
|
||||
const Vector2D MISALIGNMENT = Vector2D{pSurface->buffer->texture->width, pSurface->buffer->texture->height} - projSize;
|
||||
if (MISALIGNMENT != Vector2D{})
|
||||
uvBR -= MISALIGNMENT * PIXELASUV;
|
||||
}
|
||||
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = uvTL;
|
||||
g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = uvBR;
|
||||
|
||||
@@ -897,17 +915,17 @@ bool CHyprRenderer::attemptDirectScanout(CMonitor* pMonitor) {
|
||||
return false;
|
||||
|
||||
// finally, we should be GTG.
|
||||
wlr_output_attach_buffer(pMonitor->output, &PSURFACE->buffer->base);
|
||||
wlr_output_state_set_buffer(pMonitor->state.wlr(), &PSURFACE->buffer->base);
|
||||
|
||||
if (!wlr_output_test(pMonitor->output))
|
||||
if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr()))
|
||||
return false;
|
||||
|
||||
timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
wlr_surface_send_frame_done(PSURFACE, &now);
|
||||
wlr_presentation_surface_scanned_out_on_output(g_pCompositor->m_sWLRPresentation, PSURFACE, pMonitor->output);
|
||||
wlr_presentation_surface_scanned_out_on_output(PSURFACE, pMonitor->output);
|
||||
|
||||
if (wlr_output_commit(pMonitor->output)) {
|
||||
if (pMonitor->state.commit()) {
|
||||
if (!m_pLastScanout) {
|
||||
m_pLastScanout = PCANDIDATE;
|
||||
Debug::log(LOG, "Entered a direct scanout to {:x}: \"{}\"", (uintptr_t)PCANDIDATE, PCANDIDATE->m_szTitle);
|
||||
@@ -1008,14 +1026,15 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
|
||||
|
||||
const auto PGAMMACTRL = wlr_gamma_control_manager_v1_get_control(g_pCompositor->m_sWLRGammaCtrlMgr, pMonitor->output);
|
||||
|
||||
if (!wlr_gamma_control_v1_apply(PGAMMACTRL, &pMonitor->output->pending)) {
|
||||
if (!wlr_gamma_control_v1_apply(PGAMMACTRL, pMonitor->state.wlr())) {
|
||||
Debug::log(ERR, "Could not apply gamma control to {}", pMonitor->szName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!wlr_output_test(pMonitor->output)) {
|
||||
if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) {
|
||||
Debug::log(ERR, "Output test failed for setting gamma to {}", pMonitor->szName);
|
||||
wlr_output_rollback(pMonitor->output);
|
||||
// aka rollback
|
||||
wlr_gamma_control_v1_apply(nullptr, pMonitor->state.wlr());
|
||||
wlr_gamma_control_v1_send_failed_and_destroy(PGAMMACTRL);
|
||||
}
|
||||
}
|
||||
@@ -1144,6 +1163,8 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
|
||||
if (UNLOCK_SC)
|
||||
wlr_output_lock_software_cursors(pMonitor->output, false);
|
||||
|
||||
pMonitor->state.clear();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1230,9 +1251,9 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
|
||||
|
||||
EMIT_HOOK_EVENT("render", RENDER_POST);
|
||||
|
||||
pMonitor->output->pending.tearing_page_flip = shouldTear;
|
||||
pMonitor->state.wlr()->tearing_page_flip = shouldTear;
|
||||
|
||||
if (!wlr_output_commit(pMonitor->output)) {
|
||||
if (!pMonitor->state.commit()) {
|
||||
|
||||
if (UNLOCK_SC)
|
||||
wlr_output_lock_software_cursors(pMonitor->output, false);
|
||||
@@ -1319,6 +1340,8 @@ void CHyprRenderer::outputMgrApplyTest(wlr_output_configuration_v1* config, bool
|
||||
|
||||
std::string commandForCfg = "";
|
||||
const auto OUTPUT = head->state.output;
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromOutput(OUTPUT);
|
||||
RASSERT(PMONITOR, "nullptr monitor in outputMgrApplyTest");
|
||||
|
||||
commandForCfg += std::string(OUTPUT->name) + ",";
|
||||
|
||||
@@ -1329,7 +1352,7 @@ void CHyprRenderer::outputMgrApplyTest(wlr_output_configuration_v1* config, bool
|
||||
continue;
|
||||
}
|
||||
|
||||
wlr_output_enable(OUTPUT, head->state.enabled);
|
||||
wlr_output_state_set_enabled(PMONITOR->state.wlr(), head->state.enabled);
|
||||
|
||||
if (head->state.mode)
|
||||
commandForCfg +=
|
||||
@@ -1343,10 +1366,10 @@ void CHyprRenderer::outputMgrApplyTest(wlr_output_configuration_v1* config, bool
|
||||
|
||||
if (!test) {
|
||||
g_pConfigManager->parseKeyword("monitor", commandForCfg, true);
|
||||
wlr_output_state_set_adaptive_sync_enabled(&OUTPUT->pending, head->state.adaptive_sync_enabled);
|
||||
wlr_output_state_set_adaptive_sync_enabled(PMONITOR->state.wlr(), head->state.adaptive_sync_enabled);
|
||||
}
|
||||
|
||||
ok = wlr_output_test(OUTPUT);
|
||||
ok = wlr_output_test_state(OUTPUT, PMONITOR->state.wlr());
|
||||
|
||||
if (!ok)
|
||||
break;
|
||||
@@ -1567,8 +1590,7 @@ void CHyprRenderer::damageSurface(wlr_surface* pSurface, double x, double y, dou
|
||||
y += CORRECTION.y;
|
||||
}
|
||||
|
||||
CRegion damageBox;
|
||||
wlr_surface_get_effective_damage(pSurface, damageBox.pixman());
|
||||
CRegion damageBox{&pSurface->buffer_damage};
|
||||
if (scale != 1.0)
|
||||
wlr_region_scale(damageBox.pixman(), damageBox.pixman(), scale);
|
||||
|
||||
@@ -1745,6 +1767,9 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto WAS10B = pMonitor->enabled10bit;
|
||||
const auto OLDRES = pMonitor->vecPixelSize;
|
||||
|
||||
// Needed in case we are switching from a custom modeline to a standard mode
|
||||
pMonitor->customDrmMode = {};
|
||||
bool autoScale = false;
|
||||
@@ -1757,10 +1782,10 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
|
||||
pMonitor->scale = DEFAULTSCALE;
|
||||
}
|
||||
|
||||
wlr_output_set_scale(pMonitor->output, pMonitor->scale);
|
||||
wlr_output_state_set_scale(pMonitor->state.wlr(), pMonitor->scale);
|
||||
pMonitor->setScale = pMonitor->scale;
|
||||
|
||||
wlr_output_set_transform(pMonitor->output, pMonitorRule->transform);
|
||||
wlr_output_state_set_transform(pMonitor->state.wlr(), pMonitorRule->transform);
|
||||
pMonitor->transform = pMonitorRule->transform;
|
||||
|
||||
const auto WLRREFRESHRATE = (wlr_backend_is_wl(pMonitor->output->backend) || wlr_backend_is_x11(pMonitor->output->backend)) ? 0 : pMonitorRule->refreshRate * 1000;
|
||||
@@ -1775,9 +1800,9 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
|
||||
// if delta of refresh rate, w and h chosen and mode is < 1 we accept it
|
||||
if (DELTALESSTHAN(mode->width, pMonitorRule->resolution.x, 1) && DELTALESSTHAN(mode->height, pMonitorRule->resolution.y, 1) &&
|
||||
DELTALESSTHAN(mode->refresh / 1000.f, pMonitorRule->refreshRate, 1)) {
|
||||
wlr_output_set_mode(pMonitor->output, mode);
|
||||
wlr_output_state_set_mode(pMonitor->state.wlr(), mode);
|
||||
|
||||
if (!wlr_output_test(pMonitor->output)) {
|
||||
if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) {
|
||||
Debug::log(LOG, "Monitor {}: REJECTED available mode: {}x{}@{:2f}!", pMonitor->output->name, mode->width, mode->height, mode->refresh / 1000.f);
|
||||
continue;
|
||||
}
|
||||
@@ -1795,11 +1820,11 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
wlr_output_set_custom_mode(pMonitor->output, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, WLRREFRESHRATE);
|
||||
wlr_output_state_set_custom_mode(pMonitor->state.wlr(), (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, WLRREFRESHRATE);
|
||||
pMonitor->vecSize = pMonitorRule->resolution;
|
||||
pMonitor->refreshRate = pMonitorRule->refreshRate;
|
||||
|
||||
if (!wlr_output_test(pMonitor->output)) {
|
||||
if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) {
|
||||
Debug::log(ERR, "Custom resolution FAILED, falling back to preferred");
|
||||
|
||||
const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output);
|
||||
@@ -1811,7 +1836,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
|
||||
}
|
||||
|
||||
// Preferred is valid
|
||||
wlr_output_set_mode(pMonitor->output, PREFERREDMODE);
|
||||
wlr_output_state_set_mode(pMonitor->state.wlr(), PREFERREDMODE);
|
||||
|
||||
Debug::log(ERR, "Monitor {} got an invalid requested mode: {:X0}@{:2f}, using the preferred one instead: {}x{}@{:2f}", pMonitor->output->name,
|
||||
pMonitorRule->resolution, (float)pMonitorRule->refreshRate, PREFERREDMODE->width, PREFERREDMODE->height, PREFERREDMODE->refresh / 1000.f);
|
||||
@@ -1833,7 +1858,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
|
||||
} else {
|
||||
auto* mode = wlr_drm_connector_add_mode(pMonitor->output, &pMonitorRule->drmMode);
|
||||
if (mode) {
|
||||
wlr_output_set_mode(pMonitor->output, mode);
|
||||
wlr_output_state_set_mode(pMonitor->state.wlr(), mode);
|
||||
pMonitor->customDrmMode = pMonitorRule->drmMode;
|
||||
} else {
|
||||
Debug::log(ERR, "wlr_drm_connector_add_mode failed");
|
||||
@@ -1841,13 +1866,13 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
|
||||
}
|
||||
}
|
||||
} else {
|
||||
wlr_output_set_custom_mode(pMonitor->output, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, WLRREFRESHRATE);
|
||||
wlr_output_state_set_custom_mode(pMonitor->state.wlr(), (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, WLRREFRESHRATE);
|
||||
}
|
||||
|
||||
pMonitor->vecSize = pMonitorRule->resolution;
|
||||
pMonitor->refreshRate = pMonitorRule->refreshRate;
|
||||
|
||||
if (fail || !wlr_output_test(pMonitor->output)) {
|
||||
if (fail || !wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) {
|
||||
Debug::log(ERR, "Custom resolution FAILED, falling back to preferred");
|
||||
|
||||
const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output);
|
||||
@@ -1859,7 +1884,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
|
||||
}
|
||||
|
||||
// Preferred is valid
|
||||
wlr_output_set_mode(pMonitor->output, PREFERREDMODE);
|
||||
wlr_output_state_set_mode(pMonitor->state.wlr(), PREFERREDMODE);
|
||||
|
||||
Debug::log(ERR, "Monitor {} got an invalid requested mode: {:X0}@{:2f}, using the preferred one instead: {}x{}@{:2f}", pMonitor->output->name,
|
||||
pMonitorRule->resolution, (float)pMonitorRule->refreshRate, PREFERREDMODE->width, PREFERREDMODE->height, PREFERREDMODE->refresh / 1000.f);
|
||||
@@ -1883,8 +1908,8 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
|
||||
if (pMonitorRule->resolution == Vector2D(-1, -1)) {
|
||||
wl_list_for_each(mode, &pMonitor->output->modes, link) {
|
||||
if ((mode->width >= currentWidth && mode->height >= currentHeight && mode->refresh >= (currentRefresh - 1000.f)) || mode->refresh > (currentRefresh + 3000.f)) {
|
||||
wlr_output_set_mode(pMonitor->output, mode);
|
||||
if (wlr_output_test(pMonitor->output)) {
|
||||
wlr_output_state_set_mode(pMonitor->state.wlr(), mode);
|
||||
if (wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) {
|
||||
currentWidth = mode->width;
|
||||
currentHeight = mode->height;
|
||||
currentRefresh = mode->refresh;
|
||||
@@ -1896,8 +1921,8 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
|
||||
wl_list_for_each(mode, &pMonitor->output->modes, link) {
|
||||
if ((mode->width >= currentWidth && mode->height >= currentHeight && mode->refresh >= (currentRefresh - 1000.f)) ||
|
||||
(mode->width > currentWidth && mode->height > currentHeight)) {
|
||||
wlr_output_set_mode(pMonitor->output, mode);
|
||||
if (wlr_output_test(pMonitor->output)) {
|
||||
wlr_output_state_set_mode(pMonitor->state.wlr(), mode);
|
||||
if (wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) {
|
||||
currentWidth = mode->width;
|
||||
currentHeight = mode->height;
|
||||
currentRefresh = mode->refresh;
|
||||
@@ -1920,7 +1945,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
|
||||
}
|
||||
|
||||
// Preferred is valid
|
||||
wlr_output_set_mode(pMonitor->output, PREFERREDMODE);
|
||||
wlr_output_state_set_mode(pMonitor->state.wlr(), PREFERREDMODE);
|
||||
|
||||
Debug::log(ERR, "Monitor {} got an invalid requested mode: {:X0}@{:2f}, using the preferred one instead: {}x{}@{:2f}", pMonitor->output->name,
|
||||
pMonitorRule->resolution, (float)pMonitorRule->refreshRate, PREFERREDMODE->width, PREFERREDMODE->height, PREFERREDMODE->refresh / 1000.f);
|
||||
@@ -1945,9 +1970,9 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
|
||||
wlr_output_mode* mode;
|
||||
|
||||
wl_list_for_each(mode, &pMonitor->output->modes, link) {
|
||||
wlr_output_set_mode(pMonitor->output, mode);
|
||||
wlr_output_state_set_mode(pMonitor->state.wlr(), mode);
|
||||
|
||||
if (!wlr_output_test(pMonitor->output)) {
|
||||
if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) {
|
||||
Debug::log(LOG, "Monitor {}: REJECTED available mode: {}x{}@{:2f}!", pMonitor->output->name, mode->width, mode->height, mode->refresh / 1000.f);
|
||||
continue;
|
||||
}
|
||||
@@ -1963,7 +1988,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
|
||||
}
|
||||
} else {
|
||||
// Preferred is valid
|
||||
wlr_output_set_mode(pMonitor->output, PREFERREDMODE);
|
||||
wlr_output_state_set_mode(pMonitor->state.wlr(), PREFERREDMODE);
|
||||
|
||||
pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height);
|
||||
pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f;
|
||||
@@ -1972,7 +1997,8 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
|
||||
}
|
||||
}
|
||||
|
||||
pMonitor->vrrActive = pMonitor->output->pending.adaptive_sync_enabled; // disabled here, will be tested in CConfigManager::ensureVRR()
|
||||
pMonitor->vrrActive = pMonitor->state.wlr()->adaptive_sync_enabled // disabled here, will be tested in CConfigManager::ensureVRR()
|
||||
|| pMonitor->createdByUser; // wayland backend doesn't allow for disabling adaptive_sync
|
||||
|
||||
pMonitor->vecPixelSize = pMonitor->vecSize;
|
||||
|
||||
@@ -1989,6 +2015,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
|
||||
Vector2D logicalZero = pMonitor->vecPixelSize / scaleZero;
|
||||
if (logicalZero == logicalZero.round()) {
|
||||
pMonitor->scale = scaleZero;
|
||||
wlr_output_state_set_scale(pMonitor->state.wlr(), pMonitor->scale);
|
||||
} else {
|
||||
for (size_t i = 1; i < 90; ++i) {
|
||||
double scaleUp = (searchScale + i) / 120.0;
|
||||
@@ -2026,11 +2053,15 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
|
||||
} else
|
||||
pMonitor->scale = searchScale;
|
||||
}
|
||||
|
||||
// for wlroots, that likes flooring, we have to do this.
|
||||
double logicalX = std::round(pMonitor->vecPixelSize.x / pMonitor->scale);
|
||||
logicalX += 0.1;
|
||||
|
||||
wlr_output_state_set_scale(pMonitor->state.wlr(), pMonitor->vecPixelSize.x / logicalX);
|
||||
}
|
||||
}
|
||||
|
||||
wlr_output_set_scale(pMonitor->output, pMonitor->scale);
|
||||
|
||||
// clang-format off
|
||||
static const std::array<std::vector<std::pair<std::string, uint32_t>>, 2> formats{
|
||||
std::vector<std::pair<std::string, uint32_t>>{ /* 10-bit */
|
||||
@@ -2046,9 +2077,9 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
|
||||
pMonitor->drmFormat = DRM_FORMAT_INVALID;
|
||||
|
||||
for (auto& fmt : formats[(int)!pMonitorRule->enable10bit]) {
|
||||
wlr_output_set_render_format(pMonitor->output, fmt.second);
|
||||
wlr_output_state_set_render_format(pMonitor->state.wlr(), fmt.second);
|
||||
|
||||
if (!wlr_output_test(pMonitor->output)) {
|
||||
if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) {
|
||||
Debug::log(ERR, "output {} failed basic test on format {}", pMonitor->szName, fmt.first);
|
||||
} else {
|
||||
Debug::log(LOG, "output {} succeeded basic test on format {}", pMonitor->szName, fmt.first);
|
||||
@@ -2062,9 +2093,8 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
|
||||
|
||||
pMonitor->enabled10bit = set10bit;
|
||||
|
||||
if (!wlr_output_commit(pMonitor->output)) {
|
||||
if (!pMonitor->state.commit())
|
||||
Debug::log(ERR, "Couldn't commit output named {}", pMonitor->output->name);
|
||||
}
|
||||
|
||||
int x, y;
|
||||
wlr_output_transformed_resolution(pMonitor->output, &x, &y);
|
||||
@@ -2080,14 +2110,21 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
|
||||
|
||||
pMonitor->updateMatrix();
|
||||
|
||||
// update renderer (here because it will call rollback, so we cannot do this before committing)
|
||||
g_pHyprOpenGL->destroyMonitorResources(pMonitor);
|
||||
if (WAS10B != pMonitor->enabled10bit || OLDRES != pMonitor->vecPixelSize)
|
||||
g_pHyprOpenGL->destroyMonitorResources(pMonitor);
|
||||
|
||||
// updato wlroots
|
||||
g_pCompositor->arrangeMonitors();
|
||||
|
||||
wlr_damage_ring_set_bounds(&pMonitor->damage, pMonitor->vecTransformedSize.x, pMonitor->vecTransformedSize.y);
|
||||
|
||||
// Set scale for all surfaces on this monitor, needed for some clients
|
||||
// but not on unsafe state to avoid crashes
|
||||
if (!g_pCompositor->m_bUnsafeState) {
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
w->updateSurfaceScaleTransformDetails();
|
||||
}
|
||||
}
|
||||
// updato us
|
||||
arrangeLayersForMonitor(pMonitor->ID);
|
||||
|
||||
@@ -2422,7 +2459,7 @@ bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode
|
||||
}
|
||||
|
||||
if (!buffer) {
|
||||
if (!wlr_output_configure_primary_swapchain(pMonitor->output, &pMonitor->output->pending, &pMonitor->output->swapchain))
|
||||
if (!wlr_output_configure_primary_swapchain(pMonitor->output, pMonitor->state.wlr(), &pMonitor->output->swapchain))
|
||||
return false;
|
||||
|
||||
m_pCurrentWlrBuffer = wlr_swapchain_acquire(pMonitor->output->swapchain, &m_iLastBufferAge);
|
||||
@@ -2466,7 +2503,7 @@ void CHyprRenderer::endRender() {
|
||||
glFlush();
|
||||
|
||||
if (m_eRenderMode == RENDER_MODE_NORMAL) {
|
||||
wlr_output_state_set_buffer(&PMONITOR->output->pending, m_pCurrentWlrBuffer);
|
||||
wlr_output_state_set_buffer(PMONITOR->state.wlr(), m_pCurrentWlrBuffer);
|
||||
unsetEGL(); // flush the context
|
||||
}
|
||||
|
||||
|
@@ -57,7 +57,7 @@ class CHyprRenderer {
|
||||
void ensureCursorRenderingMode();
|
||||
bool shouldRenderCursor();
|
||||
void setCursorHidden(bool hide);
|
||||
void calculateUVForSurface(CWindow*, wlr_surface*, bool main = false);
|
||||
void calculateUVForSurface(CWindow*, wlr_surface*, bool main = false, const Vector2D& projSize = {}, bool fixMisalignedFSV1 = false);
|
||||
std::tuple<float, float, float> getRenderTimes(CMonitor* pMonitor); // avg max min
|
||||
void renderLockscreen(CMonitor* pMonitor, timespec* now);
|
||||
void setOccludedForBackLayers(CRegion& region, CWorkspace* pWorkspace);
|
||||
@@ -82,7 +82,6 @@ class CHyprRenderer {
|
||||
CMonitor* m_pMostHzMonitor = nullptr;
|
||||
bool m_bDirectScanoutBlocked = false;
|
||||
bool m_bSoftwareCursorsLocked = false;
|
||||
bool m_bTearingEnvSatisfied = false;
|
||||
|
||||
DAMAGETRACKINGMODES
|
||||
damageTrackingModeFromStr(const std::string&);
|
||||
|
@@ -42,9 +42,9 @@ class CShader {
|
||||
GLint gradientLength = -1;
|
||||
GLint angle = -1;
|
||||
|
||||
GLint time = -1;
|
||||
GLint distort = -1;
|
||||
GLint output = -1;
|
||||
GLint time = -1;
|
||||
GLint distort = -1;
|
||||
GLint wl_output = -1;
|
||||
|
||||
// Blur prepare
|
||||
GLint contrast = -1;
|
||||
|
@@ -104,5 +104,5 @@ std::string CHyprBorderDecoration::getDisplayName() {
|
||||
}
|
||||
|
||||
bool CHyprBorderDecoration::doesntWantBorders() {
|
||||
return !m_pWindow->m_sSpecialRenderData.border || m_pWindow->m_bX11DoesntWantBorders;
|
||||
return !m_pWindow->m_sSpecialRenderData.border || m_pWindow->m_bX11DoesntWantBorders || m_pWindow->getRealBorderSize() == 0;
|
||||
}
|
||||
|
@@ -26,9 +26,10 @@ CHyprGroupBarDecoration::CHyprGroupBarDecoration(CWindow* pWindow) : IHyprWindow
|
||||
CHyprGroupBarDecoration::~CHyprGroupBarDecoration() {}
|
||||
|
||||
SDecorationPositioningInfo CHyprGroupBarDecoration::getPositioningInfo() {
|
||||
static auto* const PRENDERTITLES = &g_pConfigManager->getConfigValuePtr("group:groupbar:render_titles")->intValue;
|
||||
static auto* const PTITLEFONTSIZE = &g_pConfigManager->getConfigValuePtr("group:groupbar:font_size")->intValue;
|
||||
static auto* const PENABLED = &g_pConfigManager->getConfigValuePtr("group:groupbar:enabled")->intValue;
|
||||
static auto* const PHEIGHT = &g_pConfigManager->getConfigValuePtr("group:groupbar:height")->intValue;
|
||||
static auto* const PENABLED = &g_pConfigManager->getConfigValuePtr("group:groupbar:enabled")->intValue;
|
||||
static auto* const PRENDERTITLES = &g_pConfigManager->getConfigValuePtr("group:groupbar:render_titles")->intValue;
|
||||
static auto* const PGRADIENTS = &g_pConfigManager->getConfigValuePtr("group:groupbar:gradients")->intValue;
|
||||
|
||||
SDecorationPositioningInfo info;
|
||||
info.policy = DECORATION_POSITION_STICKY;
|
||||
@@ -37,7 +38,7 @@ SDecorationPositioningInfo CHyprGroupBarDecoration::getPositioningInfo() {
|
||||
info.reserved = true;
|
||||
|
||||
if (*PENABLED && m_pWindow->m_sSpecialRenderData.decorate)
|
||||
info.desiredExtents = {{0, BAR_PADDING_OUTER_VERT * 2 + BAR_INDICATOR_HEIGHT + (*PRENDERTITLES ? *PTITLEFONTSIZE : 0) + 2}, {0, 0}};
|
||||
info.desiredExtents = {{0, BAR_PADDING_OUTER_VERT * 2 + BAR_INDICATOR_HEIGHT + (*PGRADIENTS || *PRENDERTITLES ? *PHEIGHT : 0) + 2}, {0, 0}};
|
||||
else
|
||||
info.desiredExtents = {{0, 0}, {0, 0}};
|
||||
|
||||
@@ -90,6 +91,7 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a, const Vector2D&
|
||||
static auto* const PENABLED = &g_pConfigManager->getConfigValuePtr("group:groupbar:enabled")->intValue;
|
||||
static auto* const PRENDERTITLES = &g_pConfigManager->getConfigValuePtr("group:groupbar:render_titles")->intValue;
|
||||
static auto* const PTITLEFONTSIZE = &g_pConfigManager->getConfigValuePtr("group:groupbar:font_size")->intValue;
|
||||
static auto* const PHEIGHT = &g_pConfigManager->getConfigValuePtr("group:groupbar:height")->intValue;
|
||||
static auto* const PGRADIENTS = &g_pConfigManager->getConfigValuePtr("group:groupbar:gradients")->intValue;
|
||||
|
||||
if (!*PENABLED || !m_pWindow->m_sSpecialRenderData.decorate)
|
||||
@@ -99,7 +101,7 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a, const Vector2D&
|
||||
|
||||
m_fBarWidth = (ASSIGNEDBOX.w - BAR_HORIZONTAL_PADDING * (barsToDraw - 1)) / barsToDraw;
|
||||
|
||||
const auto DESIREDHEIGHT = BAR_PADDING_OUTER_VERT * 2 + BAR_INDICATOR_HEIGHT + (*PRENDERTITLES ? *PTITLEFONTSIZE : 0) + 2;
|
||||
const auto DESIREDHEIGHT = BAR_PADDING_OUTER_VERT * 2 + BAR_INDICATOR_HEIGHT + (*PGRADIENTS || *PRENDERTITLES ? *PHEIGHT : 0) + 2;
|
||||
if (DESIREDHEIGHT != ASSIGNEDBOX.h)
|
||||
g_pDecorationPositioner->repositionDeco(this);
|
||||
|
||||
@@ -128,12 +130,18 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a, const Vector2D&
|
||||
color.a *= a;
|
||||
g_pHyprOpenGL->renderRect(&rect, color);
|
||||
|
||||
// render title if necessary
|
||||
if (*PRENDERTITLES) {
|
||||
CBox rect = {ASSIGNEDBOX.x + xoff - pMonitor->vecPosition.x + offset.x, ASSIGNEDBOX.y - pMonitor->vecPosition.y + offset.y + BAR_PADDING_OUTER_VERT, m_fBarWidth,
|
||||
ASSIGNEDBOX.h - BAR_INDICATOR_HEIGHT - BAR_PADDING_OUTER_VERT * 2};
|
||||
rect.scale(pMonitor->scale);
|
||||
rect = {ASSIGNEDBOX.x + xoff - pMonitor->vecPosition.x + offset.x, ASSIGNEDBOX.y - pMonitor->vecPosition.y + offset.y + BAR_PADDING_OUTER_VERT, m_fBarWidth,
|
||||
ASSIGNEDBOX.h - BAR_INDICATOR_HEIGHT - BAR_PADDING_OUTER_VERT * 2};
|
||||
rect.scale(pMonitor->scale);
|
||||
|
||||
if (*PGRADIENTS) {
|
||||
const auto& GRADIENTTEX = (m_dwGroupMembers[i] == g_pCompositor->m_pLastWindow ? (GROUPLOCKED ? m_tGradientLockedActive : m_tGradientActive) :
|
||||
(GROUPLOCKED ? m_tGradientLockedInactive : m_tGradientInactive));
|
||||
if (GRADIENTTEX.m_iTexID != 0)
|
||||
g_pHyprOpenGL->renderTexture(GRADIENTTEX, &rect, 1.0);
|
||||
}
|
||||
|
||||
if (*PRENDERTITLES) {
|
||||
CTitleTex* pTitleTex = textureFromTitle(m_dwGroupMembers[i]->m_szTitle);
|
||||
|
||||
if (!pTitleTex)
|
||||
@@ -142,12 +150,6 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a, const Vector2D&
|
||||
Vector2D{m_fBarWidth * pMonitor->scale, (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) * pMonitor->scale}))
|
||||
.get();
|
||||
|
||||
const auto& GRADIENTTEX = (m_dwGroupMembers[i] == g_pCompositor->m_pLastWindow ? (GROUPLOCKED ? m_tGradientLockedActive : m_tGradientActive) :
|
||||
(GROUPLOCKED ? m_tGradientLockedInactive : m_tGradientInactive));
|
||||
|
||||
if (*PGRADIENTS && GRADIENTTEX.m_iTexID != 0)
|
||||
g_pHyprOpenGL->renderTexture(GRADIENTTEX, &rect, 1.0);
|
||||
|
||||
rect.y += (ASSIGNEDBOX.h / 2.0 - (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) / 2.0) * pMonitor->scale;
|
||||
rect.height = (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) * pMonitor->scale;
|
||||
|
||||
@@ -243,7 +245,7 @@ CTitleTex::~CTitleTex() {
|
||||
tex.destroyTexture();
|
||||
}
|
||||
|
||||
void renderGradientTo(CTexture& tex, const CColor& grad) {
|
||||
void renderGradientTo(CTexture& tex, CGradientValueData* grad) {
|
||||
|
||||
if (!g_pCompositor->m_pLastMonitor)
|
||||
return;
|
||||
@@ -261,8 +263,12 @@ void renderGradientTo(CTexture& tex, const CColor& grad) {
|
||||
|
||||
cairo_pattern_t* pattern;
|
||||
pattern = cairo_pattern_create_linear(0, 0, 0, bufferSize.y);
|
||||
cairo_pattern_add_color_stop_rgba(pattern, 1, grad.r, grad.g, grad.b, grad.a);
|
||||
cairo_pattern_add_color_stop_rgba(pattern, 0, grad.r, grad.g, grad.b, 0);
|
||||
|
||||
for (unsigned long i = 0; i < grad->m_vColors.size(); i++) {
|
||||
cairo_pattern_add_color_stop_rgba(pattern, 1 - (double)(i + 1) / (grad->m_vColors.size() + 1), grad->m_vColors[i].r, grad->m_vColors[i].g, grad->m_vColors[i].b,
|
||||
grad->m_vColors[i].a);
|
||||
}
|
||||
|
||||
cairo_rectangle(CAIRO, 0, 0, bufferSize.x, bufferSize.y);
|
||||
cairo_set_source(CAIRO, pattern);
|
||||
cairo_fill(CAIRO);
|
||||
@@ -290,13 +296,13 @@ void renderGradientTo(CTexture& tex, const CColor& grad) {
|
||||
}
|
||||
|
||||
void refreshGroupBarGradients() {
|
||||
static auto* const PGRADIENTS = &g_pConfigManager->getConfigValuePtr("group:groupbar:enabled")->intValue;
|
||||
static auto* const PENABLED = &g_pConfigManager->getConfigValuePtr("group:groupbar:gradients")->intValue;
|
||||
static auto* const PGRADIENTS = &g_pConfigManager->getConfigValuePtr("group:groupbar:enabled")->intValue;
|
||||
static auto* const PENABLED = &g_pConfigManager->getConfigValuePtr("group:groupbar:gradients")->intValue;
|
||||
|
||||
static auto* const PGROUPCOLACTIVE = &g_pConfigManager->getConfigValuePtr("group:groupbar:col.active")->data;
|
||||
static auto* const PGROUPCOLINACTIVE = &g_pConfigManager->getConfigValuePtr("group:groupbar:col.inactive")->data;
|
||||
static auto* const PGROUPCOLACTIVELOCKED = &g_pConfigManager->getConfigValuePtr("group:groupbar:col.locked_active")->data;
|
||||
static auto* const PGROUPCOLINACTIVELOCKED = &g_pConfigManager->getConfigValuePtr("group:groupbar:col.locked_inactive")->data;
|
||||
CGradientValueData* PGROUPCOLACTIVE = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("group:groupbar:col.active")->data.get();
|
||||
CGradientValueData* PGROUPCOLINACTIVE = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("group:groupbar:col.inactive")->data.get();
|
||||
CGradientValueData* PGROUPCOLACTIVELOCKED = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("group:groupbar:col.locked_active")->data.get();
|
||||
CGradientValueData* PGROUPCOLINACTIVELOCKED = (CGradientValueData*)g_pConfigManager->getConfigValuePtr("group:groupbar:col.locked_inactive")->data.get();
|
||||
|
||||
g_pHyprRenderer->makeEGLCurrent();
|
||||
|
||||
@@ -310,13 +316,16 @@ void refreshGroupBarGradients() {
|
||||
if (!*PENABLED || !*PGRADIENTS)
|
||||
return;
|
||||
|
||||
renderGradientTo(m_tGradientActive, ((CGradientValueData*)PGROUPCOLACTIVE->get())->m_vColors[0]);
|
||||
renderGradientTo(m_tGradientInactive, ((CGradientValueData*)PGROUPCOLINACTIVE->get())->m_vColors[0]);
|
||||
renderGradientTo(m_tGradientLockedActive, ((CGradientValueData*)PGROUPCOLACTIVELOCKED->get())->m_vColors[0]);
|
||||
renderGradientTo(m_tGradientLockedInactive, ((CGradientValueData*)PGROUPCOLINACTIVELOCKED->get())->m_vColors[0]);
|
||||
renderGradientTo(m_tGradientActive, PGROUPCOLACTIVE);
|
||||
renderGradientTo(m_tGradientInactive, PGROUPCOLINACTIVE);
|
||||
renderGradientTo(m_tGradientLockedActive, PGROUPCOLACTIVELOCKED);
|
||||
renderGradientTo(m_tGradientLockedInactive, PGROUPCOLINACTIVELOCKED);
|
||||
}
|
||||
|
||||
bool CHyprGroupBarDecoration::onBeginWindowDragOnDeco(const Vector2D& pos) {
|
||||
if (m_pWindow == m_pWindow->m_sGroupData.pNextWindow)
|
||||
return false;
|
||||
|
||||
const float BARRELATIVEX = pos.x - assignedBoxGlobal().x;
|
||||
const int WINDOWINDEX = (BARRELATIVEX) / (m_fBarWidth + BAR_HORIZONTAL_PADDING);
|
||||
|
||||
|
@@ -1,45 +0,0 @@
|
||||
diff --git a/include/meson.build b/include/meson.build
|
||||
index e669800..687786b 100644
|
||||
--- a/include/meson.build
|
||||
+++ b/include/meson.build
|
||||
@@ -1,4 +1,5 @@
|
||||
-subdir('wlr')
|
||||
+run_command('ln', '-sf', join_paths(meson.project_source_root(), 'include', 'wlr'), join_paths(meson.project_source_root(), 'include', 'wlroots'), check: true)
|
||||
+subdir('wlroots')
|
||||
|
||||
exclude_files = ['meson.build', 'config.h.in', 'version.h.in']
|
||||
if not features.get('drm-backend')
|
||||
@@ -24,8 +25,8 @@ if not features.get('session')
|
||||
exclude_files += 'backend/session.h'
|
||||
endif
|
||||
|
||||
-install_subdir('wlr',
|
||||
- install_dir: get_option('includedir'),
|
||||
+install_subdir('wlroots',
|
||||
+ install_dir: join_paths(get_option('includedir'), 'hyprland'),
|
||||
exclude_files: exclude_files,
|
||||
)
|
||||
|
||||
diff --git a/include/wlr/meson.build b/include/wlr/meson.build
|
||||
index f7ca413..0a86d54 100644
|
||||
--- a/include/wlr/meson.build
|
||||
+++ b/include/wlr/meson.build
|
||||
@@ -22,4 +22,4 @@ ver_h = configure_file(
|
||||
configuration: version_data,
|
||||
)
|
||||
|
||||
-install_headers(conf_h, ver_h, subdir: 'wlr')
|
||||
+install_headers(conf_h, ver_h, subdir: join_paths('hyprland', 'wlroots'))
|
||||
diff --git a/meson.build b/meson.build
|
||||
index 29b103a..0b6e5a4 100644
|
||||
--- a/meson.build
|
||||
+++ b/meson.build
|
||||
@@ -15,7 +15,7 @@ project(
|
||||
# necessary for bugfix releases. Increasing soversion is required because
|
||||
# wlroots never guarantees ABI stability -- only API stability is guaranteed
|
||||
# between minor releases.
|
||||
-soversion = 13
|
||||
+soversion = 13032
|
||||
|
||||
little_endian = target_machine.endian() == 'little'
|
||||
big_endian = target_machine.endian() == 'big'
|
@@ -1,7 +0,0 @@
|
||||
[wrap-git]
|
||||
directory = wlroots
|
||||
url = https://gitlab.freedesktop.org/wlroots/wlroots.git
|
||||
revision = 5d639394f3e83b01596dcd166a44a9a1a2583350
|
||||
depth = 1
|
||||
|
||||
diff_files = wlroots-meson-build.patch
|