mirror of https://github.com/hyprwm/Hyprland
Merge branch 'main' into fix/cursor-min-padding
This commit is contained in:
commit
e58589f797
|
@ -68,6 +68,11 @@ runs:
|
|||
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
|
||||
cmake --install build
|
||||
|
||||
- name: Get hyprutils-git
|
||||
shell: bash
|
||||
run: |
|
||||
git clone https://github.com/hyprwm/hyprutils && cd hyprutils && cmake -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr -B build && cmake --build build --target hyprutils && cmake --install build
|
||||
|
||||
- name: Get Xorg pacman pkgs
|
||||
shell: bash
|
||||
if: inputs.INSTALL_XORG_PKGS == 'true'
|
||||
|
|
|
@ -113,7 +113,7 @@ pkg_check_modules(deps REQUIRED IMPORTED_TARGET
|
|||
wayland-server wayland-client wayland-cursor wayland-protocols
|
||||
cairo pango pangocairo pixman-1
|
||||
libdrm libinput hwdata libseat libdisplay-info libliftoff libudev gbm
|
||||
hyprlang>=0.3.2 hyprcursor>=0.1.7
|
||||
hyprlang>=0.3.2 hyprcursor>=0.1.7 hyprutils>=0.1.1
|
||||
)
|
||||
|
||||
find_package(hyprwayland-scanner 0.3.10 REQUIRED)
|
||||
|
|
2
Makefile
2
Makefile
|
@ -42,7 +42,7 @@ uninstall:
|
|||
pluginenv:
|
||||
@echo -en "$(MAKE) pluginenv has been deprecated.\nPlease run $(MAKE) all && sudo $(MAKE) installheaders\n"
|
||||
@exit 1
|
||||
|
||||
|
||||
installheaders:
|
||||
@if [ ! -f ./src/version.h ]; then echo -en "You need to run $(MAKE) all first.\n" && exit 1; fi
|
||||
|
||||
|
|
|
@ -125,7 +125,7 @@ dwindle {
|
|||
|
||||
# See https://wiki.hyprland.org/Configuring/Master-Layout/ for more
|
||||
master {
|
||||
new_is_master = true
|
||||
new_status = master
|
||||
}
|
||||
|
||||
# https://wiki.hyprland.org/Configuring/Variables/#misc
|
||||
|
|
57
flake.lock
57
flake.lock
|
@ -13,11 +13,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1717181720,
|
||||
"narHash": "sha256-yv+QZWsusu/NWjydkxixHC2g+tIJ9v+xkE2EiVpJj6g=",
|
||||
"lastModified": 1718368322,
|
||||
"narHash": "sha256-VfMg3RsnRLQzbq0hFIh1dCM09b5C/F/qPFUOgU/CRi0=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprcursor",
|
||||
"rev": "9e27a2c2ceb1e0b85bd55b0afefad196056fe87c",
|
||||
"rev": "dd3a853c8239d1c3f3f37de7d2b8ae4b4f3840df",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -53,6 +53,9 @@
|
|||
},
|
||||
"hyprlang": {
|
||||
"inputs": {
|
||||
"hyprutils": [
|
||||
"hyprutils"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
|
@ -61,11 +64,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1716473782,
|
||||
"narHash": "sha256-+qLn4lsHU6iL3+HTo1gTQ1tWzet8K9h+IfVemzEQZj8=",
|
||||
"lastModified": 1717881852,
|
||||
"narHash": "sha256-XeeVoKHQgfKuXoP6q90sUqKyl7EYy3ol2dVZGM+Jj94=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprlang",
|
||||
"rev": "87d5d984109c839482b88b4795db073eb9ed446f",
|
||||
"rev": "ec6938c66253429192274d612912649a0cfe4d28",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -74,6 +77,29 @@
|
|||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hyprutils": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"systems": [
|
||||
"systems"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1718271409,
|
||||
"narHash": "sha256-8KvVqtApNt4FWTdn1TqVvw00rpqyG9UuUPA2ilPVD1U=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprutils",
|
||||
"rev": "8e10e0626fb26a14b859b3811b6ed7932400c86e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprutils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hyprwayland-scanner": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
|
@ -84,11 +110,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1717784906,
|
||||
"narHash": "sha256-YxmfxHfWed1fosaa7fC1u7XoKp1anEZU+7Lh/ojRKoM=",
|
||||
"lastModified": 1718119275,
|
||||
"narHash": "sha256-nqDYXATNkyGXVmNMkT19fT4sjtSPBDS1LLOxa3Fueo4=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprwayland-scanner",
|
||||
"rev": "0f30f9eca6e404130988554accbb64d1c9ec877d",
|
||||
"rev": "1419520d5f7f38d35e05504da5c1b38212a38525",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -99,11 +125,11 @@
|
|||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1717602782,
|
||||
"narHash": "sha256-pL9jeus5QpX5R+9rsp3hhZ+uplVHscNJh8n8VpqscM0=",
|
||||
"lastModified": 1718318537,
|
||||
"narHash": "sha256-4Zu0RYRcAY/VWuu6awwq4opuiD//ahpc2aFHg2CWqFY=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "e8057b67ebf307f01bdcc8fba94d94f75039d1f6",
|
||||
"rev": "e9ee548d90ff586a6471b4ae80ae9cfcbceb3420",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -117,6 +143,7 @@
|
|||
"inputs": {
|
||||
"hyprcursor": "hyprcursor",
|
||||
"hyprlang": "hyprlang",
|
||||
"hyprutils": "hyprutils",
|
||||
"hyprwayland-scanner": "hyprwayland-scanner",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"systems": "systems",
|
||||
|
@ -152,11 +179,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1716290197,
|
||||
"narHash": "sha256-1u9Exrc7yx9qtES2brDh7/DDZ8w8ap1nboIOAtCgeuM=",
|
||||
"lastModified": 1718272114,
|
||||
"narHash": "sha256-KsX7sAwkEFpXiwyjt0HGTnnrUU58wW1jlzj5IA/LRz8=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "xdg-desktop-portal-hyprland",
|
||||
"rev": "91e48d6acd8a5a611d26f925e51559ab743bc438",
|
||||
"rev": "24be4a26f0706e456fca1b61b8c79f7486a9e86d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
|
@ -18,6 +18,13 @@
|
|||
url = "github:hyprwm/hyprlang";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
inputs.systems.follows = "systems";
|
||||
inputs.hyprutils.follows = "hyprutils";
|
||||
};
|
||||
|
||||
hyprutils = {
|
||||
url = "github:hyprwm/hyprutils";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
inputs.systems.follows = "systems";
|
||||
};
|
||||
|
||||
hyprwayland-scanner = {
|
||||
|
|
|
@ -5,8 +5,12 @@ project(
|
|||
DESCRIPTION "Control utility for Hyprland"
|
||||
)
|
||||
|
||||
pkg_check_modules(deps REQUIRED IMPORTED_TARGET hyprutils>=0.1.1)
|
||||
|
||||
add_executable(hyprctl "main.cpp")
|
||||
|
||||
target_link_libraries(hyprctl PUBLIC PkgConfig::deps)
|
||||
|
||||
# binary
|
||||
install(TARGETS hyprctl)
|
||||
|
||||
|
|
|
@ -38,7 +38,8 @@ commands:
|
|||
plugin ... → Issue a plugin request
|
||||
reload [config-only] → Issue a reload to force reload the config. Pass
|
||||
'config-only' to disable monitor reload
|
||||
rollinglog → Prints tail of the log
|
||||
rollinglog → Prints tail of the log. Also supports -f/--follow
|
||||
option
|
||||
setcursor <theme> <size> → Sets the cursor theme and reloads the cursor
|
||||
manager
|
||||
seterror <color> <message...> → Sets the hyprctl error string. Color has
|
||||
|
@ -112,7 +113,7 @@ create <backend>:
|
|||
remove <name>:
|
||||
Removes virtual output. Pass the output's name, as found in
|
||||
'hyprctl monitors'
|
||||
|
||||
|
||||
flags:
|
||||
See 'hyprctl --help')#";
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#include <ctype.h>
|
||||
#include <cctype>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
@ -12,7 +12,7 @@
|
|||
#include <unistd.h>
|
||||
#include <ranges>
|
||||
#include <algorithm>
|
||||
#include <signal.h>
|
||||
#include <csignal>
|
||||
#include <format>
|
||||
|
||||
#include <iostream>
|
||||
|
@ -22,8 +22,11 @@
|
|||
#include <vector>
|
||||
#include <deque>
|
||||
#include <filesystem>
|
||||
#include <stdarg.h>
|
||||
#include <cstdarg>
|
||||
#include <regex>
|
||||
#include <sys/socket.h>
|
||||
#include <hyprutils/string/String.hpp>
|
||||
using namespace Hyprutils::String;
|
||||
|
||||
#include "Strings.hpp"
|
||||
|
||||
|
@ -98,13 +101,53 @@ std::vector<SInstanceData> instances() {
|
|||
return result;
|
||||
}
|
||||
|
||||
int request(std::string arg, int minArgs = 0) {
|
||||
static volatile bool sigintReceived = false;
|
||||
void intHandler(int sig) {
|
||||
sigintReceived = true;
|
||||
std::cout << "[hyprctl] SIGINT received, closing connection" << std::endl;
|
||||
}
|
||||
|
||||
int rollingRead(const int socket) {
|
||||
sigintReceived = false;
|
||||
signal(SIGINT, intHandler);
|
||||
|
||||
constexpr size_t BUFFER_SIZE = 8192;
|
||||
std::array<char, BUFFER_SIZE> buffer = {0};
|
||||
int sizeWritten = 0;
|
||||
std::cout << "[hyprctl] reading from socket following up log:" << std::endl;
|
||||
while (!sigintReceived) {
|
||||
sizeWritten = read(socket, buffer.data(), BUFFER_SIZE);
|
||||
if (sizeWritten < 0 && errno != EAGAIN) {
|
||||
if (errno != EINTR)
|
||||
std::cout << "Couldn't read (5) " << strerror(errno) << ":" << errno << std::endl;
|
||||
close(socket);
|
||||
return 5;
|
||||
}
|
||||
|
||||
if (sizeWritten == 0)
|
||||
break;
|
||||
|
||||
if (sizeWritten > 0) {
|
||||
std::cout << std::string(buffer.data(), sizeWritten);
|
||||
buffer.fill('\0');
|
||||
}
|
||||
|
||||
usleep(100000);
|
||||
}
|
||||
close(socket);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int request(std::string arg, int minArgs = 0, bool needRoll = false) {
|
||||
const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
|
||||
auto t = timeval{.tv_sec = 0, .tv_usec = 100000};
|
||||
setsockopt(SERVERSOCKET, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(struct timeval));
|
||||
|
||||
const auto ARGS = std::count(arg.begin(), arg.end(), ' ');
|
||||
|
||||
if (ARGS < minArgs) {
|
||||
log("Not enough arguments, expected at least " + minArgs);
|
||||
log(std::format("Not enough arguments in '{}', expected at least {}", arg, minArgs));
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -139,6 +182,9 @@ int request(std::string arg, int minArgs = 0) {
|
|||
return 4;
|
||||
}
|
||||
|
||||
if (needRoll)
|
||||
return rollingRead(SERVERSOCKET);
|
||||
|
||||
std::string reply = "";
|
||||
char buffer[8192] = {0};
|
||||
|
||||
|
@ -270,12 +316,6 @@ std::deque<std::string> splitArgs(int argc, char** argv) {
|
|||
return result;
|
||||
}
|
||||
|
||||
bool isNumber(const std::string& str, bool allowfloat) {
|
||||
if (str.empty())
|
||||
return false;
|
||||
return std::ranges::all_of(str.begin(), str.end(), [&](char c) { return isdigit(c) != 0 || c == '-' || (allowfloat && c == '.'); });
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
bool parseArgs = true;
|
||||
|
||||
|
@ -288,6 +328,7 @@ int main(int argc, char** argv) {
|
|||
std::string fullArgs = "";
|
||||
const auto ARGS = splitArgs(argc, argv);
|
||||
bool json = false;
|
||||
bool needRoll = false;
|
||||
std::string overrideInstance = "";
|
||||
|
||||
for (std::size_t i = 0; i < ARGS.size(); ++i) {
|
||||
|
@ -307,6 +348,9 @@ int main(int argc, char** argv) {
|
|||
fullArgs += "a";
|
||||
} else if ((ARGS[i] == "-c" || ARGS[i] == "--config") && !fullArgs.contains("c")) {
|
||||
fullArgs += "c";
|
||||
} else if ((ARGS[i] == "-f" || ARGS[i] == "--follow") && !fullArgs.contains("f")) {
|
||||
fullArgs += "f";
|
||||
needRoll = true;
|
||||
} else if (ARGS[i] == "--batch") {
|
||||
fullRequest = "--batch ";
|
||||
} else if (ARGS[i] == "--instance" || ARGS[i] == "-i") {
|
||||
|
@ -366,6 +410,11 @@ int main(int argc, char** argv) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (needRoll && !fullRequest.contains("/rollinglog")) {
|
||||
log("only 'rollinglog' command supports '--follow' option");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (overrideInstance.contains("_"))
|
||||
instanceSignature = overrideInstance;
|
||||
else if (!overrideInstance.empty()) {
|
||||
|
@ -425,6 +474,8 @@ int main(int argc, char** argv) {
|
|||
exitStatus = request(fullRequest, 1);
|
||||
else if (fullRequest.contains("/--help"))
|
||||
std::cout << USAGE << std::endl;
|
||||
else if (fullRequest.contains("/rollinglog") && needRoll)
|
||||
exitStatus = request(fullRequest, 0, true);
|
||||
else {
|
||||
exitStatus = request(fullRequest);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
executable('hyprctl', 'main.cpp',
|
||||
dependencies: [
|
||||
dependency('hyprutils', version: '>= 0.1.1'),
|
||||
],
|
||||
install: true
|
||||
)
|
||||
|
||||
|
|
|
@ -9,11 +9,11 @@ file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp")
|
|||
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
|
||||
pkg_check_modules(tomlplusplus REQUIRED IMPORTED_TARGET tomlplusplus)
|
||||
pkg_check_modules(deps REQUIRED IMPORTED_TARGET tomlplusplus hyprutils>=0.1.1)
|
||||
|
||||
add_executable(hyprpm ${SRCFILES})
|
||||
|
||||
target_link_libraries(hyprpm PUBLIC PkgConfig::tomlplusplus)
|
||||
target_link_libraries(hyprpm PUBLIC PkgConfig::deps)
|
||||
|
||||
# binary
|
||||
install(TARGETS hyprpm)
|
||||
|
|
|
@ -19,30 +19,15 @@
|
|||
|
||||
#include <toml++/toml.hpp>
|
||||
|
||||
static std::string removeBeginEndSpacesTabs(std::string str) {
|
||||
if (str.empty())
|
||||
return str;
|
||||
|
||||
int countBefore = 0;
|
||||
while (str[countBefore] == ' ' || str[countBefore] == '\t') {
|
||||
countBefore++;
|
||||
}
|
||||
|
||||
int countAfter = 0;
|
||||
while ((int)str.length() - countAfter - 1 >= 0 && (str[str.length() - countAfter - 1] == ' ' || str[str.length() - 1 - countAfter] == '\t')) {
|
||||
countAfter++;
|
||||
}
|
||||
|
||||
str = str.substr(countBefore, str.length() - countBefore - countAfter);
|
||||
|
||||
return str;
|
||||
}
|
||||
#include <hyprutils/string/String.hpp>
|
||||
using namespace Hyprutils::String;
|
||||
|
||||
static std::string execAndGet(std::string cmd) {
|
||||
cmd += " 2>&1";
|
||||
std::array<char, 128> buffer;
|
||||
std::string result;
|
||||
const std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"), pclose);
|
||||
std::array<char, 128> buffer;
|
||||
std::string result;
|
||||
using PcloseType = int (*)(FILE*);
|
||||
const std::unique_ptr<FILE, PcloseType> pipe(popen(cmd.c_str(), "r"), static_cast<PcloseType>(pclose));
|
||||
if (!pipe)
|
||||
return "";
|
||||
|
||||
|
@ -374,7 +359,7 @@ eHeadersErrors CPluginManager::headersValid() {
|
|||
if (PATH.ends_with("protocols") || PATH.ends_with("wlroots-hyprland"))
|
||||
continue;
|
||||
|
||||
verHeader = removeBeginEndSpacesTabs(PATH.substr(2)) + "/hyprland/src/version.h";
|
||||
verHeader = trim(PATH.substr(2)) + "/hyprland/src/version.h";
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -442,12 +427,12 @@ bool CPluginManager::updateHeaders(bool force) {
|
|||
|
||||
progress.printMessageAbove(std::string{Colors::YELLOW} + "!" + Colors::RESET + " Cloning https://github.com/hyprwm/hyprland, this might take a moment.");
|
||||
|
||||
const bool bShallow = HLVER.branch == "main" || HLVER.branch == "";
|
||||
const bool bShallow = (HLVER.branch == "main" || HLVER.branch == "") && !m_bNoShallow;
|
||||
|
||||
// let us give a bit of leg-room for shallowing
|
||||
// due to timezones, etc.
|
||||
const std::string SHALLOW_DATE =
|
||||
removeBeginEndSpacesTabs(HLVER.date).empty() ? "" : execAndGet("LC_TIME=\"en_US.UTF-8\" date --date='" + HLVER.date + " - 1 weeks' '+\%a \%b \%d \%H:\%M:\%S \%Y'");
|
||||
trim(HLVER.date).empty() ? "" : execAndGet("LC_TIME=\"en_US.UTF-8\" date --date='" + HLVER.date + " - 1 weeks' '+\%a \%b \%d \%H:\%M:\%S \%Y'");
|
||||
|
||||
if (m_bVerbose && bShallow)
|
||||
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "will shallow since: " + SHALLOW_DATE);
|
||||
|
@ -495,13 +480,16 @@ bool CPluginManager::updateHeaders(bool force) {
|
|||
if (m_bVerbose)
|
||||
progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "cmake returned: " + ret);
|
||||
|
||||
if (ret.contains("required packages were not found")) {
|
||||
if (ret.contains("CMake Error at")) {
|
||||
// missing deps, let the user know.
|
||||
std::string missing = ret.substr(ret.find("The following required packages were not found:"));
|
||||
missing = missing.substr(0, missing.find("Call Stack"));
|
||||
std::string missing = ret.substr(ret.find("CMake Error at"));
|
||||
missing = ret.substr(ret.find_first_of('\n') + 1);
|
||||
missing = missing.substr(0, missing.find("-- Configuring incomplete"));
|
||||
missing = missing.substr(0, missing.find_last_of('\n'));
|
||||
|
||||
std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not configure the hyprland source, cmake complained:\n" << missing << "\n";
|
||||
std::cerr << "\n"
|
||||
<< Colors::RED << "✖" << Colors::RESET << " Could not configure the hyprland source, cmake complained:\n"
|
||||
<< missing << "\n\nThis likely means that you are missing the above dependencies or they are out of date.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -58,7 +58,8 @@ class CPluginManager {
|
|||
|
||||
bool hasDeps();
|
||||
|
||||
bool m_bVerbose = false;
|
||||
bool m_bVerbose = false;
|
||||
bool m_bNoShallow = false;
|
||||
|
||||
// will delete recursively if exists!!
|
||||
bool createSafeDirectory(const std::string& path);
|
||||
|
|
|
@ -26,6 +26,7 @@ const std::string HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager
|
|||
┣ --help | -h → Show this menu
|
||||
┣ --verbose | -v → Enable too much logging
|
||||
┣ --force | -f → Force an operation ignoring checks (e.g. update -f)
|
||||
┣ --no-shallow | -s → Disable shallow cloning of Hyprland sources
|
||||
┗
|
||||
)#";
|
||||
|
||||
|
@ -41,7 +42,7 @@ int main(int argc, char** argv, char** envp) {
|
|||
}
|
||||
|
||||
std::vector<std::string> command;
|
||||
bool notify = false, verbose = false, force = false;
|
||||
bool notify = false, verbose = false, force = false, noShallow = false;
|
||||
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
if (ARGS[i].starts_with("-")) {
|
||||
|
@ -52,6 +53,8 @@ int main(int argc, char** argv, char** envp) {
|
|||
notify = true;
|
||||
} else if (ARGS[i] == "--verbose" || ARGS[i] == "-v") {
|
||||
verbose = true;
|
||||
} else if (ARGS[i] == "--no-shallow" || ARGS[i] == "-s") {
|
||||
noShallow = 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";
|
||||
|
@ -69,8 +72,9 @@ int main(int argc, char** argv, char** envp) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
g_pPluginManager = std::make_unique<CPluginManager>();
|
||||
g_pPluginManager->m_bVerbose = verbose;
|
||||
g_pPluginManager = std::make_unique<CPluginManager>();
|
||||
g_pPluginManager->m_bVerbose = verbose;
|
||||
g_pPluginManager->m_bNoShallow = noShallow;
|
||||
|
||||
if (command[0] == "add") {
|
||||
if (command.size() < 2) {
|
||||
|
|
|
@ -3,6 +3,7 @@ src = globber.stdout().strip().split('\n')
|
|||
|
||||
executable('hyprpm', src,
|
||||
dependencies: [
|
||||
dependency('hyprutils', version: '>= 0.1.1'),
|
||||
dependency('threads'),
|
||||
dependency('tomlplusplus')
|
||||
],
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
git,
|
||||
hyprcursor,
|
||||
hyprlang,
|
||||
hyprutils,
|
||||
hyprwayland-scanner,
|
||||
jq,
|
||||
libGL,
|
||||
|
@ -110,6 +111,7 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov
|
|||
git
|
||||
hyprcursor.dev
|
||||
hyprlang
|
||||
hyprutils
|
||||
libGL
|
||||
libdrm
|
||||
libdatrie
|
||||
|
|
|
@ -23,6 +23,7 @@ in {
|
|||
# Dependencies
|
||||
inputs.hyprcursor.overlays.default
|
||||
inputs.hyprlang.overlays.default
|
||||
inputs.hyprutils.overlays.default
|
||||
inputs.hyprwayland-scanner.overlays.default
|
||||
self.overlays.xwayland
|
||||
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
{
|
||||
"version": "0.41.0"
|
||||
"version": "0.41.1"
|
||||
}
|
|
@ -14,7 +14,7 @@
|
|||
#include <helpers/SdDaemon.hpp> // for SdNotify
|
||||
#endif
|
||||
#include <ranges>
|
||||
#include "helpers/VarList.hpp"
|
||||
#include "helpers/varlist/VarList.hpp"
|
||||
#include "protocols/FractionalScale.hpp"
|
||||
#include "protocols/PointerConstraints.hpp"
|
||||
#include "protocols/LayerShell.hpp"
|
||||
|
@ -24,6 +24,9 @@
|
|||
#include "desktop/LayerSurface.hpp"
|
||||
#include "xwayland/XWayland.hpp"
|
||||
|
||||
#include <hyprutils/string/String.hpp>
|
||||
using namespace Hyprutils::String;
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
|
@ -348,6 +351,8 @@ void CCompositor::cleanup() {
|
|||
g_pXWaylandManager.reset();
|
||||
g_pPointerManager.reset();
|
||||
g_pSeatManager.reset();
|
||||
g_pHyprCtl.reset();
|
||||
g_pEventLoopManager.reset();
|
||||
|
||||
if (m_sWLRRenderer)
|
||||
wlr_renderer_destroy(m_sWLRRenderer);
|
||||
|
@ -361,6 +366,7 @@ void CCompositor::cleanup() {
|
|||
if (m_critSigSource)
|
||||
wl_event_source_remove(m_critSigSource);
|
||||
|
||||
wl_event_loop_destroy(m_sWLEventLoop);
|
||||
wl_display_terminate(m_sWLDisplay);
|
||||
m_sWLDisplay = nullptr;
|
||||
|
||||
|
@ -1056,7 +1062,7 @@ SP<CWLSurfaceResource> CCompositor::vectorToLayerSurface(const Vector2D& pos, st
|
|||
if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->surface->mapped) || ls->alpha.value() == 0.f)
|
||||
continue;
|
||||
|
||||
auto [surf, local] = ls->layerSurface->surface->at(pos - ls->geometry.pos());
|
||||
auto [surf, local] = ls->layerSurface->surface->at(pos - ls->geometry.pos(), true);
|
||||
|
||||
if (surf) {
|
||||
if (surf->current.input.empty())
|
||||
|
@ -1108,6 +1114,17 @@ bool CCompositor::isWorkspaceVisible(PHLWORKSPACE w) {
|
|||
return valid(w) && w->m_bVisible;
|
||||
}
|
||||
|
||||
bool CCompositor::isWorkspaceVisibleNotCovered(PHLWORKSPACE w) {
|
||||
if (!valid(w))
|
||||
return false;
|
||||
|
||||
const auto PMONITOR = getMonitorFromID(w->m_iMonitorID);
|
||||
if (PMONITOR->activeSpecialWorkspace)
|
||||
return PMONITOR->activeSpecialWorkspace->m_iID == w->m_iID;
|
||||
|
||||
return PMONITOR->activeWorkspace->m_iID == w->m_iID;
|
||||
}
|
||||
|
||||
PHLWORKSPACE CCompositor::getWorkspaceByID(const int& id) {
|
||||
for (auto& w : m_vWorkspaces) {
|
||||
if (w->m_iID == id && !w->inert())
|
||||
|
@ -1347,6 +1364,10 @@ void CCompositor::addToFadingOutSafe(PHLLS pLS) {
|
|||
m_vSurfacesFadingOut.emplace_back(pLS);
|
||||
}
|
||||
|
||||
void CCompositor::removeFromFadingOutSafe(PHLLS ls) {
|
||||
std::erase(m_vSurfacesFadingOut, ls);
|
||||
}
|
||||
|
||||
void CCompositor::addToFadingOutSafe(PHLWINDOW pWindow) {
|
||||
const auto FOUND = std::find_if(m_vWindowsFadingOut.begin(), m_vWindowsFadingOut.end(), [&](PHLWINDOWREF& other) { return other.lock() == pWindow; });
|
||||
|
||||
|
@ -2084,9 +2105,11 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, CMonitor* pMon
|
|||
if (POLDMON) {
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(POLDMON->ID);
|
||||
updateFullscreenFadeOnWorkspace(POLDMON->activeWorkspace);
|
||||
updateSuspendedStates();
|
||||
}
|
||||
|
||||
updateFullscreenFadeOnWorkspace(pWorkspace);
|
||||
updateSuspendedStates();
|
||||
|
||||
// event
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspace", pWorkspace->m_szName + "," + pMonitor->szName});
|
||||
|
|
|
@ -118,6 +118,7 @@ class CCompositor {
|
|||
PHLWINDOW getWindowFromSurface(SP<CWLSurfaceResource>);
|
||||
PHLWINDOW getWindowFromHandle(uint32_t);
|
||||
bool isWorkspaceVisible(PHLWORKSPACE);
|
||||
bool isWorkspaceVisibleNotCovered(PHLWORKSPACE);
|
||||
PHLWORKSPACE getWorkspaceByID(const int&);
|
||||
PHLWORKSPACE getWorkspaceByName(const std::string&);
|
||||
PHLWORKSPACE getWorkspaceByString(const std::string&);
|
||||
|
@ -155,6 +156,7 @@ class CCompositor {
|
|||
PHLWINDOW getX11Parent(PHLWINDOW);
|
||||
void scheduleFrameForMonitor(CMonitor*);
|
||||
void addToFadingOutSafe(PHLLS);
|
||||
void removeFromFadingOutSafe(PHLLS);
|
||||
void addToFadingOutSafe(PHLWINDOW);
|
||||
PHLWINDOW getWindowByRegex(const std::string&);
|
||||
void warpCursorTo(const Vector2D&, bool force = false);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
#include "../defines.hpp"
|
||||
#include "../helpers/VarList.hpp"
|
||||
#include "../helpers/varlist/VarList.hpp"
|
||||
#include <vector>
|
||||
|
||||
enum eConfigValueDataTypes {
|
||||
|
|
|
@ -3,9 +3,10 @@
|
|||
|
||||
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
|
||||
#include "config/ConfigDataValues.hpp"
|
||||
#include "helpers/VarList.hpp"
|
||||
#include "helpers/varlist/VarList.hpp"
|
||||
#include "../protocols/LayerShell.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
|
@ -13,6 +14,7 @@
|
|||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <glob.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
|
@ -20,7 +22,8 @@
|
|||
#include <sstream>
|
||||
#include <ranges>
|
||||
#include <unordered_set>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include <hyprutils/string/String.hpp>
|
||||
using namespace Hyprutils::String;
|
||||
|
||||
extern "C" char** environ;
|
||||
|
||||
|
@ -428,8 +431,9 @@ CConfigManager::CConfigManager() {
|
|||
|
||||
m_pConfig->addConfigValue("master:special_scale_factor", {1.f});
|
||||
m_pConfig->addConfigValue("master:mfact", {0.55f});
|
||||
m_pConfig->addConfigValue("master:new_is_master", Hyprlang::INT{1});
|
||||
m_pConfig->addConfigValue("master:new_status", {"slave"});
|
||||
m_pConfig->addConfigValue("master:always_center_master", Hyprlang::INT{0});
|
||||
m_pConfig->addConfigValue("master:new_on_active", {"none"});
|
||||
m_pConfig->addConfigValue("master:new_on_top", Hyprlang::INT{0});
|
||||
m_pConfig->addConfigValue("master:no_gaps_when_only", Hyprlang::INT{0});
|
||||
m_pConfig->addConfigValue("master:orientation", {"left"});
|
||||
|
@ -519,10 +523,13 @@ CConfigManager::CConfigManager() {
|
|||
m_pConfig->addConfigValue("opengl:force_introspection", Hyprlang::INT{2});
|
||||
|
||||
m_pConfig->addConfigValue("cursor:no_hardware_cursors", Hyprlang::INT{0});
|
||||
m_pConfig->addConfigValue("cursor:no_break_fs_vrr", Hyprlang::INT{0});
|
||||
m_pConfig->addConfigValue("cursor:min_refresh_rate", Hyprlang::INT{24});
|
||||
m_pConfig->addConfigValue("cursor:hotspot_padding", Hyprlang::INT{0});
|
||||
m_pConfig->addConfigValue("cursor:inactive_timeout", Hyprlang::INT{0});
|
||||
m_pConfig->addConfigValue("cursor:no_warps", Hyprlang::INT{0});
|
||||
m_pConfig->addConfigValue("cursor:persistent_warps", Hyprlang::INT{0});
|
||||
m_pConfig->addConfigValue("cursor:warp_on_change_workspace", Hyprlang::INT{0});
|
||||
m_pConfig->addConfigValue("cursor:default_monitor", {STRVAL_EMPTY});
|
||||
m_pConfig->addConfigValue("cursor:zoom_factor", {1.f});
|
||||
m_pConfig->addConfigValue("cursor:zoom_rigid", Hyprlang::INT{0});
|
||||
|
@ -1955,15 +1962,16 @@ std::optional<std::string> CConfigManager::handleBind(const std::string& command
|
|||
// bind[fl]=SUPER,G,exec,dmenu_run <args>
|
||||
|
||||
// flags
|
||||
bool locked = false;
|
||||
bool release = false;
|
||||
bool repeat = false;
|
||||
bool mouse = false;
|
||||
bool nonConsuming = false;
|
||||
bool transparent = false;
|
||||
bool ignoreMods = false;
|
||||
bool multiKey = false;
|
||||
const auto BINDARGS = command.substr(4);
|
||||
bool locked = false;
|
||||
bool release = false;
|
||||
bool repeat = false;
|
||||
bool mouse = false;
|
||||
bool nonConsuming = false;
|
||||
bool transparent = false;
|
||||
bool ignoreMods = false;
|
||||
bool multiKey = false;
|
||||
bool hasDescription = false;
|
||||
const auto BINDARGS = command.substr(4);
|
||||
|
||||
for (auto& arg : BINDARGS) {
|
||||
if (arg == 'l') {
|
||||
|
@ -1982,6 +1990,8 @@ std::optional<std::string> CConfigManager::handleBind(const std::string& command
|
|||
ignoreMods = true;
|
||||
} else if (arg == 's') {
|
||||
multiKey = true;
|
||||
} else if (arg == 'd') {
|
||||
hasDescription = true;
|
||||
} else {
|
||||
return "bind: invalid flag";
|
||||
}
|
||||
|
@ -1993,11 +2003,13 @@ std::optional<std::string> CConfigManager::handleBind(const std::string& command
|
|||
if (mouse && (repeat || release || locked))
|
||||
return "flag m is exclusive";
|
||||
|
||||
const auto ARGS = CVarList(value, 4);
|
||||
const int numbArgs = hasDescription ? 5 : 4;
|
||||
const auto ARGS = CVarList(value, numbArgs);
|
||||
|
||||
const int DESCR_OFFSET = hasDescription ? 1 : 0;
|
||||
if ((ARGS.size() < 3 && !mouse) || (ARGS.size() < 3 && mouse))
|
||||
return "bind: too few args";
|
||||
else if ((ARGS.size() > 4 && !mouse) || (ARGS.size() > 3 && mouse))
|
||||
else if ((ARGS.size() > (size_t)4 + DESCR_OFFSET && !mouse) || (ARGS.size() > (size_t)3 + DESCR_OFFSET && mouse))
|
||||
return "bind: too many args";
|
||||
|
||||
std::set<xkb_keysym_t> KEYSYMS;
|
||||
|
@ -2016,9 +2028,11 @@ std::optional<std::string> CConfigManager::handleBind(const std::string& command
|
|||
|
||||
const auto KEY = multiKey ? "" : ARGS[1];
|
||||
|
||||
auto HANDLER = ARGS[2];
|
||||
const auto DESCRIPTION = hasDescription ? ARGS[2] : "";
|
||||
|
||||
const auto COMMAND = mouse ? HANDLER : ARGS[3];
|
||||
auto HANDLER = ARGS[2 + DESCR_OFFSET];
|
||||
|
||||
const auto COMMAND = mouse ? HANDLER : ARGS[3 + DESCR_OFFSET];
|
||||
|
||||
if (mouse)
|
||||
HANDLER = "mouse";
|
||||
|
@ -2046,8 +2060,8 @@ std::optional<std::string> CConfigManager::handleBind(const std::string& command
|
|||
return "Invalid catchall, catchall keybinds are only allowed in submaps.";
|
||||
}
|
||||
|
||||
g_pKeybindManager->addKeybind(SKeybind{parsedKey.key, KEYSYMS, parsedKey.keycode, parsedKey.catchAll, MOD, MODS, HANDLER, COMMAND, locked, m_szCurrentSubmap, release,
|
||||
repeat, mouse, nonConsuming, transparent, ignoreMods, multiKey});
|
||||
g_pKeybindManager->addKeybind(SKeybind{parsedKey.key, KEYSYMS, parsedKey.keycode, parsedKey.catchAll, MOD, MODS, HANDLER, COMMAND, locked, m_szCurrentSubmap, DESCRIPTION,
|
||||
release, repeat, mouse, nonConsuming, transparent, ignoreMods, multiKey, hasDescription});
|
||||
}
|
||||
|
||||
return {};
|
||||
|
@ -2087,8 +2101,8 @@ bool layerRuleValid(const std::string& RULE) {
|
|||
}
|
||||
|
||||
std::optional<std::string> CConfigManager::handleWindowRule(const std::string& command, const std::string& value) {
|
||||
const auto RULE = removeBeginEndSpacesTabs(value.substr(0, value.find_first_of(',')));
|
||||
const auto VALUE = removeBeginEndSpacesTabs(value.substr(value.find_first_of(',') + 1));
|
||||
const auto RULE = trim(value.substr(0, value.find_first_of(',')));
|
||||
const auto VALUE = trim(value.substr(value.find_first_of(',') + 1));
|
||||
|
||||
// check rule and value
|
||||
if (RULE.empty() || VALUE.empty())
|
||||
|
@ -2114,8 +2128,8 @@ std::optional<std::string> CConfigManager::handleWindowRule(const std::string& c
|
|||
}
|
||||
|
||||
std::optional<std::string> CConfigManager::handleLayerRule(const std::string& command, const std::string& value) {
|
||||
const auto RULE = removeBeginEndSpacesTabs(value.substr(0, value.find_first_of(',')));
|
||||
const auto VALUE = removeBeginEndSpacesTabs(value.substr(value.find_first_of(',') + 1));
|
||||
const auto RULE = trim(value.substr(0, value.find_first_of(',')));
|
||||
const auto VALUE = trim(value.substr(value.find_first_of(',') + 1));
|
||||
|
||||
// check rule and value
|
||||
if (RULE.empty() || VALUE.empty())
|
||||
|
@ -2142,7 +2156,7 @@ std::optional<std::string> CConfigManager::handleLayerRule(const std::string& co
|
|||
}
|
||||
|
||||
std::optional<std::string> CConfigManager::handleWindowRuleV2(const std::string& command, const std::string& value) {
|
||||
const auto RULE = removeBeginEndSpacesTabs(value.substr(0, value.find_first_of(',')));
|
||||
const auto RULE = trim(value.substr(0, value.find_first_of(',')));
|
||||
const auto VALUE = value.substr(value.find_first_of(',') + 1);
|
||||
|
||||
if (!windowRuleValid(RULE) && RULE != "unset") {
|
||||
|
@ -2219,7 +2233,7 @@ std::optional<std::string> CConfigManager::handleWindowRuleV2(const std::string&
|
|||
|
||||
result = result.substr(0, min - pos);
|
||||
|
||||
result = removeBeginEndSpacesTabs(result);
|
||||
result = trim(result);
|
||||
|
||||
if (!result.empty() && result.back() == ',')
|
||||
result.pop_back();
|
||||
|
@ -2341,7 +2355,7 @@ void CConfigManager::updateBlurredLS(const std::string& name, const bool forceBl
|
|||
|
||||
std::optional<std::string> CConfigManager::handleBlurLS(const std::string& command, const std::string& value) {
|
||||
if (value.starts_with("remove,")) {
|
||||
const auto TOREMOVE = removeBeginEndSpacesTabs(value.substr(7));
|
||||
const auto TOREMOVE = trim(value.substr(7));
|
||||
if (std::erase_if(m_dBlurLSNamespaces, [&](const auto& other) { return other == TOREMOVE; }))
|
||||
updateBlurredLS(TOREMOVE, false);
|
||||
return {};
|
||||
|
@ -2358,7 +2372,7 @@ std::optional<std::string> CConfigManager::handleWorkspaceRules(const std::strin
|
|||
const auto FIRST_DELIM = value.find_first_of(',');
|
||||
|
||||
std::string name = "";
|
||||
auto first_ident = removeBeginEndSpacesTabs(value.substr(0, FIRST_DELIM));
|
||||
auto first_ident = trim(value.substr(0, FIRST_DELIM));
|
||||
int id = getWorkspaceIDFromString(first_ident, name);
|
||||
|
||||
auto rules = value.substr(FIRST_DELIM + 1);
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include <xf86drmMode.h>
|
||||
#include "../helpers/WLClasses.hpp"
|
||||
#include "../helpers/Monitor.hpp"
|
||||
#include "../helpers/VarList.hpp"
|
||||
#include "../helpers/varlist/VarList.hpp"
|
||||
#include "../desktop/Window.hpp"
|
||||
#include "../desktop/LayerSurface.hpp"
|
||||
|
||||
|
|
|
@ -138,7 +138,7 @@ dwindle {
|
|||
|
||||
# See https://wiki.hyprland.org/Configuring/Master-Layout/ for more
|
||||
master {
|
||||
new_is_master = true
|
||||
new_status = master
|
||||
}
|
||||
|
||||
# https://wiki.hyprland.org/Configuring/Variables/#misc
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "HyprCtl.hpp"
|
||||
|
||||
#include <format>
|
||||
#include <netinet/in.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -16,6 +17,9 @@
|
|||
#include <typeindex>
|
||||
#include <numeric>
|
||||
|
||||
#include <hyprutils/string/String.hpp>
|
||||
using namespace Hyprutils::String;
|
||||
|
||||
#include "../config/ConfigDataValues.hpp"
|
||||
#include "../config/ConfigValue.hpp"
|
||||
#include "../managers/CursorManager.hpp"
|
||||
|
@ -24,7 +28,9 @@
|
|||
#include "../devices/IKeyboard.hpp"
|
||||
#include "../devices/ITouch.hpp"
|
||||
#include "../devices/Tablet.hpp"
|
||||
#include "debug/RollingLogFollow.hpp"
|
||||
#include "config/ConfigManager.hpp"
|
||||
#include "helpers/MiscFunctions.hpp"
|
||||
|
||||
static void trimTrailingComma(std::string& str) {
|
||||
if (!str.empty() && str.back() == ',')
|
||||
|
@ -789,9 +795,11 @@ std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) {
|
|||
ret += "e";
|
||||
if (kb.nonConsuming)
|
||||
ret += "n";
|
||||
if (kb.hasDescription)
|
||||
ret += "d";
|
||||
|
||||
ret += std::format("\n\tmodmask: {}\n\tsubmap: {}\n\tkey: {}\n\tkeycode: {}\n\tcatchall: {}\n\tdispatcher: {}\n\targ: {}\n\n", kb.modmask, kb.submap, kb.key,
|
||||
kb.keycode, kb.catchAll, kb.handler, kb.arg);
|
||||
ret += std::format("\n\tmodmask: {}\n\tsubmap: {}\n\tkey: {}\n\tkeycode: {}\n\tcatchall: {}\n\tdescription: {}\n\tdispatcher: {}\n\targ: {}\n\n", kb.modmask, kb.submap,
|
||||
kb.key, kb.keycode, kb.catchAll, kb.description, kb.handler, kb.arg);
|
||||
}
|
||||
} else {
|
||||
// json
|
||||
|
@ -805,17 +813,19 @@ std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) {
|
|||
"release": {},
|
||||
"repeat": {},
|
||||
"non_consuming": {},
|
||||
"has_description": {},
|
||||
"modmask": {},
|
||||
"submap": "{}",
|
||||
"key": "{}",
|
||||
"keycode": {},
|
||||
"catch_all": {},
|
||||
"description": "{}",
|
||||
"dispatcher": "{}",
|
||||
"arg": "{}"
|
||||
}},)#",
|
||||
kb.locked ? "true" : "false", kb.mouse ? "true" : "false", kb.release ? "true" : "false", kb.repeat ? "true" : "false", kb.nonConsuming ? "true" : "false",
|
||||
kb.modmask, escapeJSONStrings(kb.submap), escapeJSONStrings(kb.key), kb.keycode, kb.catchAll ? "true" : "false", escapeJSONStrings(kb.handler),
|
||||
escapeJSONStrings(kb.arg));
|
||||
kb.hasDescription ? "true" : "false", kb.modmask, escapeJSONStrings(kb.submap), escapeJSONStrings(kb.key), kb.keycode, kb.catchAll ? "true" : "false",
|
||||
escapeJSONStrings(kb.description), escapeJSONStrings(kb.handler), escapeJSONStrings(kb.arg));
|
||||
}
|
||||
trimTrailingComma(ret);
|
||||
ret += "]";
|
||||
|
@ -826,7 +836,7 @@ std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) {
|
|||
|
||||
std::string versionRequest(eHyprCtlOutputFormat format, std::string request) {
|
||||
|
||||
auto commitMsg = removeBeginEndSpacesTabs(GIT_COMMIT_MESSAGE);
|
||||
auto commitMsg = trim(GIT_COMMIT_MESSAGE);
|
||||
std::replace(commitMsg.begin(), commitMsg.end(), '#', ' ');
|
||||
|
||||
if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) {
|
||||
|
@ -1051,7 +1061,7 @@ std::string dispatchBatch(eHyprCtlOutputFormat format, std::string request) {
|
|||
request = "";
|
||||
}
|
||||
|
||||
curitem = removeBeginEndSpacesTabs(curitem);
|
||||
curitem = trim(curitem);
|
||||
};
|
||||
|
||||
nextItem();
|
||||
|
@ -1305,7 +1315,7 @@ std::string dispatchGetOption(eHyprCtlOutputFormat format, std::string request)
|
|||
request = "";
|
||||
}
|
||||
|
||||
curitem = removeBeginEndSpacesTabs(curitem);
|
||||
curitem = trim(curitem);
|
||||
};
|
||||
|
||||
nextItem();
|
||||
|
@ -1723,6 +1733,46 @@ std::string CHyprCtl::makeDynamicCall(const std::string& input) {
|
|||
return getReply(input);
|
||||
}
|
||||
|
||||
bool successWrite(int fd, const std::string& data, bool needLog = true) {
|
||||
if (write(fd, data.c_str(), data.length()) > 0)
|
||||
return true;
|
||||
|
||||
if (errno == EAGAIN)
|
||||
return true;
|
||||
|
||||
if (needLog)
|
||||
Debug::log(ERR, "Couldn't write to socket. Error: " + std::string(strerror(errno)));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void runWritingDebugLogThread(const int conn) {
|
||||
using namespace std::chrono_literals;
|
||||
Debug::log(LOG, "In followlog thread, got connection, start writing: {}", conn);
|
||||
//will be finished, when reading side close connection
|
||||
std::thread([conn]() {
|
||||
while (Debug::RollingLogFollow::Get().IsRunning()) {
|
||||
if (Debug::RollingLogFollow::Get().isEmpty(conn)) {
|
||||
std::this_thread::sleep_for(1000ms);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto line = Debug::RollingLogFollow::Get().GetLog(conn);
|
||||
if (!successWrite(conn, line))
|
||||
// We cannot write, when connection is closed. So thread will successfully exit by itself
|
||||
break;
|
||||
|
||||
std::this_thread::sleep_for(100ms);
|
||||
}
|
||||
close(conn);
|
||||
Debug::RollingLogFollow::Get().StopFor(conn);
|
||||
}).detach();
|
||||
}
|
||||
|
||||
bool isFollowUpRollingLogRequest(const std::string& request) {
|
||||
return request.contains("rollinglog") && request.contains("f");
|
||||
}
|
||||
|
||||
int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
|
||||
if (mask & WL_EVENT_ERROR || mask & WL_EVENT_HANGUP)
|
||||
return 0;
|
||||
|
@ -1766,9 +1816,15 @@ int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
|
|||
reply = "Err: " + std::string(e.what());
|
||||
}
|
||||
|
||||
write(ACCEPTEDCONNECTION, reply.c_str(), reply.length());
|
||||
successWrite(ACCEPTEDCONNECTION, reply);
|
||||
|
||||
close(ACCEPTEDCONNECTION);
|
||||
if (isFollowUpRollingLogRequest(request)) {
|
||||
Debug::log(LOG, "Followup rollinglog request received. Starting thread to write to socket.");
|
||||
Debug::RollingLogFollow::Get().StartFor(ACCEPTEDCONNECTION);
|
||||
runWritingDebugLogThread(ACCEPTEDCONNECTION);
|
||||
Debug::log(LOG, Debug::RollingLogFollow::Get().DebugInfo());
|
||||
} else
|
||||
close(ACCEPTEDCONNECTION);
|
||||
|
||||
if (g_pConfigManager->m_bWantsMonitorReload)
|
||||
g_pConfigManager->ensureMonitorStatus();
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "Log.hpp"
|
||||
#include "../defines.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
#include "RollingLogFollow.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
@ -73,6 +74,9 @@ void Debug::log(LogLevel level, std::string str) {
|
|||
if (rollingLog.size() > ROLLING_LOG_SIZE)
|
||||
rollingLog = rollingLog.substr(rollingLog.size() - ROLLING_LOG_SIZE);
|
||||
|
||||
if (RollingLogFollow::Get().IsRunning())
|
||||
RollingLogFollow::Get().AddLog(str);
|
||||
|
||||
if (!disableLogs || !**disableLogs) {
|
||||
// log to a file
|
||||
std::ofstream ofs;
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
#pragma once
|
||||
|
||||
#include <shared_mutex>
|
||||
|
||||
namespace Debug {
|
||||
struct RollingLogFollow {
|
||||
std::unordered_map<int, std::string> socketToRollingLogFollowQueue;
|
||||
std::shared_mutex m;
|
||||
bool running = false;
|
||||
static constexpr size_t ROLLING_LOG_FOLLOW_TOO_BIG = 8192;
|
||||
|
||||
// Returns true if the queue is empty for the given socket
|
||||
bool isEmpty(int socket) {
|
||||
std::shared_lock<std::shared_mutex> r(m);
|
||||
return socketToRollingLogFollowQueue[socket].empty();
|
||||
}
|
||||
|
||||
std::string DebugInfo() {
|
||||
std::shared_lock<std::shared_mutex> r(m);
|
||||
return std::format("RollingLogFollow, got {} connections", socketToRollingLogFollowQueue.size());
|
||||
}
|
||||
|
||||
std::string GetLog(int socket) {
|
||||
std::unique_lock<std::shared_mutex> w(m);
|
||||
|
||||
const std::string ret = socketToRollingLogFollowQueue[socket];
|
||||
socketToRollingLogFollowQueue[socket] = "";
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
void AddLog(std::string log) {
|
||||
std::unique_lock<std::shared_mutex> w(m);
|
||||
running = true;
|
||||
std::vector<int> to_erase;
|
||||
for (const auto& p : socketToRollingLogFollowQueue)
|
||||
socketToRollingLogFollowQueue[p.first] += log + "\n";
|
||||
}
|
||||
|
||||
bool IsRunning() {
|
||||
std::shared_lock<std::shared_mutex> r(m);
|
||||
return running;
|
||||
}
|
||||
|
||||
void StopFor(int socket) {
|
||||
std::unique_lock<std::shared_mutex> w(m);
|
||||
socketToRollingLogFollowQueue.erase(socket);
|
||||
if (socketToRollingLogFollowQueue.empty())
|
||||
running = false;
|
||||
}
|
||||
|
||||
void StartFor(int socket) {
|
||||
std::unique_lock<std::shared_mutex> w(m);
|
||||
socketToRollingLogFollowQueue[socket] = std::format("[LOG] Following log to socket: {} started\n", socket);
|
||||
running = true;
|
||||
}
|
||||
|
||||
static RollingLogFollow& Get() {
|
||||
static RollingLogFollow instance;
|
||||
static std::mutex gm;
|
||||
std::lock_guard<std::mutex> lock(gm);
|
||||
return instance;
|
||||
};
|
||||
};
|
||||
}
|
|
@ -116,8 +116,12 @@ void CLayerSurface::onDestroy() {
|
|||
void CLayerSurface::onMap() {
|
||||
Debug::log(LOG, "LayerSurface {:x} mapped", (uintptr_t)layerSurface);
|
||||
|
||||
mapped = true;
|
||||
keyboardExclusive = layerSurface->current.interactivity;
|
||||
mapped = true;
|
||||
interactivity = layerSurface->current.interactivity;
|
||||
|
||||
// this layer might be re-mapped.
|
||||
fadingOut = false;
|
||||
g_pCompositor->removeFromFadingOutSafe(self.lock());
|
||||
|
||||
// fix if it changed its mon
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID);
|
||||
|
@ -133,12 +137,15 @@ void CLayerSurface::onMap() {
|
|||
|
||||
surface->resource()->enter(PMONITOR->self.lock());
|
||||
|
||||
if (layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE)
|
||||
const bool ISEXCLUSIVE = layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE;
|
||||
|
||||
if (ISEXCLUSIVE)
|
||||
g_pInputManager->m_dExclusiveLSes.push_back(self);
|
||||
|
||||
const bool GRABSFOCUS = layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE &&
|
||||
// don't focus if constrained
|
||||
(g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained());
|
||||
const bool GRABSFOCUS = ISEXCLUSIVE ||
|
||||
(layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE &&
|
||||
// don't focus if constrained
|
||||
(g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained()));
|
||||
|
||||
if (GRABSFOCUS) {
|
||||
// TODO: use the new superb really very cool grab
|
||||
|
@ -177,9 +184,6 @@ void CLayerSurface::onUnmap() {
|
|||
|
||||
std::erase_if(g_pInputManager->m_dExclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == self.lock(); });
|
||||
|
||||
if (!g_pInputManager->m_dExclusiveLSes.empty())
|
||||
g_pCompositor->focusSurface(g_pInputManager->m_dExclusiveLSes[0]->surface->resource());
|
||||
|
||||
if (!g_pCompositor->getMonitorFromID(monitorID) || g_pCompositor->m_bUnsafeState) {
|
||||
Debug::log(WARN, "Layersurface unmapping on invalid monitor (removed?) ignoring.");
|
||||
|
||||
|
@ -204,39 +208,12 @@ void CLayerSurface::onUnmap() {
|
|||
|
||||
const bool WASLASTFOCUS = g_pCompositor->m_pLastFocus == surface->resource();
|
||||
|
||||
surface.reset();
|
||||
|
||||
if (!PMONITOR)
|
||||
return;
|
||||
|
||||
// refocus if needed
|
||||
if (WASLASTFOCUS) {
|
||||
g_pInputManager->releaseAllMouseButtons();
|
||||
|
||||
Vector2D surfaceCoords;
|
||||
PHLLS pFoundLayerSurface;
|
||||
SP<CWLSurfaceResource> foundSurface = nullptr;
|
||||
|
||||
g_pCompositor->m_pLastFocus.reset();
|
||||
|
||||
// find LS-es to focus
|
||||
foundSurface = g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY],
|
||||
&surfaceCoords, &pFoundLayerSurface);
|
||||
|
||||
if (!foundSurface)
|
||||
foundSurface = g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],
|
||||
&surfaceCoords, &pFoundLayerSurface);
|
||||
|
||||
if (!foundSurface && g_pCompositor->m_pLastWindow.lock() && g_pCompositor->isWorkspaceVisible(g_pCompositor->m_pLastWindow->m_pWorkspace)) {
|
||||
// if there isn't any, focus the last window
|
||||
const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock();
|
||||
g_pCompositor->focusWindow(nullptr);
|
||||
g_pCompositor->focusWindow(PLASTWINDOW);
|
||||
} else {
|
||||
// otherwise, full refocus
|
||||
g_pInputManager->refocus();
|
||||
}
|
||||
}
|
||||
if (WASLASTFOCUS)
|
||||
g_pInputManager->refocusLastWindow(PMONITOR);
|
||||
|
||||
CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height};
|
||||
g_pHyprRenderer->damageBox(&geomFixed);
|
||||
|
@ -246,12 +223,25 @@ void CLayerSurface::onUnmap() {
|
|||
g_pHyprRenderer->damageBox(&geomFixed);
|
||||
|
||||
g_pInputManager->sendMotionEventsToFocused();
|
||||
|
||||
g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->ID);
|
||||
}
|
||||
|
||||
void CLayerSurface::onCommit() {
|
||||
if (!layerSurface)
|
||||
return;
|
||||
|
||||
if (!mapped) {
|
||||
// we're re-mapping if this is the case
|
||||
if (layerSurface->surface && !layerSurface->surface->current.buffer) {
|
||||
fadingOut = false;
|
||||
geometry = {};
|
||||
g_pHyprRenderer->arrangeLayersForMonitor(monitorID);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID);
|
||||
|
||||
if (!PMONITOR)
|
||||
|
@ -311,18 +301,35 @@ void CLayerSurface::onCommit() {
|
|||
realSize.setValueAndWarp(geometry.size());
|
||||
}
|
||||
|
||||
if (layerSurface->current.interactivity && (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained()) // don't focus if constrained
|
||||
&& !keyboardExclusive && mapped) {
|
||||
g_pCompositor->focusSurface(surface->resource());
|
||||
if (mapped) {
|
||||
const bool WASLASTFOCUS = g_pCompositor->m_pLastFocus == surface->resource();
|
||||
const bool WASEXCLUSIVE = interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE;
|
||||
const bool ISEXCLUSIVE = layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE;
|
||||
|
||||
const auto LOCAL = g_pInputManager->getMouseCoordsInternal() - Vector2D(geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y);
|
||||
g_pSeatManager->setPointerFocus(surface->resource(), LOCAL);
|
||||
g_pInputManager->m_bEmptyFocusCursorSet = false;
|
||||
} else if (!layerSurface->current.interactivity && (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained()) && keyboardExclusive) {
|
||||
g_pInputManager->refocus();
|
||||
if (!WASEXCLUSIVE && ISEXCLUSIVE)
|
||||
g_pInputManager->m_dExclusiveLSes.push_back(self);
|
||||
else if (WASEXCLUSIVE && !ISEXCLUSIVE)
|
||||
std::erase_if(g_pInputManager->m_dExclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == self.lock(); });
|
||||
|
||||
// if the surface was focused and interactive but now isn't, refocus
|
||||
if (WASLASTFOCUS && !layerSurface->current.interactivity) {
|
||||
// moveMouseUnified won't focus non interactive layers but it won't unfocus them either,
|
||||
// so unfocus the surface here.
|
||||
g_pCompositor->focusSurface(nullptr);
|
||||
g_pInputManager->refocusLastWindow(g_pCompositor->getMonitorFromID(monitorID));
|
||||
} else if (!WASEXCLUSIVE && ISEXCLUSIVE) {
|
||||
// if now exclusive and not previously
|
||||
g_pSeatManager->setGrab(nullptr);
|
||||
g_pInputManager->releaseAllMouseButtons();
|
||||
g_pCompositor->focusSurface(surface->resource());
|
||||
|
||||
const auto LOCAL = g_pInputManager->getMouseCoordsInternal() - Vector2D(geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y);
|
||||
g_pSeatManager->setPointerFocus(surface->resource(), LOCAL);
|
||||
g_pInputManager->m_bEmptyFocusCursorSet = false;
|
||||
}
|
||||
}
|
||||
|
||||
keyboardExclusive = layerSurface->current.interactivity;
|
||||
interactivity = layerSurface->current.interactivity;
|
||||
|
||||
g_pHyprRenderer->damageSurface(surface->resource(), position.x, position.y);
|
||||
|
||||
|
@ -512,4 +519,4 @@ int CLayerSurface::popupsCount() {
|
|||
int no = -1; // we have one dummy
|
||||
popupHead->breadthfirst([](CPopup* p, void* data) { *(int*)data += 1; }, &no);
|
||||
return no;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,40 +34,41 @@ class CLayerSurface {
|
|||
WP<CLayerShellResource> layerSurface;
|
||||
wl_list link;
|
||||
|
||||
bool keyboardExclusive = false;
|
||||
// the header providing the enum type cannot be imported here
|
||||
int interactivity = 0;
|
||||
|
||||
SP<CWLSurface> surface;
|
||||
SP<CWLSurface> surface;
|
||||
|
||||
bool mapped = false;
|
||||
uint32_t layer = 0;
|
||||
bool mapped = false;
|
||||
uint32_t layer = 0;
|
||||
|
||||
int monitorID = -1;
|
||||
int monitorID = -1;
|
||||
|
||||
bool fadingOut = false;
|
||||
bool readyToDelete = false;
|
||||
bool noProcess = false;
|
||||
bool noAnimations = false;
|
||||
bool fadingOut = false;
|
||||
bool readyToDelete = false;
|
||||
bool noProcess = false;
|
||||
bool noAnimations = false;
|
||||
|
||||
bool forceBlur = false;
|
||||
bool forceBlurPopups = false;
|
||||
int xray = -1;
|
||||
bool ignoreAlpha = false;
|
||||
float ignoreAlphaValue = 0.f;
|
||||
bool dimAround = false;
|
||||
bool forceBlur = false;
|
||||
bool forceBlurPopups = false;
|
||||
int xray = -1;
|
||||
bool ignoreAlpha = false;
|
||||
float ignoreAlphaValue = 0.f;
|
||||
bool dimAround = false;
|
||||
|
||||
std::optional<std::string> animationStyle;
|
||||
std::optional<std::string> animationStyle;
|
||||
|
||||
PHLLSREF self;
|
||||
PHLLSREF self;
|
||||
|
||||
CBox geometry = {0, 0, 0, 0};
|
||||
Vector2D position;
|
||||
std::string szNamespace = "";
|
||||
std::unique_ptr<CPopup> popupHead;
|
||||
CBox geometry = {0, 0, 0, 0};
|
||||
Vector2D position;
|
||||
std::string szNamespace = "";
|
||||
std::unique_ptr<CPopup> popupHead;
|
||||
|
||||
void onDestroy();
|
||||
void onMap();
|
||||
void onUnmap();
|
||||
void onCommit();
|
||||
void onDestroy();
|
||||
void onMap();
|
||||
void onUnmap();
|
||||
void onCommit();
|
||||
|
||||
private:
|
||||
struct {
|
||||
|
@ -83,4 +84,4 @@ class CLayerSurface {
|
|||
bool operator==(const CLayerSurface& rhs) const {
|
||||
return layerSurface == rhs.layerSurface && monitorID == rhs.monitorID;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include <vector>
|
||||
#include <memory>
|
||||
#include "Subsurface.hpp"
|
||||
#include "../helpers/signal/Listener.hpp"
|
||||
#include "../helpers/signal/Signal.hpp"
|
||||
|
||||
class CXDGPopupResource;
|
||||
|
||||
|
|
|
@ -12,6 +12,9 @@
|
|||
#include "../protocols/core/Compositor.hpp"
|
||||
#include "../xwayland/XWayland.hpp"
|
||||
|
||||
#include <hyprutils/string/String.hpp>
|
||||
using namespace Hyprutils::String;
|
||||
|
||||
PHLWINDOW CWindow::create(SP<CXWaylandSurface> surface) {
|
||||
PHLWINDOW pWindow = SP<CWindow>(new CWindow(surface));
|
||||
|
||||
|
@ -687,7 +690,7 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
|
|||
CGradientValueData activeBorderGradient = {};
|
||||
CGradientValueData inactiveBorderGradient = {};
|
||||
bool active = true;
|
||||
CVarList colorsAndAngles = CVarList(removeBeginEndSpacesTabs(r.szRule.substr(r.szRule.find_first_of(' ') + 1)), 0, 's', true);
|
||||
CVarList colorsAndAngles = CVarList(trim(r.szRule.substr(r.szRule.find_first_of(' ') + 1)), 0, 's', true);
|
||||
|
||||
// Basic form has only two colors, everything else can be parsed as a gradient
|
||||
if (colorsAndAngles.size() == 2 && !colorsAndAngles[1].contains("deg")) {
|
||||
|
@ -1537,3 +1540,58 @@ void CWindow::warpCursor() {
|
|||
else
|
||||
g_pCompositor->warpCursorTo(middle());
|
||||
}
|
||||
|
||||
PHLWINDOW CWindow::getSwallower() {
|
||||
static auto PSWALLOWREGEX = CConfigValue<std::string>("misc:swallow_regex");
|
||||
static auto PSWALLOWEXREGEX = CConfigValue<std::string>("misc:swallow_exception_regex");
|
||||
static auto PSWALLOW = CConfigValue<Hyprlang::INT>("misc:enable_swallow");
|
||||
|
||||
if (!*PSWALLOW || (*PSWALLOWREGEX).empty())
|
||||
return nullptr;
|
||||
|
||||
// check parent
|
||||
std::vector<PHLWINDOW> candidates;
|
||||
pid_t currentPid = getPID();
|
||||
// walk up the tree until we find someone, 25 iterations max.
|
||||
for (size_t i = 0; i < 25; ++i) {
|
||||
currentPid = getPPIDof(currentPid);
|
||||
|
||||
if (!currentPid)
|
||||
break;
|
||||
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (!w->m_bIsMapped || w->isHidden())
|
||||
continue;
|
||||
|
||||
if (w->getPID() == currentPid)
|
||||
candidates.push_back(w);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(*PSWALLOWREGEX).empty())
|
||||
std::erase_if(candidates, [&](const auto& other) { return !std::regex_match(other->m_szClass, std::regex(*PSWALLOWREGEX)); });
|
||||
|
||||
if (candidates.size() <= 0)
|
||||
return nullptr;
|
||||
|
||||
if (!(*PSWALLOWEXREGEX).empty())
|
||||
std::erase_if(candidates, [&](const auto& other) { return std::regex_match(other->m_szTitle, std::regex(*PSWALLOWEXREGEX)); });
|
||||
|
||||
if (candidates.size() <= 0)
|
||||
return nullptr;
|
||||
|
||||
if (candidates.size() == 1)
|
||||
return candidates.at(0);
|
||||
|
||||
// walk up the focus history and find the last focused
|
||||
for (auto& w : g_pCompositor->m_vWindowFocusHistory) {
|
||||
if (!w)
|
||||
continue;
|
||||
|
||||
if (std::find(candidates.begin(), candidates.end(), w.lock()) != candidates.end())
|
||||
return w.lock();
|
||||
}
|
||||
|
||||
// if none are found (??) then just return the first one
|
||||
return candidates.at(0);
|
||||
}
|
||||
|
|
|
@ -450,6 +450,7 @@ class CWindow {
|
|||
std::string fetchTitle();
|
||||
std::string fetchClass();
|
||||
void warpCursor();
|
||||
PHLWINDOW getSwallower();
|
||||
|
||||
// listeners
|
||||
void onAck(uint32_t serial);
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
#include "../Compositor.hpp"
|
||||
#include "../config/ConfigValue.hpp"
|
||||
|
||||
#include <hyprutils/string/String.hpp>
|
||||
using namespace Hyprutils::String;
|
||||
|
||||
PHLWORKSPACE CWorkspace::create(int id, int monitorID, std::string name, bool special, bool isEmtpy) {
|
||||
PHLWORKSPACE workspace = makeShared<CWorkspace>(id, monitorID, name, special, isEmtpy);
|
||||
workspace->init(workspace);
|
||||
|
@ -219,7 +222,7 @@ std::string CWorkspace::getConfigName() {
|
|||
}
|
||||
|
||||
bool CWorkspace::matchesStaticSelector(const std::string& selector_) {
|
||||
auto selector = removeBeginEndSpacesTabs(selector_);
|
||||
auto selector = trim(selector_);
|
||||
|
||||
if (selector.empty())
|
||||
return true;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "IKeyboard.hpp"
|
||||
#include "../defines.hpp"
|
||||
#include "../helpers/VarList.hpp"
|
||||
#include "../helpers/varlist/VarList.hpp"
|
||||
#include "../managers/input/InputManager.hpp"
|
||||
|
||||
uint32_t IKeyboard::getCapabilities() {
|
||||
|
|
|
@ -188,6 +188,9 @@ void Events::listener_monitorDestroy(void* owner, void* data) {
|
|||
|
||||
Debug::log(LOG, "Destroy called for monitor {}", pMonitor->output->name);
|
||||
|
||||
if (pMonitor->output->idle_frame)
|
||||
wl_event_source_remove(pMonitor->output->idle_frame);
|
||||
|
||||
pMonitor->onDisconnect(true);
|
||||
|
||||
pMonitor->output = nullptr;
|
||||
|
|
|
@ -12,6 +12,9 @@
|
|||
#include "../protocols/core/Compositor.hpp"
|
||||
#include "../xwayland/XSurface.hpp"
|
||||
|
||||
#include <hyprutils/string/String.hpp>
|
||||
using namespace Hyprutils::String;
|
||||
|
||||
// ------------------------------------------------------------ //
|
||||
// __ _______ _ _ _____ ______ _______ //
|
||||
// \ \ / /_ _| \ | | __ \ / __ \ \ / / ____| //
|
||||
|
@ -41,7 +44,6 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
|||
static auto PDIMSTRENGTH = CConfigValue<Hyprlang::FLOAT>("decoration:dim_strength");
|
||||
static auto PSWALLOW = CConfigValue<Hyprlang::INT>("misc:enable_swallow");
|
||||
static auto PSWALLOWREGEX = CConfigValue<std::string>("misc:swallow_regex");
|
||||
static auto PSWALLOWEXREGEX = CConfigValue<std::string>("misc:swallow_exception_regex");
|
||||
static auto PNEWTAKESOVERFS = CConfigValue<Hyprlang::INT>("misc:new_window_takes_over_fullscreen");
|
||||
static auto PINITIALWSTRACKING = CConfigValue<Hyprlang::INT>("misc:initial_workspace_tracking");
|
||||
|
||||
|
@ -140,7 +142,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
|||
for (auto& r : PWINDOW->m_vMatchedRules) {
|
||||
if (r.szRule.starts_with("monitor")) {
|
||||
try {
|
||||
const auto MONITORSTR = removeBeginEndSpacesTabs(r.szRule.substr(r.szRule.find(' ')));
|
||||
const auto MONITORSTR = trim(r.szRule.substr(r.szRule.find(' ')));
|
||||
|
||||
if (MONITORSTR == "unset") {
|
||||
PWINDOW->m_iMonitorID = PMONITOR->ID;
|
||||
|
@ -235,7 +237,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
|||
continue;
|
||||
|
||||
// `group` is a shorthand of `group set`
|
||||
if (removeBeginEndSpacesTabs(r.szRule) == "group") {
|
||||
if (trim(r.szRule) == "group") {
|
||||
PWINDOW->m_eGroupRules |= GROUP_SET;
|
||||
continue;
|
||||
}
|
||||
|
@ -524,71 +526,17 @@ void Events::listener_mapWindow(void* owner, void* data) {
|
|||
|
||||
// verify swallowing
|
||||
if (*PSWALLOW && std::string{*PSWALLOWREGEX} != STRVAL_EMPTY) {
|
||||
// don't swallow ourselves
|
||||
std::regex rgx(*PSWALLOWREGEX);
|
||||
if (!std::regex_match(PWINDOW->m_szClass, rgx)) {
|
||||
// check parent
|
||||
int ppid = getPPIDof(PWINDOW->getPID());
|
||||
const auto SWALLOWER = PWINDOW->getSwallower();
|
||||
|
||||
int curppid = 0;
|
||||
if (SWALLOWER) {
|
||||
// swallow
|
||||
PWINDOW->m_pSwallowed = SWALLOWER;
|
||||
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
curppid = getPPIDof(ppid);
|
||||
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(SWALLOWER);
|
||||
|
||||
if (curppid < 10) {
|
||||
break;
|
||||
}
|
||||
SWALLOWER->setHidden(true);
|
||||
|
||||
ppid = curppid;
|
||||
}
|
||||
|
||||
if (ppid) {
|
||||
// get window by pid
|
||||
std::vector<PHLWINDOW> found;
|
||||
PHLWINDOW finalFound;
|
||||
for (auto& w : g_pCompositor->m_vWindows) {
|
||||
if (!w->m_bIsMapped || w->isHidden())
|
||||
continue;
|
||||
|
||||
if (w->getPID() == ppid) {
|
||||
found.push_back(w);
|
||||
}
|
||||
}
|
||||
|
||||
if (found.size() > 1) {
|
||||
for (auto& w : found) {
|
||||
// try get the focus, otherwise we'll ignore to avoid swallowing incorrect windows
|
||||
if (w == PFOCUSEDWINDOWPREV) {
|
||||
finalFound = w;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (found.size() == 1) {
|
||||
finalFound = found[0];
|
||||
}
|
||||
|
||||
if (finalFound) {
|
||||
bool valid = std::regex_match(PWINDOW->m_szClass, rgx);
|
||||
|
||||
if (std::string{*PSWALLOWEXREGEX} != STRVAL_EMPTY) {
|
||||
std::regex exc(*PSWALLOWEXREGEX);
|
||||
|
||||
valid = valid && !std::regex_match(PWINDOW->m_szTitle, exc);
|
||||
}
|
||||
|
||||
// check if it's the window we want & not exempt from getting swallowed
|
||||
if (valid) {
|
||||
// swallow
|
||||
PWINDOW->m_pSwallowed = finalFound;
|
||||
|
||||
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(finalFound);
|
||||
|
||||
finalFound->setHidden(true);
|
||||
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->m_iMonitorID);
|
||||
}
|
||||
}
|
||||
}
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->m_iMonitorID);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -800,7 +748,7 @@ void Events::listener_commitWindow(void* owner, void* data) {
|
|||
// tearing: if solitary, redraw it. This still might be a single surface window
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
|
||||
if (PMONITOR && PMONITOR->solitaryClient.lock() == PWINDOW && PWINDOW->canBeTorn() && PMONITOR->tearingState.canTear && PWINDOW->m_pWLSurface->resource()->current.buffer) {
|
||||
CRegion damageBox{PWINDOW->m_pWLSurface->resource()->current.bufferDamage};
|
||||
CRegion damageBox{PWINDOW->m_pWLSurface->resource()->accumulateCurrentBufferDamage()};
|
||||
|
||||
if (!damageBox.empty()) {
|
||||
if (PMONITOR->tearingState.busy) {
|
||||
|
|
|
@ -11,18 +11,26 @@
|
|||
*/
|
||||
inline const std::vector<SPixelFormat> GLES3_FORMATS = {
|
||||
{
|
||||
.drmFormat = DRM_FORMAT_ARGB8888,
|
||||
.flipRB = true,
|
||||
.glFormat = GL_RGBA,
|
||||
.drmFormat = DRM_FORMAT_ARGB8888,
|
||||
.flipRB = true,
|
||||
#ifndef GLES2
|
||||
.glFormat = GL_RGBA,
|
||||
#else
|
||||
.glFormat = GL_BGRA_EXT,
|
||||
#endif
|
||||
.glType = GL_UNSIGNED_BYTE,
|
||||
.withAlpha = true,
|
||||
.alphaStripped = DRM_FORMAT_XRGB8888,
|
||||
.bytesPerBlock = 4,
|
||||
},
|
||||
{
|
||||
.drmFormat = DRM_FORMAT_XRGB8888,
|
||||
.flipRB = true,
|
||||
.glFormat = GL_RGBA,
|
||||
.drmFormat = DRM_FORMAT_XRGB8888,
|
||||
.flipRB = true,
|
||||
#ifndef GLES2
|
||||
.glFormat = GL_RGBA,
|
||||
#else
|
||||
.glFormat = GL_BGRA_EXT,
|
||||
#endif
|
||||
.glType = GL_UNSIGNED_BYTE,
|
||||
.withAlpha = false,
|
||||
.alphaStripped = DRM_FORMAT_XRGB8888,
|
||||
|
@ -93,70 +101,100 @@ inline const std::vector<SPixelFormat> GLES3_FORMATS = {
|
|||
.bytesPerBlock = 2,
|
||||
},
|
||||
{
|
||||
.drmFormat = DRM_FORMAT_XBGR2101010,
|
||||
.glFormat = GL_RGBA,
|
||||
.glType = GL_UNSIGNED_INT_2_10_10_10_REV,
|
||||
.drmFormat = DRM_FORMAT_XBGR2101010,
|
||||
.glFormat = GL_RGBA,
|
||||
#ifndef GLES2
|
||||
.glType = GL_UNSIGNED_INT_2_10_10_10_REV,
|
||||
#else
|
||||
.glType = GL_UNSIGNED_INT_2_10_10_10_REV_EXT,
|
||||
#endif
|
||||
.withAlpha = false,
|
||||
.alphaStripped = DRM_FORMAT_XBGR2101010,
|
||||
.bytesPerBlock = 4,
|
||||
},
|
||||
{
|
||||
.drmFormat = DRM_FORMAT_ABGR2101010,
|
||||
.glFormat = GL_RGBA,
|
||||
.glType = GL_UNSIGNED_INT_2_10_10_10_REV,
|
||||
.drmFormat = DRM_FORMAT_ABGR2101010,
|
||||
.glFormat = GL_RGBA,
|
||||
#ifndef GLES2
|
||||
.glType = GL_UNSIGNED_INT_2_10_10_10_REV,
|
||||
#else
|
||||
.glType = GL_UNSIGNED_INT_2_10_10_10_REV_EXT,
|
||||
#endif
|
||||
.withAlpha = true,
|
||||
.alphaStripped = DRM_FORMAT_XBGR2101010,
|
||||
.bytesPerBlock = 4,
|
||||
},
|
||||
{
|
||||
.drmFormat = DRM_FORMAT_XRGB2101010,
|
||||
.glFormat = GL_RGBA,
|
||||
.glType = GL_UNSIGNED_INT_2_10_10_10_REV,
|
||||
.drmFormat = DRM_FORMAT_XRGB2101010,
|
||||
.glFormat = GL_RGBA,
|
||||
#ifndef GLES2
|
||||
.glType = GL_UNSIGNED_INT_2_10_10_10_REV,
|
||||
#else
|
||||
.glType = GL_UNSIGNED_INT_2_10_10_10_REV_EXT,
|
||||
#endif
|
||||
.withAlpha = false,
|
||||
.alphaStripped = DRM_FORMAT_XRGB2101010,
|
||||
.bytesPerBlock = 4,
|
||||
},
|
||||
{
|
||||
.drmFormat = DRM_FORMAT_ARGB2101010,
|
||||
.glFormat = GL_RGBA,
|
||||
.glType = GL_UNSIGNED_INT_2_10_10_10_REV,
|
||||
.drmFormat = DRM_FORMAT_ARGB2101010,
|
||||
.glFormat = GL_RGBA,
|
||||
#ifndef GLES2
|
||||
.glType = GL_UNSIGNED_INT_2_10_10_10_REV,
|
||||
#else
|
||||
.glType = GL_UNSIGNED_INT_2_10_10_10_REV_EXT,
|
||||
#endif
|
||||
.withAlpha = true,
|
||||
.alphaStripped = DRM_FORMAT_XRGB2101010,
|
||||
.bytesPerBlock = 4,
|
||||
},
|
||||
{
|
||||
.drmFormat = DRM_FORMAT_XBGR16161616F,
|
||||
.glFormat = GL_RGBA,
|
||||
.glType = GL_HALF_FLOAT,
|
||||
.drmFormat = DRM_FORMAT_XBGR16161616F,
|
||||
.glFormat = GL_RGBA,
|
||||
#ifndef GLES2
|
||||
.glType = GL_HALF_FLOAT,
|
||||
#else
|
||||
.glType = GL_HALF_FLOAT_OES,
|
||||
#endif
|
||||
.withAlpha = false,
|
||||
.alphaStripped = DRM_FORMAT_XBGR16161616F,
|
||||
.bytesPerBlock = 8,
|
||||
},
|
||||
{
|
||||
.drmFormat = DRM_FORMAT_ABGR16161616F,
|
||||
.glFormat = GL_RGBA,
|
||||
.glType = GL_HALF_FLOAT,
|
||||
.drmFormat = DRM_FORMAT_ABGR16161616F,
|
||||
.glFormat = GL_RGBA,
|
||||
#ifndef GLES2
|
||||
.glType = GL_HALF_FLOAT,
|
||||
#else
|
||||
.glType = GL_HALF_FLOAT_OES,
|
||||
#endif
|
||||
.withAlpha = true,
|
||||
.alphaStripped = DRM_FORMAT_XBGR16161616F,
|
||||
.bytesPerBlock = 8,
|
||||
},
|
||||
{
|
||||
.drmFormat = DRM_FORMAT_XBGR16161616,
|
||||
.glInternalFormat = GL_RGBA16UI,
|
||||
.glFormat = GL_RGBA,
|
||||
.glType = GL_UNSIGNED_SHORT,
|
||||
.withAlpha = false,
|
||||
.alphaStripped = DRM_FORMAT_XBGR16161616,
|
||||
.bytesPerBlock = 8,
|
||||
.drmFormat = DRM_FORMAT_XBGR16161616,
|
||||
#ifndef GLES2
|
||||
.glFormat = GL_RGBA16UI,
|
||||
#else
|
||||
.glFormat = GL_RGBA16_EXT,
|
||||
#endif
|
||||
.glType = GL_UNSIGNED_SHORT,
|
||||
.withAlpha = false,
|
||||
.alphaStripped = DRM_FORMAT_XBGR16161616,
|
||||
.bytesPerBlock = 8,
|
||||
},
|
||||
{
|
||||
.drmFormat = DRM_FORMAT_ABGR16161616,
|
||||
.glInternalFormat = GL_RGBA16UI,
|
||||
.glFormat = GL_RGBA,
|
||||
.glType = GL_UNSIGNED_SHORT,
|
||||
.withAlpha = true,
|
||||
.alphaStripped = DRM_FORMAT_XBGR16161616,
|
||||
.bytesPerBlock = 8,
|
||||
.drmFormat = DRM_FORMAT_ABGR16161616,
|
||||
#ifndef GLES2
|
||||
.glFormat = GL_RGBA16UI,
|
||||
#else
|
||||
.glFormat = GL_RGBA16_EXT,
|
||||
#endif
|
||||
.glType = GL_UNSIGNED_SHORT,
|
||||
.withAlpha = true,
|
||||
.alphaStripped = DRM_FORMAT_XBGR16161616,
|
||||
.bytesPerBlock = 8,
|
||||
},
|
||||
{
|
||||
.drmFormat = DRM_FORMAT_YVYU,
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
#ifdef HAS_EXECINFO
|
||||
#include <execinfo.h>
|
||||
#endif
|
||||
#include <hyprutils/string/String.hpp>
|
||||
using namespace Hyprutils::String;
|
||||
|
||||
#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
#include <sys/sysctl.h>
|
||||
|
@ -195,25 +197,6 @@ std::string escapeJSONStrings(const std::string& str) {
|
|||
return oss.str();
|
||||
}
|
||||
|
||||
std::string removeBeginEndSpacesTabs(std::string str) {
|
||||
if (str.empty())
|
||||
return str;
|
||||
|
||||
int countBefore = 0;
|
||||
while (str[countBefore] == ' ' || str[countBefore] == '\t') {
|
||||
countBefore++;
|
||||
}
|
||||
|
||||
int countAfter = 0;
|
||||
while ((int)str.length() - countAfter - 1 >= 0 && (str[str.length() - countAfter - 1] == ' ' || str[str.length() - 1 - countAfter] == '\t')) {
|
||||
countAfter++;
|
||||
}
|
||||
|
||||
str = str.substr(countBefore, str.length() - countBefore - countAfter);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
std::optional<float> getPlusMinusKeywordResult(std::string source, float relative) {
|
||||
try {
|
||||
return relative + stof(source);
|
||||
|
@ -223,31 +206,6 @@ std::optional<float> getPlusMinusKeywordResult(std::string source, float relativ
|
|||
}
|
||||
}
|
||||
|
||||
bool isNumber(const std::string& str, bool allowfloat) {
|
||||
|
||||
std::string copy = str;
|
||||
if (*copy.begin() == '-')
|
||||
copy = copy.substr(1);
|
||||
|
||||
if (copy.empty())
|
||||
return false;
|
||||
|
||||
bool point = !allowfloat;
|
||||
for (auto& c : copy) {
|
||||
if (c == '.') {
|
||||
if (point)
|
||||
return false;
|
||||
point = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!std::isdigit(c))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isDirection(const std::string& arg) {
|
||||
return arg == "l" || arg == "r" || arg == "u" || arg == "d" || arg == "t" || arg == "b";
|
||||
}
|
||||
|
@ -579,7 +537,7 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
|
|||
|
||||
std::optional<std::string> cleanCmdForWorkspace(const std::string& inWorkspaceName, std::string dirtyCmd) {
|
||||
|
||||
std::string cmd = removeBeginEndSpacesTabs(dirtyCmd);
|
||||
std::string cmd = trim(dirtyCmd);
|
||||
|
||||
if (!cmd.empty()) {
|
||||
std::string rules;
|
||||
|
@ -622,9 +580,10 @@ float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Ve
|
|||
|
||||
// Execute a shell command and get the output
|
||||
std::string execAndGet(const char* cmd) {
|
||||
std::array<char, 128> buffer;
|
||||
std::string result;
|
||||
const std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd, "r"), pclose);
|
||||
std::array<char, 128> buffer;
|
||||
std::string result;
|
||||
using PcloseType = int (*)(FILE*);
|
||||
const std::unique_ptr<FILE, PcloseType> pipe(popen(cmd, "r"), static_cast<PcloseType>(pclose));
|
||||
if (!pipe) {
|
||||
Debug::log(ERR, "execAndGet: failed in pipe");
|
||||
return "";
|
||||
|
@ -748,7 +707,7 @@ int64_t configStringToInt(const std::string& VALUE) {
|
|||
} else if (VALUE.starts_with("rgba(") && VALUE.ends_with(')')) {
|
||||
const auto VALUEWITHOUTFUNC = VALUE.substr(5, VALUE.length() - 6);
|
||||
|
||||
if (removeBeginEndSpacesTabs(VALUEWITHOUTFUNC).length() != 8) {
|
||||
if (trim(VALUEWITHOUTFUNC).length() != 8) {
|
||||
Debug::log(WARN, "invalid length {} for rgba", VALUEWITHOUTFUNC.length());
|
||||
throw std::invalid_argument("rgba() expects length of 8 characters (4 bytes)");
|
||||
}
|
||||
|
@ -760,7 +719,7 @@ int64_t configStringToInt(const std::string& VALUE) {
|
|||
} else if (VALUE.starts_with("rgb(") && VALUE.ends_with(')')) {
|
||||
const auto VALUEWITHOUTFUNC = VALUE.substr(4, VALUE.length() - 5);
|
||||
|
||||
if (removeBeginEndSpacesTabs(VALUEWITHOUTFUNC).length() != 6) {
|
||||
if (trim(VALUEWITHOUTFUNC).length() != 6) {
|
||||
Debug::log(WARN, "invalid length {} for rgb", VALUEWITHOUTFUNC.length());
|
||||
throw std::invalid_argument("rgb() expects length of 6 characters (3 bytes)");
|
||||
}
|
||||
|
@ -822,15 +781,6 @@ double normalizeAngleRad(double ang) {
|
|||
return ang;
|
||||
}
|
||||
|
||||
std::string replaceInString(std::string subject, const std::string& search, const std::string& replace) {
|
||||
size_t pos = 0;
|
||||
while ((pos = subject.find(search, pos)) != std::string::npos) {
|
||||
subject.replace(pos, search.length(), replace);
|
||||
pos += replace.length();
|
||||
}
|
||||
return subject;
|
||||
}
|
||||
|
||||
std::vector<SCallstackFrameInfo> getBacktrace() {
|
||||
std::vector<SCallstackFrameInfo> callstack;
|
||||
|
||||
|
@ -865,7 +815,8 @@ bool envEnabled(const std::string& env) {
|
|||
}
|
||||
|
||||
std::pair<int, std::string> openExclusiveShm() {
|
||||
std::string name = g_pTokenManager->getRandomUUID();
|
||||
// Only absolute paths can be shared across different shm_open() calls
|
||||
std::string name = "/" + g_pTokenManager->getRandomUUID();
|
||||
|
||||
for (size_t i = 0; i < 69; ++i) {
|
||||
int fd = shm_open(name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600);
|
||||
|
|
|
@ -17,8 +17,6 @@ std::string absolutePath(const std::string&, const std::str
|
|||
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);
|
||||
bool isDirection(const std::string&);
|
||||
bool isDirection(const char&);
|
||||
int getWorkspaceIDFromString(const std::string&, std::string&);
|
||||
|
@ -32,7 +30,6 @@ Vector2D configStringToVector2D(const std::string&);
|
|||
std::optional<float> getPlusMinusKeywordResult(std::string in, float relative);
|
||||
void matrixProjection(float mat[9], int w, int h, wl_output_transform tr);
|
||||
double normalizeAngleRad(double ang);
|
||||
std::string replaceInString(std::string subject, const std::string& search, const std::string& replace);
|
||||
std::vector<SCallstackFrameInfo> getBacktrace();
|
||||
void throwError(const std::string& err);
|
||||
bool envEnabled(const std::string& env);
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#include "../devices/ITouch.hpp"
|
||||
#include "../protocols/LayerShell.hpp"
|
||||
#include "../protocols/PresentationTime.hpp"
|
||||
#include <hyprutils/string/String.hpp>
|
||||
using namespace Hyprutils::String;
|
||||
|
||||
int ratHandler(void* data) {
|
||||
g_pHyprRenderer->renderMonitor((CMonitor*)data);
|
||||
|
@ -71,8 +73,7 @@ void CMonitor::onConnect(bool noRule) {
|
|||
std::erase(szDescription, ',');
|
||||
|
||||
// field is backwards-compatible with intended usage of `szDescription` but excludes the parenthesized DRM node name suffix
|
||||
szShortDescription =
|
||||
removeBeginEndSpacesTabs(std::format("{} {} {}", output->make ? output->make : "", output->model ? output->model : "", output->serial ? output->serial : ""));
|
||||
szShortDescription = trim(std::format("{} {} {}", output->make ? output->make : "", output->model ? output->model : "", output->serial ? output->serial : ""));
|
||||
std::erase(szShortDescription, ',');
|
||||
|
||||
if (!wlr_backend_is_drm(output->backend))
|
||||
|
@ -361,6 +362,24 @@ void CMonitor::addDamage(const CBox* box) {
|
|||
g_pCompositor->scheduleFrameForMonitor(this);
|
||||
}
|
||||
|
||||
bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() {
|
||||
static auto PNOBREAK = CConfigValue<Hyprlang::INT>("cursor:no_break_fs_vrr");
|
||||
static auto PMINRR = CConfigValue<Hyprlang::INT>("cursor:min_refresh_rate");
|
||||
|
||||
// skip scheduling extra frames for fullsreen apps with vrr
|
||||
bool shouldSkip = *PNOBREAK && output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED && activeWorkspace && activeWorkspace->m_bHasFullscreenWindow &&
|
||||
activeWorkspace->m_efFullscreenMode == FULLSCREEN_FULL;
|
||||
|
||||
// keep requested minimum refresh rate
|
||||
if (shouldSkip && *PMINRR && lastPresentationTimer.getMillis() > 1000 / *PMINRR) {
|
||||
// damage whole screen because some previous cursor box damages were skipped
|
||||
wlr_damage_ring_add_whole(&damage);
|
||||
return false;
|
||||
}
|
||||
|
||||
return shouldSkip;
|
||||
}
|
||||
|
||||
bool CMonitor::isMirror() {
|
||||
return pMirrorOf != nullptr;
|
||||
}
|
||||
|
|
|
@ -158,6 +158,7 @@ class CMonitor {
|
|||
void addDamage(const pixman_region32_t* rg);
|
||||
void addDamage(const CRegion* rg);
|
||||
void addDamage(const CBox* box);
|
||||
bool shouldSkipScheduleFrameOnMouseEvent();
|
||||
void setMirror(const std::string&);
|
||||
bool isMirror();
|
||||
bool matchesStaticSelector(const std::string& selector) const;
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
#include "MiscFunctions.hpp"
|
||||
#include "VarList.hpp"
|
||||
#include <ranges>
|
||||
#include <algorithm>
|
||||
|
||||
CVarList::CVarList(const std::string& in, const size_t lastArgNo, const char delim, const bool removeEmpty) {
|
||||
if (in.empty())
|
||||
m_vArgs.emplace_back("");
|
||||
|
||||
std::string args{in};
|
||||
size_t idx = 0;
|
||||
size_t pos = 0;
|
||||
std::ranges::replace_if(
|
||||
args, [&](const char& c) { return delim == 's' ? std::isspace(c) : c == delim; }, 0);
|
||||
|
||||
for (const auto& s : args | std::views::split(0)) {
|
||||
if (removeEmpty && s.empty())
|
||||
continue;
|
||||
if (++idx == lastArgNo) {
|
||||
m_vArgs.emplace_back(removeBeginEndSpacesTabs(in.substr(pos)));
|
||||
break;
|
||||
}
|
||||
pos += s.size() + 1;
|
||||
m_vArgs.emplace_back(removeBeginEndSpacesTabs(std::string_view{s}.data()));
|
||||
}
|
||||
}
|
||||
|
||||
std::string CVarList::join(const std::string& joiner, size_t from, size_t to) const {
|
||||
size_t last = to == 0 ? size() : to;
|
||||
|
||||
std::string rolling;
|
||||
for (size_t i = from; i < last; ++i) {
|
||||
rolling += m_vArgs[i] + (i + 1 < last ? joiner : "");
|
||||
}
|
||||
|
||||
return rolling;
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
#pragma once
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "../macros.hpp"
|
||||
|
||||
class CVarList {
|
||||
public:
|
||||
/** Split string into arg list
|
||||
@param lastArgNo stop splitting after argv reaches maximum size, last arg will contain rest of unsplit args
|
||||
@param delim if delimiter is 's', use std::isspace
|
||||
@param removeEmpty remove empty args from argv
|
||||
*/
|
||||
CVarList(const std::string& in, const size_t maxSize = 0, const char delim = ',', const bool removeEmpty = false);
|
||||
|
||||
~CVarList() = default;
|
||||
|
||||
size_t size() const {
|
||||
return m_vArgs.size();
|
||||
}
|
||||
|
||||
std::string join(const std::string& joiner, size_t from = 0, size_t to = 0) const;
|
||||
|
||||
void map(std::function<void(std::string&)> func) {
|
||||
for (auto& s : m_vArgs)
|
||||
func(s);
|
||||
}
|
||||
|
||||
void append(const std::string arg) {
|
||||
m_vArgs.emplace_back(arg);
|
||||
}
|
||||
|
||||
std::string operator[](const size_t& idx) const {
|
||||
if (idx >= m_vArgs.size())
|
||||
return "";
|
||||
return m_vArgs[idx];
|
||||
}
|
||||
|
||||
// for range-based loops
|
||||
std::vector<std::string>::iterator begin() {
|
||||
return m_vArgs.begin();
|
||||
}
|
||||
std::vector<std::string>::const_iterator begin() const {
|
||||
return m_vArgs.begin();
|
||||
}
|
||||
std::vector<std::string>::iterator end() {
|
||||
return m_vArgs.end();
|
||||
}
|
||||
std::vector<std::string>::const_iterator end() const {
|
||||
return m_vArgs.end();
|
||||
}
|
||||
|
||||
bool contains(const std::string& el) {
|
||||
for (auto& a : m_vArgs) {
|
||||
if (a == el)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::string> m_vArgs;
|
||||
};
|
|
@ -7,7 +7,7 @@
|
|||
#include "../desktop/Popup.hpp"
|
||||
#include "AnimatedVariable.hpp"
|
||||
#include "../desktop/WLSurface.hpp"
|
||||
#include "signal/Listener.hpp"
|
||||
#include "signal/Signal.hpp"
|
||||
#include "Region.hpp"
|
||||
|
||||
class CMonitor;
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <hyprutils/memory/WeakPtr.hpp>
|
||||
|
||||
using namespace Hyprutils::Memory;
|
||||
|
||||
#define SP Hyprutils::Memory::CSharedPointer
|
||||
#define WP Hyprutils::Memory::CWeakPointer
|
||||
#define UP std::unique_ptr
|
|
@ -1,302 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <typeinfo>
|
||||
#include <typeindex>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
#define SP CSharedPointer
|
||||
|
||||
/*
|
||||
This is a custom impl of std::shared_ptr.
|
||||
It is not thread-safe like the STL one,
|
||||
but Hyprland is single-threaded anyways.
|
||||
|
||||
It differs a bit from how the STL one works,
|
||||
namely in the fact that it keeps the T* inside the
|
||||
control block, and that you can still make a CWeakPtr
|
||||
or deref an existing one inside the destructor.
|
||||
*/
|
||||
namespace CSharedPointer_ {
|
||||
|
||||
class impl_base {
|
||||
public:
|
||||
virtual ~impl_base(){};
|
||||
|
||||
virtual void inc() noexcept = 0;
|
||||
virtual void dec() noexcept = 0;
|
||||
virtual void incWeak() noexcept = 0;
|
||||
virtual void decWeak() noexcept = 0;
|
||||
virtual unsigned int ref() noexcept = 0;
|
||||
virtual unsigned int wref() noexcept = 0;
|
||||
virtual void destroy() noexcept = 0;
|
||||
virtual bool destroying() noexcept = 0;
|
||||
virtual bool dataNonNull() noexcept = 0;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class impl : public impl_base {
|
||||
public:
|
||||
impl(T* data) noexcept : _data(data) {
|
||||
;
|
||||
}
|
||||
|
||||
/* strong refcount */
|
||||
unsigned int _ref = 0;
|
||||
/* weak refcount */
|
||||
unsigned int _weak = 0;
|
||||
|
||||
T* _data = nullptr;
|
||||
|
||||
friend void swap(impl*& a, impl*& b) {
|
||||
impl* tmp = a;
|
||||
a = b;
|
||||
b = tmp;
|
||||
}
|
||||
|
||||
/* if the destructor was called,
|
||||
creating shared_ptrs is no longer valid */
|
||||
bool _destroying = false;
|
||||
|
||||
void _destroy() {
|
||||
if (!_data || _destroying)
|
||||
return;
|
||||
|
||||
// first, we destroy the data, but keep the pointer.
|
||||
// this way, weak pointers will still be able to
|
||||
// reference and use, but no longer create shared ones.
|
||||
_destroying = true;
|
||||
__deleter(_data);
|
||||
// now, we can reset the data and call it a day.
|
||||
_data = nullptr;
|
||||
_destroying = false;
|
||||
}
|
||||
|
||||
std::default_delete<T> __deleter{};
|
||||
|
||||
//
|
||||
virtual void inc() noexcept {
|
||||
_ref++;
|
||||
}
|
||||
|
||||
virtual void dec() noexcept {
|
||||
_ref--;
|
||||
}
|
||||
|
||||
virtual void incWeak() noexcept {
|
||||
_weak++;
|
||||
}
|
||||
|
||||
virtual void decWeak() noexcept {
|
||||
_weak--;
|
||||
}
|
||||
|
||||
virtual unsigned int ref() noexcept {
|
||||
return _ref;
|
||||
}
|
||||
|
||||
virtual unsigned int wref() noexcept {
|
||||
return _weak;
|
||||
}
|
||||
|
||||
virtual void destroy() noexcept {
|
||||
_destroy();
|
||||
}
|
||||
|
||||
virtual bool destroying() noexcept {
|
||||
return _destroying;
|
||||
}
|
||||
|
||||
virtual bool dataNonNull() noexcept {
|
||||
return _data;
|
||||
}
|
||||
|
||||
virtual ~impl() {
|
||||
destroy();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class CSharedPointer {
|
||||
public:
|
||||
template <typename X>
|
||||
using validHierarchy = typename std::enable_if<std::is_assignable<CSharedPointer<T>&, X>::value, CSharedPointer&>::type;
|
||||
template <typename X>
|
||||
using isConstructible = typename std::enable_if<std::is_constructible<T&, X&>::value>::type;
|
||||
|
||||
/* creates a new shared pointer managing a resource
|
||||
avoid calling. Could duplicate ownership. Prefer makeShared */
|
||||
explicit CSharedPointer(T* object) noexcept {
|
||||
impl_ = new CSharedPointer_::impl<T>(object);
|
||||
increment();
|
||||
}
|
||||
|
||||
/* creates a shared pointer from a reference */
|
||||
template <typename U, typename = isConstructible<U>>
|
||||
CSharedPointer(const CSharedPointer<U>& ref) noexcept {
|
||||
impl_ = ref.impl_;
|
||||
increment();
|
||||
}
|
||||
|
||||
CSharedPointer(const CSharedPointer& ref) noexcept {
|
||||
impl_ = ref.impl_;
|
||||
increment();
|
||||
}
|
||||
|
||||
template <typename U, typename = isConstructible<U>>
|
||||
CSharedPointer(CSharedPointer<U>&& ref) noexcept {
|
||||
std::swap(impl_, ref.impl_);
|
||||
}
|
||||
|
||||
CSharedPointer(CSharedPointer&& ref) noexcept {
|
||||
std::swap(impl_, ref.impl_);
|
||||
}
|
||||
|
||||
/* allows weakPointer to create from an impl */
|
||||
CSharedPointer(CSharedPointer_::impl_base* implementation) noexcept {
|
||||
impl_ = implementation;
|
||||
increment();
|
||||
}
|
||||
|
||||
/* creates an empty shared pointer with no implementation */
|
||||
CSharedPointer() noexcept {
|
||||
; // empty
|
||||
}
|
||||
|
||||
/* creates an empty shared pointer with no implementation */
|
||||
CSharedPointer(std::nullptr_t) noexcept {
|
||||
; // empty
|
||||
}
|
||||
|
||||
~CSharedPointer() {
|
||||
// we do not decrement here,
|
||||
// because we want to preserve the pointer
|
||||
// in case this is the last owner.
|
||||
if (impl_ && impl_->ref() == 1)
|
||||
destroyImpl();
|
||||
else
|
||||
decrement();
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
validHierarchy<const CSharedPointer<U>&> operator=(const CSharedPointer<U>& rhs) {
|
||||
if (impl_ == rhs.impl_)
|
||||
return *this;
|
||||
|
||||
decrement();
|
||||
impl_ = rhs.impl_;
|
||||
increment();
|
||||
return *this;
|
||||
}
|
||||
|
||||
CSharedPointer& operator=(const CSharedPointer& rhs) {
|
||||
if (impl_ == rhs.impl_)
|
||||
return *this;
|
||||
|
||||
decrement();
|
||||
impl_ = rhs.impl_;
|
||||
increment();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
validHierarchy<const CSharedPointer<U>&> operator=(CSharedPointer<U>&& rhs) {
|
||||
std::swap(impl_, rhs.impl_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
CSharedPointer& operator=(CSharedPointer&& rhs) {
|
||||
std::swap(impl_, rhs.impl_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator bool() const {
|
||||
return impl_ && impl_->dataNonNull();
|
||||
}
|
||||
|
||||
bool operator==(const CSharedPointer& rhs) const {
|
||||
return impl_ == rhs.impl_;
|
||||
}
|
||||
|
||||
bool operator()(const CSharedPointer& lhs, const CSharedPointer& rhs) const {
|
||||
return (uintptr_t)lhs.impl_ < (uintptr_t)rhs.impl_;
|
||||
}
|
||||
|
||||
bool operator<(const CSharedPointer& rhs) const {
|
||||
return (uintptr_t)impl_ < (uintptr_t)rhs.impl_;
|
||||
}
|
||||
|
||||
T* operator->() const {
|
||||
return get();
|
||||
}
|
||||
|
||||
T& operator*() const {
|
||||
return *get();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
decrement();
|
||||
impl_ = nullptr;
|
||||
}
|
||||
|
||||
T* get() const {
|
||||
return (T*)(impl_ ? static_cast<CSharedPointer_::impl<T>*>(impl_)->_data : nullptr);
|
||||
}
|
||||
|
||||
unsigned int strongRef() const {
|
||||
return impl_ ? impl_->ref() : 0;
|
||||
}
|
||||
|
||||
CSharedPointer_::impl_base* impl_ = nullptr;
|
||||
|
||||
private:
|
||||
/*
|
||||
no-op if there is no impl_
|
||||
may delete the stored object if ref == 0
|
||||
may delete and reset impl_ if ref == 0 and weak == 0
|
||||
*/
|
||||
void decrement() {
|
||||
if (!impl_)
|
||||
return;
|
||||
|
||||
impl_->dec();
|
||||
|
||||
// if ref == 0, we can destroy impl
|
||||
if (impl_->ref() == 0)
|
||||
destroyImpl();
|
||||
}
|
||||
/* no-op if there is no impl_ */
|
||||
void increment() {
|
||||
if (!impl_)
|
||||
return;
|
||||
|
||||
impl_->inc();
|
||||
}
|
||||
|
||||
/* destroy the pointed-to object
|
||||
if able, will also destroy impl */
|
||||
void destroyImpl() {
|
||||
// destroy the impl contents
|
||||
impl_->destroy();
|
||||
|
||||
// check for weak refs, if zero, we can also delete impl_
|
||||
if (impl_->wref() == 0) {
|
||||
delete impl_;
|
||||
impl_ = nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename U, typename... Args>
|
||||
static CSharedPointer<U> makeShared(Args&&... args) {
|
||||
return CSharedPointer<U>(new U(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct std::hash<CSharedPointer<T>> {
|
||||
std::size_t operator()(const CSharedPointer<T>& p) const noexcept {
|
||||
return std::hash<void*>{}(p.impl_);
|
||||
}
|
||||
};
|
|
@ -1,190 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "SharedPtr.hpp"
|
||||
|
||||
#define WP CWeakPointer
|
||||
|
||||
/*
|
||||
This is a Hyprland implementation of std::weak_ptr.
|
||||
|
||||
See SharedPtr.hpp for more info on how it's different.
|
||||
*/
|
||||
|
||||
template <typename T>
|
||||
class CWeakPointer {
|
||||
public:
|
||||
template <typename X>
|
||||
using validHierarchy = typename std::enable_if<std::is_assignable<CWeakPointer<T>&, X>::value, CWeakPointer&>::type;
|
||||
template <typename X>
|
||||
using isConstructible = typename std::enable_if<std::is_constructible<T&, X&>::value>::type;
|
||||
|
||||
/* create a weak ptr from a reference */
|
||||
template <typename U, typename = isConstructible<U>>
|
||||
CWeakPointer(const CSharedPointer<U>& ref) noexcept {
|
||||
if (!ref.impl_)
|
||||
return;
|
||||
|
||||
impl_ = ref.impl_;
|
||||
incrementWeak();
|
||||
}
|
||||
|
||||
/* create a weak ptr from another weak ptr */
|
||||
template <typename U, typename = isConstructible<U>>
|
||||
CWeakPointer(const CWeakPointer<U>& ref) noexcept {
|
||||
if (!ref.impl_)
|
||||
return;
|
||||
|
||||
impl_ = ref.impl_;
|
||||
incrementWeak();
|
||||
}
|
||||
|
||||
CWeakPointer(const CWeakPointer& ref) noexcept {
|
||||
if (!ref.impl_)
|
||||
return;
|
||||
|
||||
impl_ = ref.impl_;
|
||||
incrementWeak();
|
||||
}
|
||||
|
||||
template <typename U, typename = isConstructible<U>>
|
||||
CWeakPointer(CWeakPointer<U>&& ref) noexcept {
|
||||
std::swap(impl_, ref.impl_);
|
||||
}
|
||||
|
||||
CWeakPointer(CWeakPointer&& ref) noexcept {
|
||||
std::swap(impl_, ref.impl_);
|
||||
}
|
||||
|
||||
/* create a weak ptr from another weak ptr with assignment */
|
||||
template <typename U>
|
||||
validHierarchy<const CWeakPointer<U>&> operator=(const CWeakPointer<U>& rhs) {
|
||||
if (impl_ == rhs.impl_)
|
||||
return *this;
|
||||
|
||||
decrementWeak();
|
||||
impl_ = rhs.impl_;
|
||||
incrementWeak();
|
||||
return *this;
|
||||
}
|
||||
|
||||
CWeakPointer<T>& operator=(const CWeakPointer& rhs) {
|
||||
if (impl_ == rhs.impl_)
|
||||
return *this;
|
||||
|
||||
decrementWeak();
|
||||
impl_ = rhs.impl_;
|
||||
incrementWeak();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* create a weak ptr from a shared ptr with assignment */
|
||||
template <typename U>
|
||||
validHierarchy<const CWeakPointer<U>&> operator=(const CSharedPointer<U>& rhs) {
|
||||
if ((uintptr_t)impl_ == (uintptr_t)rhs.impl_)
|
||||
return *this;
|
||||
|
||||
decrementWeak();
|
||||
impl_ = rhs.impl_;
|
||||
incrementWeak();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* create an empty weak ptr */
|
||||
CWeakPointer() {
|
||||
;
|
||||
}
|
||||
|
||||
~CWeakPointer() {
|
||||
decrementWeak();
|
||||
}
|
||||
|
||||
/* expired MAY return true even if the pointer is still stored.
|
||||
the situation would be e.g. self-weak pointer in a destructor.
|
||||
for pointer validity, use valid() */
|
||||
bool expired() const {
|
||||
return !impl_ || !impl_->dataNonNull() || impl_->destroying();
|
||||
}
|
||||
|
||||
/* this means the pointed-to object is not yet deleted and can still be
|
||||
referenced, but it might be in the process of being deleted.
|
||||
check !expired() if you want to check whether it's valid and
|
||||
assignable to a SP. */
|
||||
bool valid() const {
|
||||
return impl_ && impl_->dataNonNull();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
decrementWeak();
|
||||
impl_ = nullptr;
|
||||
}
|
||||
|
||||
CSharedPointer<T> lock() const {
|
||||
if (!impl_ || !impl_->dataNonNull() || impl_->destroying())
|
||||
return {};
|
||||
|
||||
return CSharedPointer<T>(impl_);
|
||||
}
|
||||
|
||||
/* this returns valid() */
|
||||
operator bool() const {
|
||||
return valid();
|
||||
}
|
||||
|
||||
bool operator==(const CWeakPointer<T>& rhs) const {
|
||||
return impl_ == rhs.impl_;
|
||||
}
|
||||
|
||||
bool operator==(const CSharedPointer<T>& rhs) const {
|
||||
return impl_ == rhs.impl_;
|
||||
}
|
||||
|
||||
bool operator()(const CWeakPointer& lhs, const CWeakPointer& rhs) const {
|
||||
return (uintptr_t)lhs.impl_ < (uintptr_t)rhs.impl_;
|
||||
}
|
||||
|
||||
bool operator<(const CWeakPointer& rhs) const {
|
||||
return (uintptr_t)impl_ < (uintptr_t)rhs.impl_;
|
||||
}
|
||||
|
||||
T* get() const {
|
||||
return (T*)(impl_ ? static_cast<CSharedPointer_::impl<T>*>(impl_)->_data : nullptr);
|
||||
}
|
||||
|
||||
T* operator->() const {
|
||||
return get();
|
||||
}
|
||||
|
||||
CSharedPointer_::impl_base* impl_ = nullptr;
|
||||
|
||||
private:
|
||||
/* no-op if there is no impl_ */
|
||||
void decrementWeak() {
|
||||
if (!impl_)
|
||||
return;
|
||||
|
||||
impl_->decWeak();
|
||||
|
||||
// we need to check for ->destroying,
|
||||
// because otherwise we could destroy here
|
||||
// and have a shared_ptr destroy the same thing
|
||||
// later (in situations where we have a weak_ptr to self)
|
||||
if (impl_->wref() == 0 && impl_->ref() == 0 && !impl_->destroying()) {
|
||||
delete impl_;
|
||||
impl_ = nullptr;
|
||||
}
|
||||
}
|
||||
/* no-op if there is no impl_ */
|
||||
void incrementWeak() {
|
||||
if (!impl_)
|
||||
return;
|
||||
|
||||
impl_->incWeak();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct std::hash<CWeakPointer<T>> {
|
||||
std::size_t operator()(const CWeakPointer<T>& p) const noexcept {
|
||||
return std::hash<void*>{}(p.impl_);
|
||||
}
|
||||
};
|
|
@ -1,21 +0,0 @@
|
|||
#include "Listener.hpp"
|
||||
#include "Signal.hpp"
|
||||
|
||||
CSignalListener::CSignalListener(std::function<void(std::any)> handler) : m_fHandler(handler) {
|
||||
;
|
||||
}
|
||||
|
||||
void CSignalListener::emit(std::any data) {
|
||||
if (!m_fHandler)
|
||||
return;
|
||||
|
||||
m_fHandler(data);
|
||||
}
|
||||
|
||||
CStaticSignalListener::CStaticSignalListener(std::function<void(void*, std::any)> handler, void* owner) : m_pOwner(owner), m_fHandler(handler) {
|
||||
;
|
||||
}
|
||||
|
||||
void CStaticSignalListener::emit(std::any data) {
|
||||
m_fHandler(m_pOwner, data);
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <any>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include "../../macros.hpp"
|
||||
|
||||
class CSignal;
|
||||
|
||||
class CSignalListener {
|
||||
public:
|
||||
CSignalListener(std::function<void(std::any)> handler);
|
||||
|
||||
CSignalListener(CSignalListener&&) = delete;
|
||||
CSignalListener(CSignalListener&) = delete;
|
||||
CSignalListener(const CSignalListener&) = delete;
|
||||
CSignalListener(const CSignalListener&&) = delete;
|
||||
|
||||
void emit(std::any data);
|
||||
|
||||
private:
|
||||
std::function<void(std::any)> m_fHandler;
|
||||
};
|
||||
|
||||
typedef SP<CSignalListener> CHyprSignalListener;
|
||||
|
||||
class CStaticSignalListener {
|
||||
public:
|
||||
CStaticSignalListener(std::function<void(void*, std::any)> handler, void* owner);
|
||||
|
||||
CStaticSignalListener(CStaticSignalListener&&) = delete;
|
||||
CStaticSignalListener(CStaticSignalListener&) = delete;
|
||||
CStaticSignalListener(const CStaticSignalListener&) = delete;
|
||||
CStaticSignalListener(const CStaticSignalListener&&) = delete;
|
||||
|
||||
void emit(std::any data);
|
||||
|
||||
private:
|
||||
void* m_pOwner = nullptr;
|
||||
std::function<void(void*, std::any)> m_fHandler;
|
||||
};
|
|
@ -1,51 +0,0 @@
|
|||
#include "Signal.hpp"
|
||||
#include <algorithm>
|
||||
|
||||
void CSignal::emit(std::any data) {
|
||||
bool dirty = false;
|
||||
|
||||
std::vector<SP<CSignalListener>> listeners;
|
||||
for (auto& l : m_vListeners) {
|
||||
if (l.expired()) {
|
||||
dirty = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
listeners.emplace_back(l.lock());
|
||||
}
|
||||
|
||||
std::vector<CStaticSignalListener*> statics;
|
||||
for (auto& l : m_vStaticListeners) {
|
||||
statics.emplace_back(l.get());
|
||||
}
|
||||
|
||||
for (auto& l : listeners) {
|
||||
// if there is only one lock, it means the event is only held by the listeners
|
||||
// vector and was removed during our iteration
|
||||
if (l.strongRef() == 1) {
|
||||
dirty = true;
|
||||
continue;
|
||||
}
|
||||
l->emit(data);
|
||||
}
|
||||
|
||||
for (auto& l : statics) {
|
||||
l->emit(data);
|
||||
}
|
||||
|
||||
// release SPs
|
||||
listeners.clear();
|
||||
|
||||
if (dirty)
|
||||
std::erase_if(m_vListeners, [](const auto& other) { return other.expired(); });
|
||||
}
|
||||
|
||||
CHyprSignalListener CSignal::registerListener(std::function<void(std::any)> handler) {
|
||||
CHyprSignalListener listener = makeShared<CSignalListener>(handler);
|
||||
m_vListeners.emplace_back(WP<CSignalListener>(listener));
|
||||
return listener;
|
||||
}
|
||||
|
||||
void CSignal::registerStaticListener(std::function<void(void*, std::any)> handler, void* owner) {
|
||||
m_vStaticListeners.emplace_back(std::make_unique<CStaticSignalListener>(handler, owner));
|
||||
}
|
|
@ -1,24 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <any>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <hyprutils/signal/Signal.hpp>
|
||||
|
||||
#include "Listener.hpp"
|
||||
|
||||
class CSignal {
|
||||
public:
|
||||
void emit(std::any data = {});
|
||||
|
||||
//
|
||||
[[nodiscard("Listener is unregistered when the ptr is lost")]] CHyprSignalListener registerListener(std::function<void(std::any)> handler);
|
||||
|
||||
// this is for static listeners. They die with this signal.
|
||||
// TODO: can we somehow rid of the void* data and make it a custom this?
|
||||
void registerStaticListener(std::function<void(void*, std::any)> handler, void* owner);
|
||||
|
||||
private:
|
||||
std::vector<WP<CSignalListener>> m_vListeners;
|
||||
std::vector<std::unique_ptr<CStaticSignalListener>> m_vStaticListeners;
|
||||
};
|
||||
using namespace Hyprutils::Signal;
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include <hyprutils/string/VarList.hpp>
|
||||
|
||||
using namespace Hyprutils::String;
|
|
@ -76,17 +76,31 @@ void CHyprMasterLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dire
|
|||
if (pWindow->m_bIsFloating)
|
||||
return;
|
||||
|
||||
static auto PNEWTOP = CConfigValue<Hyprlang::INT>("master:new_on_top");
|
||||
static auto PNEWONACTIVE = CConfigValue<std::string>("master:new_on_active");
|
||||
static auto PNEWONTOP = CConfigValue<Hyprlang::INT>("master:new_on_top");
|
||||
static auto PNEWSTATUS = CConfigValue<std::string>("master:new_status");
|
||||
|
||||
const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
|
||||
|
||||
const auto PNODE = *PNEWTOP ? &m_lMasterNodesData.emplace_front() : &m_lMasterNodesData.emplace_back();
|
||||
const bool BNEWBEFOREACTIVE = *PNEWONACTIVE == "before";
|
||||
const bool BNEWISMASTER = *PNEWSTATUS == "master";
|
||||
|
||||
const auto PNODE = [&]() {
|
||||
if (*PNEWONACTIVE != "none" && !BNEWISMASTER) {
|
||||
const auto pLastNode = getNodeFromWindow(g_pCompositor->m_pLastWindow.lock());
|
||||
if (pLastNode && !(pLastNode->isMaster && (getMastersOnWorkspace(pWindow->workspaceID()) == 1 || *PNEWSTATUS == "slave"))) {
|
||||
auto it = std::find(m_lMasterNodesData.begin(), m_lMasterNodesData.end(), *pLastNode);
|
||||
if (!BNEWBEFOREACTIVE)
|
||||
++it;
|
||||
return &(*m_lMasterNodesData.emplace(it));
|
||||
}
|
||||
}
|
||||
return *PNEWONTOP ? &m_lMasterNodesData.emplace_front() : &m_lMasterNodesData.emplace_back();
|
||||
}();
|
||||
|
||||
PNODE->workspaceID = pWindow->workspaceID();
|
||||
PNODE->pWindow = pWindow;
|
||||
|
||||
static auto PNEWISMASTER = CConfigValue<Hyprlang::INT>("master:new_is_master");
|
||||
|
||||
const auto WINDOWSONWORKSPACE = getNodesOnWorkspace(PNODE->workspaceID);
|
||||
static auto PMFACT = CConfigValue<Hyprlang::FLOAT>("master:mfact");
|
||||
float lastSplitPercent = *PMFACT;
|
||||
|
@ -186,13 +200,27 @@ void CHyprMasterLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dire
|
|||
}
|
||||
}
|
||||
|
||||
if ((*PNEWISMASTER && g_pInputManager->dragMode != MBIND_MOVE) || WINDOWSONWORKSPACE == 1 || (WINDOWSONWORKSPACE > 2 && !pWindow->m_bFirstMap && OPENINGON->isMaster) ||
|
||||
forceDropAsMaster) {
|
||||
for (auto& nd : m_lMasterNodesData) {
|
||||
if (nd.isMaster && nd.workspaceID == PNODE->workspaceID) {
|
||||
nd.isMaster = false;
|
||||
lastSplitPercent = nd.percMaster;
|
||||
break;
|
||||
if ((BNEWISMASTER && g_pInputManager->dragMode != MBIND_MOVE) //
|
||||
|| WINDOWSONWORKSPACE == 1 //
|
||||
|| (WINDOWSONWORKSPACE > 2 && !pWindow->m_bFirstMap && OPENINGON->isMaster) //
|
||||
|| forceDropAsMaster //
|
||||
|| (*PNEWSTATUS == "inherit" && OPENINGON && OPENINGON->isMaster && g_pInputManager->dragMode != MBIND_MOVE)) {
|
||||
|
||||
if (BNEWBEFOREACTIVE) {
|
||||
for (auto& nd : m_lMasterNodesData | std::views::reverse) {
|
||||
if (nd.isMaster && nd.workspaceID == PNODE->workspaceID) {
|
||||
nd.isMaster = false;
|
||||
lastSplitPercent = nd.percMaster;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (auto& nd : m_lMasterNodesData) {
|
||||
if (nd.isMaster && nd.workspaceID == PNODE->workspaceID) {
|
||||
nd.isMaster = false;
|
||||
lastSplitPercent = nd.percMaster;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1440,7 +1468,7 @@ void CHyprMasterLayout::replaceWindowDataWith(PHLWINDOW from, PHLWINDOW to) {
|
|||
}
|
||||
|
||||
Vector2D CHyprMasterLayout::predictSizeForNewWindowTiled() {
|
||||
static auto PNEWISMASTER = CConfigValue<Hyprlang::INT>("master:new_is_master");
|
||||
static auto PNEWSTATUS = CConfigValue<std::string>("master:new_status");
|
||||
|
||||
if (!g_pCompositor->m_pLastMonitor)
|
||||
return {};
|
||||
|
@ -1454,7 +1482,7 @@ Vector2D CHyprMasterLayout::predictSizeForNewWindowTiled() {
|
|||
if (!MASTER) // wtf
|
||||
return {};
|
||||
|
||||
if (*PNEWISMASTER) {
|
||||
if (*PNEWSTATUS == "master") {
|
||||
return MASTER->size;
|
||||
} else {
|
||||
const auto SLAVES = NODES - getMastersOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspace->m_iID);
|
||||
|
|
|
@ -4,9 +4,7 @@
|
|||
#include <csignal>
|
||||
#include <utility>
|
||||
|
||||
#include "helpers/memory/WeakPtr.hpp"
|
||||
|
||||
#define UP std::unique_ptr
|
||||
#include "helpers/memory/Memory.hpp"
|
||||
|
||||
#ifndef NDEBUG
|
||||
#ifdef HYPRLAND_DEBUG
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "../desktop/Window.hpp"
|
||||
#include "../desktop/LayerSurface.hpp"
|
||||
#include "eventLoop/EventLoopManager.hpp"
|
||||
#include "../helpers/varlist/VarList.hpp"
|
||||
|
||||
int wlTick(SP<CEventLoopTimer> self, void* data) {
|
||||
if (g_pAnimationManager)
|
||||
|
@ -396,6 +397,8 @@ void CAnimationManager::onWindowPostCreateClose(PHLWINDOW pWindow, bool close) {
|
|||
auto ANIMSTYLE = pWindow->m_vRealPosition.m_pConfig->pValues->internalStyle;
|
||||
transform(ANIMSTYLE.begin(), ANIMSTYLE.end(), ANIMSTYLE.begin(), ::tolower);
|
||||
|
||||
CVarList animList(ANIMSTYLE, 0, 's');
|
||||
|
||||
// if the window is not being animated, that means the layout set a fixed size for it, don't animate.
|
||||
if (!pWindow->m_vRealPosition.isBeingAnimated() && !pWindow->m_vRealSize.isBeingAnimated())
|
||||
return;
|
||||
|
@ -407,12 +410,8 @@ void CAnimationManager::onWindowPostCreateClose(PHLWINDOW pWindow, bool close) {
|
|||
if (pWindow->m_sAdditionalConfigData.animationStyle != "") {
|
||||
// the window has config'd special anim
|
||||
if (pWindow->m_sAdditionalConfigData.animationStyle.starts_with("slide")) {
|
||||
if (pWindow->m_sAdditionalConfigData.animationStyle.contains(' ')) {
|
||||
// has a direction
|
||||
animationSlide(pWindow, pWindow->m_sAdditionalConfigData.animationStyle.substr(pWindow->m_sAdditionalConfigData.animationStyle.find(' ') + 1), close);
|
||||
} else {
|
||||
animationSlide(pWindow, "", close);
|
||||
}
|
||||
CVarList animList2(pWindow->m_sAdditionalConfigData.animationStyle, 0, 's');
|
||||
animationSlide(pWindow, animList2[1], close);
|
||||
} else {
|
||||
// anim popin, fallback
|
||||
|
||||
|
@ -429,9 +428,9 @@ void CAnimationManager::onWindowPostCreateClose(PHLWINDOW pWindow, bool close) {
|
|||
animationPopin(pWindow, close, minPerc / 100.f);
|
||||
}
|
||||
} else {
|
||||
if (ANIMSTYLE == "slide") {
|
||||
animationSlide(pWindow, "", close);
|
||||
} else {
|
||||
if (animList[0] == "slide")
|
||||
animationSlide(pWindow, animList[1], close);
|
||||
else {
|
||||
// anim popin, fallback
|
||||
|
||||
float minPerc = 0.f;
|
||||
|
@ -451,9 +450,9 @@ void CAnimationManager::onWindowPostCreateClose(PHLWINDOW pWindow, bool close) {
|
|||
|
||||
std::string CAnimationManager::styleValidInConfigVar(const std::string& config, const std::string& style) {
|
||||
if (config.starts_with("window")) {
|
||||
if (style == "slide") {
|
||||
if (style.starts_with("slide"))
|
||||
return "";
|
||||
} else if (style.starts_with("popin")) {
|
||||
else if (style.starts_with("popin")) {
|
||||
// try parsing
|
||||
float minPerc = 0.f;
|
||||
if (style.find("%") != std::string::npos) {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include "../defines.hpp"
|
||||
#include "../helpers/memory/SharedPtr.hpp"
|
||||
#include "../helpers/memory/Memory.hpp"
|
||||
|
||||
struct SHyprIPCEvent {
|
||||
std::string event;
|
||||
|
|
|
@ -1,18 +1,22 @@
|
|||
#include "../config/ConfigValue.hpp"
|
||||
#include "../devices/IKeyboard.hpp"
|
||||
#include "../managers/SeatManager.hpp"
|
||||
#include "../protocols/LayerShell.hpp"
|
||||
#include "../protocols/ShortcutsInhibit.hpp"
|
||||
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
|
||||
#include "KeybindManager.hpp"
|
||||
#include "TokenManager.hpp"
|
||||
#include "debug/Log.hpp"
|
||||
#include "helpers/VarList.hpp"
|
||||
#include "helpers/varlist/VarList.hpp"
|
||||
|
||||
#include <optional>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include <hyprutils/string/String.hpp>
|
||||
using namespace Hyprutils::String;
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <vector>
|
||||
|
@ -111,6 +115,7 @@ CKeybindManager::CKeybindManager() {
|
|||
m_mDispatchers["movewindoworgroup"] = moveWindowOrGroup;
|
||||
m_mDispatchers["setignoregrouplock"] = setIgnoreGroupLock;
|
||||
m_mDispatchers["denywindowfromgroup"] = denyWindowFromGroup;
|
||||
m_mDispatchers["event"] = event;
|
||||
m_mDispatchers["global"] = global;
|
||||
|
||||
m_tScrollTimer.reset();
|
||||
|
@ -836,7 +841,7 @@ bool CKeybindManager::handleInternalKeybinds(xkb_keysym_t keysym) {
|
|||
|
||||
void CKeybindManager::spawn(std::string args) {
|
||||
|
||||
args = removeBeginEndSpacesTabs(args);
|
||||
args = trim(args);
|
||||
|
||||
std::string RULES = "";
|
||||
|
||||
|
@ -1083,6 +1088,8 @@ void CKeybindManager::changeworkspace(std::string args) {
|
|||
if (!PMONITORWORKSPACEOWNER)
|
||||
return;
|
||||
|
||||
updateRelativeCursorCoords();
|
||||
|
||||
g_pCompositor->setActiveMonitor(PMONITORWORKSPACEOWNER);
|
||||
|
||||
if (BISWORKSPACECURRENT) {
|
||||
|
@ -1111,6 +1118,16 @@ void CKeybindManager::changeworkspace(std::string args) {
|
|||
else
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
}
|
||||
|
||||
const static auto PWARPONWORKSPACECHANGE = CConfigValue<Hyprlang::INT>("cursor:warp_on_change_workspace");
|
||||
|
||||
if (*PWARPONWORKSPACECHANGE) {
|
||||
auto PLAST = pWorkspaceToChangeTo->getLastFocusedWindow();
|
||||
auto HLSurface = CWLSurface::fromResource(g_pSeatManager->state.pointerFocus.lock());
|
||||
|
||||
if (PLAST && (!HLSurface || HLSurface->getWindow()))
|
||||
PLAST->warpCursor();
|
||||
}
|
||||
}
|
||||
|
||||
void CKeybindManager::fullscreenActive(std::string args) {
|
||||
|
@ -2677,3 +2694,7 @@ void CKeybindManager::moveGroupWindow(std::string args) {
|
|||
|
||||
PLASTWINDOW->updateWindowDecos();
|
||||
}
|
||||
|
||||
void CKeybindManager::event(std::string args) {
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"custom", args});
|
||||
}
|
||||
|
|
|
@ -14,23 +14,25 @@ class CPluginSystem;
|
|||
class IKeyboard;
|
||||
|
||||
struct SKeybind {
|
||||
std::string key = "";
|
||||
std::set<xkb_keysym_t> sMkKeys = {};
|
||||
uint32_t keycode = 0;
|
||||
bool catchAll = false;
|
||||
uint32_t modmask = 0;
|
||||
std::set<xkb_keysym_t> sMkMods = {};
|
||||
std::string handler = "";
|
||||
std::string arg = "";
|
||||
bool locked = false;
|
||||
std::string submap = "";
|
||||
bool release = false;
|
||||
bool repeat = false;
|
||||
bool mouse = false;
|
||||
bool nonConsuming = false;
|
||||
bool transparent = false;
|
||||
bool ignoreMods = false;
|
||||
bool multiKey = false;
|
||||
std::string key = "";
|
||||
std::set<xkb_keysym_t> sMkKeys = {};
|
||||
uint32_t keycode = 0;
|
||||
bool catchAll = false;
|
||||
uint32_t modmask = 0;
|
||||
std::set<xkb_keysym_t> sMkMods = {};
|
||||
std::string handler = "";
|
||||
std::string arg = "";
|
||||
bool locked = false;
|
||||
std::string submap = "";
|
||||
std::string description = "";
|
||||
bool release = false;
|
||||
bool repeat = false;
|
||||
bool mouse = false;
|
||||
bool nonConsuming = false;
|
||||
bool transparent = false;
|
||||
bool ignoreMods = false;
|
||||
bool multiKey = false;
|
||||
bool hasDescription = false;
|
||||
|
||||
// DO NOT INITIALIZE
|
||||
bool shadowed = false;
|
||||
|
@ -203,6 +205,7 @@ class CKeybindManager {
|
|||
static void setIgnoreGroupLock(std::string);
|
||||
static void denyWindowFromGroup(std::string);
|
||||
static void global(std::string);
|
||||
static void event(std::string);
|
||||
|
||||
friend class CCompositor;
|
||||
friend class CInputManager;
|
||||
|
|
|
@ -150,6 +150,20 @@ CPointerManager::CPointerManager() {
|
|||
});
|
||||
}
|
||||
|
||||
void CPointerManager::lockSoftwareAll() {
|
||||
for (auto& state : monitorStates)
|
||||
state->softwareLocks++;
|
||||
|
||||
updateCursorBackend();
|
||||
}
|
||||
|
||||
void CPointerManager::unlockSoftwareAll() {
|
||||
for (auto& state : monitorStates)
|
||||
state->softwareLocks--;
|
||||
|
||||
updateCursorBackend();
|
||||
}
|
||||
|
||||
void CPointerManager::lockSoftwareForMonitor(SP<CMonitor> mon) {
|
||||
auto state = stateFor(mon);
|
||||
state->softwareLocks++;
|
||||
|
@ -661,7 +675,7 @@ void CPointerManager::damageIfSoftware() {
|
|||
continue;
|
||||
|
||||
if ((mw->softwareLocks > 0 || mw->hardwareFailed || *PNOHW) && b.overlaps({mw->monitor->vecPosition, mw->monitor->vecSize})) {
|
||||
g_pHyprRenderer->damageBox(&b);
|
||||
g_pHyprRenderer->damageBox(&b, mw->monitor->shouldSkipScheduleFrameOnMouseEvent());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,6 +43,8 @@ class CPointerManager {
|
|||
|
||||
void lockSoftwareForMonitor(SP<CMonitor> pMonitor);
|
||||
void unlockSoftwareForMonitor(SP<CMonitor> pMonitor);
|
||||
void lockSoftwareAll();
|
||||
void unlockSoftwareAll();
|
||||
|
||||
void renderSoftwareCursorsFor(SP<CMonitor> pMonitor, timespec* now, CRegion& damage /* logical */, std::optional<Vector2D> overridePos = {} /* monitor-local */);
|
||||
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
#include "../protocols/TextInputV1.hpp"
|
||||
#include "../protocols/GlobalShortcuts.hpp"
|
||||
#include "../protocols/Screencopy.hpp"
|
||||
#include "../helpers/memory/WeakPtr.hpp"
|
||||
#include "../helpers/signal/Listener.hpp"
|
||||
#include "../helpers/memory/Memory.hpp"
|
||||
#include "../helpers/signal/Signal.hpp"
|
||||
#include <unordered_map>
|
||||
|
||||
class CProtocolManager {
|
||||
|
|
|
@ -94,7 +94,7 @@ void CSeatManager::setKeyboard(SP<IKeyboard> KEEB) {
|
|||
}
|
||||
|
||||
void CSeatManager::updateActiveKeyboardData() {
|
||||
if (keyboard)
|
||||
if (keyboard && keyboard->wlr())
|
||||
PROTO::seat->updateRepeatInfo(keyboard->wlr()->repeat_info.rate, keyboard->wlr()->repeat_info.delay);
|
||||
PROTO::seat->updateKeymap();
|
||||
}
|
||||
|
@ -191,6 +191,11 @@ void CSeatManager::setPointerFocus(SP<CWLSurfaceResource> surf, const Vector2D&
|
|||
if (state.pointerFocus == surf)
|
||||
return;
|
||||
|
||||
if (PROTO::data->dndActive() && surf) {
|
||||
Debug::log(LOG, "[seatmgr] Refusing pointer focus during an active dnd");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mouse || !mouse->wlr()) {
|
||||
Debug::log(ERR, "BUG THIS: setPointerFocus without a valid mouse set");
|
||||
return;
|
||||
|
@ -337,34 +342,11 @@ void CSeatManager::sendPointerAxis(uint32_t timeMs, wl_pointer_axis axis, double
|
|||
}
|
||||
|
||||
void CSeatManager::sendTouchDown(SP<CWLSurfaceResource> surf, uint32_t timeMs, int32_t id, const Vector2D& local) {
|
||||
if (state.touchFocus == surf)
|
||||
return;
|
||||
|
||||
listeners.touchSurfaceDestroy.reset();
|
||||
|
||||
if (state.touchFocusResource) {
|
||||
auto client = state.touchFocusResource->client();
|
||||
for (auto& s : seatResources) {
|
||||
if (s->resource->client() != client)
|
||||
continue;
|
||||
|
||||
for (auto& t : s->resource->touches) {
|
||||
if (!t)
|
||||
continue;
|
||||
|
||||
t->sendUp(timeMs, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
state.touchFocusResource.reset();
|
||||
state.touchFocus = surf;
|
||||
|
||||
if (!surf) {
|
||||
events.touchFocusChange.emit();
|
||||
return;
|
||||
}
|
||||
|
||||
auto client = surf->client();
|
||||
for (auto& r : seatResources | std::views::reverse) {
|
||||
if (r->resource->client() != client)
|
||||
|
@ -381,11 +363,34 @@ void CSeatManager::sendTouchDown(SP<CWLSurfaceResource> surf, uint32_t timeMs, i
|
|||
|
||||
listeners.touchSurfaceDestroy = surf->events.destroy.registerListener([this, timeMs, id](std::any d) { sendTouchUp(timeMs + 10, id); });
|
||||
|
||||
events.touchFocusChange.emit();
|
||||
touchLocks++;
|
||||
|
||||
if (touchLocks <= 1)
|
||||
events.touchFocusChange.emit();
|
||||
}
|
||||
|
||||
void CSeatManager::sendTouchUp(uint32_t timeMs, int32_t id) {
|
||||
sendTouchDown(nullptr, timeMs, id, {});
|
||||
if (!state.touchFocusResource || touchLocks <= 0)
|
||||
return;
|
||||
|
||||
auto client = state.touchFocusResource->client();
|
||||
for (auto& r : seatResources | std::views::reverse) {
|
||||
if (r->resource->client() != client)
|
||||
continue;
|
||||
|
||||
state.touchFocusResource = r->resource;
|
||||
for (auto& t : r->resource->touches) {
|
||||
if (!t)
|
||||
continue;
|
||||
|
||||
t->sendUp(timeMs, id);
|
||||
}
|
||||
}
|
||||
|
||||
touchLocks--;
|
||||
|
||||
if (touchLocks <= 0)
|
||||
events.touchFocusChange.emit();
|
||||
}
|
||||
|
||||
void CSeatManager::sendTouchMotion(uint32_t timeMs, int32_t id, const Vector2D& local) {
|
||||
|
|
|
@ -155,6 +155,7 @@ class CSeatManager {
|
|||
} listeners;
|
||||
|
||||
Vector2D lastLocalCoords;
|
||||
int touchLocks = 0; // we assume there aint like 20 touch devices at once...
|
||||
|
||||
friend struct SSeatResourceContainer;
|
||||
friend class CSeatGrab;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#include "../defines.hpp"
|
||||
#include "../helpers/Timer.hpp"
|
||||
#include "../helpers/signal/Listener.hpp"
|
||||
#include "../helpers/signal/Signal.hpp"
|
||||
#include <cstdint>
|
||||
#include <unordered_map>
|
||||
|
||||
|
|
|
@ -25,5 +25,6 @@ CThreadManager::CThreadManager() {
|
|||
}
|
||||
|
||||
CThreadManager::~CThreadManager() {
|
||||
//
|
||||
if (m_esConfigTimer)
|
||||
wl_event_source_remove(m_esConfigTimer);
|
||||
}
|
|
@ -5,7 +5,7 @@
|
|||
#include <unordered_map>
|
||||
#include <string>
|
||||
|
||||
#include "../helpers/memory/SharedPtr.hpp"
|
||||
#include "../helpers/memory/Memory.hpp"
|
||||
|
||||
class CUUIDToken {
|
||||
public:
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include <functional>
|
||||
#include <optional>
|
||||
|
||||
#include "../../helpers/memory/SharedPtr.hpp"
|
||||
#include "../../helpers/memory/Memory.hpp"
|
||||
|
||||
class CEventLoopTimer {
|
||||
public:
|
||||
|
|
|
@ -155,6 +155,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
|||
Vector2D surfacePos = Vector2D(-1337, -1337);
|
||||
PHLWINDOW pFoundWindow;
|
||||
PHLLS pFoundLayerSurface;
|
||||
SSessionLockSurface* pSessionLock = nullptr;
|
||||
|
||||
if (!g_pCompositor->m_bReadyToProcess || g_pCompositor->m_bIsShuttingDown || g_pCompositor->m_bUnsafeState)
|
||||
return;
|
||||
|
@ -186,7 +187,9 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
|||
if (*PZOOMFACTOR != 1.f)
|
||||
g_pHyprRenderer->damageMonitor(PMONITOR);
|
||||
|
||||
if (!PMONITOR->solitaryClient.lock() && g_pHyprRenderer->shouldRenderCursor() && PMONITOR->output->software_cursor_locks > 0)
|
||||
bool skipFrameSchedule = PMONITOR->shouldSkipScheduleFrameOnMouseEvent();
|
||||
|
||||
if (!PMONITOR->solitaryClient.lock() && g_pHyprRenderer->shouldRenderCursor() && PMONITOR->output->software_cursor_locks > 0 && !skipFrameSchedule)
|
||||
g_pCompositor->scheduleFrameForMonitor(PMONITOR);
|
||||
|
||||
PHLWINDOW forcedFocus = m_pForcedFocus.lock();
|
||||
|
@ -261,12 +264,12 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
|||
g_pCompositor->setActiveMonitor(PMONITOR);
|
||||
|
||||
if (g_pSessionLockManager->isSessionLocked()) {
|
||||
const auto PSLS = PMONITOR ? g_pSessionLockManager->getSessionLockSurfaceForMonitor(PMONITOR->ID) : nullptr;
|
||||
pSessionLock = PMONITOR ? g_pSessionLockManager->getSessionLockSurfaceForMonitor(PMONITOR->ID) : nullptr;
|
||||
|
||||
if (!PSLS)
|
||||
if (!pSessionLock)
|
||||
return;
|
||||
|
||||
foundSurface = PSLS->surface->surface();
|
||||
foundSurface = pSessionLock->surface->surface();
|
||||
surfacePos = PMONITOR->vecPosition;
|
||||
}
|
||||
|
||||
|
@ -350,6 +353,10 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
|||
if (pFoundWindow) {
|
||||
if (!pFoundWindow->m_bIsX11) {
|
||||
foundSurface = g_pCompositor->vectorWindowToSurface(mouseCoords, pFoundWindow, surfaceCoords);
|
||||
if (!foundSurface) {
|
||||
foundSurface = pFoundWindow->m_pWLSurface->resource();
|
||||
surfacePos = pFoundWindow->m_vRealPosition.value();
|
||||
}
|
||||
} else {
|
||||
foundSurface = pFoundWindow->m_pWLSurface->resource();
|
||||
surfacePos = pFoundWindow->m_vRealPosition.value();
|
||||
|
@ -365,7 +372,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
|||
foundSurface =
|
||||
g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &surfaceCoords, &pFoundLayerSurface);
|
||||
|
||||
if (g_pCompositor->m_pLastMonitor->output->software_cursor_locks > 0)
|
||||
if (g_pCompositor->m_pLastMonitor->output->software_cursor_locks > 0 && !skipFrameSchedule)
|
||||
g_pCompositor->scheduleFrameForMonitor(g_pCompositor->m_pLastMonitor.get());
|
||||
|
||||
// grabs
|
||||
|
@ -455,7 +462,9 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
|||
restoreCursorIconToApp();
|
||||
}
|
||||
|
||||
if (pFoundWindow) {
|
||||
if (pSessionLock != nullptr)
|
||||
g_pCompositor->focusSurface(foundSurface);
|
||||
else if (pFoundWindow) {
|
||||
// change cursor icon if hovering over border
|
||||
if (*PRESIZEONBORDER && *PRESIZECURSORICON) {
|
||||
if (!pFoundWindow->m_bIsFullscreen && !pFoundWindow->hasPopupAt(mouseCoords)) {
|
||||
|
@ -509,7 +518,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
|||
}
|
||||
|
||||
if (pFoundLayerSurface && (pFoundLayerSurface->layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE) && FOLLOWMOUSE != 3 &&
|
||||
allowKeyboardRefocus) {
|
||||
(allowKeyboardRefocus || pFoundLayerSurface->layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE)) {
|
||||
g_pCompositor->focusSurface(foundSurface);
|
||||
}
|
||||
|
||||
|
@ -1223,12 +1232,20 @@ void CInputManager::destroyKeyboard(SP<IKeyboard> pKeyboard) {
|
|||
std::erase_if(m_vKeyboards, [pKeyboard](const auto& other) { return other == pKeyboard; });
|
||||
|
||||
if (m_vKeyboards.size() > 0) {
|
||||
const auto PNEWKEYBOARD = m_vKeyboards.back();
|
||||
g_pSeatManager->setKeyboard(PNEWKEYBOARD);
|
||||
PNEWKEYBOARD->active = true;
|
||||
} else {
|
||||
bool found = false;
|
||||
for (auto& k : m_vKeyboards | std::views::reverse) {
|
||||
if (!k->wlr())
|
||||
continue;
|
||||
|
||||
g_pSeatManager->setKeyboard(k);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
g_pSeatManager->setKeyboard(nullptr);
|
||||
} else
|
||||
g_pSeatManager->setKeyboard(nullptr);
|
||||
}
|
||||
|
||||
removeFromHIDs(pKeyboard);
|
||||
}
|
||||
|
@ -1381,6 +1398,41 @@ void CInputManager::refocus() {
|
|||
mouseMoveUnified(0, true);
|
||||
}
|
||||
|
||||
void CInputManager::refocusLastWindow(CMonitor* pMonitor) {
|
||||
if (!pMonitor) {
|
||||
refocus();
|
||||
return;
|
||||
}
|
||||
|
||||
Vector2D surfaceCoords;
|
||||
PHLLS pFoundLayerSurface;
|
||||
SP<CWLSurfaceResource> foundSurface = nullptr;
|
||||
|
||||
g_pInputManager->releaseAllMouseButtons();
|
||||
|
||||
// first try for an exclusive layer
|
||||
if (!m_dExclusiveLSes.empty())
|
||||
foundSurface = m_dExclusiveLSes[m_dExclusiveLSes.size() - 1]->surface->resource();
|
||||
|
||||
// then any surfaces above windows on the same monitor
|
||||
if (!foundSurface)
|
||||
foundSurface = g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY],
|
||||
&surfaceCoords, &pFoundLayerSurface);
|
||||
|
||||
if (!foundSurface)
|
||||
foundSurface = g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],
|
||||
&surfaceCoords, &pFoundLayerSurface);
|
||||
|
||||
if (!foundSurface && g_pCompositor->m_pLastWindow.lock() && g_pCompositor->isWorkspaceVisibleNotCovered(g_pCompositor->m_pLastWindow->m_pWorkspace)) {
|
||||
// then the last focused window if we're on the same workspace as it
|
||||
const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock();
|
||||
g_pCompositor->focusWindow(PLASTWINDOW);
|
||||
} else {
|
||||
// otherwise fall back to a normal refocus.
|
||||
refocus();
|
||||
}
|
||||
}
|
||||
|
||||
void CInputManager::unconstrainMouse() {
|
||||
if (g_pSeatManager->mouse.expired())
|
||||
return;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include "../../helpers/WLClasses.hpp"
|
||||
#include "../../helpers/Timer.hpp"
|
||||
#include "InputMethodRelay.hpp"
|
||||
#include "../../helpers/signal/Listener.hpp"
|
||||
#include "../../helpers/signal/Signal.hpp"
|
||||
#include "../../devices/IPointer.hpp"
|
||||
#include "../../devices/ITouch.hpp"
|
||||
#include "../../devices/Tablet.hpp"
|
||||
|
@ -104,6 +104,7 @@ class CInputManager {
|
|||
|
||||
Vector2D getMouseCoordsInternal();
|
||||
void refocus();
|
||||
void refocusLastWindow(CMonitor* pMonitor);
|
||||
void simulateMouseMovement();
|
||||
void sendMotionEventsToFocused();
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include "../../desktop/WLSurface.hpp"
|
||||
#include "../../macros.hpp"
|
||||
#include "../../helpers/Box.hpp"
|
||||
#include "../../helpers/signal/Listener.hpp"
|
||||
#include "../../helpers/signal/Signal.hpp"
|
||||
|
||||
class CInputMethodPopupV2;
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include <list>
|
||||
#include "../../defines.hpp"
|
||||
#include "../../helpers/WLClasses.hpp"
|
||||
#include "../../helpers/signal/Listener.hpp"
|
||||
#include "../../helpers/signal/Signal.hpp"
|
||||
#include "TextInput.hpp"
|
||||
#include "InputMethodPopup.hpp"
|
||||
#include <any>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include "../../helpers/WLListener.hpp"
|
||||
#include "../../macros.hpp"
|
||||
#include "../../helpers/Box.hpp"
|
||||
#include "../../helpers/signal/Listener.hpp"
|
||||
#include "../../helpers/signal/Signal.hpp"
|
||||
#include <memory>
|
||||
|
||||
struct wl_client;
|
||||
|
|
|
@ -13,6 +13,7 @@ executable('Hyprland', src,
|
|||
dependency('cairo'),
|
||||
dependency('hyprcursor'),
|
||||
dependency('hyprlang', version: '>= 0.3.2'),
|
||||
dependency('hyprutils', version: '>= 0.1.1'),
|
||||
dependency('libdrm'),
|
||||
dependency('egl'),
|
||||
dependency('xkbcommon'),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "HookSystem.hpp"
|
||||
#include "../debug/Log.hpp"
|
||||
#include "../helpers/VarList.hpp"
|
||||
#include "../helpers/varlist/VarList.hpp"
|
||||
#include "../managers/TokenManager.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include <unordered_map>
|
||||
#include "WaylandProtocol.hpp"
|
||||
#include "alpha-modifier-v1.hpp"
|
||||
#include "../helpers/signal/Listener.hpp"
|
||||
#include "../helpers/signal/Signal.hpp"
|
||||
|
||||
class CWLSurfaceResource;
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include <cstdint>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include "../helpers/signal/Listener.hpp"
|
||||
#include "../helpers/signal/Signal.hpp"
|
||||
|
||||
class CFocusGrab;
|
||||
class CSeatGrab;
|
||||
|
|
|
@ -122,25 +122,19 @@ void CForeignToplevelHandleWlr::sendMonitor(CMonitor* pMonitor) {
|
|||
if (lastMonitorID == (int64_t)pMonitor->ID)
|
||||
return;
|
||||
|
||||
const auto CLIENT = resource->client();
|
||||
|
||||
struct wl_resource* outputResource;
|
||||
const auto CLIENT = resource->client();
|
||||
|
||||
if (const auto PLASTMONITOR = g_pCompositor->getMonitorFromID(lastMonitorID); PLASTMONITOR) {
|
||||
wl_resource_for_each(outputResource, &PLASTMONITOR->output->resources) {
|
||||
if (wl_resource_get_client(outputResource) != CLIENT)
|
||||
continue;
|
||||
const auto OLDRESOURCE = PROTO::outputs.at(PLASTMONITOR->szName)->outputResourceFrom(CLIENT);
|
||||
|
||||
resource->sendOutputLeave(outputResource);
|
||||
}
|
||||
if (OLDRESOURCE)
|
||||
resource->sendOutputLeave(OLDRESOURCE->getResource()->resource());
|
||||
}
|
||||
|
||||
wl_resource_for_each(outputResource, &pMonitor->output->resources) {
|
||||
if (wl_resource_get_client(outputResource) != CLIENT)
|
||||
continue;
|
||||
const auto NEWRESOURCE = PROTO::outputs.at(pMonitor->szName)->outputResourceFrom(CLIENT);
|
||||
|
||||
resource->sendOutputEnter(outputResource);
|
||||
}
|
||||
if (NEWRESOURCE)
|
||||
resource->sendOutputEnter(NEWRESOURCE->getResource()->resource());
|
||||
|
||||
lastMonitorID = pMonitor->ID;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include <cstdint>
|
||||
#include "WaylandProtocol.hpp"
|
||||
#include "wlr-gamma-control-unstable-v1.hpp"
|
||||
#include "../helpers/signal/Listener.hpp"
|
||||
#include "../helpers/signal/Signal.hpp"
|
||||
|
||||
class CMonitor;
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ SP<CInputMethodV2> CInputMethodKeyboardGrabV2::getOwner() {
|
|||
}
|
||||
|
||||
wl_client* CInputMethodKeyboardGrabV2::client() {
|
||||
return resource->client();
|
||||
return resource->resource() ? resource->client() : nullptr;
|
||||
}
|
||||
|
||||
CInputMethodPopupV2::CInputMethodPopupV2(SP<CZwpInputPopupSurfaceV2> resource_, SP<CInputMethodV2> owner_, SP<CWLSurfaceResource> surface) : resource(resource_), owner(owner_) {
|
||||
|
@ -373,4 +373,4 @@ void CInputMethodV2Protocol::onGetIME(CZwpInputMethodManagerV2* mgr, wl_resource
|
|||
LOGM(LOG, "New IME with resource id {}", id);
|
||||
|
||||
events.newIME.emit(RESOURCE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include <cstdint>
|
||||
#include "WaylandProtocol.hpp"
|
||||
#include "wlr-output-management-unstable-v1.hpp"
|
||||
#include "../helpers/signal/Listener.hpp"
|
||||
#include "../helpers/signal/Signal.hpp"
|
||||
|
||||
class CMonitor;
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include <cstdint>
|
||||
#include "WaylandProtocol.hpp"
|
||||
#include "wlr-output-power-management-unstable-v1.hpp"
|
||||
#include "../helpers/signal/Listener.hpp"
|
||||
#include "../helpers/signal/Signal.hpp"
|
||||
|
||||
class CMonitor;
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#include "pointer-constraints-unstable-v1.hpp"
|
||||
#include "../helpers/Vector2D.hpp"
|
||||
#include "../helpers/Region.hpp"
|
||||
#include "../helpers/signal/Listener.hpp"
|
||||
#include "../helpers/signal/Signal.hpp"
|
||||
|
||||
class CWLSurface;
|
||||
class CWLSurfaceResource;
|
||||
|
|
|
@ -114,9 +114,11 @@ CSessionLock::CSessionLock(SP<CExtSessionLockV1> resource_) : resource(resource_
|
|||
return;
|
||||
}
|
||||
|
||||
events.unlockAndDestroy.emit();
|
||||
inert = true;
|
||||
PROTO::sessionLock->locked = false;
|
||||
|
||||
events.unlockAndDestroy.emit();
|
||||
|
||||
inert = true;
|
||||
PROTO::sessionLock->destroyResource(this);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -100,7 +100,7 @@ wlr_keyboard* CVirtualKeyboardV1Resource::wlr() {
|
|||
}
|
||||
|
||||
wl_client* CVirtualKeyboardV1Resource::client() {
|
||||
return resource->client();
|
||||
return resource->resource() ? resource->client() : nullptr;
|
||||
}
|
||||
|
||||
void CVirtualKeyboardV1Resource::releasePressed() {
|
||||
|
@ -151,4 +151,4 @@ void CVirtualKeyboardProtocol::onCreateKeeb(CZwpVirtualKeyboardManagerV1* pMgr,
|
|||
LOGM(LOG, "New VKeyboard at id {}", id);
|
||||
|
||||
events.newKeyboard.emit(RESOURCE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -136,10 +136,12 @@ CXDGToplevelResource::CXDGToplevelResource(SP<CXdgToplevel> resource_, SP<CXDGSu
|
|||
wl_array_release(&arr);
|
||||
}
|
||||
|
||||
pendingApply.states.push_back(XDG_TOPLEVEL_STATE_TILED_LEFT);
|
||||
pendingApply.states.push_back(XDG_TOPLEVEL_STATE_TILED_RIGHT);
|
||||
pendingApply.states.push_back(XDG_TOPLEVEL_STATE_TILED_TOP);
|
||||
pendingApply.states.push_back(XDG_TOPLEVEL_STATE_TILED_BOTTOM);
|
||||
if (resource->version() >= 2) {
|
||||
pendingApply.states.push_back(XDG_TOPLEVEL_STATE_TILED_LEFT);
|
||||
pendingApply.states.push_back(XDG_TOPLEVEL_STATE_TILED_RIGHT);
|
||||
pendingApply.states.push_back(XDG_TOPLEVEL_STATE_TILED_TOP);
|
||||
pendingApply.states.push_back(XDG_TOPLEVEL_STATE_TILED_BOTTOM);
|
||||
}
|
||||
|
||||
resource->setSetTitle([this](CXdgToplevel* r, const char* t) {
|
||||
state.title = t;
|
||||
|
@ -261,6 +263,9 @@ uint32_t CXDGToplevelResource::setActive(bool active) {
|
|||
}
|
||||
|
||||
uint32_t CXDGToplevelResource::setSuspeneded(bool sus) {
|
||||
if (resource->version() < 6)
|
||||
return owner->scheduleConfigure(); // SUSPENDED is since 6
|
||||
|
||||
bool set = std::find(pendingApply.states.begin(), pendingApply.states.end(), XDG_TOPLEVEL_STATE_SUSPENDED) != pendingApply.states.end();
|
||||
|
||||
if (sus == set)
|
||||
|
@ -507,12 +512,12 @@ CXDGPositionerRules::CXDGPositionerRules(SP<CXDGPositionerResource> positioner)
|
|||
state = positioner->state;
|
||||
}
|
||||
|
||||
static Vector2D pointForAnchor(const CBox& box, xdgPositionerAnchor anchor) {
|
||||
static Vector2D pointForAnchor(const CBox& box, const Vector2D& predictionSize, xdgPositionerAnchor anchor) {
|
||||
switch (anchor) {
|
||||
case XDG_POSITIONER_ANCHOR_TOP: return box.pos() + Vector2D{box.size().x / 2.F, 0};
|
||||
case XDG_POSITIONER_ANCHOR_BOTTOM: return box.pos() + Vector2D{box.size().x / 2.F, box.size().y};
|
||||
case XDG_POSITIONER_ANCHOR_LEFT: return box.pos() + Vector2D{0, box.size().y / 2.F};
|
||||
case XDG_POSITIONER_ANCHOR_RIGHT: return box.pos() + Vector2D{box.size().x, box.size().y / 2.F};
|
||||
case XDG_POSITIONER_ANCHOR_TOP: return box.pos() + Vector2D{box.size().x / 2.F - predictionSize.x / 2.F, 0};
|
||||
case XDG_POSITIONER_ANCHOR_BOTTOM: return box.pos() + Vector2D{box.size().x / 2.F - predictionSize.x / 2.F, box.size().y};
|
||||
case XDG_POSITIONER_ANCHOR_LEFT: return box.pos() + Vector2D{0, box.size().y / 2.F - predictionSize.y / 2.F};
|
||||
case XDG_POSITIONER_ANCHOR_RIGHT: return box.pos() + Vector2D{box.size().x, box.size().y / 2.F - predictionSize.y / 2.F};
|
||||
case XDG_POSITIONER_ANCHOR_TOP_LEFT: return box.pos();
|
||||
case XDG_POSITIONER_ANCHOR_BOTTOM_LEFT: return box.pos() + Vector2D{0, box.size().y};
|
||||
case XDG_POSITIONER_ANCHOR_TOP_RIGHT: return box.pos() + Vector2D{box.size().x, 0};
|
||||
|
@ -527,7 +532,7 @@ CBox CXDGPositionerRules::getPosition(const CBox& constraint, const Vector2D& pa
|
|||
|
||||
Debug::log(LOG, "GetPosition with constraint {} {} and parent {}", constraint.pos(), constraint.size(), parentCoord);
|
||||
|
||||
CBox predictedBox = {parentCoord + constraint.pos() + pointForAnchor(state.anchorRect, state.anchor) + state.offset, state.requestedSize};
|
||||
CBox predictedBox = {parentCoord + constraint.pos() + pointForAnchor(state.anchorRect, state.requestedSize, state.anchor) + state.offset, state.requestedSize};
|
||||
|
||||
bool success = predictedBox.inside(constraint);
|
||||
|
||||
|
|
|
@ -13,13 +13,17 @@ CWLDataOfferResource::CWLDataOfferResource(SP<CWlDataOffer> resource_, SP<IDataS
|
|||
return;
|
||||
|
||||
resource->setDestroy([this](CWlDataOffer* r) {
|
||||
if (!dead)
|
||||
if (!dead && (recvd || accepted))
|
||||
PROTO::data->completeDrag();
|
||||
else
|
||||
PROTO::data->abortDrag();
|
||||
PROTO::data->destroyResource(this);
|
||||
});
|
||||
resource->setOnDestroy([this](CWlDataOffer* r) {
|
||||
if (!dead)
|
||||
if (!dead && (recvd || accepted))
|
||||
PROTO::data->completeDrag();
|
||||
else
|
||||
PROTO::data->abortDrag();
|
||||
PROTO::data->destroyResource(this);
|
||||
});
|
||||
|
||||
|
@ -85,8 +89,10 @@ void CWLDataOfferResource::sendData() {
|
|||
if (!source)
|
||||
return;
|
||||
|
||||
resource->sendSourceActions(7);
|
||||
resource->sendAction(WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE);
|
||||
if (resource->version() >= 3) {
|
||||
resource->sendSourceActions(7);
|
||||
resource->sendAction(WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE);
|
||||
}
|
||||
|
||||
for (auto& m : source->mimes()) {
|
||||
LOGM(LOG, " | offer {:x} supports mime {}", (uintptr_t)this, m);
|
||||
|
@ -536,6 +542,11 @@ void CWLDataDeviceProtocol::initiateDrag(WP<CWLDataSourceResource> currentSource
|
|||
}
|
||||
});
|
||||
|
||||
// unfocus the pointer from the surface, this is part of """standard""" wayland procedure and gtk will freak out if this isn't happening.
|
||||
// BTW, the spec does NOT require this explicitly...
|
||||
// Fuck you gtk.
|
||||
g_pSeatManager->setPointerFocus(nullptr, {});
|
||||
|
||||
// make a new offer, etc
|
||||
updateDrag();
|
||||
}
|
||||
|
@ -590,15 +601,35 @@ void CWLDataDeviceProtocol::dropDrag() {
|
|||
return;
|
||||
}
|
||||
|
||||
dnd.currentSource->sendDndDropPerformed();
|
||||
if (!wasDragSuccessful()) {
|
||||
abortDrag();
|
||||
return;
|
||||
}
|
||||
|
||||
dnd.focusedDevice->sendDrop();
|
||||
dnd.focusedDevice->sendLeave();
|
||||
|
||||
resetDndState();
|
||||
|
||||
if (dnd.overriddenCursor)
|
||||
g_pInputManager->unsetCursorImage();
|
||||
dnd.overriddenCursor = false;
|
||||
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
}
|
||||
|
||||
bool CWLDataDeviceProtocol::wasDragSuccessful() {
|
||||
if (!dnd.focusedDevice || !dnd.currentSource)
|
||||
return false;
|
||||
|
||||
for (auto& o : m_vOffers) {
|
||||
if (o->dead || !o->source || !o->source->hasDnd())
|
||||
continue;
|
||||
|
||||
if (o->recvd || o->accepted)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CWLDataDeviceProtocol::completeDrag() {
|
||||
|
@ -607,12 +638,13 @@ void CWLDataDeviceProtocol::completeDrag() {
|
|||
if (!dnd.focusedDevice || !dnd.currentSource)
|
||||
return;
|
||||
|
||||
dnd.currentSource->sendDndDropPerformed();
|
||||
dnd.currentSource->sendDndFinished();
|
||||
|
||||
dnd.focusedDevice.reset();
|
||||
dnd.currentSource.reset();
|
||||
|
||||
g_pSeatManager->resendEnterEvents();
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
}
|
||||
|
||||
void CWLDataDeviceProtocol::abortDrag() {
|
||||
|
@ -631,7 +663,7 @@ void CWLDataDeviceProtocol::abortDrag() {
|
|||
dnd.focusedDevice.reset();
|
||||
dnd.currentSource.reset();
|
||||
|
||||
g_pSeatManager->resendEnterEvents();
|
||||
g_pInputManager->simulateMouseMovement();
|
||||
}
|
||||
|
||||
void CWLDataDeviceProtocol::renderDND(CMonitor* pMonitor, timespec* when) {
|
||||
|
@ -650,5 +682,5 @@ void CWLDataDeviceProtocol::renderDND(CMonitor* pMonitor, timespec* when) {
|
|||
}
|
||||
|
||||
bool CWLDataDeviceProtocol::dndActive() {
|
||||
return dnd.currentSource;
|
||||
return dnd.currentSource && dnd.mouseButton /* test a member of the state to ensure it's also present */;
|
||||
}
|
||||
|
|
|
@ -175,6 +175,7 @@ class CWLDataDeviceProtocol : public IWaylandProtocol {
|
|||
void dropDrag();
|
||||
void completeDrag();
|
||||
void resetDndState();
|
||||
bool wasDragSuccessful();
|
||||
|
||||
//
|
||||
SP<CWLDataDeviceResource> dataDeviceForClient(wl_client*);
|
||||
|
|
|
@ -9,6 +9,9 @@ CWLOutputResource::CWLOutputResource(SP<CWlOutput> resource_, SP<CMonitor> pMoni
|
|||
|
||||
pClient = resource->client();
|
||||
|
||||
if (!monitor)
|
||||
return;
|
||||
|
||||
resource->setOnDestroy([this](CWlOutput* r) {
|
||||
if (monitor && PROTO::outputs.contains(monitor->szName))
|
||||
PROTO::outputs.at(monitor->szName)->destroyResource(this);
|
||||
|
@ -69,6 +72,9 @@ CWLOutputProtocol::CWLOutputProtocol(const wl_interface* iface, const int& ver,
|
|||
}
|
||||
|
||||
void CWLOutputProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
|
||||
if (defunct)
|
||||
Debug::log(WARN, "[wl_output] Binding a wl_output that's inert?? Possible client bug.");
|
||||
|
||||
const auto RESOURCE = m_vOutputs.emplace_back(makeShared<CWLOutputResource>(makeShared<CWlOutput>(client, ver, id), monitor.lock()));
|
||||
|
||||
if (!RESOURCE->good()) {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include <cstdint>
|
||||
#include "../WaylandProtocol.hpp"
|
||||
#include "wayland.hpp"
|
||||
#include "../../helpers/signal/Listener.hpp"
|
||||
#include "../../helpers/signal/Signal.hpp"
|
||||
|
||||
class CMonitor;
|
||||
|
||||
|
|
|
@ -25,37 +25,38 @@ void CWLTouchResource::sendDown(SP<CWLSurfaceResource> surface, uint32_t timeMs,
|
|||
if (!owner)
|
||||
return;
|
||||
|
||||
if (currentSurface) {
|
||||
LOGM(WARN, "requested CWLTouchResource::sendDown without sendUp first.");
|
||||
sendUp(timeMs, id);
|
||||
}
|
||||
|
||||
ASSERT(surface->client() == owner->client());
|
||||
|
||||
currentSurface = surface;
|
||||
listeners.destroySurface = surface->events.destroy.registerListener([this, timeMs, id](std::any d) { sendUp(timeMs + 10 /* hack */, id); });
|
||||
|
||||
resource->sendDown(g_pSeatManager->nextSerial(owner.lock()), timeMs, surface->getResource().get(), id, wl_fixed_from_double(local.x), wl_fixed_from_double(local.y));
|
||||
|
||||
fingers++;
|
||||
}
|
||||
|
||||
void CWLTouchResource::sendUp(uint32_t timeMs, int32_t id) {
|
||||
if (!owner || !currentSurface)
|
||||
if (!owner)
|
||||
return;
|
||||
|
||||
resource->sendUp(g_pSeatManager->nextSerial(owner.lock()), timeMs, id);
|
||||
currentSurface.reset();
|
||||
listeners.destroySurface.reset();
|
||||
fingers--;
|
||||
if (fingers <= 0) {
|
||||
currentSurface.reset();
|
||||
listeners.destroySurface.reset();
|
||||
fingers = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void CWLTouchResource::sendMotion(uint32_t timeMs, int32_t id, const Vector2D& local) {
|
||||
if (!owner || !currentSurface)
|
||||
if (!owner)
|
||||
return;
|
||||
|
||||
resource->sendMotion(timeMs, id, wl_fixed_from_double(local.x), wl_fixed_from_double(local.y));
|
||||
}
|
||||
|
||||
void CWLTouchResource::sendFrame() {
|
||||
if (!owner || !currentSurface)
|
||||
if (!owner)
|
||||
return;
|
||||
|
||||
resource->sendFrame();
|
||||
|
@ -97,6 +98,9 @@ CWLPointerResource::CWLPointerResource(SP<CWlPointer> resource_, SP<CWLSeatResou
|
|||
|
||||
g_pSeatManager->onSetCursor(owner.lock(), serial, surf ? CWLSurfaceResource::fromResource(surf) : nullptr, {hotX, hotY});
|
||||
});
|
||||
|
||||
if (g_pSeatManager->state.pointerFocus && g_pSeatManager->state.pointerFocus->client() == resource->client())
|
||||
sendEnter(g_pSeatManager->state.pointerFocus.lock(), {-1, -1} /* Coords don't really matter that much, they will be updated next move */);
|
||||
}
|
||||
|
||||
bool CWLPointerResource::good() {
|
||||
|
@ -199,10 +203,16 @@ CWLKeyboardResource::CWLKeyboardResource(SP<CWlKeyboard> resource_, SP<CWLSeatRe
|
|||
resource->setRelease([this](CWlKeyboard* r) { PROTO::seat->destroyResource(this); });
|
||||
resource->setOnDestroy([this](CWlKeyboard* r) { PROTO::seat->destroyResource(this); });
|
||||
|
||||
static auto REPEAT = CConfigValue<Hyprlang::INT>("input:repeat_rate");
|
||||
static auto DELAY = CConfigValue<Hyprlang::INT>("input:repeat_delay");
|
||||
if (!g_pSeatManager->keyboard) {
|
||||
LOGM(ERR, "No keyboard on bound wl_keyboard??");
|
||||
return;
|
||||
}
|
||||
|
||||
sendKeymap(g_pSeatManager->keyboard.lock());
|
||||
repeatInfo(*REPEAT, *DELAY);
|
||||
repeatInfo(g_pSeatManager->keyboard->repeatRate, g_pSeatManager->keyboard->repeatDelay);
|
||||
|
||||
if (g_pSeatManager->state.keyboardFocus && g_pSeatManager->state.keyboardFocus->client() == resource->client())
|
||||
sendEnter(g_pSeatManager->state.keyboardFocus.lock());
|
||||
}
|
||||
|
||||
bool CWLKeyboardResource::good() {
|
||||
|
|
|
@ -46,6 +46,8 @@ class CWLTouchResource {
|
|||
SP<CWlTouch> resource;
|
||||
WP<CWLSurfaceResource> currentSurface;
|
||||
|
||||
int fingers = 0;
|
||||
|
||||
struct {
|
||||
CHyprSignalListener destroySurface;
|
||||
} listeners;
|
||||
|
|
|
@ -79,20 +79,20 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() {
|
|||
m_tGlobalTimer.reset();
|
||||
}
|
||||
|
||||
std::vector<uint64_t> CHyprOpenGLImpl::getModsForFormat(EGLint format) {
|
||||
std::optional<std::vector<uint64_t>> CHyprOpenGLImpl::getModsForFormat(EGLint format) {
|
||||
// TODO: return std::expected when clang supports it
|
||||
|
||||
if (!m_sExts.EXT_image_dma_buf_import_modifiers)
|
||||
return {};
|
||||
return std::nullopt;
|
||||
|
||||
EGLint len = 0;
|
||||
if (!m_sProc.eglQueryDmaBufModifiersEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), format, 0, nullptr, nullptr, &len)) {
|
||||
Debug::log(ERR, "EGL: Failed to query mods");
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (len <= 0)
|
||||
return {DRM_FORMAT_MOD_LINEAR, DRM_FORMAT_MOD_INVALID}; // assume the driver can do linear and implicit.
|
||||
return std::vector<uint64_t>{};
|
||||
|
||||
std::vector<uint64_t> mods;
|
||||
std::vector<EGLBoolean> external;
|
||||
|
@ -103,13 +103,21 @@ std::vector<uint64_t> CHyprOpenGLImpl::getModsForFormat(EGLint format) {
|
|||
m_sProc.eglQueryDmaBufModifiersEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), format, len, mods.data(), external.data(), &len);
|
||||
|
||||
std::vector<uint64_t> result;
|
||||
bool linearIsExternal = false;
|
||||
for (size_t i = 0; i < mods.size(); ++i) {
|
||||
if (external.at(i))
|
||||
if (external.at(i)) {
|
||||
if (mods.at(i) == DRM_FORMAT_MOD_LINEAR)
|
||||
linearIsExternal = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
result.push_back(mods.at(i));
|
||||
}
|
||||
|
||||
// if the driver doesn't mark linear as external, add it. It's allowed unless the driver says otherwise. (e.g. nvidia)
|
||||
if (!linearIsExternal && std::find(mods.begin(), mods.end(), DRM_FORMAT_MOD_LINEAR) == mods.end() && mods.size() == 0)
|
||||
mods.push_back(DRM_FORMAT_MOD_LINEAR);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -147,15 +155,19 @@ void CHyprOpenGLImpl::initDRMFormats() {
|
|||
|
||||
for (auto& fmt : formats) {
|
||||
std::vector<uint64_t> mods;
|
||||
if (!DISABLE_MODS)
|
||||
mods = getModsForFormat(fmt);
|
||||
else
|
||||
if (!DISABLE_MODS) {
|
||||
auto ret = getModsForFormat(fmt);
|
||||
if (!ret.has_value())
|
||||
continue;
|
||||
|
||||
mods = *ret;
|
||||
} else
|
||||
mods = {DRM_FORMAT_MOD_LINEAR};
|
||||
|
||||
m_bHasModifiers = m_bHasModifiers || mods.size() > 0;
|
||||
|
||||
if (mods.size() == 0)
|
||||
continue;
|
||||
// EGL can always do implicit modifiers.
|
||||
mods.push_back(DRM_FORMAT_MOD_INVALID);
|
||||
|
||||
dmaFormats.push_back(SDRMFormat{
|
||||
.format = fmt,
|
||||
|
|
|
@ -238,7 +238,9 @@ class CHyprOpenGLImpl {
|
|||
void createBGTextureForMonitor(CMonitor*);
|
||||
void initShaders();
|
||||
void initDRMFormats();
|
||||
std::vector<uint64_t> getModsForFormat(EGLint format);
|
||||
|
||||
//
|
||||
std::optional<std::vector<uint64_t>> getModsForFormat(EGLint format);
|
||||
|
||||
// returns the out FB, can be either Mirror or MirrorSwap
|
||||
CFramebuffer* blurMainFramebufferWithDamage(float a, CRegion* damage);
|
||||
|
|
|
@ -90,6 +90,11 @@ CHyprRenderer::CHyprRenderer() {
|
|||
wl_event_source_timer_update(m_pCursorTicker, 500);
|
||||
}
|
||||
|
||||
CHyprRenderer::~CHyprRenderer() {
|
||||
if (m_pCursorTicker)
|
||||
wl_event_source_remove(m_pCursorTicker);
|
||||
}
|
||||
|
||||
static void renderSurface(SP<CWLSurfaceResource> surface, int x, int y, void* data) {
|
||||
if (!surface->current.buffer || !surface->current.buffer->texture)
|
||||
return;
|
||||
|
@ -1253,6 +1258,15 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
|
|||
|
||||
TRACY_GPU_ZONE("Render");
|
||||
|
||||
static bool zoomLock = false;
|
||||
if (zoomLock && *PZOOMFACTOR == 1.f) {
|
||||
g_pPointerManager->unlockSoftwareAll();
|
||||
zoomLock = false;
|
||||
} else if (!zoomLock && *PZOOMFACTOR != 1.f) {
|
||||
g_pPointerManager->lockSoftwareAll();
|
||||
zoomLock = true;
|
||||
}
|
||||
|
||||
if (pMonitor == g_pCompositor->getMonitorFromCursor())
|
||||
g_pHyprOpenGL->m_RenderData.mouseZoomFactor = std::clamp(*PZOOMFACTOR, 1.f, INFINITY);
|
||||
else
|
||||
|
@ -1265,10 +1279,6 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
|
|||
pMonitor->forceFullFrames = 10;
|
||||
}
|
||||
|
||||
bool lockSoftware = pMonitor == g_pCompositor->getMonitorFromCursor() && *PZOOMFACTOR != 1.f;
|
||||
if (lockSoftware)
|
||||
g_pPointerManager->lockSoftwareForMonitor(pMonitor->self.lock());
|
||||
|
||||
CRegion damage, finalDamage;
|
||||
if (!beginRender(pMonitor, damage, RENDER_MODE_NORMAL)) {
|
||||
Debug::log(ERR, "renderer: couldn't beginRender()!");
|
||||
|
@ -1370,9 +1380,6 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
|
|||
|
||||
endRender();
|
||||
|
||||
if (lockSoftware)
|
||||
g_pPointerManager->unlockSoftwareForMonitor(pMonitor->self.lock());
|
||||
|
||||
TRACY_GPU_COLLECT;
|
||||
|
||||
if (!pMonitor->mirrors.empty()) {
|
||||
|
@ -1756,7 +1763,7 @@ void CHyprRenderer::damageMonitor(CMonitor* pMonitor) {
|
|||
Debug::log(LOG, "Damage: Monitor {}", pMonitor->szName);
|
||||
}
|
||||
|
||||
void CHyprRenderer::damageBox(CBox* pBox) {
|
||||
void CHyprRenderer::damageBox(CBox* pBox, bool skipFrameSchedule) {
|
||||
if (g_pCompositor->m_bUnsafeState)
|
||||
return;
|
||||
|
||||
|
@ -1766,7 +1773,8 @@ void CHyprRenderer::damageBox(CBox* pBox) {
|
|||
|
||||
CBox damageBox = {pBox->x - m->vecPosition.x, pBox->y - m->vecPosition.y, pBox->width, pBox->height};
|
||||
damageBox.scale(m->scale);
|
||||
m->addDamage(&damageBox);
|
||||
if (!skipFrameSchedule)
|
||||
m->addDamage(&damageBox);
|
||||
}
|
||||
|
||||
static auto PLOGDAMAGE = CConfigValue<Hyprlang::INT>("debug:log_damage");
|
||||
|
|
|
@ -42,12 +42,13 @@ struct SSessionLockSurface;
|
|||
class CHyprRenderer {
|
||||
public:
|
||||
CHyprRenderer();
|
||||
~CHyprRenderer();
|
||||
|
||||
void renderMonitor(CMonitor* pMonitor);
|
||||
void arrangeLayersForMonitor(const int&);
|
||||
void damageSurface(SP<CWLSurfaceResource>, double, double, double scale = 1.0);
|
||||
void damageWindow(PHLWINDOW, bool forceFull = false);
|
||||
void damageBox(CBox*);
|
||||
void damageBox(CBox*, bool skipFrameSchedule = false);
|
||||
void damageBox(const int& x, const int& y, const int& w, const int& h);
|
||||
void damageRegion(const CRegion&);
|
||||
void damageMonitor(CMonitor*);
|
||||
|
|
|
@ -119,15 +119,15 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a) {
|
|||
g_pDecorationPositioner->repositionDeco(this);
|
||||
}
|
||||
|
||||
int xoff = 0;
|
||||
int yoff = 0;
|
||||
float xoff = 0;
|
||||
float yoff = 0;
|
||||
|
||||
for (int i = 0; i < barsToDraw; ++i) {
|
||||
const auto WINDOWINDEX = *PSTACKED ? m_dwGroupMembers.size() - i - 1 : i;
|
||||
|
||||
CBox rect = {ASSIGNEDBOX.x + xoff - pMonitor->vecPosition.x + m_pWindow->m_vFloatingOffset.x,
|
||||
ASSIGNEDBOX.y + ASSIGNEDBOX.h - yoff - BAR_INDICATOR_HEIGHT - BAR_PADDING_OUTER_VERT - pMonitor->vecPosition.y + m_pWindow->m_vFloatingOffset.y, m_fBarWidth,
|
||||
BAR_INDICATOR_HEIGHT};
|
||||
CBox rect = {ASSIGNEDBOX.x + floor(xoff) - pMonitor->vecPosition.x + m_pWindow->m_vFloatingOffset.x,
|
||||
ASSIGNEDBOX.y + ASSIGNEDBOX.h - floor(yoff) - BAR_INDICATOR_HEIGHT - BAR_PADDING_OUTER_VERT - pMonitor->vecPosition.y + m_pWindow->m_vFloatingOffset.y,
|
||||
m_fBarWidth, BAR_INDICATOR_HEIGHT};
|
||||
|
||||
if (rect.width <= 0 || rect.height <= 0)
|
||||
break;
|
||||
|
@ -151,8 +151,8 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a) {
|
|||
color.a *= a;
|
||||
g_pHyprOpenGL->renderRect(&rect, color);
|
||||
|
||||
rect = {ASSIGNEDBOX.x + xoff - pMonitor->vecPosition.x + m_pWindow->m_vFloatingOffset.x,
|
||||
ASSIGNEDBOX.y + ASSIGNEDBOX.h - yoff - ONEBARHEIGHT - pMonitor->vecPosition.y + m_pWindow->m_vFloatingOffset.y, m_fBarWidth,
|
||||
rect = {ASSIGNEDBOX.x + floor(xoff) - pMonitor->vecPosition.x + m_pWindow->m_vFloatingOffset.x,
|
||||
ASSIGNEDBOX.y + ASSIGNEDBOX.h - floor(yoff) - ONEBARHEIGHT - pMonitor->vecPosition.y + m_pWindow->m_vFloatingOffset.y, m_fBarWidth,
|
||||
(*PGRADIENTS || *PRENDERTITLES ? *PHEIGHT : 0)};
|
||||
rect.scale(pMonitor->scale);
|
||||
|
||||
|
@ -172,10 +172,10 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a) {
|
|||
.emplace_back(std::make_unique<CTitleTex>(m_dwGroupMembers[WINDOWINDEX].lock(),
|
||||
Vector2D{m_fBarWidth * pMonitor->scale, (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) * pMonitor->scale}, pMonitor->scale))
|
||||
.get();
|
||||
rect.y += ((rect.height - pTitleTex->textHeight) / 2.0) * pMonitor->scale;
|
||||
rect.height = (pTitleTex->textHeight) * pMonitor->scale;
|
||||
rect.width = pTitleTex->textWidth * pMonitor->scale;
|
||||
rect.x += m_fBarWidth / 2.0 - (pTitleTex->textWidth / 2.0) * pMonitor->scale;
|
||||
rect.y += (rect.height - pTitleTex->textHeight) / 2.0;
|
||||
rect.height = pTitleTex->textHeight;
|
||||
rect.width = pTitleTex->textWidth;
|
||||
rect.x += (m_fBarWidth * pMonitor->scale) / 2.0 - (pTitleTex->textWidth / 2.0);
|
||||
rect.round();
|
||||
|
||||
g_pHyprOpenGL->renderTexture(pTitleTex->tex, &rect, 1.f);
|
||||
|
|
|
@ -155,6 +155,14 @@ static int xwaylandReady(int fd, uint32_t mask, void* data) {
|
|||
return g_pXWayland->pServer->ready(fd, mask);
|
||||
}
|
||||
|
||||
static bool safeRemove(const std::string& path) {
|
||||
try {
|
||||
return std::filesystem::remove(path);
|
||||
} catch (std::exception& e) { Debug::log(ERR, "[XWayland] failed to remove {}", path); }
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CXWaylandServer::tryOpenSockets() {
|
||||
for (size_t i = 0; i <= 32; ++i) {
|
||||
auto LOCK = std::format("/tmp/.X{}-lock", i);
|
||||
|
@ -162,7 +170,7 @@ bool CXWaylandServer::tryOpenSockets() {
|
|||
if (int fd = open(LOCK.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0444); fd >= 0) {
|
||||
// we managed to open the lock
|
||||
if (!openSockets(xFDs, i)) {
|
||||
std::filesystem::remove(LOCK);
|
||||
safeRemove(LOCK);
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
|
@ -170,7 +178,7 @@ bool CXWaylandServer::tryOpenSockets() {
|
|||
const auto PIDSTR = std::format("{}", getpid());
|
||||
|
||||
if (write(fd, PIDSTR.c_str(), PIDSTR.length()) != (long)PIDSTR.length()) {
|
||||
std::filesystem::remove(LOCK);
|
||||
safeRemove(LOCK);
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
|
@ -197,7 +205,7 @@ bool CXWaylandServer::tryOpenSockets() {
|
|||
} catch (...) { continue; }
|
||||
|
||||
if (kill(pid, 0) != 0 && errno == ESRCH) {
|
||||
if (!std::filesystem::remove(LOCK))
|
||||
if (!safeRemove(LOCK))
|
||||
continue;
|
||||
|
||||
i--;
|
||||
|
@ -228,7 +236,7 @@ CXWaylandServer::~CXWaylandServer() {
|
|||
close(xFDs[1]);
|
||||
|
||||
auto LOCK = std::format("/tmp/.X{}-lock", display);
|
||||
std::filesystem::remove(LOCK);
|
||||
safeRemove(LOCK);
|
||||
|
||||
std::string path;
|
||||
#ifdef __linux__
|
||||
|
@ -236,7 +244,7 @@ CXWaylandServer::~CXWaylandServer() {
|
|||
#else
|
||||
path = std::format("/tmp/.X11-unix/X{}_", display);
|
||||
#endif
|
||||
std::filesystem::remove(path);
|
||||
safeRemove(path);
|
||||
}
|
||||
|
||||
void CXWaylandServer::die() {
|
||||
|
|
|
@ -179,7 +179,7 @@ void CXWaylandSurface::configure(const CBox& box) {
|
|||
void CXWaylandSurface::activate(bool activate) {
|
||||
if (overrideRedirect && !activate)
|
||||
return;
|
||||
g_pXWayland->pWM->activateSurface(self.lock());
|
||||
g_pXWayland->pWM->activateSurface(self.lock(), activate);
|
||||
}
|
||||
|
||||
void CXWaylandSurface::setFullscreen(bool fs) {
|
||||
|
|
|
@ -248,11 +248,11 @@ void CXWM::readProp(SP<CXWaylandSurface> XSURF, uint32_t atom, xcb_get_property_
|
|||
}
|
||||
}
|
||||
} else {
|
||||
Debug::log(LOG, "[xwm] Unhandled prop {} -> {}", atom, propName);
|
||||
Debug::log(TRACE, "[xwm] Unhandled prop {} -> {}", atom, propName);
|
||||
return;
|
||||
}
|
||||
|
||||
Debug::log(LOG, "[xwm] Handled prop {} -> {}", atom, propName);
|
||||
Debug::log(TRACE, "[xwm] Handled prop {} -> {}", atom, propName);
|
||||
}
|
||||
|
||||
void CXWM::handlePropertyNotify(xcb_property_notify_event_t* e) {
|
||||
|
@ -354,11 +354,11 @@ void CXWM::handleClientMessage(xcb_client_message_event_t* e) {
|
|||
} else if (e->type == HYPRATOMS["_NET_ACTIVE_WINDOW"]) {
|
||||
XSURF->events.activate.emit();
|
||||
} else {
|
||||
Debug::log(LOG, "[xwm] Unhandled message prop {} -> {}", e->type, propName);
|
||||
Debug::log(TRACE, "[xwm] Unhandled message prop {} -> {}", e->type, propName);
|
||||
return;
|
||||
}
|
||||
|
||||
Debug::log(LOG, "[xwm] Handled message prop {} -> {}", e->type, propName);
|
||||
Debug::log(TRACE, "[xwm] Handled message prop {} -> {}", e->type, propName);
|
||||
}
|
||||
|
||||
void CXWM::handleFocusIn(xcb_focus_in_event_t* e) {
|
||||
|
@ -394,11 +394,16 @@ void CXWM::focusWindow(SP<CXWaylandSurface> surf) {
|
|||
if (surf == focusedSurface)
|
||||
return;
|
||||
|
||||
auto oldSurf = focusedSurface.lock();
|
||||
focusedSurface = surf;
|
||||
|
||||
if (oldSurf)
|
||||
sendState(oldSurf);
|
||||
// send state to all surfaces, sometimes we might lose some
|
||||
// that could still stick with the focused atom
|
||||
for (auto& s : mappedSurfaces) {
|
||||
if (!s)
|
||||
continue;
|
||||
|
||||
sendState(s.lock());
|
||||
}
|
||||
|
||||
if (!surf) {
|
||||
xcb_set_input_focus_checked(connection, XCB_INPUT_FOCUS_POINTER_ROOT, XCB_NONE, XCB_CURRENT_TIME);
|
||||
|
@ -490,18 +495,18 @@ std::string CXWM::mimeFromAtom(xcb_atom_t atom) {
|
|||
}
|
||||
|
||||
void CXWM::handleSelectionNotify(xcb_selection_notify_event_t* e) {
|
||||
Debug::log(LOG, "[xwm] Selection notify for {} prop {} target {}", e->selection, e->property, e->target);
|
||||
Debug::log(TRACE, "[xwm] Selection notify for {} prop {} target {}", e->selection, e->property, e->target);
|
||||
|
||||
SXSelection& sel = clipboard;
|
||||
|
||||
if (e->property == XCB_ATOM_NONE) {
|
||||
if (sel.transfer) {
|
||||
Debug::log(ERR, "[xwm] converting selection failed");
|
||||
Debug::log(TRACE, "[xwm] converting selection failed");
|
||||
sel.transfer.reset();
|
||||
}
|
||||
} else if (e->target == HYPRATOMS["TARGETS"]) {
|
||||
if (!focusedSurface) {
|
||||
Debug::log(LOG, "[xwm] denying access to write to clipboard because no X client is in focus");
|
||||
Debug::log(TRACE, "[xwm] denying access to write to clipboard because no X client is in focus");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -519,7 +524,7 @@ bool CXWM::handleSelectionPropertyNotify(xcb_property_notify_event_t* e) {
|
|||
}
|
||||
|
||||
void CXWM::handleSelectionRequest(xcb_selection_request_event_t* e) {
|
||||
Debug::log(LOG, "[xwm] Selection request for {} prop {} target {} time {} requestor {} selection {}", e->selection, e->property, e->target, e->time, e->requestor,
|
||||
Debug::log(TRACE, "[xwm] Selection request for {} prop {} target {} time {} requestor {} selection {}", e->selection, e->property, e->target, e->time, e->requestor,
|
||||
e->selection);
|
||||
|
||||
SXSelection& sel = clipboard;
|
||||
|
@ -542,7 +547,7 @@ void CXWM::handleSelectionRequest(xcb_selection_request_event_t* e) {
|
|||
}
|
||||
|
||||
if (!g_pSeatManager->state.keyboardFocusResource || g_pSeatManager->state.keyboardFocusResource->client() != g_pXWayland->pServer->xwaylandClient) {
|
||||
Debug::log(LOG, "[xwm] Ignoring clipboard access: xwayland not in focus");
|
||||
Debug::log(TRACE, "[xwm] Ignoring clipboard access: xwayland not in focus");
|
||||
selectionSendNotify(e, false);
|
||||
return;
|
||||
}
|
||||
|
@ -585,7 +590,7 @@ void CXWM::handleSelectionRequest(xcb_selection_request_event_t* e) {
|
|||
}
|
||||
|
||||
bool CXWM::handleSelectionXFixesNotify(xcb_xfixes_selection_notify_event_t* e) {
|
||||
Debug::log(LOG, "[xwm] Selection xfixes notify for {}", e->selection);
|
||||
Debug::log(TRACE, "[xwm] Selection xfixes notify for {}", e->selection);
|
||||
|
||||
// IMPORTANT: mind the g_pSeatManager below
|
||||
SXSelection& sel = clipboard;
|
||||
|
@ -868,13 +873,17 @@ void CXWM::createWMWindow() {
|
|||
xcb_set_selection_owner(connection, wmWindow, HYPRATOMS["_NET_WM_CM_S0"], XCB_CURRENT_TIME);
|
||||
}
|
||||
|
||||
void CXWM::activateSurface(SP<CXWaylandSurface> surf) {
|
||||
if (surf == focusedSurface || (surf && surf->overrideRedirect))
|
||||
void CXWM::activateSurface(SP<CXWaylandSurface> surf, bool activate) {
|
||||
if ((surf == focusedSurface && activate) || (surf && surf->overrideRedirect))
|
||||
return;
|
||||
|
||||
setActiveWindow(surf ? surf->xID : (uint32_t)XCB_WINDOW_NONE);
|
||||
|
||||
focusWindow(surf);
|
||||
if (!activate || !surf) {
|
||||
setActiveWindow((uint32_t)XCB_WINDOW_NONE);
|
||||
focusWindow(nullptr);
|
||||
} else {
|
||||
setActiveWindow(surf ? surf->xID : (uint32_t)XCB_WINDOW_NONE);
|
||||
focusWindow(surf);
|
||||
}
|
||||
|
||||
xcb_flush(connection);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "../helpers/signal/Listener.hpp"
|
||||
#include "../helpers/signal/Signal.hpp"
|
||||
#include "../helpers/WLListener.hpp"
|
||||
#include "../macros.hpp"
|
||||
|
||||
|
@ -79,7 +79,7 @@ class CXWM {
|
|||
void setActiveWindow(xcb_window_t window);
|
||||
void sendState(SP<CXWaylandSurface> surf);
|
||||
void focusWindow(SP<CXWaylandSurface> surf);
|
||||
void activateSurface(SP<CXWaylandSurface> surf);
|
||||
void activateSurface(SP<CXWaylandSurface> surf, bool activate);
|
||||
bool isWMWindow(xcb_window_t w);
|
||||
|
||||
void sendWMMessage(SP<CXWaylandSurface> surf, xcb_client_message_data_t* data, uint32_t mask);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue