Bar modules upgrade

This commit is contained in:
vaxerski 2021-11-27 19:07:33 +01:00
parent ec865f0f8e
commit 6224ffb078
18 changed files with 648 additions and 118 deletions

View file

@ -25,7 +25,7 @@ Hypr is a Linux tiling window manager for Xorg. It's written in XCB with modern
## Roadmap v2 (not in order) ## Roadmap v2 (not in order)
- [x] Upgrade the status bar rendering to Cairo - [x] Upgrade the status bar rendering to Cairo
- [ ] Better status bar configability - [x] Better status bar configability ~ WIP
- [ ] Rounded corners - [ ] Rounded corners
- [x] Replace default X11 cursor with the pointer - [x] Replace default X11 cursor with the pointer
- [x] Fix ghost windows once and for all - [x] Fix ghost windows once and for all

View file

@ -6,10 +6,20 @@
gaps_in=5 gaps_in=5
border_size=1 border_size=1
gaps_out=20 gaps_out=20
bar_height=20 max_fps=60 # max fps for updates of config & animations
bar_monitor=0
bar_enabled=1 # Bar config
max_fps=60 Bar {
height=20
monitor=0
enabled=1
col.bg=0xff111111
col.high=0xffff3333
module=left,0xff8000ff,0xffffffff,1,workspaces
module=right,0xffffffff,0xff00ff33,1000,$date +%a,\ %b\ %Y\ \ %I:%M\ %p$
}
# colors # colors
col.active_border=0x77ff3333 col.active_border=0x77ff3333

View file

