2022-03-28 16:10:30 +02:00
|
|
|
#include "MiscFunctions.hpp"
|
|
|
|
#include "../defines.hpp"
|
2022-05-05 12:50:25 +02:00
|
|
|
#include <algorithm>
|
2022-05-18 12:18:58 +02:00
|
|
|
#include "../Compositor.hpp"
|
2022-06-25 20:49:06 +02:00
|
|
|
#include <sys/utsname.h>
|
2022-07-18 20:47:28 +02:00
|
|
|
#include <iomanip>
|
2022-03-28 16:10:30 +02:00
|
|
|
|
2022-06-28 11:30:07 +02:00
|
|
|
static const float transforms[][9] = {{
|
|
|
|
1.0f, 0.0f, 0.0f,
|
|
|
|
0.0f, 1.0f, 0.0f,
|
|
|
|
0.0f, 0.0f, 1.0f,
|
|
|
|
},{
|
|
|
|
0.0f, 1.0f, 0.0f,
|
|
|
|
-1.0f, 0.0f, 0.0f,
|
|
|
|
0.0f, 0.0f, 1.0f,
|
|
|
|
},{
|
|
|
|
-1.0f, 0.0f, 0.0f,
|
|
|
|
0.0f, -1.0f, 0.0f,
|
|
|
|
0.0f, 0.0f, 1.0f,
|
|
|
|
},{
|
|
|
|
0.0f, -1.0f, 0.0f,
|
|
|
|
1.0f, 0.0f, 0.0f,
|
|
|
|
0.0f, 0.0f, 1.0f,
|
|
|
|
},{
|
|
|
|
-1.0f, 0.0f, 0.0f,
|
|
|
|
0.0f, 1.0f, 0.0f,
|
|
|
|
0.0f, 0.0f, 1.0f,
|
|
|
|
},{
|
|
|
|
0.0f, 1.0f, 0.0f,
|
|
|
|
1.0f, 0.0f, 0.0f,
|
|
|
|
0.0f, 0.0f, 1.0f,
|
|
|
|
},{
|
|
|
|
1.0f, 0.0f, 0.0f,
|
|
|
|
0.0f, -1.0f, 0.0f,
|
|
|
|
0.0f, 0.0f, 1.0f,
|
|
|
|
},{
|
|
|
|
0.0f, -1.0f, 0.0f,
|
|
|
|
-1.0f, 0.0f, 0.0f,
|
|
|
|
0.0f, 0.0f, 1.0f,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2022-08-19 22:18:09 +02:00
|
|
|
std::string absolutePath(const std::string& rawpath, const std::string& currentPath) {
|
|
|
|
auto value = rawpath;
|
|
|
|
|
|
|
|
if (value[0] == '.') {
|
|
|
|
auto currentDir = currentPath.substr(0, currentPath.find_last_of('/'));
|
|
|
|
|
|
|
|
if (value[1] == '.') {
|
|
|
|
auto parentDir = currentDir.substr(0, currentDir.find_last_of('/'));
|
|
|
|
value.replace(0, 2, parentDir);
|
|
|
|
} else {
|
|
|
|
value.replace(0, 1, currentDir);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (value[0] == '~') {
|
|
|
|
static const char* const ENVHOME = getenv("HOME");
|
|
|
|
value.replace(0, 1, std::string(ENVHOME));
|
|
|
|
}
|
|
|
|
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2022-03-28 16:10:30 +02:00
|
|
|
void addWLSignal(wl_signal* pSignal, wl_listener* pListener, void* pOwner, std::string ownerString) {
|
|
|
|
ASSERT(pSignal);
|
|
|
|
ASSERT(pListener);
|
2022-09-25 20:07:48 +02:00
|
|
|
|
2022-03-28 16:10:30 +02:00
|
|
|
wl_signal_add(pSignal, pListener);
|
|
|
|
|
|
|
|
Debug::log(LOG, "Registered signal for owner %x: %x -> %x (owner: %s)", pOwner, pSignal, pListener, ownerString.c_str());
|
2022-04-02 19:09:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void handleNoop(struct wl_listener *listener, void *data) {
|
|
|
|
// Do nothing
|
|
|
|
}
|
|
|
|
|
2022-04-04 19:44:25 +02:00
|
|
|
std::string getFormat(const char *fmt, ...) {
|
2022-07-25 22:40:34 +02:00
|
|
|
char* outputStr = nullptr;
|
2022-04-04 19:44:25 +02:00
|
|
|
|
|
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
2022-07-25 22:40:34 +02:00
|
|
|
vasprintf(&outputStr, fmt, args);
|
2022-06-02 13:59:33 +02:00
|
|
|
va_end(args);
|
2022-04-04 19:44:25 +02:00
|
|
|
|
2022-06-02 13:59:33 +02:00
|
|
|
std::string output = std::string(outputStr);
|
|
|
|
free(outputStr);
|
2022-04-04 19:44:25 +02:00
|
|
|
|
2022-06-02 13:59:33 +02:00
|
|
|
return output;
|
2022-04-17 18:47:10 +02:00
|
|
|
}
|
|
|
|
|
2022-07-18 20:47:28 +02:00
|
|
|
std::string escapeJSONStrings(const std::string& str) {
|
|
|
|
std::ostringstream oss;
|
|
|
|
for (auto &c : str) {
|
|
|
|
switch (c) {
|
|
|
|
case '"': oss << "\\\""; break;
|
|
|
|
case '\\': oss << "\\\\"; break;
|
|
|
|
case '\b': oss << "\\b"; break;
|
|
|
|
case '\f': oss << "\\f"; break;
|
|
|
|
case '\n': oss << "\\n"; break;
|
|
|
|
case '\r': oss << "\\r"; break;
|
|
|
|
case '\t': oss << "\\t"; break;
|
|
|
|
default:
|
|
|
|
if ('\x00' <= c && c <= '\x1f') {
|
|
|
|
oss << "\\u"
|
|
|
|
<< std::hex << std::setw(4) << std::setfill('0') << static_cast<int>(c);
|
|
|
|
} else {
|
|
|
|
oss << c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return oss.str();
|
|
|
|
}
|
|
|
|
|
2022-04-17 18:47:10 +02:00
|
|
|
void scaleBox(wlr_box* box, float scale) {
|
2022-06-30 20:02:04 +02:00
|
|
|
box->width = std::round(box->width * scale);
|
|
|
|
box->height = std::round(box->height * scale);
|
2022-04-17 18:47:10 +02:00
|
|
|
box->x = std::round(box->x * scale);
|
|
|
|
box->y = std::round(box->y * scale);
|
2022-04-18 13:25:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
std::string removeBeginEndSpacesTabs(std::string str) {
|
|
|
|
while (str[0] == ' ' || str[0] == '\t') {
|
|
|
|
str = str.substr(1);
|
|
|
|
}
|
|
|
|
|
2022-05-12 12:08:18 +02:00
|
|
|
while (str.length() != 0 && (str[str.length() - 1] == ' ' || str[str.length() - 1] == '\t')) {
|
2022-04-18 13:25:27 +02:00
|
|
|
str = str.substr(0, str.length() - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return str;
|
2022-04-20 16:53:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
float getPlusMinusKeywordResult(std::string source, float relative) {
|
|
|
|
float result = INT_MAX;
|
|
|
|
|
|
|
|
if (source.find_first_of("+") == 0) {
|
|
|
|
try {
|
2022-07-06 16:50:11 +02:00
|
|
|
if (source.contains("."))
|
2022-04-20 16:53:41 +02:00
|
|
|
result = relative + std::stof(source.substr(1));
|
|
|
|
else
|
|
|
|
result = relative + std::stoi(source.substr(1));
|
|
|
|
} catch (...) {
|
|
|
|
Debug::log(ERR, "Invalid arg \"%s\" in getPlusMinusKeywordResult!", source.c_str());
|
|
|
|
return INT_MAX;
|
|
|
|
}
|
|
|
|
} else if (source.find_first_of("-") == 0) {
|
|
|
|
try {
|
2022-07-06 16:50:11 +02:00
|
|
|
if (source.contains("."))
|
2022-04-20 16:53:41 +02:00
|
|
|
result = relative - std::stof(source.substr(1));
|
|
|
|
else
|
|
|
|
result = relative - std::stoi(source.substr(1));
|
|
|
|
} catch (...) {
|
|
|
|
Debug::log(ERR, "Invalid arg \"%s\" in getPlusMinusKeywordResult!", source.c_str());
|
|
|
|
return INT_MAX;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
try {
|
2022-07-06 16:50:11 +02:00
|
|
|
if (source.contains("."))
|
2022-04-20 16:53:41 +02:00
|
|
|
result = stof(source);
|
|
|
|
else
|
|
|
|
result = stoi(source);
|
|
|
|
} catch (...) {
|
|
|
|
Debug::log(ERR, "Invalid arg \"%s\" in getPlusMinusKeywordResult!", source.c_str());
|
|
|
|
return INT_MAX;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
2022-05-05 12:50:25 +02:00
|
|
|
}
|
|
|
|
|
2022-06-26 22:15:06 +02:00
|
|
|
bool isNumber(const std::string& str, bool allowfloat) {
|
2022-09-28 16:32:53 +02:00
|
|
|
|
|
|
|
std::string copy = str;
|
|
|
|
if (*copy.begin() == '-')
|
|
|
|
copy = copy.substr(1);
|
|
|
|
|
|
|
|
bool point = !allowfloat;
|
|
|
|
for (auto& c : copy) {
|
|
|
|
if (c == '.') {
|
|
|
|
if (point)
|
|
|
|
return false;
|
|
|
|
point = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!std::isdigit(c))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2022-05-05 12:50:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool isDirection(const std::string& arg) {
|
|
|
|
return arg == "l" || arg == "r" || arg == "u" || arg == "d" || arg == "t" || arg == "b";
|
2022-05-18 12:18:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int getWorkspaceIDFromString(const std::string& in, std::string& outName) {
|
|
|
|
int result = INT_MAX;
|
2022-05-31 14:01:00 +02:00
|
|
|
if (in.find("special") == 0) {
|
|
|
|
outName = "special";
|
|
|
|
return SPECIAL_WORKSPACE_ID;
|
|
|
|
} else if (in.find("name:") == 0) {
|
2022-05-18 12:18:58 +02:00
|
|
|
const auto WORKSPACENAME = in.substr(in.find_first_of(':') + 1);
|
|
|
|
const auto WORKSPACE = g_pCompositor->getWorkspaceByName(WORKSPACENAME);
|
|
|
|
if (!WORKSPACE) {
|
|
|
|
result = g_pCompositor->getNextAvailableNamedWorkspace();
|
|
|
|
} else {
|
|
|
|
result = WORKSPACE->m_iID;
|
|
|
|
}
|
|
|
|
outName = WORKSPACENAME;
|
|
|
|
} else {
|
2022-09-28 16:26:41 +02:00
|
|
|
if ((in[0] == 'm' || in[0] == 'e') && (in[1] == '-' || in[1] == '+') && isNumber(in.substr(2))) {
|
2022-07-16 14:28:17 +02:00
|
|
|
bool onAllMonitors = in[0] == 'e';
|
|
|
|
|
2022-06-21 22:42:54 +02:00
|
|
|
if (!g_pCompositor->m_pLastMonitor) {
|
|
|
|
Debug::log(ERR, "Relative monitor workspace on monitor null!");
|
|
|
|
result = INT_MAX;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2022-05-31 12:33:08 +02:00
|
|
|
// monitor relative
|
|
|
|
result = (int)getPlusMinusKeywordResult(in.substr(1), 0);
|
|
|
|
|
|
|
|
// result now has +/- what we should move on mon
|
|
|
|
int remains = (int)result;
|
|
|
|
int currentID = g_pCompositor->m_pLastMonitor->activeWorkspace;
|
|
|
|
int searchID = currentID;
|
|
|
|
|
|
|
|
while (remains != 0) {
|
|
|
|
if (remains < 0)
|
|
|
|
searchID--;
|
2022-09-25 20:07:48 +02:00
|
|
|
else
|
2022-05-31 12:33:08 +02:00
|
|
|
searchID++;
|
2022-09-25 20:07:48 +02:00
|
|
|
|
2022-05-31 12:33:08 +02:00
|
|
|
if (g_pCompositor->workspaceIDOutOfBounds(searchID)){
|
|
|
|
// means we need to wrap around
|
|
|
|
int lowestID = 99999;
|
|
|
|
int highestID = -99999;
|
|
|
|
|
2022-06-30 15:44:26 +02:00
|
|
|
for (auto& w : g_pCompositor->m_vWorkspaces) {
|
2022-09-17 16:05:12 +02:00
|
|
|
if (w->m_iID == SPECIAL_WORKSPACE_ID)
|
|
|
|
continue;
|
|
|
|
|
2022-06-30 15:44:26 +02:00
|
|
|
if (w->m_iID < lowestID)
|
|
|
|
lowestID = w->m_iID;
|
2022-05-31 12:33:08 +02:00
|
|
|
|
2022-06-30 15:44:26 +02:00
|
|
|
if (w->m_iID > highestID)
|
|
|
|
highestID = w->m_iID;
|
2022-05-31 12:33:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (remains < 0)
|
|
|
|
searchID = highestID;
|
2022-09-25 20:07:48 +02:00
|
|
|
else
|
2022-05-31 12:33:08 +02:00
|
|
|
searchID = lowestID;
|
|
|
|
}
|
|
|
|
|
2022-06-02 19:50:46 +02:00
|
|
|
if (const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(searchID); PWORKSPACE && PWORKSPACE->m_iID != SPECIAL_WORKSPACE_ID) {
|
2022-07-16 14:28:17 +02:00
|
|
|
if (onAllMonitors || PWORKSPACE->m_iMonitorID == g_pCompositor->m_pLastMonitor->ID) {
|
2022-05-31 12:33:08 +02:00
|
|
|
currentID = PWORKSPACE->m_iID;
|
|
|
|
|
|
|
|
if (remains < 0)
|
|
|
|
remains++;
|
|
|
|
else
|
|
|
|
remains--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
result = currentID;
|
|
|
|
outName = g_pCompositor->getWorkspaceByID(currentID)->m_szName;
|
|
|
|
|
|
|
|
} else {
|
2022-09-28 16:26:41 +02:00
|
|
|
if (in[0] == '+' || in[0] == '-') {
|
|
|
|
if (g_pCompositor->m_pLastMonitor)
|
|
|
|
result = std::max((int)getPlusMinusKeywordResult(in, g_pCompositor->m_pLastMonitor->activeWorkspace), 1);
|
|
|
|
else {
|
|
|
|
Debug::log(ERR, "Relative workspace on no mon!");
|
|
|
|
result = INT_MAX;
|
|
|
|
}
|
|
|
|
} else if (isNumber(in))
|
2022-09-26 21:10:24 +02:00
|
|
|
result = std::max(std::stoi(in), 1);
|
2022-06-21 22:42:54 +02:00
|
|
|
else {
|
2022-09-28 16:26:41 +02:00
|
|
|
// maybe name
|
|
|
|
const auto PWORKSPACE = g_pCompositor->getWorkspaceByName(in);
|
|
|
|
if (PWORKSPACE)
|
|
|
|
result = PWORKSPACE->m_iID;
|
2022-06-21 22:42:54 +02:00
|
|
|
}
|
2022-09-28 16:26:41 +02:00
|
|
|
|
2022-05-31 12:33:08 +02:00
|
|
|
outName = std::to_string(result);
|
2022-09-25 20:07:48 +02:00
|
|
|
}
|
2022-05-18 12:18:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
2022-05-25 18:40:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Vector2D& p2) {
|
|
|
|
const float DX = std::max((double)0, std::max(p1.x - vec.x, vec.x - p2.x));
|
|
|
|
const float DY = std::max((double)0, std::max(p1.y - vec.y, vec.y - p2.y));
|
|
|
|
return DX * DX + DY * DY;
|
2022-06-25 20:49:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Execute a shell command and get the output
|
|
|
|
std::string execAndGet(const char* cmd) {
|
|
|
|
std::array<char, 128> buffer;
|
|
|
|
std::string result;
|
|
|
|
const std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd, "r"), pclose);
|
|
|
|
if (!pipe) {
|
|
|
|
Debug::log(ERR, "execAndGet: failed in pipe");
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
|
|
|
|
result += buffer.data();
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void logSystemInfo() {
|
|
|
|
struct utsname unameInfo;
|
|
|
|
|
|
|
|
uname(&unameInfo);
|
|
|
|
|
|
|
|
Debug::log(LOG, "System name: %s", unameInfo.sysname);
|
|
|
|
Debug::log(LOG, "Node name: %s", unameInfo.nodename);
|
|
|
|
Debug::log(LOG, "Release: %s", unameInfo.release);
|
|
|
|
Debug::log(LOG, "Version: %s", unameInfo.version);
|
|
|
|
|
|
|
|
// log etc
|
|
|
|
Debug::log(LOG, "os-release:");
|
|
|
|
|
|
|
|
Debug::log(NONE, "%s", execAndGet("cat /etc/os-release").c_str());
|
2022-06-28 11:30:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void matrixProjection(float mat[9], int w, int h, wl_output_transform tr) {
|
|
|
|
memset(mat, 0, sizeof(*mat) * 9);
|
|
|
|
|
|
|
|
const float* t = transforms[tr];
|
|
|
|
float x = 2.0f / w;
|
|
|
|
float y = 2.0f / h;
|
|
|
|
|
|
|
|
// Rotation + reflection
|
|
|
|
mat[0] = x * t[0];
|
|
|
|
mat[1] = x * t[1];
|
|
|
|
mat[3] = y * -t[3];
|
|
|
|
mat[4] = y * -t[4];
|
|
|
|
|
|
|
|
// Translation
|
|
|
|
mat[2] = -copysign(1.0f, mat[0] + mat[1]);
|
|
|
|
mat[5] = -copysign(1.0f, mat[3] + mat[4]);
|
|
|
|
|
|
|
|
// Identity
|
|
|
|
mat[8] = 1.0f;
|
|
|
|
}
|