mirror of
https://github.com/hyprwm/Hyprland.git
synced 2025-08-15 20:13:49 -07:00
Compare commits
51 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
29e2e59fdb | ||
|
1fdb5ba09e | ||
|
aa421c2e95 | ||
|
3c36e083f1 | ||
|
3fc0abcb56 | ||
|
273f43bda6 | ||
|
0a3948107a | ||
|
189e18394e | ||
|
3eb859bb4e | ||
|
eaa9663057 | ||
|
5da8281d68 | ||
|
d2031ba3e0 | ||
|
c22f46768c | ||
|
66470020a7 | ||
|
ed2f50d5ad | ||
|
5ee35f914f | ||
|
aa1bd647b1 | ||
|
fdb7ca6c8f | ||
|
6ab5a0befb | ||
|
6384f4acf4 | ||
|
4600043a49 | ||
|
279b06044c | ||
|
ccbdba7ee2 | ||
|
c7f0519faf | ||
|
7ea4fbf0ba | ||
|
f6ca4bac51 | ||
|
155eba57d8 | ||
|
7b10530a0d | ||
|
a25a214523 | ||
|
c8d80a2920 | ||
|
03385fc07f | ||
|
cca0f48b74 | ||
|
60edb376f2 | ||
|
6f74d8d7e9 | ||
|
ec4bea7901 | ||
|
9171db1984 | ||
|
5f60fc7d00 | ||
|
c4f46473df | ||
|
011d7ccb91 | ||
|
efc51eb7d1 | ||
|
c2835b6b0f | ||
|
d5d7f69d1e | ||
|
5cef2f44fe | ||
|
22154fa272 | ||
|
2ddd16ef28 | ||
|
d7382aa8a1 | ||
|
90306bdae6 | ||
|
b1ab0f7539 | ||
|
bf5e4bf116 | ||
|
4c471218c9 | ||
|
e59680481d |
2
.github/workflows/ci.yaml
vendored
2
.github/workflows/ci.yaml
vendored
@@ -21,7 +21,7 @@ jobs:
|
||||
|
||||
- name: Build Hyprland
|
||||
run: |
|
||||
make all
|
||||
CFLAGS=-Werror CXXFLAGS=-Werror make all
|
||||
|
||||
- name: Compress and package artifacts
|
||||
run: |
|
||||
|
@@ -102,7 +102,7 @@ else()
|
||||
endif()
|
||||
find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION})
|
||||
|
||||
pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=0.4.5)
|
||||
pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=0.8.0)
|
||||
pkg_check_modules(hyprlang_dep REQUIRED IMPORTED_TARGET hyprlang>=0.3.2)
|
||||
pkg_check_modules(hyprcursor_dep REQUIRED IMPORTED_TARGET hyprcursor>=0.1.7)
|
||||
pkg_check_modules(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=0.5.1)
|
||||
@@ -444,4 +444,5 @@ install(
|
||||
DIRECTORY ${HEADERS_SRC}
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland
|
||||
FILES_MATCHING
|
||||
PATTERN "*.h*")
|
||||
PATTERN "*.h*"
|
||||
PATTERN "*.frag")
|
||||
|
@@ -139,10 +139,10 @@ animations {
|
||||
# uncomment all if you wish to use that.
|
||||
# workspace = w[tv1], gapsout:0, gapsin:0
|
||||
# workspace = f[1], gapsout:0, gapsin:0
|
||||
# windowrulev2 = bordersize 0, floating:0, onworkspace:w[tv1]
|
||||
# windowrulev2 = rounding 0, floating:0, onworkspace:w[tv1]
|
||||
# windowrulev2 = bordersize 0, floating:0, onworkspace:f[1]
|
||||
# windowrulev2 = rounding 0, floating:0, onworkspace:f[1]
|
||||
# windowrule = bordersize 0, floating:0, onworkspace:w[tv1]
|
||||
# windowrule = rounding 0, floating:0, onworkspace:w[tv1]
|
||||
# windowrule = bordersize 0, floating:0, onworkspace:f[1]
|
||||
# windowrule = rounding 0, floating:0, onworkspace:f[1]
|
||||
|
||||
# See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more
|
||||
dwindle {
|
||||
@@ -276,14 +276,11 @@ bindl = , XF86AudioPrev, exec, playerctl previous
|
||||
# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
|
||||
# See https://wiki.hyprland.org/Configuring/Workspace-Rules/ for workspace rules
|
||||
|
||||
# Example windowrule v1
|
||||
# windowrule = float, ^(kitty)$
|
||||
|
||||
# Example windowrule v2
|
||||
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
|
||||
# Example windowrule
|
||||
# windowrule = float,class:^(kitty)$,title:^(kitty)$
|
||||
|
||||
# Ignore maximize requests from apps. You'll probably like this.
|
||||
windowrulev2 = suppressevent maximize, class:.*
|
||||
windowrule = suppressevent maximize, class:.*
|
||||
|
||||
# Fix some dragging issues with XWayland
|
||||
windowrulev2 = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0
|
||||
windowrule = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0
|
||||
|
24
flake.lock
generated
24
flake.lock
generated
@@ -16,11 +16,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1741934125,
|
||||
"narHash": "sha256-qwI47l3aKXRpDvmCKDbLV70iVfAqhpuKqT7qYHA4KJk=",
|
||||
"lastModified": 1742213273,
|
||||
"narHash": "sha256-0l0vDb4anfsBu1rOs94bC73Hub+xEivgBAo6QXl2MmU=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "aquamarine",
|
||||
"rev": "bea48d0bbe15fb3d758a8b6be865836c97056575",
|
||||
"rev": "484b732195cc53f4536ce4bd59a5c6402b1e7ccf",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -79,11 +79,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1738664950,
|
||||
"narHash": "sha256-xIeGNM+iivwVHkv9tHwOqoUP5dDrtees34bbFKKMZYs=",
|
||||
"lastModified": 1742215578,
|
||||
"narHash": "sha256-zfs71PXVVPEe56WEyNi2TJQPs0wabU4WAlq0XV7GcdE=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprcursor",
|
||||
"rev": "7c6d165e1eb9045a996551eb9f121b6d1b30adc3",
|
||||
"rev": "2fd36421c21aa87e2fe3bee11067540ae612f719",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -276,11 +276,11 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1741851582,
|
||||
"narHash": "sha256-cPfs8qMccim2RBgtKGF+x9IBCduRvd/N5F4nYpU0TVE=",
|
||||
"lastModified": 1742069588,
|
||||
"narHash": "sha256-C7jVfohcGzdZRF6DO+ybyG/sqpo1h6bZi9T56sxLy+k=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "6607cf789e541e7873d40d3a8f7815ea92204f32",
|
||||
"rev": "c80f6a7e10b39afcc1894e02ef785b1ad0b0d7e5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -299,11 +299,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1741379162,
|
||||
"narHash": "sha256-srpAbmJapkaqGRE3ytf3bj4XshspVR5964OX5LfjDWc=",
|
||||
"lastModified": 1742058297,
|
||||
"narHash": "sha256-b4SZc6TkKw8WQQssbN5O2DaCEzmFfvSTPYHlx/SFW9Y=",
|
||||
"owner": "cachix",
|
||||
"repo": "git-hooks.nix",
|
||||
"rev": "b5a62751225b2f62ff3147d0a334055ebadcd5cc",
|
||||
"rev": "59f17850021620cd348ad2e9c0c64f4e6325ce2a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@@ -165,7 +165,8 @@ int main(int argc, char** argv, char** envp) {
|
||||
} else if (command[0] == "reload") {
|
||||
auto ret = g_pPluginManager->ensurePluginsLoadState(force);
|
||||
|
||||
if (ret != LOADSTATE_OK && notify) {
|
||||
if (ret != LOADSTATE_OK) {
|
||||
if (notify) {
|
||||
switch (ret) {
|
||||
case LOADSTATE_FAIL:
|
||||
case LOADSTATE_PARTIAL_FAIL: g_pPluginManager->notify(ICON_ERROR, 0, 10000, "[hyprpm] Failed to load plugins"); break;
|
||||
@@ -174,6 +175,8 @@ int main(int argc, char** argv, char** envp) {
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
} else if (notify && !notifyFail) {
|
||||
g_pPluginManager->notify(ICON_OK, 0, 4000, "[hyprpm] Loaded plugins");
|
||||
|
@@ -31,7 +31,7 @@ if cpp_compiler.check_header('execinfo.h')
|
||||
add_project_arguments('-DHAS_EXECINFO', language: 'cpp')
|
||||
endif
|
||||
|
||||
aquamarine = dependency('aquamarine', version: '>=0.4.5')
|
||||
aquamarine = dependency('aquamarine', version: '>=0.8.0')
|
||||
hyprcursor = dependency('hyprcursor', version: '>=0.1.7')
|
||||
hyprgraphics = dependency('hyprgraphics', version: '>= 0.1.1')
|
||||
hyprlang = dependency('hyprlang', version: '>= 0.3.2')
|
||||
@@ -89,7 +89,7 @@ endif
|
||||
run_command('sh', '-c', 'scripts/generateVersion.sh', check: true)
|
||||
|
||||
# Install headers
|
||||
globber = run_command('find', 'src', '-name', '*.h*', check: true)
|
||||
globber = run_command('find', 'src', '-name', '*.h*', '-o', '-name', '*.frag', check: true)
|
||||
headers = globber.stdout().strip().split('\n')
|
||||
foreach file : headers
|
||||
install_headers(file, subdir: 'hyprland', preserve_path: true)
|
||||
|
@@ -2627,7 +2627,13 @@ PHLWORKSPACE CCompositor::createNewWorkspace(const WORKSPACEID& id, const MONITO
|
||||
|
||||
const bool SPECIAL = id >= SPECIAL_WORKSPACE_START && id <= -2;
|
||||
|
||||
const auto PWORKSPACE = m_vWorkspaces.emplace_back(CWorkspace::create(id, getMonitorFromID(monID), NAME, SPECIAL, isEmpty));
|
||||
const auto PMONITOR = getMonitorFromID(monID);
|
||||
if (!PMONITOR) {
|
||||
Debug::log(ERR, "BUG THIS: No pMonitor for new workspace in createNewWorkspace");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto PWORKSPACE = m_vWorkspaces.emplace_back(CWorkspace::create(id, PMONITOR, NAME, SPECIAL, isEmpty));
|
||||
|
||||
PWORKSPACE->m_fAlpha->setValueAndWarp(0);
|
||||
|
||||
@@ -3061,6 +3067,8 @@ bool CCompositor::shouldChangePreferredImageDescription() {
|
||||
}
|
||||
|
||||
void CCompositor::ensurePersistentWorkspacesPresent(const std::vector<SWorkspaceRule>& rules, PHLWORKSPACE pWorkspace) {
|
||||
if (!m_pLastMonitor)
|
||||
return;
|
||||
|
||||
for (const auto& rule : rules) {
|
||||
if (!rule.isPersistent)
|
||||
@@ -3076,6 +3084,9 @@ void CCompositor::ensurePersistentWorkspacesPresent(const std::vector<SWorkspace
|
||||
|
||||
const auto PMONITOR = getMonitorFromString(rule.monitor);
|
||||
|
||||
if (!rule.monitor.empty() && !PMONITOR)
|
||||
continue; // don't do anything yet, as the monitor is not yet present.
|
||||
|
||||
if (!PWORKSPACE) {
|
||||
WORKSPACEID id = rule.workspaceId;
|
||||
std::string wsname = rule.workspaceName;
|
||||
@@ -3092,7 +3103,7 @@ void CCompositor::ensurePersistentWorkspacesPresent(const std::vector<SWorkspace
|
||||
}
|
||||
PWORKSPACE = getWorkspaceByID(id);
|
||||
if (!PWORKSPACE)
|
||||
createNewWorkspace(id, PMONITOR ? PMONITOR : m_pLastMonitor.lock(), wsname, false);
|
||||
createNewWorkspace(id, PMONITOR ? PMONITOR->ID : m_pLastMonitor->ID, wsname, false);
|
||||
}
|
||||
|
||||
if (PWORKSPACE)
|
||||
|
@@ -1054,9 +1054,9 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "misc:vrr",
|
||||
.description = " controls the VRR (Adaptive Sync) of your monitors. 0 - off, 1 - on, 2 - fullscreen only [0/1/2]",
|
||||
.description = " controls the VRR (Adaptive Sync) of your monitors. 0 - off, 1 - on, 2 - fullscreen only, 3 - fullscreen with game or video content type [0/1/2/3]",
|
||||
.type = CONFIG_OPTION_INT,
|
||||
.data = SConfigOptionDescription::SRangeData{0, 0, 2},
|
||||
.data = SConfigOptionDescription::SRangeData{.value = 0, .min = 0, .max = 3},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "misc:mouse_move_enables_dpms",
|
||||
@@ -1319,6 +1319,12 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{false},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "xwayland:create_abstract_socket",
|
||||
.description = "Create the abstract Unix domain socket for XWayland",
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{false},
|
||||
},
|
||||
|
||||
/*
|
||||
* opengl:
|
||||
@@ -1375,6 +1381,12 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
|
||||
SConfigOptionDescription{
|
||||
.value = "render:cm_fs_passthrough",
|
||||
.description = "Passthrough color settings for fullscreen apps when possible",
|
||||
.type = CONFIG_OPTION_INT,
|
||||
.data = SConfigOptionDescription::SRangeData{.value = 2, .min = 0, .max = 2},
|
||||
},
|
||||
SConfigOptionDescription{
|
||||
.value = "render:cm_enabled",
|
||||
.description = "Enable Color Management pipelines (requires restart to fully take effect)",
|
||||
.type = CONFIG_OPTION_BOOL,
|
||||
.data = SConfigOptionDescription::SBoolData{true},
|
||||
},
|
||||
|
@@ -49,6 +49,7 @@
|
||||
#include <memory>
|
||||
using namespace Hyprutils::String;
|
||||
using namespace Hyprutils::Animation;
|
||||
using enum NContentType::eContentType;
|
||||
|
||||
//NOLINTNEXTLINE
|
||||
extern "C" char** environ;
|
||||
@@ -293,7 +294,7 @@ static Hyprlang::CParseResult handleWindowRuleV2(const char* c, const char* v) {
|
||||
const std::string VALUE = v;
|
||||
const std::string COMMAND = c;
|
||||
|
||||
const auto RESULT = g_pConfigManager->handleWindowRuleV2(COMMAND, VALUE);
|
||||
const auto RESULT = g_pConfigManager->handleWindowRule(COMMAND, VALUE);
|
||||
|
||||
Hyprlang::CParseResult result;
|
||||
if (RESULT.has_value())
|
||||
@@ -652,6 +653,7 @@ CConfigManager::CConfigManager() {
|
||||
registerConfigVar("xwayland:enabled", Hyprlang::INT{1});
|
||||
registerConfigVar("xwayland:use_nearest_neighbor", Hyprlang::INT{1});
|
||||
registerConfigVar("xwayland:force_zero_scaling", Hyprlang::INT{0});
|
||||
registerConfigVar("xwayland:create_abstract_socket", Hyprlang::INT{0});
|
||||
|
||||
registerConfigVar("opengl:nvidia_anti_flicker", Hyprlang::INT{1});
|
||||
|
||||
@@ -691,7 +693,8 @@ CConfigManager::CConfigManager() {
|
||||
registerConfigVar("render:expand_undersized_textures", Hyprlang::INT{1});
|
||||
registerConfigVar("render:xp_mode", Hyprlang::INT{0});
|
||||
registerConfigVar("render:ctm_animation", Hyprlang::INT{2});
|
||||
registerConfigVar("render:cm_fs_passthrough", Hyprlang::INT{1});
|
||||
registerConfigVar("render:cm_fs_passthrough", Hyprlang::INT{2});
|
||||
registerConfigVar("render:cm_enabled", Hyprlang::INT{1});
|
||||
|
||||
registerConfigVar("ecosystem:no_update_news", Hyprlang::INT{0});
|
||||
registerConfigVar("ecosystem:no_donation_nag", Hyprlang::INT{0});
|
||||
@@ -1650,37 +1653,34 @@ void CConfigManager::ensureVRR(PHLMONITOR pMonitor) {
|
||||
}
|
||||
m->vrrActive = true;
|
||||
return;
|
||||
} else if (USEVRR == 2) {
|
||||
} else if (USEVRR == 2 || USEVRR == 3) {
|
||||
const auto PWORKSPACE = m->activeWorkspace;
|
||||
|
||||
if (!PWORKSPACE)
|
||||
return; // ???
|
||||
|
||||
const auto WORKSPACEFULL = PWORKSPACE->m_bHasFullscreenWindow && (PWORKSPACE->m_efFullscreenMode & FSMODE_FULLSCREEN);
|
||||
bool wantVRR = PWORKSPACE->m_bHasFullscreenWindow && (PWORKSPACE->m_efFullscreenMode & FSMODE_FULLSCREEN);
|
||||
if (wantVRR && USEVRR == 3) {
|
||||
const auto contentType = PWORKSPACE->getFullscreenWindow()->getContentType();
|
||||
wantVRR = contentType == CONTENT_TYPE_GAME || contentType == CONTENT_TYPE_VIDEO;
|
||||
}
|
||||
|
||||
if (WORKSPACEFULL) {
|
||||
if (wantVRR) {
|
||||
/* fullscreen */
|
||||
m->vrrActive = true;
|
||||
|
||||
m->output->state->resetExplicitFences();
|
||||
if (!m->output->state->state().adaptiveSync) {
|
||||
m->output->state->setAdaptiveSync(true);
|
||||
|
||||
if (!m->state.test()) {
|
||||
Debug::log(LOG, "Pending output {} does not accept VRR.", m->output->name);
|
||||
m->output->state->setAdaptiveSync(false);
|
||||
}
|
||||
|
||||
if (!m->state.commit())
|
||||
Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> true", m->output->name);
|
||||
|
||||
} else if (!WORKSPACEFULL) {
|
||||
}
|
||||
} else {
|
||||
m->vrrActive = false;
|
||||
|
||||
m->output->state->resetExplicitFences();
|
||||
m->output->state->setAdaptiveSync(false);
|
||||
|
||||
if (!m->state.commit())
|
||||
Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> false", m->output->name);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -2347,69 +2347,6 @@ std::optional<std::string> CConfigManager::handleUnbind(const std::string& comma
|
||||
}
|
||||
|
||||
std::optional<std::string> CConfigManager::handleWindowRule(const std::string& command, const std::string& value) {
|
||||
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())
|
||||
return "empty rule?";
|
||||
|
||||
if (RULE == "unset") {
|
||||
std::erase_if(m_vWindowRules, [&](const auto& other) { return other->szValue == VALUE; });
|
||||
return {};
|
||||
}
|
||||
|
||||
auto newRule = makeShared<CWindowRule>(RULE, VALUE, false);
|
||||
|
||||
// verify we support a rule
|
||||
if (newRule->ruleType == CWindowRule::RULE_INVALID) {
|
||||
Debug::log(ERR, "Invalid rule found: {}", RULE);
|
||||
return "Invalid rule: " + RULE;
|
||||
}
|
||||
|
||||
newRule->rV1Regex = {VALUE.starts_with("title:") ? VALUE.substr(6) : VALUE};
|
||||
|
||||
if (RULE.starts_with("size") || RULE.starts_with("maxsize") || RULE.starts_with("minsize"))
|
||||
m_vWindowRules.insert(m_vWindowRules.begin(), newRule);
|
||||
else
|
||||
m_vWindowRules.emplace_back(newRule);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<std::string> CConfigManager::handleLayerRule(const std::string& command, const std::string& value) {
|
||||
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())
|
||||
return "empty rule?";
|
||||
|
||||
if (RULE == "unset") {
|
||||
std::erase_if(m_vLayerRules, [&](const auto& other) { return other->targetNamespace == VALUE; });
|
||||
return {};
|
||||
}
|
||||
|
||||
auto rule = makeShared<CLayerRule>(RULE, VALUE);
|
||||
|
||||
if (rule->ruleType == CLayerRule::RULE_INVALID) {
|
||||
Debug::log(ERR, "Invalid rule found: {}", RULE);
|
||||
return "Invalid rule found: " + RULE;
|
||||
}
|
||||
|
||||
rule->targetNamespaceRegex = {VALUE};
|
||||
|
||||
m_vLayerRules.emplace_back(rule);
|
||||
|
||||
for (auto const& m : g_pCompositor->m_vMonitors)
|
||||
for (auto const& lsl : m->m_aLayerSurfaceLayers)
|
||||
for (auto const& ls : lsl)
|
||||
ls->applyRules();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<std::string> CConfigManager::handleWindowRuleV2(const std::string& command, const std::string& value) {
|
||||
const auto RULE = trim(value.substr(0, value.find_first_of(',')));
|
||||
const auto VALUE = value.substr(value.find_first_of(',') + 1);
|
||||
|
||||
@@ -2608,6 +2545,38 @@ std::optional<std::string> CConfigManager::handleWindowRuleV2(const std::string&
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<std::string> CConfigManager::handleLayerRule(const std::string& command, const std::string& value) {
|
||||
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())
|
||||
return "empty rule?";
|
||||
|
||||
if (RULE == "unset") {
|
||||
std::erase_if(m_vLayerRules, [&](const auto& other) { return other->targetNamespace == VALUE; });
|
||||
return {};
|
||||
}
|
||||
|
||||
auto rule = makeShared<CLayerRule>(RULE, VALUE);
|
||||
|
||||
if (rule->ruleType == CLayerRule::RULE_INVALID) {
|
||||
Debug::log(ERR, "Invalid rule found: {}", RULE);
|
||||
return "Invalid rule found: " + RULE;
|
||||
}
|
||||
|
||||
rule->targetNamespaceRegex = {VALUE};
|
||||
|
||||
m_vLayerRules.emplace_back(rule);
|
||||
|
||||
for (auto const& m : g_pCompositor->m_vMonitors)
|
||||
for (auto const& lsl : m->m_aLayerSurfaceLayers)
|
||||
for (auto const& ls : lsl)
|
||||
ls->applyRules();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void CConfigManager::updateBlurredLS(const std::string& name, const bool forceBlur) {
|
||||
const bool BYADDRESS = name.starts_with("address:");
|
||||
std::string matchName = name;
|
||||
|
@@ -235,7 +235,6 @@ class CConfigManager {
|
||||
std::optional<std::string> handleUnbind(const std::string&, const std::string&);
|
||||
std::optional<std::string> handleWindowRule(const std::string&, const std::string&);
|
||||
std::optional<std::string> handleLayerRule(const std::string&, const std::string&);
|
||||
std::optional<std::string> handleWindowRuleV2(const std::string&, const std::string&);
|
||||
std::optional<std::string> handleWorkspaceRules(const std::string&, const std::string&);
|
||||
std::optional<std::string> handleBezier(const std::string&, const std::string&);
|
||||
std::optional<std::string> handleAnimation(const std::string&, const std::string&);
|
||||
|
@@ -152,10 +152,10 @@ animations {
|
||||
# uncomment all if you wish to use that.
|
||||
# workspace = w[tv1], gapsout:0, gapsin:0
|
||||
# workspace = f[1], gapsout:0, gapsin:0
|
||||
# windowrulev2 = bordersize 0, floating:0, onworkspace:w[tv1]
|
||||
# windowrulev2 = rounding 0, floating:0, onworkspace:w[tv1]
|
||||
# windowrulev2 = bordersize 0, floating:0, onworkspace:f[1]
|
||||
# windowrulev2 = rounding 0, floating:0, onworkspace:f[1]
|
||||
# windowrule = bordersize 0, floating:0, onworkspace:w[tv1]
|
||||
# windowrule = rounding 0, floating:0, onworkspace:w[tv1]
|
||||
# windowrule = bordersize 0, floating:0, onworkspace:f[1]
|
||||
# windowrule = rounding 0, floating:0, onworkspace:f[1]
|
||||
|
||||
# See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more
|
||||
dwindle {
|
||||
@@ -269,7 +269,7 @@ bindm = $mainMod, mouse:272, movewindow
|
||||
bindm = $mainMod, mouse:273, resizewindow
|
||||
|
||||
# Laptop multimedia keys for volume and LCD brightness
|
||||
bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+
|
||||
bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+
|
||||
bindel = ,XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-
|
||||
bindel = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle
|
||||
bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle
|
||||
@@ -289,15 +289,12 @@ bindl = , XF86AudioPrev, exec, playerctl previous
|
||||
# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
|
||||
# See https://wiki.hyprland.org/Configuring/Workspace-Rules/ for workspace rules
|
||||
|
||||
# Example windowrule v1
|
||||
# windowrule = float, ^(kitty)$
|
||||
|
||||
# Example windowrule v2
|
||||
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
|
||||
# Example windowrule
|
||||
# windowrule = float,class:^(kitty)$,title:^(kitty)$
|
||||
|
||||
# Ignore maximize requests from apps. You'll probably like this.
|
||||
windowrulev2 = suppressevent maximize, class:.*
|
||||
windowrule = suppressevent maximize, class:.*
|
||||
|
||||
# Fix some dragging issues with XWayland
|
||||
windowrulev2 = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0
|
||||
windowrule = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0
|
||||
)#";
|
||||
|
@@ -98,7 +98,7 @@ CRegion CWLSurface::computeDamage() const {
|
||||
if (!m_pResource->current.texture)
|
||||
return {};
|
||||
|
||||
CRegion damage = m_pResource->accumulateCurrentBufferDamage();
|
||||
CRegion damage = m_pResource->current.accumulateBufferDamage();
|
||||
damage.transform(wlTransformToHyprutils(m_pResource->current.transform), m_pResource->current.bufferSize.x, m_pResource->current.bufferSize.y);
|
||||
|
||||
const auto BUFSIZE = m_pResource->current.bufferSize;
|
||||
|
@@ -1258,7 +1258,7 @@ void CWindow::setAnimationsToMove() {
|
||||
|
||||
void CWindow::onWorkspaceAnimUpdate() {
|
||||
// clip box for animated offsets
|
||||
if (!m_bIsFloating || m_bPinned || isFullscreen()) {
|
||||
if (!m_bIsFloating || m_bPinned || isFullscreen() || m_bDraggingTiled) {
|
||||
m_vFloatingOffset = Vector2D(0, 0);
|
||||
return;
|
||||
}
|
||||
|
@@ -880,7 +880,7 @@ void Events::listener_commitWindow(void* owner, void* data) {
|
||||
|
||||
// tearing: if solitary, redraw it. This still might be a single surface window
|
||||
if (PMONITOR && PMONITOR->solitaryClient.lock() == PWINDOW && PWINDOW->canBeTorn() && PMONITOR->tearingState.canTear && PWINDOW->m_pWLSurface->resource()->current.texture) {
|
||||
CRegion damageBox{PWINDOW->m_pWLSurface->resource()->accumulateCurrentBufferDamage()};
|
||||
CRegion damageBox{PWINDOW->m_pWLSurface->resource()->current.accumulateBufferDamage()};
|
||||
|
||||
if (!damageBox.empty()) {
|
||||
if (PMONITOR->tearingState.busy) {
|
||||
|
@@ -58,7 +58,6 @@ void CMonitor::onConnect(bool noRule) {
|
||||
|
||||
if (output->supportsExplicit) {
|
||||
inTimeline = CSyncTimeline::create(output->getBackend()->drmFD());
|
||||
outTimeline = CSyncTimeline::create(output->getBackend()->drmFD());
|
||||
}
|
||||
|
||||
listeners.frame = output->events.frame.registerListener([this](std::any d) { onMonitorFrame(); });
|
||||
@@ -1240,7 +1239,7 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) {
|
||||
}
|
||||
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", pWorkspace->m_szName + "," + szName});
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"activespecialv2", pWorkspace->m_iID + "," + pWorkspace->m_szName + "," + szName});
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"activespecialv2", std::to_string(pWorkspace->m_iID) + "," + pWorkspace->m_szName + "," + szName});
|
||||
|
||||
g_pHyprRenderer->damageMonitor(self.lock());
|
||||
|
||||
@@ -1342,7 +1341,7 @@ bool CMonitor::attemptDirectScanout() {
|
||||
|
||||
const auto PSURFACE = g_pXWaylandManager->getWindowSurface(PCANDIDATE);
|
||||
|
||||
if (!PSURFACE || !PSURFACE->current.texture || !PSURFACE->current.buffer || PSURFACE->current.buffer->buffer.expired())
|
||||
if (!PSURFACE || !PSURFACE->current.texture || !PSURFACE->current.buffer)
|
||||
return false;
|
||||
|
||||
if (PSURFACE->current.bufferSize != vecPixelSize || PSURFACE->current.transform != transform)
|
||||
@@ -1355,9 +1354,26 @@ bool CMonitor::attemptDirectScanout() {
|
||||
|
||||
Debug::log(TRACE, "attemptDirectScanout: surface {:x} passed, will attempt, buffer {}", (uintptr_t)PSURFACE.get(), (uintptr_t)PSURFACE->current.buffer->buffer.get());
|
||||
|
||||
auto PBUFFER = PSURFACE->current.buffer->buffer.lock();
|
||||
if (PBUFFER == output->state->state().buffer)
|
||||
auto PBUFFER = PSURFACE->current.buffer->buffer;
|
||||
|
||||
if (PBUFFER == output->state->state().buffer) {
|
||||
if (scanoutNeedsCursorUpdate) {
|
||||
if (!state.test()) {
|
||||
Debug::log(TRACE, "attemptDirectScanout: failed basic test");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!output->commit()) {
|
||||
Debug::log(TRACE, "attemptDirectScanout: failed to commit cursor update");
|
||||
lastScanout.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
scanoutNeedsCursorUpdate = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// FIXME: make sure the buffer actually follows the available scanout dmabuf formats
|
||||
// and comes from the appropriate device. This may implode on multi-gpu!!
|
||||
@@ -1384,7 +1400,7 @@ bool CMonitor::attemptDirectScanout() {
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
PSURFACE->presentFeedback(&now, self.lock());
|
||||
|
||||
output->state->addDamage(CBox{{}, vecPixelSize});
|
||||
output->state->addDamage(PSURFACE->current.accumulateBufferDamage());
|
||||
output->state->resetExplicitFences();
|
||||
|
||||
auto cleanup = CScopeGuard([this]() { output->state->resetExplicitFences(); });
|
||||
@@ -1404,8 +1420,6 @@ bool CMonitor::attemptDirectScanout() {
|
||||
}
|
||||
}
|
||||
|
||||
commitSeq++;
|
||||
|
||||
bool ok = output->commit();
|
||||
|
||||
if (!ok && DOEXPLICIT) {
|
||||
@@ -1426,6 +1440,8 @@ bool CMonitor::attemptDirectScanout() {
|
||||
Debug::log(LOG, "Entered a direct scanout to {:x}: \"{}\"", (uintptr_t)PCANDIDATE.get(), PCANDIDATE->m_szTitle);
|
||||
}
|
||||
|
||||
scanoutNeedsCursorUpdate = false;
|
||||
|
||||
if (!PBUFFER->lockedByBackend || PBUFFER->hlEvents.backendRelease)
|
||||
return true;
|
||||
|
||||
|
@@ -57,6 +57,7 @@ struct SMonitorRule {
|
||||
|
||||
class CMonitor;
|
||||
class CSyncTimeline;
|
||||
class CEGLSync;
|
||||
|
||||
class CMonitorState {
|
||||
public:
|
||||
@@ -139,9 +140,9 @@ class CMonitor {
|
||||
|
||||
// explicit sync
|
||||
SP<CSyncTimeline> inTimeline;
|
||||
SP<CSyncTimeline> outTimeline;
|
||||
Hyprutils::OS::CFileDescriptor inFence;
|
||||
uint64_t commitSeq = 0;
|
||||
SP<CEGLSync> eglSync;
|
||||
uint64_t inTimelinePoint = 0;
|
||||
|
||||
PHLMONITORREF self;
|
||||
|
||||
@@ -158,6 +159,7 @@ class CMonitor {
|
||||
|
||||
// for direct scanout
|
||||
PHLWINDOWREF lastScanout;
|
||||
bool scanoutNeedsCursorUpdate = false;
|
||||
|
||||
struct {
|
||||
bool canTear = false;
|
||||
|
@@ -58,7 +58,7 @@ namespace NSplashes {
|
||||
"Thanks ThatOneCalculator!",
|
||||
"The AUR packages always work, except for the times they don't.",
|
||||
"Funny animation compositor woo",
|
||||
"2 years!",
|
||||
"3 years!",
|
||||
// music reference / quote section
|
||||
"J'remue le ciel, le jour, la nuit.",
|
||||
"aezakmi, aezakmi, aezakmi, aezakmi, aezakmi, aezakmi, aezakmi!",
|
||||
|
@@ -19,12 +19,13 @@ SP<CSyncTimeline> CSyncTimeline::create(int drmFD_) {
|
||||
return timeline;
|
||||
}
|
||||
|
||||
SP<CSyncTimeline> CSyncTimeline::create(int drmFD_, int drmSyncobjFD) {
|
||||
SP<CSyncTimeline> CSyncTimeline::create(int drmFD_, CFileDescriptor&& drmSyncobjFD) {
|
||||
auto timeline = SP<CSyncTimeline>(new CSyncTimeline);
|
||||
timeline->drmFD = drmFD_;
|
||||
timeline->syncobjFd = std::move(drmSyncobjFD);
|
||||
timeline->self = timeline;
|
||||
|
||||
if (drmSyncobjFDToHandle(drmFD_, drmSyncobjFD, &timeline->handle)) {
|
||||
if (drmSyncobjFDToHandle(drmFD_, timeline->syncobjFd.get(), &timeline->handle)) {
|
||||
Debug::log(ERR, "CSyncTimeline: failed to create a drm syncobj from fd??");
|
||||
return nullptr;
|
||||
}
|
||||
|
@@ -17,7 +17,7 @@ struct wl_event_source;
|
||||
class CSyncTimeline {
|
||||
public:
|
||||
static SP<CSyncTimeline> create(int drmFD_);
|
||||
static SP<CSyncTimeline> create(int drmFD_, int drmSyncobjFD);
|
||||
static SP<CSyncTimeline> create(int drmFD_, Hyprutils::OS::CFileDescriptor&& drmSyncobjFD);
|
||||
~CSyncTimeline();
|
||||
|
||||
struct SWaiter {
|
||||
@@ -41,6 +41,7 @@ class CSyncTimeline {
|
||||
void signal(uint64_t point);
|
||||
|
||||
int drmFD = -1;
|
||||
Hyprutils::OS::CFileDescriptor syncobjFd;
|
||||
uint32_t handle = 0;
|
||||
WP<CSyncTimeline> self;
|
||||
|
||||
|
@@ -89,6 +89,7 @@
|
||||
{ \
|
||||
Debug::log(CRIT, "\n\nMEMORY CORRUPTED: Unreachable failed! (Reached an unreachable position, memory corruption!!!)"); \
|
||||
raise(SIGABRT); \
|
||||
std::unreachable(); \
|
||||
}
|
||||
#else
|
||||
#define UNREACHABLE() std::unreachable();
|
||||
|
@@ -323,6 +323,8 @@ void CPointerManager::onCursorMoved() {
|
||||
|
||||
const auto CURSORPOS = getCursorPosForMonitor(m);
|
||||
m->output->moveCursor(CURSORPOS, m->shouldSkipScheduleFrameOnMouseEvent());
|
||||
|
||||
state->monitor->scanoutNeedsCursorUpdate = true;
|
||||
}
|
||||
|
||||
if (recalc)
|
||||
@@ -382,6 +384,8 @@ bool CPointerManager::setHWCursorBuffer(SP<SMonitorPointerState> state, SP<Aquam
|
||||
if (!state->monitor->shouldSkipScheduleFrameOnMouseEvent())
|
||||
g_pCompositor->scheduleFrameForMonitor(state->monitor.lock(), Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_SHAPE);
|
||||
|
||||
state->monitor->scanoutNeedsCursorUpdate = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -419,7 +423,9 @@ SP<Aquamarine::IBuffer> CPointerManager::renderHWCursorBuffer(SP<CPointerManager
|
||||
}
|
||||
}
|
||||
|
||||
state->monitor->cursorSwapchain = Aquamarine::CSwapchain::create(allocator, state->monitor->output->getBackend());
|
||||
auto backend = state->monitor->output->getBackend();
|
||||
auto primary = backend->getPrimary();
|
||||
state->monitor->cursorSwapchain = Aquamarine::CSwapchain::create(allocator, primary ? primary.lock() : backend);
|
||||
}
|
||||
|
||||
auto options = state->monitor->cursorSwapchain->currentOptions();
|
||||
@@ -617,12 +623,8 @@ void CPointerManager::renderSoftwareCursorsFor(PHLMONITOR pMonitor, timespec* no
|
||||
CTexPassElement::SRenderData data;
|
||||
data.tex = texture;
|
||||
data.box = box.round();
|
||||
data.syncTimeline = currentCursorImage.waitTimeline;
|
||||
data.syncPoint = currentCursorImage.waitPoint;
|
||||
g_pHyprRenderer->m_sRenderPass.add(makeShared<CTexPassElement>(data));
|
||||
|
||||
currentCursorImage.waitTimeline.reset();
|
||||
currentCursorImage.waitPoint = 0;
|
||||
g_pHyprRenderer->m_sRenderPass.add(makeShared<CTexPassElement>(data));
|
||||
|
||||
if (currentCursorImage.surface)
|
||||
currentCursorImage.surface->resource()->frame(now);
|
||||
|
@@ -148,8 +148,6 @@ class CPointerManager {
|
||||
|
||||
CHyprSignalListener destroySurface;
|
||||
CHyprSignalListener commitSurface;
|
||||
SP<CSyncTimeline> waitTimeline = nullptr;
|
||||
uint64_t waitPoint = 0;
|
||||
} currentCursorImage; // TODO: support various sizes per-output so we can have pixel-perfect cursors
|
||||
|
||||
Vector2D pointerPos = {0, 0};
|
||||
|
@@ -98,6 +98,7 @@ void CProtocolManager::onMonitorModeChange(PHLMONITOR pMonitor) {
|
||||
CProtocolManager::CProtocolManager() {
|
||||
|
||||
static const auto PENABLEEXPLICIT = CConfigValue<Hyprlang::INT>("render:explicit_sync");
|
||||
static const auto PENABLECM = CConfigValue<Hyprlang::INT>("render:cm_enabled");
|
||||
static const auto PENABLEXXCM = CConfigValue<Hyprlang::INT>("experimental:xx_color_management_v4");
|
||||
static const auto PDEBUGCM = CConfigValue<Hyprlang::INT>("debug:full_cm_proto");
|
||||
|
||||
@@ -181,14 +182,17 @@ CProtocolManager::CProtocolManager() {
|
||||
PROTO::ctm = makeUnique<CHyprlandCTMControlProtocol>(&hyprland_ctm_control_manager_v1_interface, 2, "CTMControl");
|
||||
PROTO::hyprlandSurface = makeUnique<CHyprlandSurfaceProtocol>(&hyprland_surface_manager_v1_interface, 2, "HyprlandSurface");
|
||||
PROTO::contentType = makeUnique<CContentTypeProtocol>(&wp_content_type_manager_v1_interface, 1, "ContentType");
|
||||
PROTO::colorManagement = makeUnique<CColorManagementProtocol>(&wp_color_manager_v1_interface, 1, "ColorManagement", *PDEBUGCM);
|
||||
// please read the top of this file before adding another protocol
|
||||
|
||||
if (*PENABLEXXCM) {
|
||||
if (*PENABLECM)
|
||||
PROTO::colorManagement = makeUnique<CColorManagementProtocol>(&wp_color_manager_v1_interface, 1, "ColorManagement", *PDEBUGCM);
|
||||
|
||||
if (*PENABLEXXCM && *PENABLECM) {
|
||||
PROTO::xxColorManagement = makeUnique<CXXColorManagementProtocol>(&xx_color_manager_v4_interface, 1, "XXColorManagement");
|
||||
PROTO::frogColorManagement = makeUnique<CFrogColorManagementProtocol>(&frog_color_management_factory_v1_interface, 1, "FrogColorManagement");
|
||||
}
|
||||
|
||||
// ! please read the top of this file before adding another protocol
|
||||
|
||||
for (auto const& b : g_pCompositor->m_pAqBackend->getImplementations()) {
|
||||
if (b->type() != Aquamarine::AQ_BACKEND_DRM)
|
||||
continue;
|
||||
|
@@ -606,11 +606,11 @@ void CSeatManager::setGrab(SP<CSeatGrab> grab) {
|
||||
|
||||
if (!refocus) {
|
||||
surf = CWLSurface::fromResource(currentFocus);
|
||||
layer = surf->getLayer();
|
||||
layer = surf ? surf->getLayer() : nullptr;
|
||||
}
|
||||
|
||||
if (!refocus && !layer) {
|
||||
auto popup = surf->getPopup();
|
||||
auto popup = surf ? surf->getPopup() : nullptr;
|
||||
if (popup) {
|
||||
auto parent = popup->getT1Owner();
|
||||
layer = parent->getLayer();
|
||||
|
@@ -293,9 +293,10 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus, bool mouse) {
|
||||
const auto BOX = HLSurface->getSurfaceBoxGlobal();
|
||||
|
||||
if (BOX) {
|
||||
const auto PWINDOW = HLSurface->getWindow();
|
||||
surfacePos = BOX->pos();
|
||||
pFoundLayerSurface = HLSurface->getLayer();
|
||||
pFoundWindow = HLSurface->getWindow();
|
||||
pFoundWindow = !PWINDOW || PWINDOW->isHidden() ? g_pCompositor->m_pLastWindow.lock() : PWINDOW;
|
||||
} else // reset foundSurface, find one normally
|
||||
foundSurface = nullptr;
|
||||
} else // reset foundSurface, find one normally
|
||||
|
@@ -59,6 +59,13 @@ struct SVersionInfo {
|
||||
#define OPTIONAL
|
||||
#define HANDLE void*
|
||||
|
||||
// C ABI is needed to prevent symbol mangling, but we don't actually need C compatibility,
|
||||
// so we ignore this warning about return types that are potentially incompatible with C.
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
|
||||
#endif
|
||||
|
||||
class IHyprLayout;
|
||||
class CWindow;
|
||||
class IHyprWindowDecoration;
|
||||
@@ -315,3 +322,7 @@ APICALL inline EXPORT const char* __hyprland_api_get_client_hash() {
|
||||
return GIT_COMMIT_HASH;
|
||||
}
|
||||
// NOLINTEND
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
@@ -9,51 +9,27 @@
|
||||
#include <fcntl.h>
|
||||
using namespace Hyprutils::OS;
|
||||
|
||||
CDRMSyncPointState::CDRMSyncPointState(WP<CDRMSyncobjTimelineResource> resource_, uint64_t point_, bool acquirePoint) :
|
||||
m_resource(resource_), m_point(point_), m_acquirePoint(acquirePoint) {}
|
||||
CDRMSyncPointState::CDRMSyncPointState(SP<CSyncTimeline> timeline_, uint64_t point_) : m_timeline(timeline_), m_point(point_) {}
|
||||
|
||||
const uint64_t& CDRMSyncPointState::point() {
|
||||
return m_point;
|
||||
}
|
||||
|
||||
WP<CDRMSyncobjTimelineResource> CDRMSyncPointState::resource() {
|
||||
return m_resource;
|
||||
}
|
||||
|
||||
WP<CSyncTimeline> CDRMSyncPointState::timeline() {
|
||||
if (expired()) {
|
||||
Debug::log(ERR, "CDRMSyncPointState: getting a timeline on a expired point");
|
||||
return {};
|
||||
}
|
||||
|
||||
return m_resource->timeline;
|
||||
}
|
||||
|
||||
bool CDRMSyncPointState::expired() {
|
||||
return !m_resource || !m_resource->timeline;
|
||||
return m_timeline;
|
||||
}
|
||||
|
||||
UP<CSyncReleaser> CDRMSyncPointState::createSyncRelease() {
|
||||
if (expired()) {
|
||||
Debug::log(ERR, "CDRMSyncPointState: creating a sync releaser on an expired point");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (m_releaseTaken)
|
||||
Debug::log(ERR, "CDRMSyncPointState: creating a sync releaser on an already created SyncRelease");
|
||||
|
||||
m_releaseTaken = true;
|
||||
return makeUnique<CSyncReleaser>(m_resource->timeline, m_point);
|
||||
return makeUnique<CSyncReleaser>(m_timeline, m_point);
|
||||
}
|
||||
|
||||
bool CDRMSyncPointState::addWaiter(const std::function<void()>& waiter) {
|
||||
if (expired()) {
|
||||
Debug::log(ERR, "CDRMSyncPointState: adding a waiter on an expired point");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_acquireCommitted = true;
|
||||
return m_resource->timeline->addWaiter(waiter, m_point, 0u);
|
||||
return m_timeline->addWaiter(waiter, m_point, 0u);
|
||||
}
|
||||
|
||||
bool CDRMSyncPointState::comitted() {
|
||||
@@ -61,21 +37,11 @@ bool CDRMSyncPointState::comitted() {
|
||||
}
|
||||
|
||||
CFileDescriptor CDRMSyncPointState::exportAsFD() {
|
||||
if (expired()) {
|
||||
Debug::log(ERR, "CDRMSyncPointState: exporting a FD on an expired point");
|
||||
return {};
|
||||
}
|
||||
|
||||
return m_resource->timeline->exportAsSyncFileFD(m_point);
|
||||
return m_timeline->exportAsSyncFileFD(m_point);
|
||||
}
|
||||
|
||||
void CDRMSyncPointState::signal() {
|
||||
if (expired()) {
|
||||
Debug::log(ERR, "CDRMSyncPointState: signaling on an expired point");
|
||||
return;
|
||||
}
|
||||
|
||||
m_resource->timeline->signal(m_point);
|
||||
m_timeline->signal(m_point);
|
||||
}
|
||||
|
||||
CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(UP<CWpLinuxDrmSyncobjSurfaceV1>&& resource_, SP<CWLSurfaceResource> surface_) :
|
||||
@@ -95,7 +61,7 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(UP<CWpLinuxDrmSyncobjSurf
|
||||
}
|
||||
|
||||
auto timeline = CDRMSyncobjTimelineResource::fromResource(timeline_);
|
||||
pendingAcquire = {timeline, ((uint64_t)hi << 32) | (uint64_t)lo, true};
|
||||
pendingAcquire = {timeline->timeline, ((uint64_t)hi << 32) | (uint64_t)lo};
|
||||
});
|
||||
|
||||
resource->setSetReleasePoint([this](CWpLinuxDrmSyncobjSurfaceV1* r, wl_resource* timeline_, uint32_t hi, uint32_t lo) {
|
||||
@@ -105,34 +71,36 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(UP<CWpLinuxDrmSyncobjSurf
|
||||
}
|
||||
|
||||
auto timeline = CDRMSyncobjTimelineResource::fromResource(timeline_);
|
||||
pendingRelease = {timeline, ((uint64_t)hi << 32) | (uint64_t)lo, false};
|
||||
pendingRelease = {timeline->timeline, ((uint64_t)hi << 32) | (uint64_t)lo};
|
||||
});
|
||||
|
||||
listeners.surfacePrecommit = surface->events.precommit.registerListener([this](std::any d) {
|
||||
if (!surface->pending.buffer && surface->pending.newBuffer && !surface->pending.texture) {
|
||||
const bool PENDING_HAS_NEW_BUFFER = surface->pending.updated & SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_BUFFER;
|
||||
|
||||
if (!surface->pending.buffer && PENDING_HAS_NEW_BUFFER && !surface->pending.texture) {
|
||||
removeAllWaiters();
|
||||
surface->commitPendingState(surface->pending);
|
||||
return; // null buffer attached.
|
||||
}
|
||||
|
||||
if (!surface->pending.buffer && !surface->pending.newBuffer && surface->current.buffer) {
|
||||
if (!surface->pending.buffer && !PENDING_HAS_NEW_BUFFER && surface->current.buffer) {
|
||||
surface->current.bufferDamage.clear();
|
||||
surface->current.damage.clear();
|
||||
surface->commitPendingState(surface->current);
|
||||
return; // no new buffer, but we still have current around and a commit happend, commit current again.
|
||||
}
|
||||
|
||||
if (!surface->pending.buffer && !surface->pending.newBuffer && !surface->current.buffer) {
|
||||
if (!surface->pending.buffer && !PENDING_HAS_NEW_BUFFER && !surface->current.buffer) {
|
||||
surface->commitPendingState(surface->pending); // no pending buffer, no current buffer. probably first commit
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pendingAcquire.expired()) {
|
||||
if (pendingAcquire.timeline()) {
|
||||
surface->pending.buffer->acquire = makeUnique<CDRMSyncPointState>(std::move(pendingAcquire));
|
||||
pendingAcquire = {};
|
||||
}
|
||||
|
||||
if (!pendingRelease.expired()) {
|
||||
if (pendingRelease.timeline()) {
|
||||
surface->pending.buffer->release = makeUnique<CDRMSyncPointState>(std::move(pendingRelease));
|
||||
pendingRelease = {};
|
||||
}
|
||||
@@ -143,7 +111,8 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(UP<CWpLinuxDrmSyncobjSurf
|
||||
const auto& state = pendingStates.emplace_back(makeShared<SSurfaceState>(surface->pending));
|
||||
surface->pending.damage.clear();
|
||||
surface->pending.bufferDamage.clear();
|
||||
surface->pending.newBuffer = false;
|
||||
surface->pending.updated &= ~SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_BUFFER;
|
||||
surface->pending.updated &= ~SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_DAMAGE;
|
||||
surface->pending.buffer.reset();
|
||||
|
||||
state->buffer->buffer->syncReleaser = state->buffer->release->createSyncRelease();
|
||||
@@ -159,8 +128,8 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(UP<CWpLinuxDrmSyncobjSurf
|
||||
|
||||
void CDRMSyncobjSurfaceResource::removeAllWaiters() {
|
||||
for (auto& s : pendingStates) {
|
||||
if (s && s->buffer && s->buffer->acquire && !s->buffer->acquire->expired())
|
||||
s->buffer->acquire->resource()->timeline->removeAllWaiters();
|
||||
if (s && s->buffer && s->buffer->acquire)
|
||||
s->buffer->acquire->timeline()->removeAllWaiters();
|
||||
}
|
||||
|
||||
pendingStates.clear();
|
||||
@@ -171,15 +140,20 @@ CDRMSyncobjSurfaceResource::~CDRMSyncobjSurfaceResource() {
|
||||
}
|
||||
|
||||
bool CDRMSyncobjSurfaceResource::protocolError() {
|
||||
if (!surface->pending.texture) {
|
||||
if (!surface->pending.buffer) {
|
||||
resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_BUFFER, "Missing buffer");
|
||||
surface->pending.rejected = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!!surface->pending.buffer->acquire != !!surface->pending.buffer->release) {
|
||||
resource->error(surface->pending.buffer->acquire ? WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_RELEASE_POINT : WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_ACQUIRE_POINT,
|
||||
"Missing timeline");
|
||||
if (!surface->pending.buffer->acquire || !surface->pending.buffer->acquire->timeline()) {
|
||||
resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_ACQUIRE_POINT, "Missing acquire timeline");
|
||||
surface->pending.rejected = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!surface->pending.buffer->release || !surface->pending.buffer->release->timeline()) {
|
||||
resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_RELEASE_POINT, "Missing release timeline");
|
||||
surface->pending.rejected = true;
|
||||
return true;
|
||||
}
|
||||
@@ -208,7 +182,7 @@ CDRMSyncobjTimelineResource::CDRMSyncobjTimelineResource(UP<CWpLinuxDrmSyncobjTi
|
||||
resource->setOnDestroy([this](CWpLinuxDrmSyncobjTimelineV1* r) { PROTO::sync->destroyResource(this); });
|
||||
resource->setDestroy([this](CWpLinuxDrmSyncobjTimelineV1* r) { PROTO::sync->destroyResource(this); });
|
||||
|
||||
timeline = CSyncTimeline::create(PROTO::sync->drmFD, fd.get());
|
||||
timeline = CSyncTimeline::create(PROTO::sync->drmFD, std::move(fd));
|
||||
|
||||
if (!timeline) {
|
||||
resource->error(WP_LINUX_DRM_SYNCOBJ_MANAGER_V1_ERROR_INVALID_TIMELINE, "Timeline failed importing");
|
||||
|
@@ -17,13 +17,11 @@ struct SSurfaceState;
|
||||
class CDRMSyncPointState {
|
||||
public:
|
||||
CDRMSyncPointState() = default;
|
||||
CDRMSyncPointState(WP<CDRMSyncobjTimelineResource> resource_, uint64_t point_, bool acquirePoint);
|
||||
CDRMSyncPointState(SP<CSyncTimeline> timeline_, uint64_t point_);
|
||||
~CDRMSyncPointState() = default;
|
||||
|
||||
const uint64_t& point();
|
||||
WP<CDRMSyncobjTimelineResource> resource();
|
||||
WP<CSyncTimeline> timeline();
|
||||
bool expired();
|
||||
Hyprutils::Memory::CUniquePointer<CSyncReleaser> createSyncRelease();
|
||||
bool addWaiter(const std::function<void()>& waiter);
|
||||
bool comitted();
|
||||
@@ -31,10 +29,8 @@ class CDRMSyncPointState {
|
||||
void signal();
|
||||
|
||||
private:
|
||||
WP<CDRMSyncobjTimelineResource> m_resource = {};
|
||||
SP<CSyncTimeline> m_timeline = {};
|
||||
uint64_t m_point = 0;
|
||||
WP<CSyncTimeline> m_timeline = {};
|
||||
bool m_acquirePoint = false;
|
||||
bool m_acquireCommitted = false;
|
||||
bool m_releaseTaken = false;
|
||||
};
|
||||
|
@@ -1,5 +1,6 @@
|
||||
#include "FrogColorManagement.hpp"
|
||||
#include "color-management-v1.hpp"
|
||||
#include "macros.hpp"
|
||||
#include "protocols/ColorManagement.hpp"
|
||||
#include "protocols/core/Subcompositor.hpp"
|
||||
#include "protocols/types/ColorManagement.hpp"
|
||||
@@ -13,6 +14,7 @@ static wpColorManagerV1TransferFunction getWPTransferFunction(frogColorManagedSu
|
||||
case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_GAMMA_22: return WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22;
|
||||
case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_ST2084_PQ: return WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ;
|
||||
case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_SCRGB_LINEAR: return WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR;
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,9 +105,10 @@ CFrogColorManagementSurface::CFrogColorManagementSurface(SP<CFrogColorManagedSur
|
||||
surface->colorManagement->m_imageDescription.transferFunction =
|
||||
convertTransferFunction(getWPTransferFunction(FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_ST2084_PQ));
|
||||
break;
|
||||
}; // intended fall through
|
||||
};
|
||||
[[fallthrough]];
|
||||
case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_UNDEFINED:
|
||||
case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_SCRGB_LINEAR: LOGM(TRACE, "FIXME: add tf support for {}", (uint32_t)tf); // intended fall through
|
||||
case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_SCRGB_LINEAR: LOGM(TRACE, "FIXME: add tf support for {}", (uint32_t)tf); [[fallthrough]];
|
||||
case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_SRGB:
|
||||
surface->colorManagement->m_imageDescription.transferFunction = convertTransferFunction(getWPTransferFunction(tf));
|
||||
|
||||
|
@@ -221,6 +221,7 @@ void CLinuxDMABUFParamsResource::create(uint32_t id) {
|
||||
|
||||
if UNLIKELY (!buf->good() || !buf->buffer->success) {
|
||||
resource->sendFailed();
|
||||
PROTO::linuxDma->m_vBuffers.pop_back();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -33,7 +33,6 @@ class CPointerConstraint {
|
||||
private:
|
||||
SP<CZwpLockedPointerV1> resourceL;
|
||||
SP<CZwpConfinedPointerV1> resourceC;
|
||||
wl_client* pClient = nullptr;
|
||||
|
||||
WP<CWLSurface> pHLSurface;
|
||||
|
||||
|
@@ -12,6 +12,7 @@
|
||||
#include "../helpers/Format.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
CScreencopyFrame::~CScreencopyFrame() {
|
||||
if (buffer && buffer->locked())
|
||||
@@ -174,19 +175,15 @@ void CScreencopyFrame::share() {
|
||||
timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
|
||||
if (bufferDMA) {
|
||||
if (!copyDmabuf()) {
|
||||
LOGM(ERR, "Dmabuf copy failed in {:x}", (uintptr_t)this);
|
||||
auto callback = [this, now, weak = self](bool success) {
|
||||
if (weak.expired())
|
||||
return;
|
||||
|
||||
if (!success) {
|
||||
LOGM(ERR, "{} copy failed in {:x}", bufferDMA ? "Dmabuf" : "Shm", (uintptr_t)this);
|
||||
resource->sendFailed();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (!copyShm()) {
|
||||
LOGM(ERR, "Shm copy failed in {:x}", (uintptr_t)this);
|
||||
resource->sendFailed();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
resource->sendFlags((zwlrScreencopyFrameV1Flags)0);
|
||||
if (withDamage) {
|
||||
@@ -197,16 +194,23 @@ void CScreencopyFrame::share() {
|
||||
uint32_t tvSecHi = (sizeof(now.tv_sec) > 4) ? now.tv_sec >> 32 : 0;
|
||||
uint32_t tvSecLo = now.tv_sec & 0xFFFFFFFF;
|
||||
resource->sendReady(tvSecHi, tvSecLo, now.tv_nsec);
|
||||
};
|
||||
|
||||
if (bufferDMA)
|
||||
copyDmabuf(callback);
|
||||
else
|
||||
callback(copyShm());
|
||||
}
|
||||
|
||||
bool CScreencopyFrame::copyDmabuf() {
|
||||
void CScreencopyFrame::copyDmabuf(std::function<void(bool)> callback) {
|
||||
auto TEXTURE = makeShared<CTexture>(pMonitor->output->state->state().buffer);
|
||||
|
||||
CRegion fakeDamage = {0, 0, INT16_MAX, INT16_MAX};
|
||||
|
||||
if (!g_pHyprRenderer->beginRender(pMonitor.lock(), fakeDamage, RENDER_MODE_TO_BUFFER, buffer.lock(), nullptr, true)) {
|
||||
LOGM(ERR, "Can't copy: failed to begin rendering to dma frame");
|
||||
return false;
|
||||
callback(false);
|
||||
return;
|
||||
}
|
||||
|
||||
CBox monbox = CBox{0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y}
|
||||
@@ -221,9 +225,18 @@ bool CScreencopyFrame::copyDmabuf() {
|
||||
g_pHyprOpenGL->m_RenderData.blockScreenShader = true;
|
||||
g_pHyprRenderer->endRender();
|
||||
|
||||
auto explicitOptions = g_pHyprRenderer->getExplicitSyncSettings(pMonitor->output);
|
||||
if (pMonitor->inTimeline && explicitOptions.explicitEnabled) {
|
||||
pMonitor->inTimeline->addWaiter(
|
||||
[callback]() {
|
||||
LOGM(TRACE, "Copied frame via dma with explicit sync");
|
||||
callback(true);
|
||||
},
|
||||
pMonitor->inTimelinePoint, 0);
|
||||
} else {
|
||||
LOGM(TRACE, "Copied frame via dma");
|
||||
|
||||
return true;
|
||||
callback(true);
|
||||
}
|
||||
}
|
||||
|
||||
bool CScreencopyFrame::copyShm() {
|
||||
@@ -278,6 +291,8 @@ bool CScreencopyFrame::copyShm() {
|
||||
const auto drmFmt = NFormatUtils::getPixelFormatFromDRM(shm.format);
|
||||
uint32_t packStride = NFormatUtils::minStride(drmFmt, box.w);
|
||||
|
||||
// This could be optimized by using a pixel buffer object to make this async,
|
||||
// but really clients should just use a dma buffer anyways.
|
||||
if (packStride == (uint32_t)shm.stride) {
|
||||
glReadPixels(0, 0, box.w, box.h, glFormat, PFORMAT->glType, pixelData);
|
||||
} else {
|
||||
|
@@ -73,7 +73,7 @@ class CScreencopyFrame {
|
||||
CBox box = {};
|
||||
|
||||
void copy(CZwlrScreencopyFrameV1* pFrame, wl_resource* buffer);
|
||||
bool copyDmabuf();
|
||||
void copyDmabuf(std::function<void(bool)> callback);
|
||||
bool copyShm();
|
||||
void share();
|
||||
|
||||
|
@@ -52,7 +52,7 @@ CViewportResource::CViewportResource(SP<CWpViewport> resource_, SP<CWLSurfaceRes
|
||||
});
|
||||
|
||||
listeners.surfacePrecommit = surface->events.precommit.registerListener([this](std::any d) {
|
||||
if (!surface || !surface->pending.texture)
|
||||
if (!surface || !surface->pending.buffer)
|
||||
return;
|
||||
|
||||
if (surface->pending.viewport.hasSource) {
|
||||
|
@@ -18,7 +18,6 @@ class CXDGActivationToken {
|
||||
uint32_t serial = 0;
|
||||
std::string appID = "";
|
||||
bool committed = false;
|
||||
bool used = false;
|
||||
|
||||
std::string token = "";
|
||||
|
||||
|
@@ -319,8 +319,11 @@ uint32_t CXDGToplevelResource::setSuspeneded(bool sus) {
|
||||
void CXDGToplevelResource::applyState() {
|
||||
wl_array arr;
|
||||
wl_array_init(&arr);
|
||||
|
||||
if (!pendingApply.states.empty()) {
|
||||
wl_array_add(&arr, pendingApply.states.size() * sizeof(int));
|
||||
memcpy(arr.data, pendingApply.states.data(), pendingApply.states.size() * sizeof(int));
|
||||
}
|
||||
|
||||
resource->sendConfigure(pendingApply.size.x, pendingApply.size.y, &arr);
|
||||
|
||||
@@ -387,7 +390,7 @@ CXDGSurfaceResource::CXDGSurfaceResource(SP<CXdgSurface> resource_, SP<CXDGWMBas
|
||||
if (toplevel)
|
||||
toplevel->current = toplevel->pending;
|
||||
|
||||
if UNLIKELY (initialCommit && surface->pending.texture) {
|
||||
if UNLIKELY (initialCommit && surface->pending.buffer) {
|
||||
resource->error(-1, "Buffer attached before initial commit");
|
||||
return;
|
||||
}
|
||||
|
@@ -23,6 +23,7 @@ static wpColorManagerV1TransferFunction getWPTransferFunction(xxColorManagerV4Tr
|
||||
case XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ: return WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ;
|
||||
case XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST428: return WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST428;
|
||||
case XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_HLG: return WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_HLG;
|
||||
default: UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -12,6 +12,8 @@
|
||||
#include "../DRMSyncobj.hpp"
|
||||
#include "../../render/Renderer.hpp"
|
||||
#include "config/ConfigValue.hpp"
|
||||
#include "protocols/types/SurfaceRole.hpp"
|
||||
#include "render/Texture.hpp"
|
||||
#include <cstring>
|
||||
|
||||
class CDefaultSurfaceRole : public ISurfaceRole {
|
||||
@@ -70,11 +72,12 @@ CWLSurfaceResource::CWLSurfaceResource(SP<CWlSurface> resource_) : resource(reso
|
||||
|
||||
resource->setAttach([this](CWlSurface* r, wl_resource* buffer, int32_t x, int32_t y) {
|
||||
pending.offset = {x, y};
|
||||
pending.newBuffer = true;
|
||||
pending.updated |= SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_BUFFER | SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_OFFSET;
|
||||
|
||||
if (!buffer) {
|
||||
pending.buffer.reset();
|
||||
pending.texture.reset();
|
||||
pending.bufferSize = Vector2D{};
|
||||
} else {
|
||||
auto res = CWLBufferResource::fromResource(buffer);
|
||||
pending.buffer = res && res->buffer ? makeShared<CHLBufferReference>(res->buffer.lock(), self.lock()) : nullptr;
|
||||
@@ -83,18 +86,15 @@ CWLSurfaceResource::CWLSurfaceResource(SP<CWlSurface> resource_) : resource(reso
|
||||
pending.bufferSize = res && res->buffer ? res->buffer->size : Vector2D{};
|
||||
}
|
||||
|
||||
Vector2D oldBufSize = current.buffer ? current.bufferSize : Vector2D{};
|
||||
Vector2D newBufSize = pending.buffer ? pending.bufferSize : Vector2D{};
|
||||
|
||||
if (oldBufSize != newBufSize || current.buffer != pending.buffer)
|
||||
if (pending.bufferSize != current.bufferSize)
|
||||
pending.bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}};
|
||||
});
|
||||
|
||||
resource->setCommit([this](CWlSurface* r) {
|
||||
if (pending.texture)
|
||||
if (pending.buffer)
|
||||
pending.bufferDamage.intersect(CBox{{}, pending.bufferSize});
|
||||
|
||||
if (!pending.texture)
|
||||
if (!pending.buffer)
|
||||
pending.size = {};
|
||||
else if (pending.viewport.hasDestination)
|
||||
pending.size = pending.viewport.destination;
|
||||
@@ -117,11 +117,29 @@ CWLSurfaceResource::CWLSurfaceResource(SP<CWlSurface> resource_) : resource(reso
|
||||
commitPendingState(pending);
|
||||
});
|
||||
|
||||
resource->setDamage([this](CWlSurface* r, int32_t x, int32_t y, int32_t w, int32_t h) { pending.damage.add(CBox{x, y, w, h}); });
|
||||
resource->setDamageBuffer([this](CWlSurface* r, int32_t x, int32_t y, int32_t w, int32_t h) { pending.bufferDamage.add(CBox{x, y, w, h}); });
|
||||
resource->setDamage([this](CWlSurface* r, int32_t x, int32_t y, int32_t w, int32_t h) {
|
||||
pending.updated |= SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_DAMAGE;
|
||||
pending.damage.add(CBox{x, y, w, h});
|
||||
});
|
||||
resource->setDamageBuffer([this](CWlSurface* r, int32_t x, int32_t y, int32_t w, int32_t h) {
|
||||
pending.updated |= SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_DAMAGE;
|
||||
pending.bufferDamage.add(CBox{x, y, w, h});
|
||||
});
|
||||
|
||||
resource->setSetBufferScale([this](CWlSurface* r, int32_t scale) { pending.scale = scale; });
|
||||
resource->setSetBufferTransform([this](CWlSurface* r, uint32_t tr) { pending.transform = (wl_output_transform)tr; });
|
||||
resource->setSetBufferScale([this](CWlSurface* r, int32_t scale) {
|
||||
if (scale == pending.scale)
|
||||
return;
|
||||
pending.updated |= SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_SCALE | SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_DAMAGE;
|
||||
pending.scale = scale;
|
||||
pending.bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}};
|
||||
});
|
||||
resource->setSetBufferTransform([this](CWlSurface* r, uint32_t tr) {
|
||||
if (tr == pending.transform)
|
||||
return;
|
||||
pending.updated |= SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_TRANSFORM | SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_DAMAGE;
|
||||
pending.transform = (wl_output_transform)tr;
|
||||
pending.bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}};
|
||||
});
|
||||
|
||||
resource->setSetInputRegion([this](CWlSurface* r, wl_resource* region) {
|
||||
if (!region) {
|
||||
@@ -129,6 +147,8 @@ CWLSurfaceResource::CWLSurfaceResource(SP<CWlSurface> resource_) : resource(reso
|
||||
return;
|
||||
}
|
||||
|
||||
pending.updated |= SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_INPUT;
|
||||
|
||||
auto RG = CWLRegionResource::fromResource(region);
|
||||
pending.input = RG->region;
|
||||
});
|
||||
@@ -139,13 +159,18 @@ CWLSurfaceResource::CWLSurfaceResource(SP<CWlSurface> resource_) : resource(reso
|
||||
return;
|
||||
}
|
||||
|
||||
pending.updated |= SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_OPAQUE;
|
||||
|
||||
auto RG = CWLRegionResource::fromResource(region);
|
||||
pending.opaque = RG->region;
|
||||
});
|
||||
|
||||
resource->setFrame([this](CWlSurface* r, uint32_t id) { callbacks.emplace_back(makeShared<CWLCallbackResource>(makeShared<CWlCallback>(pClient, 1, id))); });
|
||||
|
||||
resource->setOffset([this](CWlSurface* r, int32_t x, int32_t y) { pending.offset = {x, y}; });
|
||||
resource->setOffset([this](CWlSurface* r, int32_t x, int32_t y) {
|
||||
pending.updated |= SSurfaceState::eUpdatedProperties::SURFACE_UPDATED_OFFSET;
|
||||
pending.offset = {x, y};
|
||||
});
|
||||
}
|
||||
|
||||
CWLSurfaceResource::~CWLSurfaceResource() {
|
||||
@@ -399,58 +424,24 @@ CBox CWLSurfaceResource::extends() {
|
||||
return full.getExtents();
|
||||
}
|
||||
|
||||
Vector2D CWLSurfaceResource::sourceSize() {
|
||||
if UNLIKELY (!current.texture)
|
||||
return {};
|
||||
|
||||
if UNLIKELY (current.viewport.hasSource)
|
||||
return current.viewport.source.size();
|
||||
|
||||
Vector2D trc = current.transform % 2 == 1 ? Vector2D{current.bufferSize.y, current.bufferSize.x} : current.bufferSize;
|
||||
return trc / current.scale;
|
||||
}
|
||||
|
||||
CRegion CWLSurfaceResource::accumulateCurrentBufferDamage() {
|
||||
if UNLIKELY (!current.texture)
|
||||
return {};
|
||||
|
||||
CRegion surfaceDamage = current.damage;
|
||||
if (current.viewport.hasDestination) {
|
||||
Vector2D scale = sourceSize() / current.viewport.destination;
|
||||
surfaceDamage.scale(scale);
|
||||
}
|
||||
|
||||
if (current.viewport.hasSource)
|
||||
surfaceDamage.translate(current.viewport.source.pos());
|
||||
|
||||
Vector2D trc = current.transform % 2 == 1 ? Vector2D{current.bufferSize.y, current.bufferSize.x} : current.bufferSize;
|
||||
|
||||
return surfaceDamage.scale(current.scale).transform(wlTransformToHyprutils(invertTransform(current.transform)), trc.x, trc.y).add(current.bufferDamage);
|
||||
}
|
||||
|
||||
void CWLSurfaceResource::commitPendingState(SSurfaceState& state) {
|
||||
if (state.newBuffer) {
|
||||
state.newBuffer = false;
|
||||
current = state;
|
||||
state.damage.clear();
|
||||
state.bufferDamage.clear();
|
||||
state.buffer.reset();
|
||||
auto lastTexture = current.texture;
|
||||
current.updateFrom(state);
|
||||
state.updated = 0;
|
||||
|
||||
if (current.buffer) {
|
||||
if (current.buffer->buffer->isSynchronous())
|
||||
current.updateSynchronousTexture(lastTexture);
|
||||
|
||||
// if the surface is a cursor, update the shm buffer
|
||||
// TODO: don't update the entire texture
|
||||
if (role->role() == SURFACE_ROLE_CURSOR)
|
||||
updateCursorShm(current.accumulateBufferDamage());
|
||||
}
|
||||
|
||||
if (current.texture)
|
||||
current.texture->m_eTransform = wlTransformToHyprutils(current.transform);
|
||||
|
||||
if (current.buffer && current.buffer->buffer) {
|
||||
const auto DAMAGE = accumulateCurrentBufferDamage();
|
||||
current.buffer->buffer->update(DAMAGE);
|
||||
|
||||
// if the surface is a cursor, update the shm buffer
|
||||
// TODO: don't update the entire texture
|
||||
if (role->role() == SURFACE_ROLE_CURSOR && !DAMAGE.empty())
|
||||
updateCursorShm(DAMAGE);
|
||||
}
|
||||
|
||||
// TODO: we should _accumulate_ and not replace above if sync
|
||||
if (role->role() == SURFACE_ROLE_SUBSURFACE) {
|
||||
auto subsurface = ((CSubsurfaceRole*)role.get())->subsurface.lock();
|
||||
if (subsurface->sync)
|
||||
@@ -471,16 +462,18 @@ void CWLSurfaceResource::commitPendingState(SSurfaceState& state) {
|
||||
nullptr);
|
||||
}
|
||||
|
||||
// release the buffer if it's synchronous as update() has done everything thats needed
|
||||
// release the buffer if it's synchronous (SHM) as update() has done everything thats needed
|
||||
// so we can let the app know we're done.
|
||||
// if (!syncobj && current.buffer && current.buffer->buffer && current.buffer->buffer->isSynchronous()) {
|
||||
// dropCurrentBuffer(); // lets not drop it at all, it will get dropped on next commit if a new buffer arrives.
|
||||
// solves flickering on nonsyncobj apps on explicit sync.
|
||||
// }
|
||||
// if it doesn't have a role, we can't release it yet, in case it gets turned into a cursor.
|
||||
if (current.buffer && current.buffer->buffer && current.buffer->buffer->isSynchronous() && role->role() != SURFACE_ROLE_UNASSIGNED)
|
||||
dropCurrentBuffer();
|
||||
}
|
||||
|
||||
void CWLSurfaceResource::updateCursorShm(CRegion damage) {
|
||||
auto buf = current.buffer ? current.buffer->buffer : WP<IHLBuffer>{};
|
||||
if (damage.empty())
|
||||
return;
|
||||
|
||||
auto buf = current.buffer ? current.buffer->buffer : SP<IHLBuffer>{};
|
||||
|
||||
if UNLIKELY (!buf)
|
||||
return;
|
||||
@@ -524,7 +517,7 @@ void CWLSurfaceResource::presentFeedback(timespec* when, PHLMONITOR pMonitor, bo
|
||||
FEEDBACK->presented();
|
||||
PROTO::presentation->queueData(FEEDBACK);
|
||||
|
||||
if (!pMonitor || !pMonitor->outTimeline || !syncobj)
|
||||
if (!pMonitor || !pMonitor->inTimeline || !syncobj)
|
||||
return;
|
||||
|
||||
// attach explicit sync
|
||||
|
@@ -11,6 +11,7 @@
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include "../WaylandProtocol.hpp"
|
||||
#include "../../render/Texture.hpp"
|
||||
#include "wayland.hpp"
|
||||
#include "../../helpers/signal/Signal.hpp"
|
||||
#include "../../helpers/math/Math.hpp"
|
||||
@@ -75,7 +76,6 @@ class CWLSurfaceResource {
|
||||
SP<CWlSurface> getResource();
|
||||
CBox extends();
|
||||
void resetRole();
|
||||
Vector2D sourceSize();
|
||||
|
||||
struct {
|
||||
CSignal precommit; // before commit
|
||||
@@ -102,7 +102,6 @@ class CWLSurfaceResource {
|
||||
|
||||
void breadthfirst(std::function<void(SP<CWLSurfaceResource>, const Vector2D&, void*)> fn, void* data);
|
||||
SP<CWLSurfaceResource> findFirstPreorder(std::function<bool(SP<CWLSurfaceResource>)> fn);
|
||||
CRegion accumulateCurrentBufferDamage();
|
||||
void presentFeedback(timespec* when, PHLMONITOR pMonitor, bool discarded = false);
|
||||
void commitPendingState(SSurfaceState& state);
|
||||
|
||||
|
@@ -50,7 +50,6 @@ class CWLDataOfferResource : public IDataOffer {
|
||||
|
||||
private:
|
||||
SP<CWlDataOffer> resource;
|
||||
wl_client* pClient = nullptr;
|
||||
|
||||
friend class CWLDataDeviceResource;
|
||||
};
|
||||
@@ -89,7 +88,6 @@ class CWLDataSourceResource : public IDataSource {
|
||||
|
||||
private:
|
||||
SP<CWlDataSource> resource;
|
||||
wl_client* pClient = nullptr;
|
||||
|
||||
friend class CWLDataDeviceProtocol;
|
||||
};
|
||||
|
@@ -22,7 +22,7 @@ bool CWLTouchResource::good() {
|
||||
}
|
||||
|
||||
void CWLTouchResource::sendDown(SP<CWLSurfaceResource> surface, uint32_t timeMs, int32_t id, const Vector2D& local) {
|
||||
if (!owner)
|
||||
if (!owner || !surface || !surface->getResource()->resource())
|
||||
return;
|
||||
|
||||
if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_TOUCH))
|
||||
@@ -124,7 +124,7 @@ CWLPointerResource::CWLPointerResource(SP<CWlPointer> resource_, SP<CWLSeatResou
|
||||
return;
|
||||
}
|
||||
|
||||
if (surfResource) {
|
||||
if (surfResource && surfResource->role->role() != SURFACE_ROLE_CURSOR) {
|
||||
surfResource->role = makeShared<CCursorSurfaceRole>();
|
||||
surfResource->updateCursorShm();
|
||||
}
|
||||
@@ -145,7 +145,7 @@ bool CWLPointerResource::good() {
|
||||
}
|
||||
|
||||
void CWLPointerResource::sendEnter(SP<CWLSurfaceResource> surface, const Vector2D& local) {
|
||||
if (!owner || currentSurface == surface)
|
||||
if (!owner || currentSurface == surface || !surface->getResource()->resource())
|
||||
return;
|
||||
|
||||
if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_POINTER))
|
||||
@@ -165,7 +165,7 @@ void CWLPointerResource::sendEnter(SP<CWLSurfaceResource> surface, const Vector2
|
||||
}
|
||||
|
||||
void CWLPointerResource::sendLeave() {
|
||||
if (!owner || !currentSurface)
|
||||
if (!owner || !currentSurface || !currentSurface->getResource()->resource())
|
||||
return;
|
||||
|
||||
if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_POINTER))
|
||||
@@ -336,7 +336,7 @@ void CWLKeyboardResource::sendKeymap(SP<IKeyboard> keyboard) {
|
||||
}
|
||||
|
||||
void CWLKeyboardResource::sendEnter(SP<CWLSurfaceResource> surface) {
|
||||
if (!owner || currentSurface == surface)
|
||||
if (!owner || currentSurface == surface || !surface->getResource()->resource())
|
||||
return;
|
||||
|
||||
if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_KEYBOARD))
|
||||
@@ -361,7 +361,7 @@ void CWLKeyboardResource::sendEnter(SP<CWLSurfaceResource> surface) {
|
||||
}
|
||||
|
||||
void CWLKeyboardResource::sendLeave() {
|
||||
if (!owner || !currentSurface)
|
||||
if (!owner || !currentSurface || !currentSurface->getResource()->resource())
|
||||
return;
|
||||
|
||||
if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_KEYBOARD))
|
||||
|
@@ -22,19 +22,12 @@ CWLSHMBuffer::CWLSHMBuffer(SP<CWLSHMPoolResource> pool_, uint32_t id, int32_t of
|
||||
offset = offset_;
|
||||
opaque = NFormatUtils::isFormatOpaque(NFormatUtils::shmToDRM(fmt_));
|
||||
|
||||
texture = makeShared<CTexture>(NFormatUtils::shmToDRM(fmt), (uint8_t*)pool->data + offset, stride, size_);
|
||||
|
||||
resource = CWLBufferResource::create(makeShared<CWlBuffer>(pool_->resource->client(), 1, id));
|
||||
|
||||
listeners.bufferResourceDestroy = events.destroy.registerListener([this](std::any d) {
|
||||
listeners.bufferResourceDestroy.reset();
|
||||
PROTO::shm->destroyResource(this);
|
||||
});
|
||||
|
||||
success = texture->m_iTexID;
|
||||
|
||||
if UNLIKELY (!success)
|
||||
Debug::log(ERR, "Failed creating a shm texture: null texture id");
|
||||
}
|
||||
|
||||
CWLSHMBuffer::~CWLSHMBuffer() {
|
||||
@@ -74,11 +67,11 @@ void CWLSHMBuffer::endDataPtr() {
|
||||
}
|
||||
|
||||
bool CWLSHMBuffer::good() {
|
||||
return success;
|
||||
return true;
|
||||
}
|
||||
|
||||
void CWLSHMBuffer::update(const CRegion& damage) {
|
||||
texture->update(NFormatUtils::shmToDRM(fmt), (uint8_t*)pool->data + offset, stride, damage);
|
||||
;
|
||||
}
|
||||
|
||||
CSHMPool::CSHMPool(CFileDescriptor fd_, size_t size_) : fd(std::move(fd_)), size(size_), data(mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd.get(), 0)) {
|
||||
|
@@ -50,8 +50,6 @@ class CWLSHMBuffer : public IHLBuffer {
|
||||
SP<CSHMPool> pool;
|
||||
|
||||
private:
|
||||
bool success = false;
|
||||
|
||||
struct {
|
||||
CHyprSignalListener bufferResourceDestroy;
|
||||
} listeners;
|
||||
|
@@ -45,7 +45,7 @@ class CHLBufferReference {
|
||||
CHLBufferReference(SP<IHLBuffer> buffer, SP<CWLSurfaceResource> surface);
|
||||
~CHLBufferReference();
|
||||
|
||||
WP<IHLBuffer> buffer;
|
||||
SP<IHLBuffer> buffer;
|
||||
UP<CDRMSyncPointState> acquire;
|
||||
UP<CDRMSyncPointState> release;
|
||||
|
||||
|
93
src/protocols/types/SurfaceState.cpp
Normal file
93
src/protocols/types/SurfaceState.cpp
Normal file
@@ -0,0 +1,93 @@
|
||||
#include "SurfaceState.hpp"
|
||||
#include "helpers/Format.hpp"
|
||||
#include "protocols/types/Buffer.hpp"
|
||||
#include "render/Texture.hpp"
|
||||
|
||||
Vector2D SSurfaceState::sourceSize() {
|
||||
if UNLIKELY (!texture)
|
||||
return {};
|
||||
|
||||
if UNLIKELY (viewport.hasSource)
|
||||
return viewport.source.size();
|
||||
|
||||
Vector2D trc = transform % 2 == 1 ? Vector2D{bufferSize.y, bufferSize.x} : bufferSize;
|
||||
return trc / scale;
|
||||
}
|
||||
|
||||
CRegion SSurfaceState::accumulateBufferDamage() {
|
||||
if (damage.empty())
|
||||
return bufferDamage;
|
||||
|
||||
CRegion surfaceDamage = damage;
|
||||
if (viewport.hasDestination) {
|
||||
Vector2D scale = sourceSize() / viewport.destination;
|
||||
surfaceDamage.scale(scale);
|
||||
}
|
||||
|
||||
if (viewport.hasSource)
|
||||
surfaceDamage.translate(viewport.source.pos());
|
||||
|
||||
Vector2D trc = transform % 2 == 1 ? Vector2D{bufferSize.y, bufferSize.x} : bufferSize;
|
||||
|
||||
bufferDamage = surfaceDamage.scale(scale).transform(wlTransformToHyprutils(invertTransform(transform)), trc.x, trc.y).add(bufferDamage);
|
||||
damage.clear();
|
||||
return bufferDamage;
|
||||
}
|
||||
|
||||
void SSurfaceState::updateSynchronousTexture(SP<CTexture> lastTexture) {
|
||||
auto [dataPtr, fmt, size] = buffer->buffer->beginDataPtr(0);
|
||||
if (dataPtr) {
|
||||
auto drmFmt = NFormatUtils::shmToDRM(fmt);
|
||||
auto stride = bufferSize.y ? size / bufferSize.y : 0;
|
||||
if (lastTexture && lastTexture->m_isSynchronous && lastTexture->m_vSize == bufferSize) {
|
||||
texture = lastTexture;
|
||||
texture->update(drmFmt, dataPtr, stride, accumulateBufferDamage());
|
||||
} else
|
||||
texture = makeShared<CTexture>(drmFmt, dataPtr, stride, bufferSize);
|
||||
}
|
||||
buffer->buffer->endDataPtr();
|
||||
}
|
||||
|
||||
void SSurfaceState::reset() {
|
||||
damage.clear();
|
||||
bufferDamage.clear();
|
||||
transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
scale = 1;
|
||||
offset = {};
|
||||
size = {};
|
||||
}
|
||||
|
||||
void SSurfaceState::updateFrom(SSurfaceState& ref) {
|
||||
updated = ref.updated;
|
||||
|
||||
if (ref.updated & SURFACE_UPDATED_BUFFER) {
|
||||
ref.updated &= ~SURFACE_UPDATED_BUFFER;
|
||||
*this = ref;
|
||||
ref.damage.clear();
|
||||
ref.bufferDamage.clear();
|
||||
ref.buffer.reset();
|
||||
} else {
|
||||
if (ref.updated & SURFACE_UPDATED_DAMAGE) {
|
||||
damage = ref.damage;
|
||||
bufferDamage = ref.bufferDamage;
|
||||
}
|
||||
|
||||
if (ref.updated & SURFACE_UPDATED_INPUT)
|
||||
input = ref.input;
|
||||
|
||||
if (ref.updated & SURFACE_UPDATED_OPAQUE)
|
||||
opaque = ref.opaque;
|
||||
|
||||
if (ref.updated & SURFACE_UPDATED_OFFSET)
|
||||
offset = ref.offset;
|
||||
|
||||
if (ref.updated & SURFACE_UPDATED_SCALE)
|
||||
scale = ref.scale;
|
||||
|
||||
if (ref.updated & SURFACE_UPDATED_VIEWPORT)
|
||||
viewport = ref.viewport;
|
||||
|
||||
if (ref.updated & SURFACE_UPDATED_TRANSFORM)
|
||||
transform = ref.transform;
|
||||
}
|
||||
}
|
@@ -7,6 +7,17 @@ class CHLBufferReference;
|
||||
class CTexture;
|
||||
|
||||
struct SSurfaceState {
|
||||
enum eUpdatedProperties : uint8_t {
|
||||
SURFACE_UPDATED_OPAQUE = 1 << 0,
|
||||
SURFACE_UPDATED_INPUT = 1 << 1,
|
||||
SURFACE_UPDATED_DAMAGE = 1 << 2,
|
||||
SURFACE_UPDATED_SCALE = 1 << 3,
|
||||
SURFACE_UPDATED_BUFFER = 1 << 4,
|
||||
SURFACE_UPDATED_OFFSET = 1 << 5,
|
||||
SURFACE_UPDATED_VIEWPORT = 1 << 6,
|
||||
SURFACE_UPDATED_TRANSFORM = 1 << 7,
|
||||
};
|
||||
|
||||
CRegion opaque, input = CBox{{}, {INT32_MAX, INT32_MAX}}, damage, bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}} /* initial damage */;
|
||||
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
int scale = 1;
|
||||
@@ -21,15 +32,14 @@ struct SSurfaceState {
|
||||
CBox source;
|
||||
} viewport;
|
||||
bool rejected = false;
|
||||
bool newBuffer = false;
|
||||
uint8_t updated = 0; // eUpdatedProperties. Stores what the last update changed
|
||||
|
||||
//
|
||||
void reset() {
|
||||
damage.clear();
|
||||
bufferDamage.clear();
|
||||
transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
scale = 1;
|
||||
offset = {};
|
||||
size = {};
|
||||
}
|
||||
Vector2D sourceSize();
|
||||
// Translates damage into bufferDamage, clearing damage and returning the updated bufferDamage
|
||||
CRegion accumulateBufferDamage();
|
||||
void updateSynchronousTexture(SP<CTexture> lastTexture);
|
||||
void reset();
|
||||
// updates this state from a reference state. Mutates the reference state. If a new buffer is committed,
|
||||
// reference state gets its damage and buffer cleared.
|
||||
void updateFrom(SSurfaceState& ref);
|
||||
};
|
||||
|
@@ -158,6 +158,7 @@ void CHyprOpenGLImpl::initEGL(bool gbm) {
|
||||
#else
|
||||
attrs.push_back(EGL_CONTEXT_CLIENT_VERSION);
|
||||
attrs.push_back(2);
|
||||
m_eglContextVersion = EGL_CONTEXT_GLES_2_0;
|
||||
#endif
|
||||
|
||||
attrs.push_back(EGL_NONE);
|
||||
@@ -177,6 +178,7 @@ void CHyprOpenGLImpl::initEGL(bool gbm) {
|
||||
attrs.push_back(EGL_NONE);
|
||||
|
||||
m_pEglContext = eglCreateContext(m_pEglDisplay, EGL_NO_CONFIG_KHR, EGL_NO_CONTEXT, attrs.data());
|
||||
m_eglContextVersion = EGL_CONTEXT_GLES_3_0;
|
||||
|
||||
if (m_pEglContext == EGL_NO_CONTEXT)
|
||||
RASSERT(false, "EGL: failed to create a context with either GLES3.2 or 3.0");
|
||||
@@ -564,7 +566,7 @@ EGLImageKHR CHyprOpenGLImpl::createEGLImage(const Aquamarine::SDMABUFAttrs& attr
|
||||
return image;
|
||||
}
|
||||
|
||||
void CHyprOpenGLImpl::logShaderError(const GLuint& shader, bool program) {
|
||||
void CHyprOpenGLImpl::logShaderError(const GLuint& shader, bool program, bool silent) {
|
||||
GLint maxLength = 0;
|
||||
if (program)
|
||||
glGetProgramiv(shader, GL_INFO_LOG_LENGTH, &maxLength);
|
||||
@@ -582,18 +584,19 @@ void CHyprOpenGLImpl::logShaderError(const GLuint& shader, bool program) {
|
||||
|
||||
Debug::log(ERR, "Failed to link shader: {}", FULLERROR);
|
||||
|
||||
if (!silent)
|
||||
g_pConfigManager->addParseError(FULLERROR);
|
||||
}
|
||||
|
||||
GLuint CHyprOpenGLImpl::createProgram(const std::string& vert, const std::string& frag, bool dynamic) {
|
||||
auto vertCompiled = compileShader(GL_VERTEX_SHADER, vert, dynamic);
|
||||
GLuint CHyprOpenGLImpl::createProgram(const std::string& vert, const std::string& frag, bool dynamic, bool silent) {
|
||||
auto vertCompiled = compileShader(GL_VERTEX_SHADER, vert, dynamic, silent);
|
||||
if (dynamic) {
|
||||
if (vertCompiled == 0)
|
||||
return 0;
|
||||
} else
|
||||
RASSERT(vertCompiled, "Compiling shader failed. VERTEX nullptr! Shader source:\n\n{}", vert);
|
||||
|
||||
auto fragCompiled = compileShader(GL_FRAGMENT_SHADER, frag, dynamic);
|
||||
auto fragCompiled = compileShader(GL_FRAGMENT_SHADER, frag, dynamic, silent);
|
||||
if (dynamic) {
|
||||
if (fragCompiled == 0)
|
||||
return 0;
|
||||
@@ -614,7 +617,7 @@ GLuint CHyprOpenGLImpl::createProgram(const std::string& vert, const std::string
|
||||
glGetProgramiv(prog, GL_LINK_STATUS, &ok);
|
||||
if (dynamic) {
|
||||
if (ok == GL_FALSE) {
|
||||
logShaderError(prog, true);
|
||||
logShaderError(prog, true, silent);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
@@ -626,7 +629,7 @@ GLuint CHyprOpenGLImpl::createProgram(const std::string& vert, const std::string
|
||||
return prog;
|
||||
}
|
||||
|
||||
GLuint CHyprOpenGLImpl::compileShader(const GLuint& type, std::string src, bool dynamic) {
|
||||
GLuint CHyprOpenGLImpl::compileShader(const GLuint& type, std::string src, bool dynamic, bool silent) {
|
||||
auto shader = glCreateShader(type);
|
||||
|
||||
auto shaderSource = src.c_str();
|
||||
@@ -639,7 +642,7 @@ GLuint CHyprOpenGLImpl::compileShader(const GLuint& type, std::string src, bool
|
||||
|
||||
if (dynamic) {
|
||||
if (ok == GL_FALSE) {
|
||||
logShaderError(shader, false);
|
||||
logShaderError(shader, false, silent);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
@@ -868,14 +871,14 @@ void CHyprOpenGLImpl::initShaders() {
|
||||
m_RenderData.pCurrentMonData->m_shQUAD.roundingPower = glGetUniformLocation(prog, "roundingPower");
|
||||
|
||||
#ifndef GLES2
|
||||
prog = createProgram(TEXVERTSRC320, TEXFRAGSRCCM, true);
|
||||
if (m_eglContextVersion == EGL_CONTEXT_GLES_3_2 /* GLES2 and GLES3.0 can't compile the CM shader */) {
|
||||
prog = createProgram(TEXVERTSRC320, TEXFRAGSRCCM, true, true);
|
||||
m_bCMSupported = prog > 0;
|
||||
if (m_bCMSupported) {
|
||||
m_RenderData.pCurrentMonData->m_shCM.program = prog;
|
||||
m_RenderData.pCurrentMonData->m_shCM.proj = glGetUniformLocation(prog, "proj");
|
||||
m_RenderData.pCurrentMonData->m_shCM.tex = glGetUniformLocation(prog, "tex");
|
||||
m_RenderData.pCurrentMonData->m_shCM.texType = glGetUniformLocation(prog, "texType");
|
||||
m_RenderData.pCurrentMonData->m_shCM.skipCM = glGetUniformLocation(prog, "skipCM");
|
||||
m_RenderData.pCurrentMonData->m_shCM.sourceTF = glGetUniformLocation(prog, "sourceTF");
|
||||
m_RenderData.pCurrentMonData->m_shCM.targetTF = glGetUniformLocation(prog, "targetTF");
|
||||
m_RenderData.pCurrentMonData->m_shCM.sourcePrimaries = glGetUniformLocation(prog, "sourcePrimaries");
|
||||
@@ -905,6 +908,7 @@ void CHyprOpenGLImpl::initShaders() {
|
||||
ERR,
|
||||
"WARNING: CM Shader failed compiling, color management will not work. It's likely because your GPU is an old piece of garbage, don't file bug reports about this!");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
prog = createProgram(TEXVERTSRC, TEXFRAGSRCRGBA);
|
||||
@@ -1321,8 +1325,9 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP<CTexture> tex, const CB
|
||||
CBox newBox = box;
|
||||
m_RenderData.renderModif.applyToBox(newBox);
|
||||
|
||||
static auto PDT = CConfigValue<Hyprlang::INT>("debug:damage_tracking");
|
||||
static auto PPASS = CConfigValue<Hyprlang::INT>("render:cm_fs_passthrough");
|
||||
static const auto PDT = CConfigValue<Hyprlang::INT>("debug:damage_tracking");
|
||||
static const auto PPASS = CConfigValue<Hyprlang::INT>("render:cm_fs_passthrough");
|
||||
static const auto PENABLECM = CConfigValue<Hyprlang::INT>("render:cm_enabled");
|
||||
|
||||
// get the needed transform for this texture
|
||||
const bool TRANSFORMS_MATCH = wlTransformToHyprutils(m_RenderData.pMonitor->transform) == tex->m_eTransform; // FIXME: combine them properly!!!
|
||||
@@ -1352,11 +1357,6 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP<CTexture> tex, const CB
|
||||
shader = &m_RenderData.pCurrentMonData->m_shPASSTHRURGBA;
|
||||
usingFinalShader = true;
|
||||
} else {
|
||||
#ifndef GLES2
|
||||
if (m_bCMSupported)
|
||||
shader = &m_RenderData.pCurrentMonData->m_shCM;
|
||||
else
|
||||
#endif
|
||||
switch (tex->m_iType) {
|
||||
case TEXTURE_RGBA: shader = &m_RenderData.pCurrentMonData->m_shRGBA; break;
|
||||
case TEXTURE_RGBX: shader = &m_RenderData.pCurrentMonData->m_shRGBX; break;
|
||||
@@ -1367,12 +1367,8 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP<CTexture> tex, const CB
|
||||
}
|
||||
}
|
||||
|
||||
if (m_RenderData.currentWindow && m_RenderData.currentWindow->m_sWindowData.RGBX.valueOrDefault()) {
|
||||
#ifdef GLES2
|
||||
shader = &m_RenderData.pCurrentMonData->m_shRGBX;
|
||||
#endif
|
||||
if (m_RenderData.currentWindow && m_RenderData.currentWindow->m_sWindowData.RGBX.valueOrDefault())
|
||||
texType = TEXTURE_RGBX;
|
||||
}
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(tex->m_iTarget, tex->m_iTexID);
|
||||
@@ -1388,24 +1384,26 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP<CTexture> tex, const CB
|
||||
glTexParameteri(tex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
}
|
||||
|
||||
const auto imageDescription =
|
||||
m_RenderData.surface.valid() && m_RenderData.surface->colorManagement.valid() ? m_RenderData.surface->colorManagement->imageDescription() : SImageDescription{};
|
||||
|
||||
const bool skipCM = !*PENABLECM /* CM disabled by the user */
|
||||
|| !m_RenderData.surface /* FIXME unknown texture settings should be treated as sRGB and go through CM if monitor isn't in sRGB mode */
|
||||
|| !m_bCMSupported /* CM unsupported - hw failed to compile the shader probably */
|
||||
|| (imageDescription == m_RenderData.pMonitor->imageDescription) /* Source and target have the same image description */
|
||||
|| ((*PPASS == 1 || (*PPASS == 2 && imageDescription.transferFunction == CM_TRANSFER_FUNCTION_ST2084_PQ)) && m_RenderData.pMonitor->activeWorkspace &&
|
||||
m_RenderData.pMonitor->activeWorkspace->m_bHasFullscreenWindow &&
|
||||
m_RenderData.pMonitor->activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN) /* Fullscreen window with pass cm enabled */;
|
||||
|
||||
glUseProgram(shader->program);
|
||||
|
||||
#ifndef GLES2
|
||||
glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix.getMatrix().data());
|
||||
#else
|
||||
glMatrix.transpose();
|
||||
glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix.getMatrix().data());
|
||||
#endif
|
||||
glUniform1i(shader->tex, 0);
|
||||
#ifndef GLES2
|
||||
if (shader == &m_RenderData.pCurrentMonData->m_shCM && !usingFinalShader && (texType == TEXTURE_RGBA || texType == TEXTURE_RGBX)) {
|
||||
const bool skipCM = *PPASS && m_RenderData.pMonitor->activeWorkspace && m_RenderData.pMonitor->activeWorkspace->m_bHasFullscreenWindow &&
|
||||
m_RenderData.pMonitor->activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN;
|
||||
if (!skipCM && !usingFinalShader && (texType == TEXTURE_RGBA || texType == TEXTURE_RGBX)) {
|
||||
shader = &m_RenderData.pCurrentMonData->m_shCM;
|
||||
glUseProgram(shader->program);
|
||||
glUniform1i(shader->texType, texType);
|
||||
glUniform1i(shader->skipCM, skipCM);
|
||||
if (!skipCM) {
|
||||
const auto imageDescription =
|
||||
m_RenderData.surface.valid() && m_RenderData.surface->colorManagement.valid() ? m_RenderData.surface->colorManagement->imageDescription() : SImageDescription{};
|
||||
m_RenderData.surface && m_RenderData.surface->colorManagement ? m_RenderData.surface->colorManagement->imageDescription() : SImageDescription{};
|
||||
glUniform1i(shader->sourceTF, imageDescription.transferFunction);
|
||||
glUniform1i(shader->targetTF, m_RenderData.pMonitor->imageDescription.transferFunction);
|
||||
const auto sourcePrimaries =
|
||||
@@ -1438,9 +1436,16 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP<CTexture> tex, const CB
|
||||
m_RenderData.pMonitor->sdrBrightness :
|
||||
1.0f);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef GLES2
|
||||
glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix.getMatrix().data());
|
||||
#else
|
||||
glMatrix.transpose();
|
||||
glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix.getMatrix().data());
|
||||
#endif
|
||||
glUniform1i(shader->tex, 0);
|
||||
|
||||
if ((usingFinalShader && *PDT == 0) || CRASHING) {
|
||||
glUniform1f(shader->time, m_tGlobalTimer.getSeconds() - shader->initialTime);
|
||||
} else if (usingFinalShader && shader->time != -1) {
|
||||
@@ -3016,7 +3021,7 @@ CEGLSync::~CEGLSync() {
|
||||
if (sync == EGL_NO_SYNC_KHR)
|
||||
return;
|
||||
|
||||
if (g_pHyprOpenGL->m_sProc.eglDestroySyncKHR(g_pHyprOpenGL->m_pEglDisplay, sync) != EGL_TRUE)
|
||||
if (g_pHyprOpenGL && g_pHyprOpenGL->m_sProc.eglDestroySyncKHR(g_pHyprOpenGL->m_pEglDisplay, sync) != EGL_TRUE)
|
||||
Debug::log(ERR, "eglDestroySyncKHR failed");
|
||||
}
|
||||
|
||||
|
@@ -276,6 +276,14 @@ class CHyprOpenGLImpl {
|
||||
} m_sExts;
|
||||
|
||||
private:
|
||||
enum eEGLContextVersion : uint8_t {
|
||||
EGL_CONTEXT_GLES_2_0 = 0,
|
||||
EGL_CONTEXT_GLES_3_0,
|
||||
EGL_CONTEXT_GLES_3_2,
|
||||
};
|
||||
|
||||
eEGLContextVersion m_eglContextVersion = EGL_CONTEXT_GLES_3_2;
|
||||
|
||||
std::list<GLuint> m_lBuffers;
|
||||
std::list<GLuint> m_lTextures;
|
||||
|
||||
@@ -297,9 +305,9 @@ class CHyprOpenGLImpl {
|
||||
|
||||
SP<CTexture> m_pMissingAssetTexture, m_pBackgroundTexture, m_pLockDeadTexture, m_pLockDead2Texture, m_pLockTtyTextTexture; // TODO: don't always load lock
|
||||
|
||||
void logShaderError(const GLuint&, bool program = false);
|
||||
GLuint createProgram(const std::string&, const std::string&, bool dynamic = false);
|
||||
GLuint compileShader(const GLuint&, std::string, bool dynamic = false);
|
||||
void logShaderError(const GLuint&, bool program = false, bool silent = false);
|
||||
GLuint createProgram(const std::string&, const std::string&, bool dynamic = false, bool silent = false);
|
||||
GLuint compileShader(const GLuint&, std::string, bool dynamic = false, bool silent = false);
|
||||
void createBGTextureForMonitor(PHLMONITOR);
|
||||
void initShaders();
|
||||
void initDRMFormats();
|
||||
|
@@ -33,9 +33,7 @@
|
||||
#include "pass/SurfacePassElement.hpp"
|
||||
#include "debug/Log.hpp"
|
||||
#include "../protocols/ColorManagement.hpp"
|
||||
#if AQUAMARINE_VERSION_NUMBER > 702 // >0.7.2
|
||||
#include "../protocols/types/ContentType.hpp"
|
||||
#endif
|
||||
|
||||
#include <hyprutils/utils/ScopeGuard.hpp>
|
||||
using namespace Hyprutils::Utils;
|
||||
@@ -1216,7 +1214,8 @@ void CHyprRenderer::renderMonitor(PHLMONITOR pMonitor) {
|
||||
pMonitor->tearingState.activelyTearing = shouldTear;
|
||||
|
||||
if ((*PDIRECTSCANOUT == 1 ||
|
||||
(*PDIRECTSCANOUT == 2 && pMonitor->activeWorkspace->getFullscreenWindow() && pMonitor->activeWorkspace->getFullscreenWindow()->getContentType() == CONTENT_TYPE_GAME)) &&
|
||||
(*PDIRECTSCANOUT == 2 && pMonitor->activeWorkspace && pMonitor->activeWorkspace->m_bHasFullscreenWindow &&
|
||||
pMonitor->activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN && pMonitor->activeWorkspace->getFullscreenWindow()->getContentType() == CONTENT_TYPE_GAME)) &&
|
||||
!shouldTear) {
|
||||
if (pMonitor->attemptDirectScanout()) {
|
||||
return;
|
||||
@@ -1412,11 +1411,16 @@ void CHyprRenderer::renderMonitor(PHLMONITOR pMonitor) {
|
||||
static const hdr_output_metadata NO_HDR_METADATA = {.hdmi_metadata_type1 = hdr_metadata_infoframe{.eotf = 0}};
|
||||
|
||||
static hdr_output_metadata createHDRMetadata(SImageDescription settings, Aquamarine::IOutput::SParsedEDID edid) {
|
||||
if (settings.transferFunction != CM_TRANSFER_FUNCTION_ST2084_PQ)
|
||||
return NO_HDR_METADATA; // empty metadata for SDR
|
||||
uint8_t eotf = 0;
|
||||
switch (settings.transferFunction) {
|
||||
case CM_TRANSFER_FUNCTION_SRGB: eotf = 0; break; // used to send primaries and luminances to AQ. ignored for now
|
||||
case CM_TRANSFER_FUNCTION_ST2084_PQ: eotf = 2; break;
|
||||
// case CM_TRANSFER_FUNCTION_HLG: eotf = 3; break; TODO check display capabilities first
|
||||
default: return NO_HDR_METADATA; // empty metadata for SDR
|
||||
}
|
||||
|
||||
const auto toNits = [](uint32_t value) { return uint16_t(std::round(value)); };
|
||||
const auto to16Bit = [](uint32_t value) { return uint16_t(std::round(value * 50000)); };
|
||||
const auto to16Bit = [](float value) { return uint16_t(std::round(value * 50000)); };
|
||||
|
||||
auto colorimetry = settings.primariesNameSet || settings.primaries == SPCPRimaries{} ? getPrimaries(settings.primariesNamed) : settings.primaries;
|
||||
auto luminances = settings.masteringLuminances.max > 0 ?
|
||||
@@ -1430,7 +1434,7 @@ static hdr_output_metadata createHDRMetadata(SImageDescription settings, A
|
||||
.metadata_type = 0,
|
||||
.hdmi_metadata_type1 =
|
||||
hdr_metadata_infoframe{
|
||||
.eotf = 2,
|
||||
.eotf = eotf,
|
||||
.metadata_type = 0,
|
||||
.display_primaries =
|
||||
{
|
||||
@@ -1448,8 +1452,6 @@ static hdr_output_metadata createHDRMetadata(SImageDescription settings, A
|
||||
}
|
||||
|
||||
bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) {
|
||||
pMonitor->commitSeq++;
|
||||
|
||||
static auto PPASS = CConfigValue<Hyprlang::INT>("render:cm_fs_passthrough");
|
||||
const bool PHDR = pMonitor->imageDescription.transferFunction == CM_TRANSFER_FUNCTION_ST2084_PQ;
|
||||
|
||||
@@ -1457,24 +1459,42 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) {
|
||||
Debug::log(TRACE, "ColorManagement supportsBT2020 {}, supportsPQ {}", pMonitor->output->parsedEDID.supportsBT2020, SUPPORTSPQ);
|
||||
|
||||
if (pMonitor->output->parsedEDID.supportsBT2020 && SUPPORTSPQ) {
|
||||
// HDR metadata determined by
|
||||
// PPASS = 0 monitor settings
|
||||
// PPASS = 1
|
||||
// windowed: monitor settings
|
||||
// fullscreen surface: surface settings FIXME: fullscreen SDR surface passthrough - pass degamma, ctm, gamma if needed
|
||||
// PPASS = 2
|
||||
// windowed: monitor settings
|
||||
// fullscreen SDR surface: monitor settings
|
||||
// fullscreen HDR surface: surface settings
|
||||
|
||||
bool wantHDR = PHDR;
|
||||
bool hdrIsHandled = false;
|
||||
if (*PPASS && pMonitor->activeWorkspace && pMonitor->activeWorkspace->m_bHasFullscreenWindow && pMonitor->activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN) {
|
||||
const auto WINDOW = pMonitor->activeWorkspace->getFullscreenWindow();
|
||||
const auto ROOT_SURF = WINDOW->m_pWLSurface->resource();
|
||||
const auto SURF =
|
||||
ROOT_SURF->findFirstPreorder([ROOT_SURF](SP<CWLSurfaceResource> surf) { return surf->colorManagement.valid() && surf->extends() == ROOT_SURF->extends(); });
|
||||
|
||||
if (SURF && SURF->colorManagement.valid() && SURF->colorManagement->hasImageDescription()) {
|
||||
wantHDR = PHDR && *PPASS == 2;
|
||||
|
||||
// we have a surface with image description and it's allowed by wantHDR
|
||||
if (SURF && SURF->colorManagement.valid() && SURF->colorManagement->hasImageDescription() &&
|
||||
(!wantHDR || SURF->colorManagement->imageDescription().transferFunction == CM_TRANSFER_FUNCTION_ST2084_PQ)) {
|
||||
bool needsHdrMetadataUpdate = SURF->colorManagement->needsHdrMetadataUpdate() || pMonitor->m_previousFSWindow != WINDOW;
|
||||
if (SURF->colorManagement->needsHdrMetadataUpdate())
|
||||
SURF->colorManagement->setHDRMetadata(createHDRMetadata(SURF->colorManagement->imageDescription(), pMonitor->output->parsedEDID));
|
||||
if (needsHdrMetadataUpdate)
|
||||
pMonitor->output->state->setHDRMetadata(SURF->colorManagement->hdrMetadata());
|
||||
} else if ((pMonitor->output->state->state().hdrMetadata.hdmi_metadata_type1.eotf == 2) != PHDR)
|
||||
pMonitor->output->state->setHDRMetadata(PHDR ? createHDRMetadata(pMonitor->imageDescription, pMonitor->output->parsedEDID) : NO_HDR_METADATA);
|
||||
hdrIsHandled = true;
|
||||
}
|
||||
|
||||
pMonitor->m_previousFSWindow = WINDOW;
|
||||
} else {
|
||||
if ((pMonitor->output->state->state().hdrMetadata.hdmi_metadata_type1.eotf == 2) != PHDR)
|
||||
pMonitor->output->state->setHDRMetadata(PHDR ? createHDRMetadata(pMonitor->imageDescription, pMonitor->output->parsedEDID) : NO_HDR_METADATA);
|
||||
}
|
||||
if (!hdrIsHandled) {
|
||||
if ((pMonitor->output->state->state().hdrMetadata.hdmi_metadata_type1.eotf == 2) != wantHDR)
|
||||
pMonitor->output->state->setHDRMetadata(wantHDR ? createHDRMetadata(pMonitor->imageDescription, pMonitor->output->parsedEDID) : NO_HDR_METADATA);
|
||||
pMonitor->m_previousFSWindow.reset();
|
||||
}
|
||||
}
|
||||
@@ -1495,13 +1515,11 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) {
|
||||
}
|
||||
}
|
||||
|
||||
#if AQUAMARINE_VERSION_NUMBER > 702 // >0.7.2
|
||||
if (pMonitor->activeWorkspace && pMonitor->activeWorkspace->m_bHasFullscreenWindow && pMonitor->activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN) {
|
||||
const auto WINDOW = pMonitor->activeWorkspace->getFullscreenWindow();
|
||||
pMonitor->output->state->setContentType(NContentType::toDRM(WINDOW->getContentType()));
|
||||
} else
|
||||
pMonitor->output->state->setContentType(NContentType::toDRM(CONTENT_TYPE_NONE));
|
||||
#endif
|
||||
|
||||
if (pMonitor->ctmUpdated) {
|
||||
pMonitor->ctmUpdated = false;
|
||||
@@ -1530,21 +1548,19 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) {
|
||||
return ok;
|
||||
|
||||
Debug::log(TRACE, "Explicit: {} presented", explicitPresented.size());
|
||||
auto sync = g_pHyprOpenGL->createEGLSync(pMonitor->inFence.get());
|
||||
|
||||
if (!sync)
|
||||
Debug::log(TRACE, "Explicit: can't add sync, EGLSync failed");
|
||||
if (!pMonitor->eglSync)
|
||||
Debug::log(TRACE, "Explicit: can't add sync, monitor has no EGLSync");
|
||||
else {
|
||||
for (auto const& e : explicitPresented) {
|
||||
if (!e->current.buffer || !e->current.buffer->buffer || !e->current.buffer->buffer->syncReleaser)
|
||||
if (!e->current.buffer || !e->current.buffer->buffer->syncReleaser)
|
||||
continue;
|
||||
|
||||
e->current.buffer->buffer->syncReleaser->addReleaseSync(sync);
|
||||
e->current.buffer->buffer->syncReleaser->addReleaseSync(pMonitor->eglSync);
|
||||
}
|
||||
}
|
||||
|
||||
explicitPresented.clear();
|
||||
pMonitor->output->state->resetExplicitFences();
|
||||
|
||||
return ok;
|
||||
}
|
||||
@@ -2255,38 +2271,40 @@ void CHyprRenderer::endRender() {
|
||||
if (m_eRenderMode == RENDER_MODE_FULL_FAKE)
|
||||
return;
|
||||
|
||||
if (m_eRenderMode == RENDER_MODE_NORMAL) {
|
||||
if (m_eRenderMode == RENDER_MODE_NORMAL)
|
||||
PMONITOR->output->state->setBuffer(m_pCurrentBuffer);
|
||||
|
||||
auto explicitOptions = getExplicitSyncSettings(PMONITOR->output);
|
||||
|
||||
if (PMONITOR->inTimeline && explicitOptions.explicitEnabled && explicitOptions.explicitKMSEnabled) {
|
||||
auto sync = g_pHyprOpenGL->createEGLSync();
|
||||
if (!sync) {
|
||||
if (PMONITOR->inTimeline && explicitOptions.explicitEnabled) {
|
||||
PMONITOR->eglSync = g_pHyprOpenGL->createEGLSync();
|
||||
if (!PMONITOR->eglSync) {
|
||||
Debug::log(ERR, "renderer: couldn't create an EGLSync for out in endRender");
|
||||
return;
|
||||
}
|
||||
|
||||
bool ok = PMONITOR->inTimeline->importFromSyncFileFD(PMONITOR->commitSeq, sync->fd());
|
||||
PMONITOR->inTimelinePoint++;
|
||||
bool ok = PMONITOR->inTimeline->importFromSyncFileFD(PMONITOR->inTimelinePoint, PMONITOR->eglSync->fd());
|
||||
if (!ok) {
|
||||
Debug::log(ERR, "renderer: couldn't import from sync file fd in endRender");
|
||||
return;
|
||||
}
|
||||
|
||||
PMONITOR->inFence = CFileDescriptor{PMONITOR->inTimeline->exportAsSyncFileFD(PMONITOR->commitSeq)};
|
||||
if (m_eRenderMode == RENDER_MODE_NORMAL && explicitOptions.explicitKMSEnabled) {
|
||||
PMONITOR->inFence = CFileDescriptor{PMONITOR->inTimeline->exportAsSyncFileFD(PMONITOR->inTimelinePoint)};
|
||||
if (!PMONITOR->inFence.isValid()) {
|
||||
Debug::log(ERR, "renderer: couldn't export from sync timeline in endRender");
|
||||
return;
|
||||
}
|
||||
|
||||
PMONITOR->output->state->setExplicitInFence(PMONITOR->inFence.get());
|
||||
}
|
||||
} else {
|
||||
if (isNvidia() && *PNVIDIAANTIFLICKER)
|
||||
glFinish();
|
||||
else
|
||||
glFlush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CHyprRenderer::onRenderbufferDestroy(CRenderbuffer* rb) {
|
||||
|
@@ -12,7 +12,6 @@ class CShader {
|
||||
GLint color = -1;
|
||||
GLint alphaMatte = -1;
|
||||
GLint texType = -1;
|
||||
GLint skipCM = -1;
|
||||
GLint sourceTF = -1;
|
||||
GLint targetTF = -1;
|
||||
GLint sourcePrimaries = -1;
|
||||
|
@@ -66,6 +66,7 @@ void CTexture::createFromShm(uint32_t drmFormat, uint8_t* pixels, uint32_t strid
|
||||
|
||||
m_iType = format->withAlpha ? TEXTURE_RGBA : TEXTURE_RGBX;
|
||||
m_vSize = size_;
|
||||
m_isSynchronous = true;
|
||||
allocate();
|
||||
|
||||
GLCALL(glBindTexture(GL_TEXTURE_2D, m_iTexID));
|
||||
|
@@ -43,6 +43,7 @@ class CTexture {
|
||||
eTransform m_eTransform = HYPRUTILS_TRANSFORM_NORMAL;
|
||||
bool m_bOpaque = false;
|
||||
uint32_t m_iDrmFormat = 0; // for shm
|
||||
bool m_isSynchronous = false;
|
||||
|
||||
private:
|
||||
void createFromShm(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size);
|
||||
|
@@ -46,7 +46,7 @@ SDecorationPositioningInfo CHyprGroupBarDecoration::getPositioningInfo() {
|
||||
const auto ONEBARHEIGHT = *POUTERGAP + *PINDICATORHEIGHT + (*PGRADIENTS || *PRENDERTITLES ? *PHEIGHT : 0);
|
||||
info.desiredExtents = {{0, (ONEBARHEIGHT * m_dwGroupMembers.size()) + 2 + *POUTERGAP}, {0, 0}};
|
||||
} else
|
||||
info.desiredExtents = {{0, *POUTERGAP * 2 + *PINDICATORHEIGHT + (*PGRADIENTS || *PRENDERTITLES ? *PHEIGHT : 0) + 2}, {0, 0}};
|
||||
info.desiredExtents = {{0, *POUTERGAP * 2 + *PINDICATORHEIGHT + (*PGRADIENTS || *PRENDERTITLES ? *PHEIGHT : 0)}, {0, 0}};
|
||||
} else
|
||||
info.desiredExtents = {{0, 0}, {0, 0}};
|
||||
return info;
|
||||
@@ -54,7 +54,6 @@ SDecorationPositioningInfo CHyprGroupBarDecoration::getPositioningInfo() {
|
||||
|
||||
void CHyprGroupBarDecoration::onPositioningReply(const SDecorationPositioningReply& reply) {
|
||||
m_bAssignedBox = reply.assignedGeometry;
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateWindow(m_pWindow.lock());
|
||||
}
|
||||
|
||||
eDecorationType CHyprGroupBarDecoration::getDecorationType() {
|
||||
@@ -143,7 +142,7 @@ void CHyprGroupBarDecoration::draw(PHLMONITOR pMonitor, float const& a) {
|
||||
ASSIGNEDBOX.y + ASSIGNEDBOX.h - floor(yoff) - *PINDICATORHEIGHT - *POUTERGAP - pMonitor->vecPosition.y + m_pWindow->m_vFloatingOffset.y, m_fBarWidth,
|
||||
*PINDICATORHEIGHT};
|
||||
|
||||
rect.scale(pMonitor->scale);
|
||||
rect.scale(pMonitor->scale).round();
|
||||
|
||||
const bool GROUPLOCKED = m_pWindow->getGroupHead()->m_sGroupData.locked || g_pKeybindManager->m_bGroupsLocked;
|
||||
const auto* const PCOLACTIVE = GROUPLOCKED ? GROUPCOLACTIVELOCKED : GROUPCOLACTIVE;
|
||||
@@ -279,7 +278,7 @@ CTitleTex::CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float
|
||||
const CHyprColor COLOR = CHyprColor(*PTEXTCOLOR);
|
||||
const auto FONTFAMILY = *PTITLEFONTFAMILY != STRVAL_EMPTY ? *PTITLEFONTFAMILY : *FALLBACKFONT;
|
||||
|
||||
tex = g_pHyprOpenGL->renderText(pWindow->m_szTitle, COLOR, *PTITLEFONTSIZE, false, FONTFAMILY, bufferSize.x - 2 /* some padding yk */);
|
||||
tex = g_pHyprOpenGL->renderText(pWindow->m_szTitle, COLOR, *PTITLEFONTSIZE * monitorScale, false, FONTFAMILY, bufferSize.x - 2 /* some padding yk */);
|
||||
|
||||
if (tex)
|
||||
texSize = tex->m_vSize;
|
||||
@@ -574,5 +573,5 @@ CBox CHyprGroupBarDecoration::assignedBoxGlobal() {
|
||||
if (PWORKSPACE && !m_pWindow->m_bPinned)
|
||||
box.translate(PWORKSPACE->m_vRenderOffset->value());
|
||||
|
||||
return box;
|
||||
return box.round();
|
||||
}
|
||||
|
@@ -33,5 +33,13 @@ std::optional<CBox> CRectPassElement::boundingBox() {
|
||||
}
|
||||
|
||||
CRegion CRectPassElement::opaqueRegion() {
|
||||
return data.color.a >= 1.F ? boundingBox()->expand(-data.round) : CRegion{};
|
||||
if (data.color.a < 1.F)
|
||||
return CRegion{};
|
||||
|
||||
CRegion rg = boundingBox()->expand(-data.round);
|
||||
|
||||
if (!data.clipBox.empty())
|
||||
rg.intersect(data.clipBox);
|
||||
|
||||
return rg;
|
||||
}
|
||||
|
@@ -22,8 +22,7 @@ void CTexPassElement::draw(const CRegion& damage) {
|
||||
|
||||
if (data.replaceProjection)
|
||||
g_pHyprOpenGL->m_RenderData.monitorProjection = *data.replaceProjection;
|
||||
g_pHyprOpenGL->renderTextureInternalWithDamage(data.tex, data.box, data.a, data.damage.empty() ? damage : data.damage, data.round, data.roundingPower, data.syncTimeline,
|
||||
data.syncPoint);
|
||||
g_pHyprOpenGL->renderTextureInternalWithDamage(data.tex, data.box, data.a, data.damage.empty() ? damage : data.damage, data.round, data.roundingPower);
|
||||
if (data.replaceProjection)
|
||||
g_pHyprOpenGL->m_RenderData.monitorProjection = g_pHyprOpenGL->m_RenderData.pMonitor->projMatrix;
|
||||
}
|
||||
|
@@ -16,8 +16,6 @@ class CTexPassElement : public IPassElement {
|
||||
int round = 0;
|
||||
float roundingPower = 2.0f;
|
||||
bool flipEndFrame = false;
|
||||
SP<CSyncTimeline> syncTimeline;
|
||||
int64_t syncPoint = 0;
|
||||
std::optional<Mat3x3> replaceProjection;
|
||||
CBox clipBox;
|
||||
};
|
||||
|
@@ -8,7 +8,6 @@ uniform sampler2D tex;
|
||||
//uniform samplerExternalOES texture0;
|
||||
|
||||
uniform int texType; // eTextureType: 0 - rgba, 1 - rgbx, 2 - ext
|
||||
uniform int skipCM;
|
||||
uniform int sourceTF; // eTransferFunction
|
||||
uniform int targetTF; // eTransferFunction
|
||||
uniform mat4x2 sourcePrimaries;
|
||||
@@ -408,25 +407,27 @@ void main() {
|
||||
if (discardAlpha == 1 && pixColor[3] <= discardAlphaValue)
|
||||
discard;
|
||||
|
||||
if (skipCM == 0) {
|
||||
pixColor.rgb /= max(pixColor.a, 0.001);
|
||||
pixColor.rgb = toLinearRGB(pixColor.rgb, sourceTF);
|
||||
mat3 srcxyz = primaries2xyz(sourcePrimaries);
|
||||
mat3 dstxyz;
|
||||
|
||||
if (sourcePrimaries == targetPrimaries)
|
||||
dstxyz = srcxyz;
|
||||
else {
|
||||
dstxyz = primaries2xyz(targetPrimaries);
|
||||
pixColor = convertPrimaries(pixColor, srcxyz, sourcePrimaries[3], dstxyz, targetPrimaries[3]);
|
||||
}
|
||||
|
||||
pixColor = toNit(pixColor, sourceTF);
|
||||
pixColor.rgb *= pixColor.a;
|
||||
pixColor = tonemap(pixColor, dstxyz);
|
||||
|
||||
if (sourceTF == CM_TRANSFER_FUNCTION_SRGB && targetTF == CM_TRANSFER_FUNCTION_ST2084_PQ)
|
||||
pixColor = saturate(pixColor, srcxyz, sdrSaturation);
|
||||
|
||||
pixColor *= sdrBrightnessMultiplier;
|
||||
pixColor = fromLinearNit(pixColor, targetTF);
|
||||
}
|
||||
|
||||
if (applyTint == 1)
|
||||
pixColor = vec4(pixColor.rgb * tint.rgb, pixColor[3]);
|
||||
|
@@ -129,7 +129,7 @@ void CX11DataDevice::sendEnter(uint32_t serial, SP<CWLSurfaceResource> surf, con
|
||||
|
||||
xcb_window_t targetWindow = getProxyWindow(XSURF->xID);
|
||||
|
||||
xcb_client_message_data_t data = {0};
|
||||
xcb_client_message_data_t data = {{0}};
|
||||
data.data32[0] = g_pXWayland->pWM->dndSelection.window;
|
||||
data.data32[1] = XDND_VERSION << 24;
|
||||
data.data32[1] |= 1;
|
||||
@@ -164,7 +164,7 @@ void CX11DataDevice::sendLeave() {
|
||||
|
||||
xcb_window_t targetWindow = getProxyWindow(lastSurface->xID);
|
||||
|
||||
xcb_client_message_data_t data = {0};
|
||||
xcb_client_message_data_t data = {{0}};
|
||||
data.data32[0] = g_pXWayland->pWM->dndSelection.window;
|
||||
|
||||
sendDndEvent(targetWindow, HYPRATOMS["XdndLeave"], data);
|
||||
@@ -183,7 +183,7 @@ void CX11DataDevice::sendMotion(uint32_t timeMs, const Vector2D& local) {
|
||||
const auto XCOORDS = g_pXWaylandManager->waylandToXWaylandCoords(lastSurfaceCoords + local);
|
||||
const uint32_t coords = ((uint32_t)XCOORDS.x << 16) | (uint32_t)XCOORDS.y;
|
||||
|
||||
xcb_client_message_data_t data = {0};
|
||||
xcb_client_message_data_t data = {{0}};
|
||||
data.data32[0] = g_pXWayland->pWM->dndSelection.window;
|
||||
data.data32[2] = coords;
|
||||
data.data32[3] = timeMs;
|
||||
@@ -204,7 +204,7 @@ void CX11DataDevice::sendDrop() {
|
||||
|
||||
xcb_window_t targetWindow = getProxyWindow(lastSurface->xID);
|
||||
|
||||
xcb_client_message_data_t data = {0};
|
||||
xcb_client_message_data_t data = {{0}};
|
||||
data.data32[0] = g_pXWayland->pWM->dndSelection.window;
|
||||
data.data32[2] = lastTime;
|
||||
|
||||
|
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "Server.hpp"
|
||||
#include "XWayland.hpp"
|
||||
#include "config/ConfigValue.hpp"
|
||||
#include "debug/Log.hpp"
|
||||
#include "../defines.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
@@ -32,31 +33,45 @@ constexpr int SOCKET_BACKLOG = 1;
|
||||
constexpr int MAX_SOCKET_RETRIES = 32;
|
||||
constexpr int LOCK_FILE_MODE = 0444;
|
||||
|
||||
static CFileDescriptor createSocket(struct sockaddr_un* addr, size_t path_size) {
|
||||
socklen_t size = offsetof(struct sockaddr_un, sun_path) + path_size + 1;
|
||||
static CFileDescriptor createSocket(struct sockaddr_un* addr, size_t pathSize) {
|
||||
const bool isRegularSocket(addr->sun_path[0]);
|
||||
const char dbgSocketPathPrefix = isRegularSocket ? addr->sun_path[0] : '@';
|
||||
const char* const dbgSocketPathRem = addr->sun_path + 1;
|
||||
|
||||
socklen_t size = offsetof(struct sockaddr_un, sun_path) + pathSize + 1;
|
||||
CFileDescriptor fd{socket(AF_UNIX, SOCK_STREAM, 0)};
|
||||
if (!fd.isValid()) {
|
||||
Debug::log(ERR, "Failed to create socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1);
|
||||
Debug::log(ERR, "Failed to create socket {}{}", dbgSocketPathPrefix, dbgSocketPathRem);
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!fd.setFlags(fd.getFlags() | FD_CLOEXEC)) {
|
||||
Debug::log(ERR, "Failed to set flags for socket {}{}", dbgSocketPathPrefix, dbgSocketPathRem);
|
||||
return {};
|
||||
}
|
||||
|
||||
if (addr->sun_path[0])
|
||||
if (isRegularSocket)
|
||||
unlink(addr->sun_path);
|
||||
|
||||
if (bind(fd.get(), (struct sockaddr*)addr, size) < 0) {
|
||||
Debug::log(ERR, "Failed to bind socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1);
|
||||
if (addr->sun_path[0])
|
||||
Debug::log(ERR, "Failed to bind socket {}{}", dbgSocketPathPrefix, dbgSocketPathRem);
|
||||
if (isRegularSocket)
|
||||
unlink(addr->sun_path);
|
||||
return {};
|
||||
}
|
||||
|
||||
// Required for the correct functioning of `xhost` #9574
|
||||
// The operation is safe because XWayland controls socket access by itself
|
||||
// and rejects connections not matched by the `xhost` ACL
|
||||
if (isRegularSocket && chmod(addr->sun_path, 0666) < 0) {
|
||||
// We are only extending the default permissions,
|
||||
// and I don't see the reason to make a full stop in case of a failed operation.
|
||||
Debug::log(ERR, "Failed to set permission mode for socket {}{}", dbgSocketPathPrefix, dbgSocketPathRem);
|
||||
}
|
||||
|
||||
if (listen(fd.get(), SOCKET_BACKLOG) < 0) {
|
||||
Debug::log(ERR, "Failed to listen to socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1);
|
||||
if (addr->sun_path[0])
|
||||
Debug::log(ERR, "Failed to listen to socket {}{}", dbgSocketPathPrefix, dbgSocketPathRem);
|
||||
if (isRegularSocket)
|
||||
unlink(addr->sun_path);
|
||||
return {};
|
||||
}
|
||||
@@ -113,14 +128,32 @@ static std::string getSocketPath(int display, bool isLinux) {
|
||||
}
|
||||
|
||||
static bool openSockets(std::array<CFileDescriptor, 2>& sockets, int display) {
|
||||
static auto CREATEABSTRACTSOCKET = CConfigValue<Hyprlang::INT>("xwayland:create_abstract_socket");
|
||||
|
||||
if (!ensureSocketDirExists())
|
||||
return false;
|
||||
|
||||
sockaddr_un addr = {.sun_family = AF_UNIX};
|
||||
std::string path;
|
||||
|
||||
#ifdef __linux__
|
||||
if (*CREATEABSTRACTSOCKET) {
|
||||
// cursed...
|
||||
// but is kept as an option for better compatibility
|
||||
addr.sun_path[0] = 0;
|
||||
path = getSocketPath(display, true);
|
||||
strncpy(addr.sun_path + 1, path.c_str(), path.length() + 1);
|
||||
} else {
|
||||
path = getSocketPath(display, false);
|
||||
strncpy(addr.sun_path, path.c_str(), path.length() + 1);
|
||||
}
|
||||
#else
|
||||
if (*CREATEABSTRACTSOCKET) {
|
||||
Debug::log(WARN, "The abstract XWayland Unix domain socket might be used only on Linux systems. A regular one'll be created insted.");
|
||||
}
|
||||
path = getSocketPath(display, false);
|
||||
strncpy(addr.sun_path, path.c_str(), path.length() + 1);
|
||||
#endif
|
||||
|
||||
sockets[0] = CFileDescriptor{createSocket(&addr, path.length())};
|
||||
if (!sockets[0].isValid())
|
||||
@@ -144,8 +177,7 @@ static void startServer(void* data) {
|
||||
}
|
||||
|
||||
static int xwaylandReady(int fd, uint32_t mask, void* data) {
|
||||
CFileDescriptor xwlFd{fd};
|
||||
return g_pXWayland->pServer->ready(std::move(xwlFd), mask);
|
||||
return g_pXWayland->pServer->ready(fd, mask);
|
||||
}
|
||||
|
||||
static bool safeRemove(const std::string& path) {
|
||||
@@ -220,12 +252,10 @@ CXWaylandServer::~CXWaylandServer() {
|
||||
safeRemove(lockPath);
|
||||
|
||||
std::string path;
|
||||
#ifdef __linux__
|
||||
path = getSocketPath(display, true);
|
||||
#else
|
||||
path = getSocketPath(display, false);
|
||||
#endif
|
||||
for (bool isLinux : {true, false}) {
|
||||
path = getSocketPath(display, isLinux);
|
||||
safeRemove(path);
|
||||
}
|
||||
}
|
||||
|
||||
void CXWaylandServer::die() {
|
||||
@@ -322,7 +352,7 @@ bool CXWaylandServer::start() {
|
||||
return false;
|
||||
}
|
||||
|
||||
waylandFDs[0].take(); // does this leak?
|
||||
waylandFDs[0].take(); // wl_client owns this fd now
|
||||
|
||||
int notify[2] = {-1, -1};
|
||||
if (pipe(notify) < 0) {
|
||||
@@ -342,30 +372,24 @@ bool CXWaylandServer::start() {
|
||||
pipeSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, notifyFds[0].get(), WL_EVENT_READABLE, ::xwaylandReady, nullptr);
|
||||
pipeFd = std::move(notifyFds[0]);
|
||||
|
||||
serverPID = fork();
|
||||
auto serverPID = fork();
|
||||
if (serverPID < 0) {
|
||||
Debug::log(ERR, "fork failed");
|
||||
die();
|
||||
return false;
|
||||
} else if (serverPID == 0) {
|
||||
pid_t pid = fork();
|
||||
if (pid < 0) {
|
||||
Debug::log(ERR, "second fork failed");
|
||||
_exit(1);
|
||||
} else if (pid == 0)
|
||||
runXWayland(notifyFds[1]);
|
||||
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int CXWaylandServer::ready(CFileDescriptor fd, uint32_t mask) {
|
||||
int CXWaylandServer::ready(int fd, uint32_t mask) {
|
||||
if (mask & WL_EVENT_READABLE) {
|
||||
// xwayland writes twice
|
||||
char buf[64];
|
||||
ssize_t n = read(fd.get(), buf, sizeof(buf));
|
||||
ssize_t n = read(fd, buf, sizeof(buf));
|
||||
if (n < 0 && errno != EINTR) {
|
||||
Debug::log(ERR, "Xwayland: read from displayFd failed");
|
||||
mask = 0;
|
||||
@@ -373,14 +397,6 @@ int CXWaylandServer::ready(CFileDescriptor fd, uint32_t mask) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (waitpid(serverPID, nullptr, 0) < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
Debug::log(ERR, "Xwayland: waitpid for fork failed");
|
||||
g_pXWayland->pServer.reset();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// if we don't have readable here, it failed
|
||||
if (!(mask & WL_EVENT_READABLE)) {
|
||||
Debug::log(ERR, "Xwayland: startup failed, not setting up xwm");
|
||||
@@ -391,6 +407,7 @@ int CXWaylandServer::ready(CFileDescriptor fd, uint32_t mask) {
|
||||
Debug::log(LOG, "XWayland is ready");
|
||||
|
||||
wl_event_source_remove(pipeSource);
|
||||
pipeFd.reset();
|
||||
pipeSource = nullptr;
|
||||
|
||||
// start the wm
|
||||
|
@@ -20,7 +20,7 @@ class CXWaylandServer {
|
||||
bool start();
|
||||
|
||||
// called on ready
|
||||
int ready(Hyprutils::OS::CFileDescriptor fd, uint32_t mask);
|
||||
int ready(int fd, uint32_t mask);
|
||||
|
||||
void die();
|
||||
|
||||
@@ -34,8 +34,6 @@ class CXWaylandServer {
|
||||
bool tryOpenSockets();
|
||||
void runXWayland(Hyprutils::OS::CFileDescriptor& notifyFD);
|
||||
|
||||
pid_t serverPID = 0;
|
||||
|
||||
std::string displayName;
|
||||
int display = -1;
|
||||
std::array<Hyprutils::OS::CFileDescriptor, 2> xFDs;
|
||||
|
@@ -62,12 +62,12 @@ void CXWaylandSurface::ensureListeners() {
|
||||
});
|
||||
|
||||
listeners.commitSurface = surface->events.commit.registerListener([this](std::any d) {
|
||||
if (surface->pending.texture && !mapped) {
|
||||
if (surface->current.texture && !mapped) {
|
||||
map();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!surface->pending.texture && mapped) {
|
||||
if (!surface->current.texture && mapped) {
|
||||
unmap();
|
||||
return;
|
||||
}
|
||||
@@ -131,7 +131,7 @@ void CXWaylandSurface::considerMap() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (surface->pending.texture) {
|
||||
if (surface->current.texture) {
|
||||
Debug::log(LOG, "XWayland surface: considerMap, sure, we have a buffer");
|
||||
map();
|
||||
return;
|
||||
|
@@ -494,7 +494,7 @@ void CXWM::focusWindow(SP<CXWaylandSurface> surf) {
|
||||
if (surf->overrideRedirect)
|
||||
return;
|
||||
|
||||
xcb_client_message_data_t msg = {0};
|
||||
xcb_client_message_data_t msg = {{0}};
|
||||
msg.data32[0] = HYPRATOMS["WM_TAKE_FOCUS"];
|
||||
msg.data32[1] = XCB_TIME_CURRENT_TIME;
|
||||
|
||||
|
Reference in New Issue
Block a user