tests: Test the no_focus_on_activate window rule (#13015)
This commit is contained in:
parent
0896775f1b
commit
eb0480ba0d
1 changed files with 87 additions and 21 deletions
|
|
@ -25,6 +25,28 @@ static bool spawnKitty(const std::string& class_, const std::vector<std::string>
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Spawns a kitty and creates a file and returns its name. The removal of the file triggers
|
||||||
|
/// activation of the spawned kitty window.
|
||||||
|
///
|
||||||
|
/// On failure, returns an empty string, possibly leaving a temporary file.
|
||||||
|
static std::string spawnKittyActivating(const std::string& class_ = "kitty_activating") {
|
||||||
|
// `XXXXXX` is what `mkstemp` expects to find in the string
|
||||||
|
std::string tmpFilename = (std::filesystem::temp_directory_path() / "XXXXXX").string();
|
||||||
|
int fd = mkstemp(tmpFilename.data());
|
||||||
|
if (fd < 0) {
|
||||||
|
NLog::log("{}Error: could not create tmp file: errno {}", Colors::RED, errno);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
(void)close(fd);
|
||||||
|
bool ok =
|
||||||
|
spawnKitty(class_, {"-o", "allow_remote_control=yes", "--", "/bin/sh", "-c", "while [ -f \"" + tmpFilename + "\" ]; do :; done; kitten @ focus-window; sleep infinity"});
|
||||||
|
if (!ok) {
|
||||||
|
NLog::log("{}Error: failed to spawn kitty", Colors::RED);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return tmpFilename;
|
||||||
|
}
|
||||||
|
|
||||||
static std::string getWindowAttribute(const std::string& winInfo, const std::string& attr) {
|
static std::string getWindowAttribute(const std::string& winInfo, const std::string& attr) {
|
||||||
auto pos = winInfo.find(attr);
|
auto pos = winInfo.find(attr);
|
||||||
if (pos == std::string::npos) {
|
if (pos == std::string::npos) {
|
||||||
|
|
@ -198,7 +220,7 @@ static void testGroupRules() {
|
||||||
Tests::killAllWindows();
|
Tests::killAllWindows();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isActiveWindow(const std::string& class_, char fullscreen, bool log = true) {
|
static bool isActiveWindow(const std::string& class_, char fullscreen = '0', bool log = true) {
|
||||||
std::string activeWin = getFromSocket("/activewindow");
|
std::string activeWin = getFromSocket("/activewindow");
|
||||||
auto winClass = getWindowAttribute(activeWin, "class:");
|
auto winClass = getWindowAttribute(activeWin, "class:");
|
||||||
auto winFullscreen = getWindowAttribute(activeWin, "fullscreen:").back();
|
auto winFullscreen = getWindowAttribute(activeWin, "fullscreen:").back();
|
||||||
|
|
@ -211,13 +233,13 @@ static bool isActiveWindow(const std::string& class_, char fullscreen, bool log
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool waitForActiveWindow(const std::string& class_, char fullscreen, int maxTries = 50) {
|
static bool waitForActiveWindow(const std::string& class_, char fullscreen = '0', bool logLastCheck = true, int maxTries = 50) {
|
||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
while (!isActiveWindow(class_, fullscreen, false)) {
|
while (!isActiveWindow(class_, fullscreen, false)) {
|
||||||
++cnt;
|
++cnt;
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||||
if (cnt > maxTries) {
|
if (cnt > maxTries) {
|
||||||
return isActiveWindow(class_, fullscreen, true);
|
return isActiveWindow(class_, fullscreen, logLastCheck);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -233,24 +255,6 @@ static bool testWindowFocusOnFullscreenConflict() {
|
||||||
|
|
||||||
OK(getFromSocket("/keyword misc:focus_on_activate true"));
|
OK(getFromSocket("/keyword misc:focus_on_activate true"));
|
||||||
|
|
||||||
auto spawnKittyActivating = [] -> std::string {
|
|
||||||
// `XXXXXX` is what `mkstemp` expects to find in the string
|
|
||||||
std::string tmpFilename = (std::filesystem::temp_directory_path() / "XXXXXX").string();
|
|
||||||
int fd = mkstemp(tmpFilename.data());
|
|
||||||
if (fd < 0) {
|
|
||||||
NLog::log("{}Error: could not create tmp file: errno {}", Colors::RED, errno);
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
(void)close(fd);
|
|
||||||
bool ok = spawnKitty("kitty_activating",
|
|
||||||
{"-o", "allow_remote_control=yes", "--", "/bin/sh", "-c", "while [ -f \"" + tmpFilename + "\" ]; do :; done; kitten @ focus-window; sleep infinity"});
|
|
||||||
if (!ok) {
|
|
||||||
NLog::log("{}Error: failed to spawn kitty", Colors::RED);
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return tmpFilename;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Unfullscreen on conflict
|
// Unfullscreen on conflict
|
||||||
{
|
{
|
||||||
OK(getFromSocket("/keyword misc:on_focus_under_fullscreen 2"));
|
OK(getFromSocket("/keyword misc:on_focus_under_fullscreen 2"));
|
||||||
|
|
@ -481,6 +485,67 @@ static void testInitialFloatSize() {
|
||||||
Tests::killAllWindows();
|
Tests::killAllWindows();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Tests that the `focus_on_activate` effect of window rules always overrides
|
||||||
|
/// the `misc:focus_on_activate` variable.
|
||||||
|
static bool testWindowRuleFocusOnActivate() {
|
||||||
|
OK(getFromSocket("/reload"));
|
||||||
|
|
||||||
|
if (!spawnKitty("kitty_default")) {
|
||||||
|
NLog::log("{}Error: failed to spawn kitty", Colors::RED);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do not focus anyone automatically
|
||||||
|
///////////OK(getFromSocket("/keyword windowrule match:class .*, no_initial_focus true"));
|
||||||
|
|
||||||
|
// `focus_on_activate off` takes over
|
||||||
|
{
|
||||||
|
OK(getFromSocket("/keyword misc:focus_on_activate true"));
|
||||||
|
OK(getFromSocket("/keyword windowrule match:class kitty_antifocus, focus_on_activate off"));
|
||||||
|
|
||||||
|
const std::string removeToActivate = spawnKittyActivating("kitty_antifocus");
|
||||||
|
if (removeToActivate.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
EXPECT(waitForActiveWindow("kitty_antifocus"), true);
|
||||||
|
OK(getFromSocket("/dispatch focuswindow class:kitty_default"));
|
||||||
|
EXPECT(isActiveWindow("kitty_default"), true);
|
||||||
|
|
||||||
|
std::filesystem::remove(removeToActivate);
|
||||||
|
// The focus should NOT transition, since the window rule explicitly forbids that
|
||||||
|
EXPECT(waitForActiveWindow("kitty_antifocus", '0', false), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// `focus_on_activate on` takes over
|
||||||
|
{
|
||||||
|
OK(getFromSocket("/keyword misc:focus_on_activate false"));
|
||||||
|
OK(getFromSocket("/keyword windowrule match:class kitty_superfocus, focus_on_activate on"));
|
||||||
|
|
||||||
|
const std::string removeToActivate = spawnKittyActivating("kitty_superfocus");
|
||||||
|
if (removeToActivate.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
EXPECT(waitForActiveWindow("kitty_superfocus"), true);
|
||||||
|
OK(getFromSocket("/dispatch focuswindow class:kitty_default"));
|
||||||
|
EXPECT(isActiveWindow("kitty_default"), true);
|
||||||
|
|
||||||
|
std::filesystem::remove(removeToActivate);
|
||||||
|
// Now that we requested activation, the focus SHOULD transition to kitty_superfocus, according to the window rule
|
||||||
|
EXPECT(waitForActiveWindow("kitty_superfocus"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
NLog::log("{}Reloading config", Colors::YELLOW);
|
||||||
|
OK(getFromSocket("/reload"));
|
||||||
|
|
||||||
|
NLog::log("{}Killing all windows", Colors::YELLOW);
|
||||||
|
Tests::killAllWindows();
|
||||||
|
|
||||||
|
NLog::log("{}Expecting 0 windows", Colors::YELLOW);
|
||||||
|
EXPECT(Tests::windowCount(), 0);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool test() {
|
static bool test() {
|
||||||
NLog::log("{}Testing windows", Colors::GREEN);
|
NLog::log("{}Testing windows", Colors::GREEN);
|
||||||
|
|
||||||
|
|
@ -932,6 +997,7 @@ static bool test() {
|
||||||
testBringActiveToTopMouseMovement();
|
testBringActiveToTopMouseMovement();
|
||||||
testGroupFallbackFocus();
|
testGroupFallbackFocus();
|
||||||
testInitialFloatSize();
|
testInitialFloatSize();
|
||||||
|
testWindowRuleFocusOnActivate();
|
||||||
|
|
||||||
NLog::log("{}Reloading config", Colors::YELLOW);
|
NLog::log("{}Reloading config", Colors::YELLOW);
|
||||||
OK(getFromSocket("/reload"));
|
OK(getFromSocket("/reload"));
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue