mirror of
https://github.com/hyprwm/Hyprland
synced 2024-11-26 05:05:59 +01:00
Added window rules
This commit is contained in:
parent
8cec07c39d
commit
ccbc0e4a2e
8 changed files with 178 additions and 11 deletions
|
@ -20,6 +20,7 @@ Nevertheless, REPORT any you find! Make an issue!
|
||||||
- Config reloaded instantly upon saving
|
- Config reloaded instantly upon saving
|
||||||
- Easily expandable and readable codebase
|
- Easily expandable and readable codebase
|
||||||
- Support for docks/whatever
|
- Support for docks/whatever
|
||||||
|
- Window rules
|
||||||
- Monitor rules
|
- Monitor rules
|
||||||
- Socket-based IPC
|
- Socket-based IPC
|
||||||
- Tiling/floating/fullscreen windows
|
- Tiling/floating/fullscreen windows
|
||||||
|
@ -30,7 +31,6 @@ Nevertheless, REPORT any you find! Make an issue!
|
||||||
- Rounded corners
|
- Rounded corners
|
||||||
- Blur
|
- Blur
|
||||||
- Fadein/out
|
- Fadein/out
|
||||||
- Window rules
|
|
||||||
- Fix electron rendering issues
|
- Fix electron rendering issues
|
||||||
- Optimization
|
- Optimization
|
||||||
- Fix weird scroll on XWayland
|
- Fix weird scroll on XWayland
|
||||||
|
|
|
@ -18,6 +18,22 @@ general {
|
||||||
col.inactive_border=0x66333333
|
col.inactive_border=0x66333333
|
||||||
}
|
}
|
||||||
|
|
||||||
|
animations {
|
||||||
|
enabled=1
|
||||||
|
windows=1
|
||||||
|
borders=1 # not yet implemented
|
||||||
|
fadein=1 # not yet implemented
|
||||||
|
}
|
||||||
|
|
||||||
|
# example window rules
|
||||||
|
# for windows named/classed as abc and xyz
|
||||||
|
windowrule=move 69 420,abc
|
||||||
|
windowrule=size 420 69,abc
|
||||||
|
windowrule=tile,xyz
|
||||||
|
windowrule=float,abc
|
||||||
|
windowrule=monitor 0,xyz
|
||||||
|
|
||||||
|
# example binds
|
||||||
bind=SUPER,Q,exec,kitty
|
bind=SUPER,Q,exec,kitty
|
||||||
bind=SUPER,C,killactive,
|
bind=SUPER,C,killactive,
|
||||||
bind=SUPER,M,exec,pkill Hyprland
|
bind=SUPER,M,exec,pkill Hyprland
|
||||||
|
|
|
@ -163,6 +163,30 @@ void CConfigManager::handleBind(const std::string& command, const std::string& v
|
||||||
g_pKeybindManager->addKeybind(SKeybind{KEY, MOD, HANDLER, COMMAND});
|
g_pKeybindManager->addKeybind(SKeybind{KEY, MOD, HANDLER, COMMAND});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CConfigManager::handleWindowRule(const std::string& command, const std::string& value) {
|
||||||
|
const auto RULE = value.substr(0, value.find_first_of(","));
|
||||||
|
const auto VALUE = value.substr(value.find_first_of(",") + 1);
|
||||||
|
|
||||||
|
// check rule and value
|
||||||
|
if (RULE == "" || VALUE == "") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify we support a rule
|
||||||
|
if (RULE != "float"
|
||||||
|
&& RULE != "tile"
|
||||||
|
&& RULE.find("move") != 0
|
||||||
|
&& RULE.find("size") != 0
|
||||||
|
&& RULE.find("monitor") != 0) {
|
||||||
|
Debug::log(ERR, "Invalid rule found: %s", RULE.c_str());
|
||||||
|
parseError = "Invalid rule found: " + RULE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_dWindowRules.push_back({RULE, VALUE});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void CConfigManager::handleDefaultWorkspace(const std::string& command, const std::string& value) {
|
void CConfigManager::handleDefaultWorkspace(const std::string& command, const std::string& value) {
|
||||||
|
|
||||||
const auto DISPLAY = value.substr(0, value.find_first_of(','));
|
const auto DISPLAY = value.substr(0, value.find_first_of(','));
|
||||||
|
@ -230,6 +254,9 @@ void CConfigManager::parseLine(std::string& line) {
|
||||||
} else if (COMMAND == "workspace") {
|
} else if (COMMAND == "workspace") {
|
||||||
handleDefaultWorkspace(COMMAND, VALUE);
|
handleDefaultWorkspace(COMMAND, VALUE);
|
||||||
return;
|
return;
|
||||||
|
} else if (COMMAND == "windowrule") {
|
||||||
|
handleWindowRule(COMMAND, VALUE);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
configSetValueSafe(currentCategory + (currentCategory == "" ? "" : ":") + COMMAND, VALUE);
|
configSetValueSafe(currentCategory + (currentCategory == "" ? "" : ":") + COMMAND, VALUE);
|
||||||
|
@ -241,6 +268,7 @@ void CConfigManager::loadConfigLoadVars() {
|
||||||
currentCategory = ""; // reset the category
|
currentCategory = ""; // reset the category
|
||||||
|
|
||||||
m_dMonitorRules.clear();
|
m_dMonitorRules.clear();
|
||||||
|
m_dWindowRules.clear();
|
||||||
g_pKeybindManager->clearKeybinds();
|
g_pKeybindManager->clearKeybinds();
|
||||||
|
|
||||||
const char* const ENVHOME = getenv("HOME");
|
const char* const ENVHOME = getenv("HOME");
|
||||||
|
@ -357,4 +385,33 @@ SMonitorRule CConfigManager::getMonitorRuleFor(std::string name) {
|
||||||
Debug::log(WARN, "No rules configured. Using the default hardcoded one.");
|
Debug::log(WARN, "No rules configured. Using the default hardcoded one.");
|
||||||
|
|
||||||
return SMonitorRule{.name = "", .resolution = Vector2D(1280, 720), .offset = Vector2D(0, 0), .mfact = 0.5f, .scale = 1};
|
return SMonitorRule{.name = "", .resolution = Vector2D(1280, 720), .offset = Vector2D(0, 0), .mfact = 0.5f, .scale = 1};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<SWindowRule> CConfigManager::getMatchingRules(CWindow* pWindow) {
|
||||||
|
if (!g_pCompositor->windowValidMapped(pWindow))
|
||||||
|
return std::vector<SWindowRule>();
|
||||||
|
|
||||||
|
std::vector<SWindowRule> returns;
|
||||||
|
|
||||||
|
std::string title = g_pXWaylandManager->getTitle(pWindow);
|
||||||
|
std::string appidclass = g_pXWaylandManager->getAppIDClass(pWindow);
|
||||||
|
|
||||||
|
for (auto& rule : m_dWindowRules) {
|
||||||
|
// check if we have a matching rule
|
||||||
|
try {
|
||||||
|
std::regex classCheck(rule.szValue);
|
||||||
|
|
||||||
|
if (!std::regex_search(title, classCheck) && !std::regex_search(appidclass, classCheck))
|
||||||
|
continue;
|
||||||
|
} catch (...) {
|
||||||
|
Debug::log(ERR, "Regex error at %s", rule.szValue.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// applies. Read the rule and behave accordingly
|
||||||
|
Debug::log(LOG, "Window rule %s -> %s matched %x [%s]", rule.szRule.c_str(), rule.szValue.c_str(), pWindow, pWindow->m_szTitle.c_str());
|
||||||
|
|
||||||
|
returns.push_back(rule);
|
||||||
|
}
|
||||||
|
|
||||||
|
return returns;
|
||||||
}
|
}
|
|
@ -6,6 +6,9 @@
|
||||||
#include "../defines.hpp"
|
#include "../defines.hpp"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <regex>
|
||||||
|
#include "../Window.hpp"
|
||||||
|
|
||||||
struct SConfigValue {
|
struct SConfigValue {
|
||||||
int64_t intValue = -1;
|
int64_t intValue = -1;
|
||||||
|
@ -23,6 +26,11 @@ struct SMonitorRule {
|
||||||
int defaultWorkspaceID = -1;
|
int defaultWorkspaceID = -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SWindowRule {
|
||||||
|
std::string szRule;
|
||||||
|
std::string szValue;
|
||||||
|
};
|
||||||
|
|
||||||
class CConfigManager {
|
class CConfigManager {
|
||||||
public:
|
public:
|
||||||
CConfigManager();
|
CConfigManager();
|
||||||
|
@ -36,6 +44,8 @@ public:
|
||||||
|
|
||||||
SMonitorRule getMonitorRuleFor(std::string);
|
SMonitorRule getMonitorRuleFor(std::string);
|
||||||
|
|
||||||
|
std::vector<SWindowRule> getMatchingRules(CWindow*);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unordered_map<std::string, SConfigValue> configValues;
|
std::unordered_map<std::string, SConfigValue> configValues;
|
||||||
time_t lastModifyTime = 0; // for reloading the config if changed
|
time_t lastModifyTime = 0; // for reloading the config if changed
|
||||||
|
@ -47,6 +57,7 @@ private:
|
||||||
bool isFirstLaunch = true; // For exec-once
|
bool isFirstLaunch = true; // For exec-once
|
||||||
|
|
||||||
std::deque<SMonitorRule> m_dMonitorRules;
|
std::deque<SMonitorRule> m_dMonitorRules;
|
||||||
|
std::deque<SWindowRule> m_dWindowRules;
|
||||||
|
|
||||||
// internal methods
|
// internal methods
|
||||||
void loadConfigLoadVars();
|
void loadConfigLoadVars();
|
||||||
|
@ -56,6 +67,7 @@ private:
|
||||||
void handleRawExec(const std::string&, const std::string&);
|
void handleRawExec(const std::string&, const std::string&);
|
||||||
void handleMonitor(const std::string&, const std::string&);
|
void handleMonitor(const std::string&, const std::string&);
|
||||||
void handleBind(const std::string&, const std::string&);
|
void handleBind(const std::string&, const std::string&);
|
||||||
|
void handleWindowRule(const std::string&, const std::string&);
|
||||||
void handleDefaultWorkspace(const std::string&, const std::string&);
|
void handleDefaultWorkspace(const std::string&, const std::string&);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -36,13 +36,73 @@ void Events::listener_mapWindow(wl_listener* listener, void* data) {
|
||||||
|
|
||||||
wl_signal_add(&PWINDOWSURFACE->events.new_subsurface, &PWINDOW->listen_newSubsurfaceWindow);
|
wl_signal_add(&PWINDOWSURFACE->events.new_subsurface, &PWINDOW->listen_newSubsurfaceWindow);
|
||||||
|
|
||||||
if (g_pXWaylandManager->shouldBeFloated(PWINDOW)) {
|
if (g_pXWaylandManager->shouldBeFloated(PWINDOW))
|
||||||
g_pLayoutManager->getCurrentLayout()->onWindowCreatedFloating(PWINDOW);
|
|
||||||
PWINDOW->m_bIsFloating = true;
|
PWINDOW->m_bIsFloating = true;
|
||||||
|
|
||||||
|
// window rules
|
||||||
|
const auto WINDOWRULES = g_pConfigManager->getMatchingRules(PWINDOW);
|
||||||
|
|
||||||
|
for (auto& r : WINDOWRULES) {
|
||||||
|
if (r.szRule.find("monitor") == 0) {
|
||||||
|
try {
|
||||||
|
const long int MONITOR = std::stoi(r.szRule.substr(r.szRule.find(" ")));
|
||||||
|
|
||||||
|
Debug::log(LOG, "Rule monitor, applying to window %x", PWINDOW);
|
||||||
|
|
||||||
|
if (MONITOR >= (long int)g_pCompositor->m_lMonitors.size() || MONITOR < (long int)0)
|
||||||
|
PWINDOW->m_iMonitorID = 0;
|
||||||
|
else
|
||||||
|
PWINDOW->m_iMonitorID = MONITOR;
|
||||||
|
|
||||||
|
PWINDOW->m_iWorkspaceID = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)->activeWorkspace;
|
||||||
|
} catch (...) {
|
||||||
|
Debug::log(LOG, "Rule monitor failed, rule: %s -> %s", r.szRule.c_str(), r.szValue.c_str());
|
||||||
|
}
|
||||||
|
} else if (r.szRule.find("float") == 0) {
|
||||||
|
PWINDOW->m_bIsFloating = true;
|
||||||
|
} else if (r.szRule.find("tile") == 0) {
|
||||||
|
PWINDOW->m_bIsFloating = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PWINDOW->m_bIsFloating) {
|
||||||
|
g_pLayoutManager->getCurrentLayout()->onWindowCreatedFloating(PWINDOW);
|
||||||
|
|
||||||
|
// size and move rules
|
||||||
|
for (auto& r : WINDOWRULES) {
|
||||||
|
if (r.szRule.find("size") == 0) {
|
||||||
|
try {
|
||||||
|
const auto VALUE = r.szRule.substr(r.szRule.find(" ") + 1);
|
||||||
|
const auto SIZEX = stoi(VALUE.substr(0, VALUE.find(" ")));
|
||||||
|
const auto SIZEY = stoi(VALUE.substr(VALUE.find(" ") + 1));
|
||||||
|
|
||||||
|
Debug::log(LOG, "Rule size, applying to window %x", PWINDOW);
|
||||||
|
|
||||||
|
PWINDOW->m_vEffectiveSize = Vector2D(SIZEX, SIZEY);
|
||||||
|
g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vEffectiveSize);
|
||||||
|
} catch (...) {
|
||||||
|
Debug::log(LOG, "Rule size failed, rule: %s -> %s", r.szRule.c_str(), r.szValue.c_str());
|
||||||
|
}
|
||||||
|
} else if (r.szRule.find("move") == 0) {
|
||||||
|
try {
|
||||||
|
const auto VALUE = r.szRule.substr(r.szRule.find(" ") + 1);
|
||||||
|
const auto POSX = stoi(VALUE.substr(0, VALUE.find(" ")));
|
||||||
|
const auto POSY = stoi(VALUE.substr(VALUE.find(" ") + 1));
|
||||||
|
|
||||||
|
Debug::log(LOG, "Rule move, applying to window %x", PWINDOW);
|
||||||
|
|
||||||
|
PWINDOW->m_vEffectivePosition = Vector2D(POSX, POSY) + PMONITOR->vecPosition;
|
||||||
|
} catch (...) {
|
||||||
|
Debug::log(LOG, "Rule move failed, rule: %s -> %s", r.szRule.c_str(), r.szValue.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW);
|
g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW);
|
||||||
|
|
||||||
|
PWINDOW->m_szTitle = g_pXWaylandManager->getTitle(PWINDOW);
|
||||||
|
|
||||||
if (!PWINDOW->m_bIsModal)
|
if (!PWINDOW->m_bIsModal)
|
||||||
g_pCompositor->focusWindow(PWINDOW);
|
g_pCompositor->focusWindow(PWINDOW);
|
||||||
|
|
||||||
|
|
|
@ -357,8 +357,13 @@ void CHyprDwindleLayout::onWindowCreatedFloating(CWindow* pWindow) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pWindow->m_vRealPosition = pWindow->m_vEffectivePosition + pWindow->m_vEffectiveSize / 2.f;
|
if (!pWindow->m_bX11DoesntWantBorders) {
|
||||||
pWindow->m_vRealSize = Vector2D(5,5);
|
pWindow->m_vRealPosition = pWindow->m_vEffectivePosition + pWindow->m_vEffectiveSize / 2.f;
|
||||||
|
pWindow->m_vRealSize = Vector2D(5, 5);
|
||||||
|
} else {
|
||||||
|
pWindow->m_vRealPosition = pWindow->m_vEffectivePosition;
|
||||||
|
pWindow->m_vRealSize = pWindow->m_vEffectiveSize;
|
||||||
|
}
|
||||||
|
|
||||||
g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize);
|
g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize);
|
||||||
g_pCompositor->fixXWaylandWindowsOnWorkspace(PMONITOR->activeWorkspace);
|
g_pCompositor->fixXWaylandWindowsOnWorkspace(PMONITOR->activeWorkspace);
|
||||||
|
|
|
@ -54,11 +54,7 @@ std::string CHyprXWaylandManager::getTitle(CWindow* pWindow) {
|
||||||
if (pWindow->m_uSurface.xwayland) {
|
if (pWindow->m_uSurface.xwayland) {
|
||||||
return std::string(pWindow->m_uSurface.xwayland->title);
|
return std::string(pWindow->m_uSurface.xwayland->title);
|
||||||
}
|
}
|
||||||
} else {
|
} else if (pWindow->m_uSurface.xdg) {
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pWindow->m_uSurface.xdg) {
|
|
||||||
if (pWindow->m_uSurface.xdg->toplevel) {
|
if (pWindow->m_uSurface.xdg->toplevel) {
|
||||||
return std::string(pWindow->m_uSurface.xdg->toplevel->title);
|
return std::string(pWindow->m_uSurface.xdg->toplevel->title);
|
||||||
}
|
}
|
||||||
|
@ -72,6 +68,26 @@ std::string CHyprXWaylandManager::getTitle(CWindow* pWindow) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string CHyprXWaylandManager::getAppIDClass(CWindow* pWindow) {
|
||||||
|
try {
|
||||||
|
if (pWindow->m_bIsX11) {
|
||||||
|
if (pWindow->m_uSurface.xwayland) {
|
||||||
|
return std::string(pWindow->m_uSurface.xwayland->_class);
|
||||||
|
}
|
||||||
|
} else if (pWindow->m_uSurface.xdg) {
|
||||||
|
if (pWindow->m_uSurface.xdg->toplevel) {
|
||||||
|
return std::string(pWindow->m_uSurface.xdg->toplevel->app_id);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
} catch (std::logic_error& e) {
|
||||||
|
Debug::log(ERR, "Error in getAppIDClass: %s", e.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
void CHyprXWaylandManager::sendCloseWindow(CWindow* pWindow) {
|
void CHyprXWaylandManager::sendCloseWindow(CWindow* pWindow) {
|
||||||
if (pWindow->m_bIsX11) {
|
if (pWindow->m_bIsX11) {
|
||||||
wlr_xwayland_surface_close(pWindow->m_uSurface.xwayland);
|
wlr_xwayland_surface_close(pWindow->m_uSurface.xwayland);
|
||||||
|
|
|
@ -14,6 +14,7 @@ public:
|
||||||
void activateSurface(wlr_surface*, bool);
|
void activateSurface(wlr_surface*, bool);
|
||||||
void getGeometryForWindow(CWindow*, wlr_box*);
|
void getGeometryForWindow(CWindow*, wlr_box*);
|
||||||
std::string getTitle(CWindow*);
|
std::string getTitle(CWindow*);
|
||||||
|
std::string getAppIDClass(CWindow*);
|
||||||
void sendCloseWindow(CWindow*);
|
void sendCloseWindow(CWindow*);
|
||||||
void setWindowSize(CWindow*, const Vector2D&);
|
void setWindowSize(CWindow*, const Vector2D&);
|
||||||
void setWindowStyleTiled(CWindow*, uint32_t);
|
void setWindowStyleTiled(CWindow*, uint32_t);
|
||||||
|
|
Loading…
Reference in a new issue