@ -55,9 +55,19 @@ int64_t barMainThread() {
Debug::log(LOG, "Bar setup finished!"); Debug::log(LOG, "Bar setup finished!");
int lazyUpdateCounter = 0;
while (1) { while (1) {
// Don't spam these
if (lazyUpdateCounter > 10) {
ConfigManager::tick(); ConfigManager::tick();
lazyUpdateCounter = 0;
}
++lazyUpdateCounter;
// Recieve the message and send our reply // Recieve the message and send our reply
IPCRecieveMessageB(g_pWindowManager->m_sIPCBarPipeIn.szPipeName); IPCRecieveMessageB(g_pWindowManager->m_sIPCBarPipeIn.szPipeName);
SIPCMessageBarToMain message; SIPCMessageBarToMain message;
@ -86,6 +96,19 @@ int64_t barMainThread() {
return 0; return 0;
} }
void CStatusBar::setupModule(SBarModule* module) {
uint32_t values[2];
module->bgcontext = xcb_generate_id(g_pWindowManager->DisplayConnection);
values[0] = module->bgcolor;
values[1] = module->bgcolor;
xcb_create_gc(g_pWindowManager->DisplayConnection, module->bgcontext, m_iPixmap, XCB_GC_BACKGROUND | XCB_GC_FOREGROUND, values);
}
void CStatusBar::destroyModule(SBarModule* module) {
if (module->bgcontext)
xcb_free_gc(g_pWindowManager->DisplayConnection, module->bgcontext);
}
void CStatusBar::setup(int MonitorID) { void CStatusBar::setup(int MonitorID) {
Debug::log(LOG, "Creating the bar!"); Debug::log(LOG, "Creating the bar!");
@ -98,7 +121,7 @@ void CStatusBar::setup(int MonitorID) {
m_iMonitorID = MonitorID; m_iMonitorID = MonitorID;
m_vecPosition = MONITOR.vecPosition; m_vecPosition = MONITOR.vecPosition;
m_vecSize = Vector2D(MONITOR.vecSize.x, ConfigManager::getInt("bar_height")); m_vecSize = Vector2D(MONITOR.vecSize.x, ConfigManager::getInt("bar:height"));
uint32_t values[4]; uint32_t values[4];
@ -129,8 +152,8 @@ void CStatusBar::setup(int MonitorID) {
auto contextBG = &m_mContexts["BG"]; auto contextBG = &m_mContexts["BG"];
contextBG->GContext = xcb_generate_id(g_pWindowManager->DisplayConnection); contextBG->GContext = xcb_generate_id(g_pWindowManager->DisplayConnection);
values[0] = 0xFF111111; values[0] = ConfigManager::getInt("bar:col.bg");
values[1] = 0xFF111111; values[1] = ConfigManager::getInt("bar:col.bg");
xcb_create_gc(g_pWindowManager->DisplayConnection, contextBG->GContext, m_iPixmap, XCB_GC_BACKGROUND | XCB_GC_FOREGROUND, values); xcb_create_gc(g_pWindowManager->DisplayConnection, contextBG->GContext, m_iPixmap, XCB_GC_BACKGROUND | XCB_GC_FOREGROUND, values);
// //
@ -145,43 +168,16 @@ void CStatusBar::setup(int MonitorID) {
// //
// //
auto contextHIGH = &m_mContexts["HIGH"];
contextHIGH->GContext = xcb_generate_id(g_pWindowManager->DisplayConnection);
auto contextBASETEXT = &m_mContexts["BASETEXT"]; values[0] = ConfigManager::getInt("bar:col.high");
values[1] = ConfigManager::getInt("bar:col.high");
contextBASETEXT->GContext = xcb_generate_id(g_pWindowManager->DisplayConnection); xcb_create_gc(g_pWindowManager->DisplayConnection, contextHIGH->GContext, m_iPixmap, XCB_GC_BACKGROUND | XCB_GC_FOREGROUND, values);
contextBASETEXT->Font = xcb_generate_id(g_pWindowManager->DisplayConnection);
xcb_open_font(g_pWindowManager->DisplayConnection, contextBASETEXT->Font, 5, "fixed");
values[0] = 0xFFFFFFFF;
values[1] = 0xFF111111;
values[2] = contextBASETEXT->Font;
xcb_create_gc(g_pWindowManager->DisplayConnection, contextBASETEXT->GContext, m_iPixmap, XCB_GC_BACKGROUND | XCB_GC_FOREGROUND | XCB_GC_FONT, values);
// //
// //
auto contextHITEXT = &m_mContexts["HITEXT"];
contextHITEXT->GContext = xcb_generate_id(g_pWindowManager->DisplayConnection);
contextHITEXT->Font = contextBASETEXT->Font;
values[0] = 0xFF000000;
values[1] = 0xFFFF3333;
values[2] = contextHITEXT->Font;
xcb_create_gc(g_pWindowManager->DisplayConnection, contextHITEXT->GContext, m_iPixmap, XCB_GC_BACKGROUND | XCB_GC_FOREGROUND | XCB_GC_FONT, values);
//
//
auto contextMEDBG = &m_mContexts["MEDBG"];
contextMEDBG->GContext = xcb_generate_id(g_pWindowManager->DisplayConnection);
values[0] = 0xFFFF3333;
values[1] = 0xFF111111;
xcb_create_gc(g_pWindowManager->DisplayConnection, contextMEDBG->GContext, m_iPixmap, XCB_GC_BACKGROUND | XCB_GC_FOREGROUND, values);
// don't, i use it later
//xcb_close_font(g_pWindowManager->DisplayConnection, contextBASETEXT->Font);
m_pCairoSurface = cairo_xcb_surface_create(g_pWindowManager->DisplayConnection, m_iPixmap, g_pWindowManager->VisualType, m_pCairoSurface = cairo_xcb_surface_create(g_pWindowManager->DisplayConnection, m_iPixmap, g_pWindowManager->VisualType,
m_vecSize.x, m_vecSize.y); m_vecSize.x, m_vecSize.y);
m_pCairo = cairo_create(m_pCairoSurface); m_pCairo = cairo_create(m_pCairoSurface);
@ -223,6 +219,10 @@ void CStatusBar::drawText(Vector2D pos, std::string text, uint32_t color) {
cairo_show_text(m_pCairo, text.c_str()); cairo_show_text(m_pCairo, text.c_str());
} }
int CStatusBar::getTextHalfY() {
return m_vecSize.y - (m_vecSize.y - 9) / 2.f;
}
void CStatusBar::draw() { void CStatusBar::draw() {
// const auto WORKSPACE = g_pWindowManager->getWorkspaceByID(g_pWindowManager->activeWorkspaces[m_iMonitorID]); // const auto WORKSPACE = g_pWindowManager->getWorkspaceByID(g_pWindowManager->activeWorkspaces[m_iMonitorID]);
@ -235,13 +235,53 @@ void CStatusBar::draw() {
return; return;
} }
if (ALPHA((uint32_t)ConfigManager::getInt("bar:col.bg")) != 0) {
xcb_rectangle_t rectangles[] = {{(int)0, (int)0, (int)m_vecSize.x, (int)m_vecSize.y}}; xcb_rectangle_t rectangles[] = {{(int)0, (int)0, (int)m_vecSize.x, (int)m_vecSize.y}};
xcb_poly_fill_rectangle(g_pWindowManager->DisplayConnection, m_iPixmap, m_mContexts["BG"].GContext, 1, rectangles); xcb_poly_fill_rectangle(g_pWindowManager->DisplayConnection, m_iPixmap, m_mContexts["BG"].GContext, 1, rectangles);
}
//
//
// DRAW ALL MODULES
int offLeft = 0;
int offRight = 0;
for (auto& module : modules) {
if (!module.bgcontext && !module.isPad)
setupModule(&module);
if (module.value == "workspaces") {
offLeft += drawWorkspacesModule(&module, offLeft);
} else {
if (module.alignment == LEFT) {
offLeft += drawModule(&module, offLeft);
} else if (module.alignment == RIGHT) {
offRight += drawModule(&module, offRight);
} else {
drawModule(&module, 0);
}
}
}
//
//
//
cairo_surface_flush(m_pCairoSurface);
xcb_copy_area(g_pWindowManager->DisplayConnection, m_iPixmap, m_iWindowID, m_mContexts["BG"].GContext,
0, 0, 0, 0, m_vecSize.x, m_vecSize.y);
xcb_flush(g_pWindowManager->DisplayConnection);
}
// Returns the width
int CStatusBar::drawWorkspacesModule(SBarModule* mod, int off) {
// Draw workspaces // Draw workspaces
int drawnWorkspaces = 0; int drawnWorkspaces = 0;
for (long unsigned int i = 0; i < openWorkspaces.size(); ++i) { for (long unsigned int i = 0; i < openWorkspaces.size(); ++i) {
const auto WORKSPACE = openWorkspaces[i]; const auto WORKSPACE = openWorkspaces[i];
// The LastWindow may be on a different one. This is where the mouse is. // The LastWindow may be on a different one. This is where the mouse is.
@ -252,32 +292,57 @@ void CStatusBar::draw() {
std::string workspaceName = std::to_string(openWorkspaces[i]); std::string workspaceName = std::to_string(openWorkspaces[i]);
xcb_rectangle_t rectangleActive[] = { { m_vecSize.y * drawnWorkspaces, 0, m_vecSize.y, m_vecSize.y } }; xcb_rectangle_t rectangleActive[] = {{off + m_vecSize.y * drawnWorkspaces, 0, m_vecSize.y, m_vecSize.y}};
xcb_poly_fill_rectangle(g_pWindowManager->DisplayConnection, m_iPixmap, WORKSPACE == MOUSEWORKSPACEID ? m_mContexts["MEDBG"].GContext : m_mContexts["BG"].GContext, 1, rectangleActive); xcb_poly_fill_rectangle(g_pWindowManager->DisplayConnection, m_iPixmap, WORKSPACE == MOUSEWORKSPACEID ? m_mContexts["HIGH"].GContext : m_mContexts["BG"].GContext, 1, rectangleActive);
drawText(Vector2D(m_vecSize.y * drawnWorkspaces + m_vecSize.y / 2.f - getTextWidth(workspaceName) / 2.f, m_vecSize.y - (m_vecSize.y - 9) / 2.f), drawText(Vector2D(off + m_vecSize.y * drawnWorkspaces + m_vecSize.y / 2.f - getTextWidth(workspaceName) / 2.f, getTextHalfY()),
workspaceName, WORKSPACE == MOUSEWORKSPACEID ? 0xFF111111 : 0xFFFFFFFF); workspaceName, WORKSPACE == MOUSEWORKSPACEID ? 0xFF111111 : 0xFFFFFFFF);
drawnWorkspaces++; drawnWorkspaces++;
} }
// Draw STATUS to the right return drawnWorkspaces * m_vecSize.y;
std::string STATUS = exec(m_szStatusCommand.c_str()); }
STATUS = STATUS.substr(0, (STATUS.length() > 0 ? STATUS.length() - 1 : 9999999));
if (STATUS != "") { int CStatusBar::drawModule(SBarModule* mod, int off) {
drawText(Vector2D(m_vecSize.x - getTextWidth(STATUS), m_vecSize.y - (m_vecSize.y - 9) / 2.f),
STATUS, 0xFFFFFFFF); if (mod->isPad)
return mod->pad;
const int PAD = 4;
// check if we need to update
if (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - mod->updateLast).count() > mod->updateEveryMs) {
// Yes. Set the new last and do it.
mod->updateLast = std::chrono::system_clock::now();
mod->valueCalculated = BarCommands::parseCommand(mod->value);
} }
// We have the value, draw the module!
cairo_surface_flush(m_pCairoSurface); const auto MODULEWIDTH = getTextWidth(mod->valueCalculated) + PAD;
// clear before copying if (!MODULEWIDTH || mod->valueCalculated == "")
//xcb_clear_area(g_pWindowManager->DisplayConnection, 0, m_iWindowID, 0, 0, m_vecSize.x, m_vecSize.y); return 0; // empty module
//xcb_flush(g_pWindowManager->DisplayConnection);
xcb_copy_area(g_pWindowManager->DisplayConnection, m_iPixmap, m_iWindowID, m_mContexts["BG"].GContext, Vector2D position;
0, 0, 0, 0, m_vecSize.x, m_vecSize.y); switch (mod->alignment) {
case LEFT:
position = Vector2D(off, 0);
break;
case RIGHT:
position = Vector2D(m_vecSize.x - off - MODULEWIDTH, 0);
break;
case CENTER:
position = Vector2D(m_vecSize.x / 2.f - MODULEWIDTH / 2.f, 0);
break;
}
xcb_flush(g_pWindowManager->DisplayConnection); xcb_rectangle_t rects[] = {{ position.x, position.y, MODULEWIDTH, m_vecSize.y }};
xcb_poly_fill_rectangle(g_pWindowManager->DisplayConnection, m_iPixmap, mod->bgcontext, 1, rects);
drawText(position + Vector2D(PAD / 2, getTextHalfY()), mod->valueCalculated, mod->color);
return MODULEWIDTH;
} }

View file

@ -4,26 +4,56 @@
#include "../defines.hpp" #include "../defines.hpp"
#include "../ipc/ipc.hpp" #include "../ipc/ipc.hpp"
#include "BarCommands.hpp"
#include <chrono>
struct SDrawingContext { struct SDrawingContext {
xcb_gcontext_t GContext; xcb_gcontext_t GContext;
xcb_font_t Font; xcb_font_t Font;
}; };
enum ModuleAlignment {
LEFT = 0,
CENTER,
RIGHT
};
struct SBarModule {
ModuleAlignment alignment;
std::string value;
std::string valueCalculated = "";
uint64_t color;
uint64_t bgcolor;
uint64_t updateEveryMs;
std::chrono::system_clock::time_point updateLast;
xcb_gcontext_t bgcontext = NULL;
// PADS
bool isPad = false;
int pad = 0;
};
class CStatusBar { class CStatusBar {
public: public:
EXPOSED_MEMBER(WindowID, xcb_window_t, i); EXPOSED_MEMBER(WindowID, xcb_window_t, i);
EXPOSED_MEMBER(MonitorID, int, i); EXPOSED_MEMBER(MonitorID, int, i);
EXPOSED_MEMBER(StatusCommand, std::string, sz); // TODO: make the bar better EXPOSED_MEMBER(StatusCommand, std::string, sz); // TODO: make the bar better
EXPOSED_MEMBER(LastWindowName, std::string, sz);
void draw(); void draw();
void setup(int MonitorID); void setup(int MonitorID);
void destroy(); void destroy();
void setupModule(SBarModule*);
void destroyModule(SBarModule*);
std::vector<int> openWorkspaces; std::vector<int> openWorkspaces;
EXPOSED_MEMBER(CurrentWorkspace, int, i); EXPOSED_MEMBER(CurrentWorkspace, int, i);
std::vector<SBarModule> modules;
private: private:
Vector2D m_vecSize; Vector2D m_vecSize;
Vector2D m_vecPosition; Vector2D m_vecPosition;
@ -38,6 +68,9 @@ private:
void drawText(Vector2D, std::string, uint32_t); void drawText(Vector2D, std::string, uint32_t);
int getTextWidth(std::string); int getTextWidth(std::string);
int drawModule(SBarModule*, int);
int drawWorkspacesModule(SBarModule*, int);
int getTextHalfY();
std::unordered_map<std::string, SDrawingContext> m_mContexts; std::unordered_map<std::string, SDrawingContext> m_mContexts;
}; };

178
src/bar/BarCommands.cpp Normal file
View file

@ -0,0 +1,178 @@
#include "BarCommands.hpp"
#include "../windowManager.hpp"
std::vector<std::pair<int, int>> lastReads;
std::string getCpuString() {
std::vector<std::pair<int, int>> usageRead;
std::ifstream cpuif;
cpuif.open("/proc/stat");
std::string line;
while (std::getline(cpuif, line)) {
// parse line
const auto stats = splitString(line, ' ');
if (stats.size() < 1)
continue;
if (stats[0].find("cpu") == std::string::npos)
break;
// get the percent
try {
const auto user = stol(stats[1]);
const auto nice = stol(stats[2]);
const auto kern = stol(stats[3]);
// get total
long total = 0;
for (const auto& t : stats) {
if (t.find("c") != std::string::npos)
continue;
total += stol(t);
}
usageRead.push_back({user + nice + kern, total});
} catch( ... ) { ; } // oops
}
// Compare the values
std::pair<int, int> lastReadsTotal = {0, 0};
for (const auto& lr : lastReads) {
lastReadsTotal.first += lr.first;
lastReadsTotal.second += lr.second;
}
std::pair<int, int> newReadsTotal = {0, 0};
for (const auto& nr : usageRead) {
newReadsTotal.first += nr.first;
newReadsTotal.second += nr.second;
}
std::pair<int, int> difference = {newReadsTotal.first - lastReadsTotal.first, newReadsTotal.second - lastReadsTotal.second};
float percUsage = (float)difference.first / (float)difference.second;
lastReads.clear();
for (const auto& nr : usageRead) {
lastReads.push_back(nr);
}
return std::to_string((int)(percUsage * 100.f)) + "%";
}
std::string getRamString() {
float available = 0;
float total = 0;
std::ifstream ramif;
ramif.open("/proc/meminfo");
std::string line;
while (std::getline(ramif, line)) {
// parse line
const auto KEY = line.substr(0, line.find_first_of(':'));
int startValue = 0;
for (int i = 0; i < line.length(); ++i) {
const auto& c = line[i];
if (c >= '0' && c <= '9') {
startValue = i;
break;
}
}
float VALUE = 0.f;
try {
std::string toVal = line.substr(startValue);
toVal = toVal.substr(0, line.find_first_of(' ', startValue));
VALUE = stol(toVal);
} catch (...) { ; } // oops
VALUE /= 1024.f;
if (KEY == "MemTotal") {
total = VALUE;
} else if (KEY == "MemAvailable") {
available = VALUE;
}
}
return std::to_string((int)(total - available)) + "MB/" + std::to_string((int)total) + "MB";
}
std::string getCurrentWindowName() {
return g_pWindowManager->statusBar->getLastWindowName();
}
std::string BarCommands::parsePercent(std::string token) {
// check what the token is and act accordingly.
if (token == "RAM") return getRamString();
else if (token == "CPU") return getCpuString();
else if (token == "WINNAME") return getCurrentWindowName();
Debug::log(ERR, "Unknown token while parsing module: %" + token + "%");
return "Error";
}
std::string BarCommands::parseDollar(std::string token) {
const auto result = exec(token.c_str());
return result.substr(0, result.length() - 1);
}
std::string BarCommands::parseCommand(std::string command) {
std::string result = "";
for (int i = 0; i < command.length(); ++i) {
const auto c = command[i];
if (c == '%') {
// find the next one
for (int j = i + 1; i < command.length(); ++j) {
if (command[j] == '%') {
// found!
auto toSend = command.substr(i + 1);
toSend = toSend.substr(0, toSend.find_first_of('%'));
result += parsePercent(toSend);
i = j;
break;
}
if (command[j] == ' ')
break; // if there is a space it's not a token
}
}
else if (c == '$') {
// find the next one
for (int j = i + 1; i < command.length(); ++j) {
if (command[j] == '$') {
// found!
auto toSend = command.substr(i + 1);
toSend = toSend.substr(0, toSend.find_first_of('$'));
result += parseDollar(toSend);
i = j;
break;
}
if (j + 1 == command.length()) {
Debug::log(ERR, "Unescaped $ in a module, module command: ");
Debug::log(NONE, command);
}
}
}
else {
result += command[i];
}
}
return result;
}

10
src/bar/BarCommands.hpp Normal file
View file

@ -0,0 +1,10 @@
#pragma once
#include "../defines.hpp"
#include "../utilities/Util.hpp"
namespace BarCommands {
std::string parseCommand(std::string);
std::string parsePercent(std::string);
std::string parseDollar(std::string);
};

View file

@ -16,9 +16,11 @@ void ConfigManager::init() {
configValues["max_fps"].intValue = 60; configValues["max_fps"].intValue = 60;
configValues["bar_monitor"].intValue = 0; configValues["bar:monitor"].intValue = 0;
configValues["bar_enabled"].intValue = 1; configValues["bar:enabled"].intValue = 1;
configValues["bar_height"].intValue = 15; configValues["bar:height"].intValue = 15;
configValues["bar:col.bg"].intValue = 0xFF111111;
configValues["bar:col.high"].intValue = 0xFFFF3333;
configValues["status_command"].strValue = "date +%I:%M\\ %p"; // Time configValues["status_command"].strValue = "date +%I:%M\\ %p"; // Time
@ -36,6 +38,37 @@ void ConfigManager::init() {
applyKeybindsToX(); applyKeybindsToX();
} }
void configSetValueSafe(const std::string& COMMAND, const std::string& VALUE) {
if (ConfigManager::configValues.find(COMMAND) == ConfigManager::configValues.end())
return;
auto& CONFIGENTRY = ConfigManager::configValues.at(COMMAND);
if (CONFIGENTRY.intValue != -1) {
try {
if (VALUE.find("0x") == 0) {
// Values with 0x are hex
const auto VALUEWITHOUTHEX = VALUE.substr(2);
CONFIGENTRY.intValue = stol(VALUEWITHOUTHEX, nullptr, 16);
} else
CONFIGENTRY.intValue = stol(VALUE);
} catch (...) {
Debug::log(WARN, "Error reading value of " + COMMAND);
}
} else if (CONFIGENTRY.floatValue != -1) {
try {
CONFIGENTRY.floatValue = stof(VALUE);
} catch (...) {
Debug::log(WARN, "Error reading value of " + COMMAND);
}
} else if (CONFIGENTRY.strValue != "") {
try {
CONFIGENTRY.strValue = VALUE;
} catch (...) {
Debug::log(WARN, "Error reading value of " + COMMAND);
}
}
}
void handleBind(const std::string& command, const std::string& value) { void handleBind(const std::string& command, const std::string& value) {
// example: // example:
@ -85,6 +118,96 @@ void handleStatusCommand(const std::string& command, const std::string& args) {
g_pWindowManager->statusBar->setStatusCommand(args); g_pWindowManager->statusBar->setStatusCommand(args);
} }
void parseModule(const std::string& COMMANDC, const std::string& VALUE) {
SBarModule module;
auto valueCopy = VALUE;
const auto ALIGN = valueCopy.substr(0, valueCopy.find_first_of(","));
valueCopy = valueCopy.substr(valueCopy.find_first_of(",") + 1);
if (ALIGN == "pad") {
const auto ALIGNR = valueCopy.substr(0, valueCopy.find_first_of(","));
valueCopy = valueCopy.substr(valueCopy.find_first_of(",") + 1);
const auto PADW = valueCopy;
if (ALIGNR == "left") module.alignment = LEFT;
else if (ALIGNR == "right") module.alignment = RIGHT;
else if (ALIGNR == "center") module.alignment = CENTER;
try {
module.pad = stol(PADW);
} catch (...) {
Debug::log(ERR, "Module creation pad error: invalid pad");
return;
}
module.isPad = true;
module.color = 0;
module.bgcolor = 0;
g_pWindowManager->statusBar->modules.push_back(module);
return;
}
const auto COL1 = valueCopy.substr(0, valueCopy.find_first_of(","));
valueCopy = valueCopy.substr(valueCopy.find_first_of(",") + 1);
const auto COL2 = valueCopy.substr(0, valueCopy.find_first_of(","));
valueCopy = valueCopy.substr(valueCopy.find_first_of(",") + 1);
const auto UPDATE = valueCopy.substr(0, valueCopy.find_first_of(","));
valueCopy = valueCopy.substr(valueCopy.find_first_of(",") + 1);
const auto COMMAND = valueCopy;
if (ALIGN == "left") module.alignment = LEFT;
else if (ALIGN == "right") module.alignment = RIGHT;
else if (ALIGN == "center") module.alignment = CENTER;
try {
module.color = stol(COL1.substr(2), nullptr, 16);
module.bgcolor = stol(COL2.substr(2), nullptr, 16);
} catch (...) {
Debug::log(ERR, "Module creation color error: invalid color");
return;
}
try {
module.updateEveryMs = stol(UPDATE);
} catch (...) {
Debug::log(ERR, "Module creation error: invalid update interval");
return;
}
module.value = COMMAND;
g_pWindowManager->statusBar->modules.push_back(module);
}
void parseBarLine(const std::string& line) {
// And parse
// check if command
const auto EQUALSPLACE = line.find_first_of('=');
if (EQUALSPLACE == std::string::npos)
return;
const auto COMMAND = line.substr(0, EQUALSPLACE);
const auto VALUE = line.substr(EQUALSPLACE + 1);
// Now check commands
if (COMMAND == "module") {
parseModule(COMMAND, VALUE);
} else {
configSetValueSafe("bar:" + COMMAND, VALUE);
}
}
void parseLine(std::string& line) { void parseLine(std::string& line) {
// first check if its not a comment // first check if its not a comment
const auto COMMENTSTART = line.find_first_of('#'); const auto COMMENTSTART = line.find_first_of('#');
@ -95,6 +218,27 @@ void parseLine(std::string& line) {
if (COMMENTSTART != std::string::npos) if (COMMENTSTART != std::string::npos)
line = line.substr(COMMENTSTART); line = line.substr(COMMENTSTART);
// remove shit at the beginning
while (line[0] == ' ' || line[0] == '\t') {
line = line.substr(1);
}
if (line.find("Bar {") != std::string::npos) {
ConfigManager::isBar = true;
return;
}
if (line.find("}") != std::string::npos && ConfigManager::isBar) {
ConfigManager::isBar = false;
return;
}
if (ConfigManager::isBar) {
if (g_pWindowManager->statusBar)
parseBarLine(line);
return;
}
// And parse // And parse
// check if command // check if command
const auto EQUALSPLACE = line.find_first_of('='); const auto EQUALSPLACE = line.find_first_of('=');
@ -116,39 +260,20 @@ void parseLine(std::string& line) {
return; return;
} }
if (ConfigManager::configValues.find(COMMAND) == ConfigManager::configValues.end()) configSetValueSafe(COMMAND, VALUE);
return;
auto& CONFIGENTRY = ConfigManager::configValues.at(COMMAND);
if (CONFIGENTRY.intValue != -1) {
try {
if (VALUE.find("0x") == 0) {
// Values with 0x are hex
const auto VALUEWITHOUTHEX = VALUE.substr(2);
CONFIGENTRY.intValue = stoi(VALUEWITHOUTHEX, nullptr, 16);
} else
CONFIGENTRY.intValue = stoi(VALUE);
} catch (...) {
Debug::log(WARN, "Error reading value of " + COMMAND);
}
} else if (CONFIGENTRY.floatValue != -1) {
try {
CONFIGENTRY.floatValue = stof(VALUE);
} catch (...) {
Debug::log(WARN, "Error reading value of " + COMMAND);
}
} else if (CONFIGENTRY.strValue != "") {
try {
CONFIGENTRY.strValue = VALUE;
} catch (...) {
Debug::log(WARN, "Error reading value of " + COMMAND);
}
}
} }
void ConfigManager::loadConfigLoadVars() { void ConfigManager::loadConfigLoadVars() {
Debug::log(LOG, "Reloading the config!"); Debug::log(LOG, "Reloading the config!");
if (loadBar && g_pWindowManager->statusBar) {
// clear modules as we overwrite them
for (auto& m : g_pWindowManager->statusBar->modules) {
g_pWindowManager->statusBar->destroyModule(&m);
}
g_pWindowManager->statusBar->modules.clear();
}
KeybindManager::keybinds.clear(); KeybindManager::keybinds.clear();
const char* const ENVHOME = getenv("HOME"); const char* const ENVHOME = getenv("HOME");
@ -184,7 +309,7 @@ void ConfigManager::loadConfigLoadVars() {
// Reload the bar as well, don't load it before the default is loaded. // Reload the bar as well, don't load it before the default is loaded.
if (loadBar && g_pWindowManager->statusBar) { if (loadBar && g_pWindowManager->statusBar) {
g_pWindowManager->statusBar->destroy(); g_pWindowManager->statusBar->destroy();
g_pWindowManager->statusBar->setup(configValues["bar_monitor"].intValue); g_pWindowManager->statusBar->setup(configValues["bar:monitor"].intValue);
} }
loadBar = true; loadBar = true;

View file

@ -4,7 +4,7 @@
#include "../utilities/Debug.hpp" #include "../utilities/Debug.hpp"
struct SConfigValue { struct SConfigValue {
int intValue = -1; int64_t intValue = -1;
float floatValue = -1; float floatValue = -1;
std::string strValue = ""; std::string strValue = "";
}; };
@ -15,6 +15,8 @@ namespace ConfigManager {
inline bool loadBar = false; inline bool loadBar = false;
inline bool isBar = false; // If true we send the command to the bar parser
void init(); void init();
void loadConfigLoadVars(); void loadConfigLoadVars();
void tick(); void tick();

View file

@ -1,6 +1,8 @@
#include "events.hpp" #include "events.hpp"
gpointer handle(gpointer data) { gpointer handle(gpointer data) {
int lazyUpdateCounter = 0;
while (1) { while (1) {
// wait for the main thread to be idle // wait for the main thread to be idle
while (g_pWindowManager->mainThreadBusy) { while (g_pWindowManager->mainThreadBusy) {
@ -10,13 +12,26 @@ gpointer handle(gpointer data) {
// set state to let the main thread know to wait. // set state to let the main thread know to wait.
g_pWindowManager->animationUtilBusy = true; g_pWindowManager->animationUtilBusy = true;
// check config
ConfigManager::tick();
// update animations. // update animations.
AnimationUtil::move(); AnimationUtil::move();
// //
// Don't spam these
if (lazyUpdateCounter > 10){
// Update the active window name
g_pWindowManager->updateActiveWindowName();
// Update the bar
g_pWindowManager->updateBarInfo();
// check config
ConfigManager::tick();
lazyUpdateCounter = 0;
}
++lazyUpdateCounter;
// restore anim state // restore anim state
g_pWindowManager->animationUtilBusy = false; g_pWindowManager->animationUtilBusy = false;
@ -80,6 +95,11 @@ CWindow* Events::remapFloatingWindow(int windowID, int forcemonitor) {
window.setWorkspaceID(g_pWindowManager->activeWorkspaces[CURRENTSCREEN]); window.setWorkspaceID(g_pWindowManager->activeWorkspaces[CURRENTSCREEN]);
window.setMonitor(CURRENTSCREEN); window.setMonitor(CURRENTSCREEN);
// Window name
const auto WINNAME = getWindowName(windowID);
Debug::log(LOG, "New window got name: " + WINNAME);
window.setName(WINNAME);
// For all floating windows, get their default size // For all floating windows, get their default size
const auto GEOMETRYCOOKIE = xcb_get_geometry(g_pWindowManager->DisplayConnection, windowID); const auto GEOMETRYCOOKIE = xcb_get_geometry(g_pWindowManager->DisplayConnection, windowID);
const auto GEOMETRY = xcb_get_geometry_reply(g_pWindowManager->DisplayConnection, GEOMETRYCOOKIE, 0); const auto GEOMETRY = xcb_get_geometry_reply(g_pWindowManager->DisplayConnection, GEOMETRYCOOKIE, 0);
@ -132,6 +152,11 @@ CWindow* Events::remapWindow(int windowID, bool wasfloating, int forcemonitor) {
window.setWorkspaceID(g_pWindowManager->activeWorkspaces[CURRENTSCREEN]); window.setWorkspaceID(g_pWindowManager->activeWorkspaces[CURRENTSCREEN]);
window.setMonitor(CURRENTSCREEN); window.setMonitor(CURRENTSCREEN);
// Window name
const auto WINNAME = getWindowName(windowID);
Debug::log(LOG, "New window got name: " + WINNAME);
window.setName(WINNAME);
// For all floating windows, get their default size // For all floating windows, get their default size
const auto GEOMETRYCOOKIE = xcb_get_geometry(g_pWindowManager->DisplayConnection, windowID); const auto GEOMETRYCOOKIE = xcb_get_geometry(g_pWindowManager->DisplayConnection, windowID);
const auto GEOMETRY = xcb_get_geometry_reply(g_pWindowManager->DisplayConnection, GEOMETRYCOOKIE, 0); const auto GEOMETRY = xcb_get_geometry_reply(g_pWindowManager->DisplayConnection, GEOMETRYCOOKIE, 0);

View file

@ -65,8 +65,16 @@ void IPCSendMessage(const std::string path, SIPCMessageMainToBar smessage) {
message += std::to_string(w) + ","; message += std::to_string(w) + ",";
} }
message += IPC_MESSAGE_SEPARATOR + "lastwindowname" + IPC_MESSAGE_EQUALITY;
if (const auto PLASTWINDOW = g_pWindowManager->getWindowFromDrawable(g_pWindowManager->LastWindow); PLASTWINDOW) {
message += PLASTWINDOW->getName() + IPC_MESSAGE_SEPARATOR;
} else {
message += IPC_MESSAGE_SEPARATOR;
}
// append the EOF // append the EOF
message += IPC_MESSAGE_SEPARATOR + IPC_END_OF_FILE; message += IPC_END_OF_FILE;
// Send // Send
writeToIPCChannel(path, message); writeToIPCChannel(path, message);
@ -86,21 +94,21 @@ void IPCRecieveMessageB(const std::string path) {
try { try {
std::string message = readFromIPCChannel(path); std::string message = readFromIPCChannel(path);
const auto EOFPOS = message.find_first_of(IPC_END_OF_FILE); const auto EOFPOS = message.find(IPC_END_OF_FILE);
if (EOFPOS == std::string::npos) if (EOFPOS == std::string::npos)
return; return;
message = message.substr(0, EOFPOS); message = message.substr(0, EOFPOS);
while (message.find_first_of(IPC_MESSAGE_SEPARATOR) != 0 && message.find_first_of(IPC_MESSAGE_SEPARATOR) != std::string::npos) { while (message.find(IPC_MESSAGE_SEPARATOR) != std::string::npos && message.find(IPC_MESSAGE_SEPARATOR) != 0) {
// read until done. // read until done.
const auto PROP = message.substr(0, message.find_first_of(IPC_MESSAGE_SEPARATOR)); const auto PROP = message.substr(0, message.find(IPC_MESSAGE_SEPARATOR));
message = message.substr(message.find_first_of(IPC_MESSAGE_SEPARATOR) + 1); message = message.substr(message.find(IPC_MESSAGE_SEPARATOR) + IPC_MESSAGE_SEPARATOR.length());
// Get the name and value // Get the name and value
const auto PROPNAME = PROP.substr(0, PROP.find_first_of(IPC_MESSAGE_EQUALITY)); const auto PROPNAME = PROP.substr(0, PROP.find(IPC_MESSAGE_EQUALITY));
const auto PROPVALUE = PROP.substr(PROP.find_first_of(IPC_MESSAGE_EQUALITY) + 1); const auto PROPVALUE = PROP.substr(PROP.find(IPC_MESSAGE_EQUALITY) + 1);
if (PROPNAME == "active") { if (PROPNAME == "active") {
try { try {
@ -125,6 +133,9 @@ void IPCRecieveMessageB(const std::string path) {
// sort // sort
std::sort(g_pWindowManager->statusBar->openWorkspaces.begin(), g_pWindowManager->statusBar->openWorkspaces.end()); std::sort(g_pWindowManager->statusBar->openWorkspaces.begin(), g_pWindowManager->statusBar->openWorkspaces.end());
} else if (PROPNAME == "lastwindowname") {
g_pWindowManager->statusBar->setLastWindowName(PROPVALUE);
Debug::log(LOG, "update window name to " + PROPVALUE);
} }
} }
} catch(...) { } catch(...) {
@ -143,21 +154,21 @@ void IPCRecieveMessageM(const std::string path) {
try { try {
std::string message = readFromIPCChannel(path); std::string message = readFromIPCChannel(path);
const auto EOFPOS = message.find_first_of(IPC_END_OF_FILE); const auto EOFPOS = message.find(IPC_END_OF_FILE);
if (EOFPOS == std::string::npos) if (EOFPOS == std::string::npos)
return; return;
message = message.substr(0, EOFPOS); message = message.substr(0, EOFPOS);
while (message.find_first_of(IPC_MESSAGE_SEPARATOR) != 0 && message.find_first_of(IPC_MESSAGE_SEPARATOR) != std::string::npos) { while (message.find(IPC_MESSAGE_SEPARATOR) != std::string::npos && message.find(IPC_MESSAGE_SEPARATOR) != 0) {
// read until done. // read until done.
const auto PROP = message.substr(0, message.find_first_of(IPC_MESSAGE_SEPARATOR)); const auto PROP = message.substr(0, message.find(IPC_MESSAGE_SEPARATOR));
message = message.substr(message.find_first_of(IPC_MESSAGE_SEPARATOR) + 1); message = message.substr(message.find(IPC_MESSAGE_SEPARATOR) + IPC_MESSAGE_SEPARATOR.length());
// Get the name and value // Get the name and value
const auto PROPNAME = PROP.substr(0, PROP.find_first_of(IPC_MESSAGE_EQUALITY)); const auto PROPNAME = PROP.substr(0, PROP.find(IPC_MESSAGE_EQUALITY));
const auto PROPVALUE = PROP.substr(PROP.find_first_of(IPC_MESSAGE_EQUALITY) + 1); const auto PROPVALUE = PROP.substr(PROP.find(IPC_MESSAGE_EQUALITY) + 1);
if (PROPNAME == "wid") { if (PROPNAME == "wid") {
try { try {

View file

@ -5,12 +5,13 @@ std::string readFromIPCChannel(const std::string);
int writeToIPCChannel(const std::string, std::string); int writeToIPCChannel(const std::string, std::string);
#define IPC_END_OF_FILE (std::string)"HYPR_END_OF_FILE" #define IPC_END_OF_FILE (std::string)"HYPR_END_OF_FILE"
#define IPC_MESSAGE_SEPARATOR (std::string)"\t" #define IPC_MESSAGE_SEPARATOR std::string("\t")
#define IPC_MESSAGE_EQUALITY (std::string)"=" #define IPC_MESSAGE_EQUALITY std::string("=")
struct SIPCMessageMainToBar { struct SIPCMessageMainToBar {
std::vector<int> openWorkspaces; std::vector<int> openWorkspaces;
uint64_t activeWorkspace; uint64_t activeWorkspace;
std::string lastWindowName;
}; };
struct SIPCMessageBarToMain { struct SIPCMessageBarToMain {

View file

@ -55,3 +55,21 @@ bool xcbContainsAtom(xcb_get_property_reply_t* PROP, xcb_atom_t ATOM) {
return false; return false;
} }
std::vector<std::string> splitString(std::string in, char c) {
std::vector<std::string> returns;
while(in.length() > 0) {
std::string toPush = in.substr(0, in.find_first_of(c));
if (toPush != "") {
returns.push_back(toPush);
}
if (in.find_first_of(c) != std::string::npos)
in = in.substr(in.find_first_of(c) + 1);
else
in = "";
}
return returns;
}

View file

@ -9,3 +9,5 @@ void emptyEvent();
bool xcbContainsAtom(xcb_get_property_reply_t* PROP, xcb_atom_t ATOM); bool xcbContainsAtom(xcb_get_property_reply_t* PROP, xcb_atom_t ATOM);
double parabolic(double from, double to, double incline); double parabolic(double from, double to, double incline);
std::vector<std::string> splitString(std::string, char);

View file

@ -44,3 +44,16 @@ std::string getRoleName(int64_t window) {
return returns; return returns;
} }
std::string getWindowName(uint64_t window) {
PROP(name_cookie, HYPRATOMS["_NET_WM_NAME"], 128);
const int len = xcb_get_property_value_length(name_cookiereply);
char* name = strndup((const char*)xcb_get_property_value(name_cookiereply), len);
std::string stringname(name);
free(name);
free(name_cookiereply);
return stringname;
}

View file

@ -6,3 +6,4 @@
std::pair<std::string, std::string> getClassName(int64_t window); std::pair<std::string, std::string> getClassName(int64_t window);
std::string getRoleName(int64_t window); std::string getRoleName(int64_t window);
std::string getWindowName(uint64_t window);

View file

@ -1,7 +1,7 @@
#include "window.hpp" #include "window.hpp"
#include "windowManager.hpp" #include "windowManager.hpp"
CWindow::CWindow() { this->setDirty(true); this->setFullscreen(false); this->setIsFloating(false); this->setParentNodeID(0); this->setChildNodeAID(0); this->setChildNodeBID(0); } CWindow::CWindow() { this->setDirty(true); this->setFullscreen(false); this->setIsFloating(false); this->setParentNodeID(0); this->setChildNodeAID(0); this->setChildNodeBID(0); this->setName(""); }
CWindow::~CWindow() { } CWindow::~CWindow() { }
void CWindow::generateNodeID() { void CWindow::generateNodeID() {

View file

@ -255,6 +255,12 @@ bool CWindowManager::handleEvent() {
// remove unused workspaces // remove unused workspaces
cleanupUnusedWorkspaces(); cleanupUnusedWorkspaces();
// Update last window name
updateActiveWindowName();
// Update the bar with the freshest stuff
updateBarInfo();
xcb_flush(DisplayConnection); xcb_flush(DisplayConnection);
// Restore thread state // Restore thread state
@ -541,9 +547,9 @@ void CWindowManager::setEffectiveSizePosUsingConfig(CWindow* pWindow) {
pWindow->setEffectiveSize(pWindow->getSize() - (Vector2D(ConfigManager::getInt("border_size"), ConfigManager::getInt("border_size")) * 2)); pWindow->setEffectiveSize(pWindow->getSize() - (Vector2D(ConfigManager::getInt("border_size"), ConfigManager::getInt("border_size")) * 2));
// do gaps, set top left // do gaps, set top left
pWindow->setEffectivePosition(pWindow->getEffectivePosition() + Vector2D(DISPLAYLEFT ? ConfigManager::getInt("gaps_out") : ConfigManager::getInt("gaps_in"), DISPLAYTOP ? ConfigManager::getInt("gaps_out") + (MONITOR->ID == ConfigManager::getInt("bar_monitor") ? ConfigManager::getInt("bar_height") : 0) : ConfigManager::getInt("gaps_in"))); pWindow->setEffectivePosition(pWindow->getEffectivePosition() + Vector2D(DISPLAYLEFT ? ConfigManager::getInt("gaps_out") : ConfigManager::getInt("gaps_in"), DISPLAYTOP ? ConfigManager::getInt("gaps_out") + (MONITOR->ID == ConfigManager::getInt("bar:monitor") ? ConfigManager::getInt("bar:height") : 0) : ConfigManager::getInt("gaps_in")));
// fix to old size bottom right // fix to old size bottom right
pWindow->setEffectiveSize(pWindow->getEffectiveSize() - Vector2D(DISPLAYLEFT ? ConfigManager::getInt("gaps_out") : ConfigManager::getInt("gaps_in"), DISPLAYTOP ? ConfigManager::getInt("gaps_out") + (MONITOR->ID == ConfigManager::getInt("bar_monitor") ? ConfigManager::getInt("bar_height") : 0) : ConfigManager::getInt("gaps_in"))); pWindow->setEffectiveSize(pWindow->getEffectiveSize() - Vector2D(DISPLAYLEFT ? ConfigManager::getInt("gaps_out") : ConfigManager::getInt("gaps_in"), DISPLAYTOP ? ConfigManager::getInt("gaps_out") + (MONITOR->ID == ConfigManager::getInt("bar:monitor") ? ConfigManager::getInt("bar:height") : 0) : ConfigManager::getInt("gaps_in")));
// set bottom right // set bottom right
pWindow->setEffectiveSize(pWindow->getEffectiveSize() - Vector2D(DISPLAYRIGHT ? ConfigManager::getInt("gaps_out") : ConfigManager::getInt("gaps_in"), DISPLAYBOTTOM ? ConfigManager::getInt("gaps_out") : ConfigManager::getInt("gaps_in"))); pWindow->setEffectiveSize(pWindow->getEffectiveSize() - Vector2D(DISPLAYRIGHT ? ConfigManager::getInt("gaps_out") : ConfigManager::getInt("gaps_in"), DISPLAYBOTTOM ? ConfigManager::getInt("gaps_out") : ConfigManager::getInt("gaps_in")));
} }
@ -1073,8 +1079,22 @@ void CWindowManager::updateBarInfo() {
return; return;
} }
message.activeWorkspace = activeWorkspaces[getMonitorFromCursor()->ID]; message.activeWorkspace = activeWorkspaces[getMonitorFromCursor()->ID];
auto winname = getWindowFromDrawable(LastWindow) ? getWindowFromDrawable(LastWindow)->getName() : "";
for (auto& c : winname) {
// Remove illegal chars
if (c == '=')
c = ' ';
else if (c == '\t')
c = ' ';
}
message.lastWindowName = winname;
for (auto& workspace : workspaces) { for (auto& workspace : workspaces) {
message.openWorkspaces.push_back(workspace.getID()); message.openWorkspaces.push_back(workspace.getID());
} }
@ -1121,6 +1141,7 @@ bool CWindowManager::shouldBeFloatedOnInit(int64_t window) {
return true; return true;
} }
// //
// Type stuff // Type stuff
// //
@ -1147,3 +1168,16 @@ bool CWindowManager::shouldBeFloatedOnInit(int64_t window) {
return false; return false;
} }
void CWindowManager::updateActiveWindowName() {
if (!getWindowFromDrawable(LastWindow))
return;
const auto PLASTWINDOW = getWindowFromDrawable(LastWindow);
auto WINNAME = getWindowName(LastWindow);
if (WINNAME != PLASTWINDOW->getName()) {
Debug::log(LOG, "Update, window got name: " + WINNAME);
PLASTWINDOW->setName(WINNAME);
}
}

View file

@ -96,6 +96,9 @@ public:
void createAndOpenAllPipes(); void createAndOpenAllPipes();
void setupDepth(); void setupDepth();
void updateActiveWindowName();
void updateBarInfo();
private: private:
// Internal WM functions that don't have to be exposed // Internal WM functions that don't have to be exposed
@ -110,7 +113,6 @@ public:
void setEffectiveSizePosUsingConfig(CWindow* pWindow); void setEffectiveSizePosUsingConfig(CWindow* pWindow);
void cleanupUnusedWorkspaces(); void cleanupUnusedWorkspaces();
xcb_visualtype_t* setupColors(); xcb_visualtype_t* setupColors();
void updateBarInfo();
void updateRootCursor(); void updateRootCursor();
}; };