Added a tray module

This commit is contained in:
vaxerski 2021-12-06 18:56:24 +01:00
parent b897a1b64e
commit 2ca2ddfd2e
9 changed files with 442 additions and 49 deletions

View file

@ -30,6 +30,8 @@ Bar {
col.high=0xffff3333 col.high=0xffff3333
module=left,X,0xff8000ff,0xffffffff,1,workspaces module=left,X,0xff8000ff,0xffffffff,1,workspaces
module=pad,left,10
module=left,,0xff7000dd,0xff7000dd,1,tray
module=right,X,0xffffffff,0xff00ff33,1000,$date +%a,\ %b\ %Y\ \ %I:%M\ %p$ module=right,X,0xffffffff,0xff00ff33,1000,$date +%a,\ %b\ %Y\ \ %I:%M\ %p$
} }

View file

@ -11,6 +11,12 @@ bool isParentDead() {
return PPID == 1; return PPID == 1;
} }
void parseEvent() {
while(1) {
g_pWindowManager->recieveEvent();
}
}
int64_t barMainThread() { int64_t barMainThread() {
// Main already created all the pipes // Main already created all the pipes
@ -18,14 +24,14 @@ int64_t barMainThread() {
// Well now this is the init // Well now this is the init
// it's pretty tricky because we only need to init the stuff we need // it's pretty tricky because we only need to init the stuff we need
g_pWindowManager->DisplayConnection = xcb_connect(NULL, NULL); g_pWindowManager->DisplayConnection = xcb_connect(NULL, &barScreen);
if (const auto RET = xcb_connection_has_error(g_pWindowManager->DisplayConnection); RET != 0) { if (const auto RET = xcb_connection_has_error(g_pWindowManager->DisplayConnection); RET != 0) {
Debug::log(CRIT, "Connection Failed! Return: " + std::to_string(RET)); Debug::log(CRIT, "Connection Failed! Return: " + std::to_string(RET));
return RET; return RET;
} }
// Screen // Screen
g_pWindowManager->Screen = xcb_setup_roots_iterator(xcb_get_setup(g_pWindowManager->DisplayConnection)).data; g_pWindowManager->Screen = xcb_aux_get_screen(g_pWindowManager->DisplayConnection, barScreen);
if (!g_pWindowManager->Screen) { if (!g_pWindowManager->Screen) {
Debug::log(CRIT, "Screen was null!"); Debug::log(CRIT, "Screen was null!");
@ -69,6 +75,11 @@ int64_t barMainThread() {
Debug::log(LOG, "Bar init Phase 2 done."); Debug::log(LOG, "Bar init Phase 2 done.");
// Start the parse event thread
std::thread([=]() {
parseEvent();
}).detach();
// Init config manager // Init config manager
ConfigManager::init(); ConfigManager::init();
@ -78,6 +89,9 @@ int64_t barMainThread() {
int lazyUpdateCounter = 0; int lazyUpdateCounter = 0;
// setup the tray so apps send to us
STATUSBAR.setupTray();
while (1) { while (1) {
// Don't spam these // Don't spam these
@ -130,6 +144,142 @@ void CStatusBar::destroyModule(SBarModule* module) {
xcb_free_gc(g_pWindowManager->DisplayConnection, module->bgcontext); xcb_free_gc(g_pWindowManager->DisplayConnection, module->bgcontext);
} }
void CStatusBar::setupTray() {
Debug::log(LOG, "Setting up tray!");
char atomName[strlen("_NET_SYSTEM_TRAY_S") + 11];
snprintf(atomName, strlen("_NET_SYSTEM_TRAY_S") + 11, "_NET_SYSTEM_TRAY_S%d", barScreen);
// init the atom
const auto TRAYCOOKIE = xcb_intern_atom(g_pWindowManager->DisplayConnection, 0, strlen(atomName), atomName);
trayWindowID = xcb_generate_id(g_pWindowManager->DisplayConnection);
uint32_t values[] = {g_pWindowManager->Screen->black_pixel, g_pWindowManager->Screen->black_pixel, 1, g_pWindowManager->Colormap};
xcb_create_window(g_pWindowManager->DisplayConnection, g_pWindowManager->Depth, trayWindowID,
g_pWindowManager->Screen->root, -1, -1, 1, 1, 0,
XCB_WINDOW_CLASS_INPUT_OUTPUT, g_pWindowManager->VisualType->visual_id,
XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_COLORMAP,
values);
const uint32_t ORIENTATION = 0; // Horizontal
xcb_change_property(g_pWindowManager->DisplayConnection, XCB_PROP_MODE_REPLACE, trayWindowID,
HYPRATOMS["_NET_SYSTEM_TRAY_ORIENTATION"], XCB_ATOM_CARDINAL,
32, 1, &ORIENTATION);
xcb_change_property(g_pWindowManager->DisplayConnection, XCB_PROP_MODE_REPLACE, trayWindowID,
HYPRATOMS["_NET_SYSTEM_TRAY_VISUAL"], XCB_ATOM_VISUALID,
32, 1, &g_pWindowManager->VisualType->visual_id);
// COLORS
// Check if the tray module is active
SBarModule* pBarModule = nullptr;
for (auto& mod : modules) {
if (mod.value == "tray") {
pBarModule = &mod;
break;
}
}
if (pBarModule) {
// init colors
const auto R = (uint16_t)(RED(pBarModule->bgcolor) * 255.f);
const auto G = (uint16_t)(GREEN(pBarModule->bgcolor) * 255.f);
const auto B = (uint16_t)(BLUE(pBarModule->bgcolor) * 255.f);
const unsigned short TRAYCOLORS[] = {
R, G, B, R, G, B, R, G, B, R, G, B // Foreground, Error, Warning, Success
};
xcb_change_property(g_pWindowManager->DisplayConnection, XCB_PROP_MODE_REPLACE, trayWindowID,
HYPRATOMS["_NET_SYSTEM_TRAY_COLORS"], XCB_ATOM_CARDINAL, 32, 12, TRAYCOLORS);
}
//
const auto TRAYREPLY = xcb_intern_atom_reply(g_pWindowManager->DisplayConnection, TRAYCOOKIE, NULL);
if (!TRAYREPLY) {
Debug::log(ERR, "Tray reply NULL! Aborting tray...");
free(TRAYREPLY);
return;
}
// set the owner and check
xcb_set_selection_owner(g_pWindowManager->DisplayConnection, trayWindowID, TRAYREPLY->atom, XCB_CURRENT_TIME);
const auto SELCOOKIE = xcb_get_selection_owner(g_pWindowManager->DisplayConnection, TRAYREPLY->atom);
const auto SELREPLY = xcb_get_selection_owner_reply(g_pWindowManager->DisplayConnection, SELCOOKIE, NULL);
if (!SELREPLY) {
Debug::log(ERR, "Selection owner reply NULL! Aborting tray...");
free(SELREPLY);
free(TRAYREPLY);
return;
}
if (SELREPLY->owner != trayWindowID) {
Debug::log(ERR, "Couldn't set the Tray owner, maybe a different tray is running??");
free(SELREPLY);
free(TRAYREPLY);
return;
}
free(SELREPLY);
free(TRAYREPLY);
Debug::log(LOG, "Tray setup done, sending message!");
uint8_t buf[32] = {NULL};
xcb_client_message_event_t* event = (xcb_client_message_event_t*)buf;
event->response_type = XCB_CLIENT_MESSAGE;
event->window = g_pWindowManager->Screen->root;
event->type = HYPRATOMS["MANAGER"];
event->format = 32;
event->data.data32[0] = 0L;
event->data.data32[1] = TRAYREPLY->atom;
event->data.data32[2] = trayWindowID;
xcb_send_event(g_pWindowManager->DisplayConnection, 0, g_pWindowManager->Screen->root, 0xFFFFFF, (char*)buf);
Debug::log(LOG, "Tray message sent!");
}
void CStatusBar::fixTrayOnCreate() {
if (m_bHasTray) {
for (auto& tray : g_pWindowManager->trayclients) {
xcb_reparent_window(g_pWindowManager->DisplayConnection, tray.window, g_pWindowManager->statusBar->getWindowID(), 0, 0);
xcb_map_window(g_pWindowManager->DisplayConnection, tray.window);
tray.hidden = false;
}
} else {
uint32_t values[2];
values[0] = 0;
values[1] = 0;
for (auto& tray : g_pWindowManager->trayclients) {
tray.hidden = true;
values[0] = 0;
values[1] = 0;
xcb_configure_window(g_pWindowManager->DisplayConnection, tray.window, XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, values);
values[0] = 30000;
values[1] = 30000;
xcb_configure_window(g_pWindowManager->DisplayConnection, tray.window, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, values);
}
}
}
void CStatusBar::saveTrayOnDestroy() {
for (auto& tray : g_pWindowManager->trayclients) {
xcb_reparent_window(g_pWindowManager->DisplayConnection, tray.window, g_pWindowManager->Screen->root, -999, -999);
}
}
void CStatusBar::setup(int MonitorID) { void CStatusBar::setup(int MonitorID) {
Debug::log(LOG, "Creating the bar!"); Debug::log(LOG, "Creating the bar!");
@ -137,7 +287,15 @@ void CStatusBar::setup(int MonitorID) {
MonitorID = 0; MonitorID = 0;
Debug::log(ERR, "Incorrect value in MonitorID for the bar. Setting to 0."); Debug::log(ERR, "Incorrect value in MonitorID for the bar. Setting to 0.");
} }
m_bHasTray = false;
for (auto& mod : g_pWindowManager->statusBar->modules) {
if (mod.value == "tray") {
m_bHasTray = true;
break;
}
}
const auto MONITOR = g_pWindowManager->monitors[MonitorID]; const auto MONITOR = g_pWindowManager->monitors[MonitorID];
m_iMonitorID = MonitorID; m_iMonitorID = MonitorID;
@ -191,11 +349,16 @@ void CStatusBar::setup(int MonitorID) {
m_vecSize.x, m_vecSize.y); m_vecSize.x, m_vecSize.y);
m_pCairo = cairo_create(m_pCairoSurface); m_pCairo = cairo_create(m_pCairoSurface);
cairo_surface_destroy(m_pCairoSurface); cairo_surface_destroy(m_pCairoSurface);
// fix tray
fixTrayOnCreate();
} }
void CStatusBar::destroy() { void CStatusBar::destroy() {
Debug::log(LOG, "Destroying the bar!"); Debug::log(LOG, "Destroying the bar!");
saveTrayOnDestroy();
xcb_close_font(g_pWindowManager->DisplayConnection, m_mContexts["HITEXT"].Font); xcb_close_font(g_pWindowManager->DisplayConnection, m_mContexts["HITEXT"].Font);
xcb_destroy_window(g_pWindowManager->DisplayConnection, m_iWindowID); xcb_destroy_window(g_pWindowManager->DisplayConnection, m_iWindowID);
xcb_destroy_window(g_pWindowManager->DisplayConnection, m_iPixmap); xcb_destroy_window(g_pWindowManager->DisplayConnection, m_iPixmap);
@ -285,7 +448,19 @@ void CStatusBar::draw() {
// //
// //
// //
// fix the fucking tray
if (!m_bHasTray) {
uint32_t values[2];
for (auto& tray : g_pWindowManager->trayclients) {
tray.hidden = true;
values[0] = 30000;
values[1] = 30000;
xcb_configure_window(g_pWindowManager->DisplayConnection, tray.window, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, values);
}
}
cairo_surface_flush(m_pCairoSurface); cairo_surface_flush(m_pCairoSurface);
xcb_copy_area(g_pWindowManager->DisplayConnection, m_iPixmap, m_iWindowID, m_mContexts["BG"].GContext, xcb_copy_area(g_pWindowManager->DisplayConnection, m_iPixmap, m_iWindowID, m_mContexts["BG"].GContext,
@ -320,11 +495,59 @@ int CStatusBar::drawWorkspacesModule(SBarModule* mod, int off) {
return drawnWorkspaces * m_vecSize.y; return drawnWorkspaces * m_vecSize.y;
} }
int CStatusBar::drawTrayModule(SBarModule* mod, int off) {
const auto PAD = 2;
const auto ELEMENTWIDTH = (m_vecSize.y - 2 < 1 ? 1 : m_vecSize.y - 2);
const auto MODULEWIDTH = g_pWindowManager->trayclients.size() * (ELEMENTWIDTH + PAD);
Vector2D position;
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;
}
// draw tray
if (MODULEWIDTH < 1)
return 0;
drawCairoRectangle(position, Vector2D(MODULEWIDTH, m_vecSize.y), mod->bgcolor);
int i = 0;
for (auto& tray : g_pWindowManager->trayclients) {
if (tray.hidden)
continue;
uint32_t values[] = {(int)(position.x + (i * (ELEMENTWIDTH + PAD)) + PAD / 2.f), (int)position.y + 1, (int)XCB_STACK_MODE_ABOVE};
xcb_configure_window(g_pWindowManager->DisplayConnection, g_pWindowManager->trayclients[i].window,
XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_STACK_MODE, values);
++i;
}
return MODULEWIDTH;
}
int CStatusBar::drawModule(SBarModule* mod, int off) { int CStatusBar::drawModule(SBarModule* mod, int off) {
if (mod->isPad) if (mod->isPad)
return mod->pad; return mod->pad;
if (mod->value == "tray")
return drawTrayModule(mod, off);
const int PAD = ConfigManager::getInt("bar:mod_pad_in"); const int PAD = ConfigManager::getInt("bar:mod_pad_in");
// check if we need to update // check if we need to update
@ -362,4 +585,24 @@ int CStatusBar::drawModule(SBarModule* mod, int off) {
drawText(position + Vector2D(PAD / 2 + ICONWIDTH, getTextHalfY()), mod->valueCalculated, mod->color, ConfigManager::getString("bar:font.main")); drawText(position + Vector2D(PAD / 2 + ICONWIDTH, getTextHalfY()), mod->valueCalculated, mod->color, ConfigManager::getString("bar:font.main"));
return MODULEWIDTH + ICONWIDTH; return MODULEWIDTH + ICONWIDTH;
}
void CStatusBar::ensureTrayClientDead(xcb_window_t window) {
auto temp = g_pWindowManager->trayclients;
g_pWindowManager->trayclients.clear();
for (auto& trayitem : temp) {
if (trayitem.window != window)
g_pWindowManager->trayclients.push_back(trayitem);
}
Debug::log(LOG, "Ensured client dead (Bar, Tray)");
}
void CStatusBar::ensureTrayClientHidden(xcb_window_t window, bool hide) {
for (auto& trayitem : g_pWindowManager->trayclients) {
if (trayitem.window == window)
trayitem.hidden = hide;
}
} }

View file

@ -7,6 +7,8 @@
#include "BarCommands.hpp" #include "BarCommands.hpp"
#include <chrono> #include <chrono>
inline int barScreen = 0;
struct SDrawingContext { struct SDrawingContext {
xcb_gcontext_t GContext; xcb_gcontext_t GContext;
xcb_font_t Font; xcb_font_t Font;
@ -45,12 +47,16 @@ public:
EXPOSED_MEMBER(LastWindowName, std::string, sz); EXPOSED_MEMBER(LastWindowName, std::string, sz);
EXPOSED_MEMBER(LastWindowClass, std::string, sz); EXPOSED_MEMBER(LastWindowClass, std::string, sz);
EXPOSED_MEMBER(IsCovered, bool, b); EXPOSED_MEMBER(IsCovered, bool, b);
EXPOSED_MEMBER(HasTray, bool, b);
void draw(); void draw();
void setup(int MonitorID); void setup(int MonitorID);
void destroy(); void destroy();
void setupModule(SBarModule*); void setupModule(SBarModule*);
void destroyModule(SBarModule*); void destroyModule(SBarModule*);
void ensureTrayClientDead(xcb_window_t);
void ensureTrayClientHidden(xcb_window_t, bool);
void setupTray();
std::vector<int> openWorkspaces; std::vector<int> openWorkspaces;
EXPOSED_MEMBER(CurrentWorkspace, int, i); EXPOSED_MEMBER(CurrentWorkspace, int, i);
@ -77,6 +83,12 @@ private:
int getTextHalfY(); int getTextHalfY();
std::unordered_map<std::string, SDrawingContext> m_mContexts; std::unordered_map<std::string, SDrawingContext> m_mContexts;
void fixTrayOnCreate();
void saveTrayOnDestroy();
int drawTrayModule(SBarModule*, int);
xcb_window_t trayWindowID = 0;
}; };
// Main thread for the bar. Is only initted once in main.cpp so we can do this. // Main thread for the bar. Is only initted once in main.cpp so we can do this.

View file

@ -79,4 +79,7 @@
#define GREEN(c) ((double)(((c) >> 8) & 0xff) / 255.0) #define GREEN(c) ((double)(((c) >> 8) & 0xff) / 255.0)
#define BLUE(c) ((double)(((c)) & 0xff) / 255.0) #define BLUE(c) ((double)(((c)) & 0xff) / 255.0)
#define CONTAINS(s, f) s.find(f) != std::string::npos #define CONTAINS(s, f) s.find(f) != std::string::npos
#define RETURNIFBAR if (g_pWindowManager->statusBar) return;
#define RETURNIFMAIN if (!g_pWindowManager->statusBar) return;

View file

@ -49,18 +49,13 @@ void Events::setThread() {
Debug::log(ERR, "Gthread failed!"); Debug::log(ERR, "Gthread failed!");
return; return;
} }
/*g_pWindowManager->barThread = new std::thread([&]() {
for (;;) {
handle();
std::this_thread::sleep_for(std::chrono::milliseconds(1000 / ConfigManager::getInt("max_fps")));
}
});*/
} }
void Events::eventEnter(xcb_generic_event_t* event) { void Events::eventEnter(xcb_generic_event_t* event) {
const auto E = reinterpret_cast<xcb_enter_notify_event_t*>(event); const auto E = reinterpret_cast<xcb_enter_notify_event_t*>(event);
RETURNIFBAR;
const auto PENTERWINDOW = g_pWindowManager->getWindowFromDrawable(E->event); const auto PENTERWINDOW = g_pWindowManager->getWindowFromDrawable(E->event);
@ -79,12 +74,20 @@ void Events::eventEnter(xcb_generic_event_t* event) {
void Events::eventLeave(xcb_generic_event_t* event) { void Events::eventLeave(xcb_generic_event_t* event) {
const auto E = reinterpret_cast<xcb_leave_notify_event_t*>(event); const auto E = reinterpret_cast<xcb_leave_notify_event_t*>(event);
RETURNIFBAR;
// //
} }
void Events::eventDestroy(xcb_generic_event_t* event) { void Events::eventDestroy(xcb_generic_event_t* event) {
const auto E = reinterpret_cast<xcb_destroy_notify_event_t*>(event); const auto E = reinterpret_cast<xcb_destroy_notify_event_t*>(event);
// let bar check if it wasnt a tray item
if (g_pWindowManager->statusBar)
g_pWindowManager->statusBar->ensureTrayClientDead(E->window);
RETURNIFBAR;
g_pWindowManager->closeWindowAllChecks(E->window); g_pWindowManager->closeWindowAllChecks(E->window);
// refocus on new window // refocus on new window
@ -94,6 +97,12 @@ void Events::eventDestroy(xcb_generic_event_t* event) {
void Events::eventUnmapWindow(xcb_generic_event_t* event) { void Events::eventUnmapWindow(xcb_generic_event_t* event) {
const auto E = reinterpret_cast<xcb_unmap_notify_event_t*>(event); const auto E = reinterpret_cast<xcb_unmap_notify_event_t*>(event);
// let bar check if it wasnt a tray item
if (g_pWindowManager->statusBar)
g_pWindowManager->statusBar->ensureTrayClientHidden(E->window, true);
RETURNIFBAR;
g_pWindowManager->closeWindowAllChecks(E->window); g_pWindowManager->closeWindowAllChecks(E->window);
// refocus on new window // refocus on new window
@ -330,6 +339,12 @@ CWindow* Events::remapWindow(int windowID, bool wasfloating, int forcemonitor) {
void Events::eventMapWindow(xcb_generic_event_t* event) { void Events::eventMapWindow(xcb_generic_event_t* event) {
const auto E = reinterpret_cast<xcb_map_request_event_t*>(event); const auto E = reinterpret_cast<xcb_map_request_event_t*>(event);
// let bar check if it wasnt a tray item
if (g_pWindowManager->statusBar)
g_pWindowManager->statusBar->ensureTrayClientHidden(E->window, false);
RETURNIFBAR;
// Map the window // Map the window
xcb_map_window(g_pWindowManager->DisplayConnection, E->window); xcb_map_window(g_pWindowManager->DisplayConnection, E->window);
@ -362,6 +377,8 @@ void Events::eventMapWindow(xcb_generic_event_t* event) {
void Events::eventButtonPress(xcb_generic_event_t* event) { void Events::eventButtonPress(xcb_generic_event_t* event) {
const auto E = reinterpret_cast<xcb_button_press_event_t*>(event); const auto E = reinterpret_cast<xcb_button_press_event_t*>(event);
RETURNIFBAR;
// mouse down! // mouse down!
g_pWindowManager->mouseKeyDown = E->detail; g_pWindowManager->mouseKeyDown = E->detail;
xcb_grab_pointer(g_pWindowManager->DisplayConnection, 0, g_pWindowManager->Screen->root, XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_BUTTON_MOTION | XCB_EVENT_MASK_POINTER_MOTION_HINT, xcb_grab_pointer(g_pWindowManager->DisplayConnection, 0, g_pWindowManager->Screen->root, XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_BUTTON_MOTION | XCB_EVENT_MASK_POINTER_MOTION_HINT,
@ -379,6 +396,8 @@ void Events::eventButtonPress(xcb_generic_event_t* event) {
void Events::eventButtonRelease(xcb_generic_event_t* event) { void Events::eventButtonRelease(xcb_generic_event_t* event) {
const auto E = reinterpret_cast<xcb_button_release_event_t*>(event); const auto E = reinterpret_cast<xcb_button_release_event_t*>(event);
RETURNIFBAR;
// ungrab the mouse ptr // ungrab the mouse ptr
xcb_ungrab_pointer(g_pWindowManager->DisplayConnection, XCB_CURRENT_TIME); xcb_ungrab_pointer(g_pWindowManager->DisplayConnection, XCB_CURRENT_TIME);
const auto PACTINGWINDOW = g_pWindowManager->getWindowFromDrawable(g_pWindowManager->actingOnWindowFloating); const auto PACTINGWINDOW = g_pWindowManager->getWindowFromDrawable(g_pWindowManager->actingOnWindowFloating);
@ -391,6 +410,8 @@ void Events::eventButtonRelease(xcb_generic_event_t* event) {
void Events::eventKeyPress(xcb_generic_event_t* event) { void Events::eventKeyPress(xcb_generic_event_t* event) {
const auto E = reinterpret_cast<xcb_key_press_event_t*>(event); const auto E = reinterpret_cast<xcb_key_press_event_t*>(event);
RETURNIFBAR;
const auto KEYSYM = KeybindManager::getKeysymFromKeycode(E->detail); const auto KEYSYM = KeybindManager::getKeysymFromKeycode(E->detail);
for (auto& keybind : KeybindManager::keybinds) { for (auto& keybind : KeybindManager::keybinds) {
@ -405,6 +426,8 @@ void Events::eventKeyPress(xcb_generic_event_t* event) {
void Events::eventMotionNotify(xcb_generic_event_t* event) { void Events::eventMotionNotify(xcb_generic_event_t* event) {
const auto E = reinterpret_cast<xcb_motion_notify_event_t*>(event); const auto E = reinterpret_cast<xcb_motion_notify_event_t*>(event);
RETURNIFBAR;
if (!g_pWindowManager->mouseKeyDown) if (!g_pWindowManager->mouseKeyDown)
return; // mouse up. return; // mouse up.
@ -463,4 +486,89 @@ void Events::eventExpose(xcb_generic_event_t* event) {
const auto E = reinterpret_cast<xcb_expose_event_t*>(event); const auto E = reinterpret_cast<xcb_expose_event_t*>(event);
// nothing // nothing
}
void Events::eventClientMessage(xcb_generic_event_t* event) {
const auto E = reinterpret_cast<xcb_client_message_event_t*>(event);
RETURNIFMAIN; // Only for the bar
// Tray clients
if (E->type == HYPRATOMS["_NET_SYSTEM_TRAY_OPCODE"] && E->format == 32) {
// Tray request!
Debug::log(LOG, "Docking a window to the tray!");
if (E->data.data32[1] == 0) { // Request dock
const xcb_window_t CLIENT = E->data.data32[2];
uint32_t values[3] = {0,0,0};
values[0] = XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_RESIZE_REDIRECT;
xcb_change_window_attributes(g_pWindowManager->DisplayConnection, CLIENT,
XCB_CW_EVENT_MASK, values);
// get XEMBED
const auto XEMBEDCOOKIE = xcb_get_property(g_pWindowManager->DisplayConnection, 0, CLIENT, HYPRATOMS["_XEMBED_INFO"],
XCB_GET_PROPERTY_TYPE_ANY, 0, 64);
xcb_generic_error_t* err;
const auto XEMBEDREPLY = xcb_get_property_reply(g_pWindowManager->DisplayConnection, XEMBEDCOOKIE, &err);
if (!XEMBEDREPLY || err || XEMBEDREPLY->length == 0) {
Debug::log(ERR, "Tray dock opcode recieved with no XEmbed?");
if (err)
Debug::log(ERR, "Error code: " + std::to_string(err->error_code));
free(XEMBEDREPLY);
return;
}
const uint32_t* XEMBEDPROP = (uint32_t*)xcb_get_property_value(XEMBEDREPLY);
Debug::log(LOG, "XEmbed recieved with format " + std::to_string(XEMBEDREPLY->format) + ", length " + std::to_string(XEMBEDREPLY->length)
+ ", version " + std::to_string(XEMBEDPROP[0]) + ", flags " + std::to_string(XEMBEDPROP[1]));
const auto XEMBEDVERSION = XEMBEDPROP[0] > 1 ? 1 : XEMBEDPROP[0];
free(XEMBEDREPLY);
xcb_reparent_window(g_pWindowManager->DisplayConnection, CLIENT, g_pWindowManager->statusBar->getWindowID(), 0, 0);
// icon sizes are barY - 2 - pad: 1
values[0] = ConfigManager::getInt("bar:height") - 2 < 1 ? 1 : ConfigManager::getInt("bar:height") - 2;
values[1] = values[0];
xcb_configure_window(g_pWindowManager->DisplayConnection, CLIENT, XCB_CONFIG_WINDOW_HEIGHT | XCB_CONFIG_WINDOW_WIDTH, values);
// Notify the thing we did it
uint8_t buf[32] = {NULL};
xcb_client_message_event_t* event = (xcb_client_message_event_t*)buf;
event->response_type = XCB_CLIENT_MESSAGE;
event->window = CLIENT;
event->type = HYPRATOMS["_XEMBED"];
event->format = 32;
event->data.data32[0] = XCB_CURRENT_TIME;
event->data.data32[1] = 0;
event->data.data32[2] = g_pWindowManager->statusBar->getWindowID();
event->data.data32[3] = XEMBEDVERSION;
xcb_send_event(g_pWindowManager->DisplayConnection, 0, CLIENT, XCB_EVENT_MASK_NO_EVENT, (char*)event);
// put it into the save set
xcb_change_save_set(g_pWindowManager->DisplayConnection, XCB_SET_MODE_INSERT, CLIENT);
// make a tray client
CTrayClient newTrayClient;
newTrayClient.window = CLIENT;
newTrayClient.XEVer = XEMBEDVERSION;
g_pWindowManager->trayclients.push_back(newTrayClient);
xcb_map_window(g_pWindowManager->DisplayConnection, CLIENT);
}
}
} }

View file

@ -15,6 +15,7 @@ namespace Events {
EVENT(Expose); EVENT(Expose);
EVENT(KeyPress); EVENT(KeyPress);
EVENT(MotionNotify); EVENT(MotionNotify);
EVENT(ClientMessage);
// Bypass some events for floating windows // Bypass some events for floating windows
CWindow* remapWindow(int, bool floating = false, int forcemonitor = -1); CWindow* remapWindow(int, bool floating = false, int forcemonitor = -1);

8
src/utilities/Tray.hpp Normal file
View file

@ -0,0 +1,8 @@
#pragma once
class CTrayClient {
public:
uint32_t window = 0;
int XEVer = -1;
bool hidden = false;
};

View file

@ -198,19 +198,52 @@ bool CWindowManager::handleEvent() {
return false; return false;
xcb_flush(DisplayConnection); xcb_flush(DisplayConnection);
// recieve the event. Blocks.
recieveEvent();
// refresh and apply the parameters of all dirty windows.
refreshDirtyWindows();
// Sanity checks
for (const auto active : activeWorkspaces) {
sanityCheckOnWorkspace(active);
}
// remove unused workspaces
cleanupUnusedWorkspaces();
// Update last window name
updateActiveWindowName();
// Update the bar with the freshest stuff
updateBarInfo();
xcb_flush(DisplayConnection);
// Restore thread state
mainThreadBusy = false;
return true;
}
void CWindowManager::recieveEvent() {
const auto ev = xcb_wait_for_event(DisplayConnection); const auto ev = xcb_wait_for_event(DisplayConnection);
if (ev != NULL) { if (ev != NULL) {
while (animationUtilBusy) { while (animationUtilBusy) {
; // wait for it to finish ; // wait for it to finish
} }
// Set thread state, halt animations until done. // Set thread state, halt animations until done.
mainThreadBusy = true; mainThreadBusy = true;
// Read from the bar // Read from the bar
IPCRecieveMessageM(m_sIPCBarPipeOut.szPipeName); if (!g_pWindowManager->statusBar)
IPCRecieveMessageM(m_sIPCBarPipeOut.szPipeName);
switch (ev->response_type & ~0x80) { const auto EVENTCODE = ev->response_type & ~0x80;
switch (EVENTCODE) {
case XCB_ENTER_NOTIFY: case XCB_ENTER_NOTIFY:
Events::eventEnter(ev); Events::eventEnter(ev);
Debug::log(LOG, "Event dispatched ENTER"); Debug::log(LOG, "Event dispatched ENTER");
@ -241,7 +274,7 @@ bool CWindowManager::handleEvent() {
break; break;
case XCB_MOTION_NOTIFY: case XCB_MOTION_NOTIFY:
Events::eventMotionNotify(ev); Events::eventMotionNotify(ev);
//Debug::log(LOG, "Event dispatched MOTION_NOTIFY"); // Spam!! // Debug::log(LOG, "Event dispatched MOTION_NOTIFY"); // Spam!!
break; break;
case XCB_EXPOSE: case XCB_EXPOSE:
Events::eventExpose(ev); Events::eventExpose(ev);
@ -251,39 +284,20 @@ bool CWindowManager::handleEvent() {
Events::eventKeyPress(ev); Events::eventKeyPress(ev);
Debug::log(LOG, "Event dispatched KEY_PRESS"); Debug::log(LOG, "Event dispatched KEY_PRESS");
break; break;
case XCB_CLIENT_MESSAGE:
Events::eventClientMessage(ev);
Debug::log(LOG, "Event dispatched CLIENT_MESSAGE");
break;
default: default:
if (ev->response_type & ~0x80 != 14)
if ((EVENTCODE != 14) && (EVENTCODE != 13) && (EVENTCODE != 0) && (EVENTCODE != 22))
Debug::log(WARN, "Unknown event: " + std::to_string(ev->response_type & ~0x80)); Debug::log(WARN, "Unknown event: " + std::to_string(ev->response_type & ~0x80));
break; break;
} }
free(ev); free(ev);
} }
// refresh and apply the parameters of all dirty windows.
refreshDirtyWindows();
// Sanity checks
for (const auto active : activeWorkspaces) {
sanityCheckOnWorkspace(active);
}
// remove unused workspaces
cleanupUnusedWorkspaces();
// Update last window name
updateActiveWindowName();
// Update the bar with the freshest stuff
updateBarInfo();
xcb_flush(DisplayConnection);
// Restore thread state
mainThreadBusy = false;
return true;
} }
void CWindowManager::cleanupUnusedWorkspaces() { void CWindowManager::cleanupUnusedWorkspaces() {

View file

@ -16,6 +16,7 @@
#include "utilities/XCBProps.hpp" #include "utilities/XCBProps.hpp"
#include "ewmh/ewmh.hpp" #include "ewmh/ewmh.hpp"
#include "bar/Bar.hpp" #include "bar/Bar.hpp"
#include "utilities/Tray.hpp"
#include "ipc/ipc.hpp" #include "ipc/ipc.hpp"
@ -51,6 +52,8 @@ public:
Vector2D lastKnownBarPosition = {-1,-1}; Vector2D lastKnownBarPosition = {-1,-1};
uint64_t barWindowID = 0; uint64_t barWindowID = 0;
GThread* barThread; /* Well right now anything but the bar but lol */ GThread* barThread; /* Well right now anything but the bar but lol */
std::vector<CTrayClient> trayclients;
std::atomic<bool> mainThreadBusy = false; std::atomic<bool> mainThreadBusy = false;
std::atomic<bool> animationUtilBusy = false; std::atomic<bool> animationUtilBusy = false;
@ -64,6 +67,7 @@ public:
void setupManager(); void setupManager();
bool handleEvent(); bool handleEvent();
void recieveEvent();
void refreshDirtyWindows(); void refreshDirtyWindows();
void setFocusedWindow(xcb_drawable_t); void setFocusedWindow(xcb_drawable_t);
@ -111,7 +115,7 @@ public:
void recalcAllWorkspaces(); void recalcAllWorkspaces();
private: private:
// Internal WM functions that don't have to be exposed // Internal WM functions that don't have to be exposed
@ -181,15 +185,13 @@ inline std::map<std::string, xcb_atom_t> HYPRATOMS = {
HYPRATOM("WM_CLIENT_LEADER"), HYPRATOM("WM_CLIENT_LEADER"),
HYPRATOM("WM_TAKE_FOCUS"), HYPRATOM("WM_TAKE_FOCUS"),
HYPRATOM("WM_WINDOW_ROLE"), HYPRATOM("WM_WINDOW_ROLE"),
HYPRATOM("I3_SOCKET_PATH"),
HYPRATOM("I3_CONFIG_PATH"),
HYPRATOM("I3_SYNC"),
HYPRATOM("I3_SHMLOG_PATH"),
HYPRATOM("I3_PID"),
HYPRATOM("I3_LOG_STREAM_SOCKET_PATH"),
HYPRATOM("I3_FLOATING_WINDOW"),
HYPRATOM("_NET_REQUEST_FRAME_EXTENTS"), HYPRATOM("_NET_REQUEST_FRAME_EXTENTS"),
HYPRATOM("_NET_FRAME_EXTENTS"), HYPRATOM("_NET_FRAME_EXTENTS"),
HYPRATOM("_MOTIF_WM_HINTS"), HYPRATOM("_MOTIF_WM_HINTS"),
HYPRATOM("WM_CHANGE_STATE"), HYPRATOM("WM_CHANGE_STATE"),
HYPRATOM("_NET_SYSTEM_TRAY_OPCODE"),
HYPRATOM("_NET_SYSTEM_TRAY_COLORS"),
HYPRATOM("_NET_SYSTEM_TRAY_VISUAL"),
HYPRATOM("_NET_SYSTEM_TRAY_ORIENTATION"),
HYPRATOM("_XEMBED_INFO"),
HYPRATOM("MANAGER")}; HYPRATOM("MANAGER")};