Hyprland/src/helpers/MiscFunctions.cpp

324 lines
9.6 KiB
C++
Raw Normal View History

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-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-03-28 16:10:30 +02:00
void addWLSignal(wl_signal* pSignal, wl_listener* pListener, void* pOwner, std::string ownerString) {
ASSERT(pSignal);
ASSERT(pListener);
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
}
void wlr_signal_emit_safe(struct wl_signal *signal, void *data) {
struct wl_listener cursor;
struct wl_listener end;
/* Add two special markers: one cursor and one end marker. This way, we know
* that we've already called listeners on the left of the cursor and that we
* don't want to call listeners on the right of the end marker. The 'it'
* function can remove any element it wants from the list without troubles.
* wl_list_for_each_safe tries to be safe but it fails: it works fine
* if the current item is removed, but not if the next one is. */
wl_list_insert(&signal->listener_list, &cursor.link);
cursor.notify = handleNoop;
wl_list_insert(signal->listener_list.prev, &end.link);
end.notify = handleNoop;
while (cursor.link.next != &end.link) {
struct wl_list *pos = cursor.link.next;
struct wl_listener *l = wl_container_of(pos, l, link);
wl_list_remove(&cursor.link);
wl_list_insert(pos, &cursor.link);
l->notify(l, data);
}
wl_list_remove(&cursor.link);
wl_list_remove(&end.link);
}
2022-04-04 19:44:25 +02:00
std::string getFormat(const char *fmt, ...) {
2022-06-02 13:59:33 +02:00
char buf[LOGMESSAGESIZE] = "";
char* outputStr;
int logLen;
2022-04-04 19:44:25 +02:00
va_list args;
va_start(args, fmt);
2022-06-02 13:59:33 +02:00
logLen = vsnprintf(buf, sizeof buf, fmt, args);
va_end(args);
2022-04-04 19:44:25 +02:00
2022-06-02 13:59:33 +02:00
if ((long unsigned int)logLen < sizeof buf) {
outputStr = strdup(buf);
} else {
outputStr = (char*)malloc(logLen + 1);
2022-04-04 19:44:25 +02:00
2022-06-02 13:59:33 +02:00
if (!outputStr) {
printf("CRITICAL: Cannot alloc size %d for log! (Out of memory?)", logLen + 1);
return "";
}
va_start(args, fmt);
vsnprintf(outputStr, logLen + 1U, fmt, args);
va_end(args);
}
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;
}
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);
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);
}
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 {
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 {
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 {
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) {
return std::ranges::all_of(str.begin(), str.end(), [&](char c) { return isdigit(c) != 0 || c == '-' || (allowfloat && c == '.'); });
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 {
if (in[0] == 'm') {
if (!g_pCompositor->m_pLastMonitor) {
Debug::log(ERR, "Relative monitor workspace on monitor null!");
result = INT_MAX;
return result;
}
// 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--;
else
searchID++;
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) {
if (w->m_iID < lowestID)
lowestID = w->m_iID;
2022-06-30 15:44:26 +02:00
if (w->m_iID > highestID)
highestID = w->m_iID;
}
if (remains < 0)
searchID = highestID;
else
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) {
if (PWORKSPACE->m_iMonitorID == g_pCompositor->m_pLastMonitor->ID) {
currentID = PWORKSPACE->m_iID;
if (remains < 0)
remains++;
else
remains--;
}
}
}
result = currentID;
outName = g_pCompositor->getWorkspaceByID(currentID)->m_szName;
} else {
if (g_pCompositor->m_pLastMonitor)
result = std::clamp((int)getPlusMinusKeywordResult(in, g_pCompositor->m_pLastMonitor->activeWorkspace), 1, INT_MAX);
else if (isNumber(in))
result = std::clamp(std::stoi(in), 1, INT_MAX);
else {
Debug::log(ERR, "Relative workspace on no mon!");
result = INT_MAX;
}
outName = std::to_string(result);
}
2022-05-18 12:18:58 +02:00
}
return result;
}
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;
}