diff --git a/example/hypr.conf b/example/hypr.conf index 993c1cf..efbcb26 100644 --- a/example/hypr.conf +++ b/example/hypr.conf @@ -30,6 +30,8 @@ Bar { col.high=0xffff3333 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$ } diff --git a/src/bar/Bar.cpp b/src/bar/Bar.cpp index dd3030d..d989020 100644 --- a/src/bar/Bar.cpp +++ b/src/bar/Bar.cpp @@ -11,6 +11,12 @@ bool isParentDead() { return PPID == 1; } +void parseEvent() { + while(1) { + g_pWindowManager->recieveEvent(); + } +} + int64_t barMainThread() { // Main already created all the pipes @@ -18,14 +24,14 @@ int64_t barMainThread() { // Well now this is the init // 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) { Debug::log(CRIT, "Connection Failed! Return: " + std::to_string(RET)); return RET; } // 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) { Debug::log(CRIT, "Screen was null!"); @@ -69,6 +75,11 @@ int64_t barMainThread() { Debug::log(LOG, "Bar init Phase 2 done."); + // Start the parse event thread + std::thread([=]() { + parseEvent(); + }).detach(); + // Init config manager ConfigManager::init(); @@ -78,6 +89,9 @@ int64_t barMainThread() { int lazyUpdateCounter = 0; + // setup the tray so apps send to us + STATUSBAR.setupTray(); + while (1) { // Don't spam these @@ -130,6 +144,142 @@ void CStatusBar::destroyModule(SBarModule* module) { 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) { Debug::log(LOG, "Creating the bar!"); @@ -137,7 +287,15 @@ void CStatusBar::setup(int MonitorID) { MonitorID = 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]; m_iMonitorID = MonitorID; @@ -191,11 +349,16 @@ void CStatusBar::setup(int MonitorID) { m_vecSize.x, m_vecSize.y); m_pCairo = cairo_create(m_pCairoSurface); cairo_surface_destroy(m_pCairoSurface); + + // fix tray + fixTrayOnCreate(); } void CStatusBar::destroy() { Debug::log(LOG, "Destroying the bar!"); + saveTrayOnDestroy(); + 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_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); 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; } +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) { if (mod->isPad) return mod->pad; + if (mod->value == "tray") + return drawTrayModule(mod, off); + const int PAD = ConfigManager::getInt("bar:mod_pad_in"); // 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")); 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; + } } \ No newline at end of file diff --git a/src/bar/Bar.hpp b/src/bar/Bar.hpp index 47c3a9f..3da30ef 100644 --- a/src/bar/Bar.hpp +++ b/src/bar/Bar.hpp @@ -7,6 +7,8 @@ #include "BarCommands.hpp" #include +inline int barScreen = 0; + struct SDrawingContext { xcb_gcontext_t GContext; xcb_font_t Font; @@ -45,12 +47,16 @@ public: EXPOSED_MEMBER(LastWindowName, std::string, sz); EXPOSED_MEMBER(LastWindowClass, std::string, sz); EXPOSED_MEMBER(IsCovered, bool, b); + EXPOSED_MEMBER(HasTray, bool, b); void draw(); void setup(int MonitorID); void destroy(); void setupModule(SBarModule*); void destroyModule(SBarModule*); + void ensureTrayClientDead(xcb_window_t); + void ensureTrayClientHidden(xcb_window_t, bool); + void setupTray(); std::vector openWorkspaces; EXPOSED_MEMBER(CurrentWorkspace, int, i); @@ -77,6 +83,12 @@ private: int getTextHalfY(); std::unordered_map 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. diff --git a/src/defines.hpp b/src/defines.hpp index 821ab30..ceea6e6 100644 --- a/src/defines.hpp +++ b/src/defines.hpp @@ -79,4 +79,7 @@ #define GREEN(c) ((double)(((c) >> 8) & 0xff) / 255.0) #define BLUE(c) ((double)(((c)) & 0xff) / 255.0) -#define CONTAINS(s, f) s.find(f) != std::string::npos \ No newline at end of file +#define CONTAINS(s, f) s.find(f) != std::string::npos + +#define RETURNIFBAR if (g_pWindowManager->statusBar) return; +#define RETURNIFMAIN if (!g_pWindowManager->statusBar) return; \ No newline at end of file diff --git a/src/events/events.cpp b/src/events/events.cpp index 60d5615..2a8a184 100644 --- a/src/events/events.cpp +++ b/src/events/events.cpp @@ -49,18 +49,13 @@ void Events::setThread() { Debug::log(ERR, "Gthread failed!"); 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) { const auto E = reinterpret_cast(event); + RETURNIFBAR; + 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) { const auto E = reinterpret_cast(event); + RETURNIFBAR; + // } void Events::eventDestroy(xcb_generic_event_t* event) { const auto E = reinterpret_cast(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); // refocus on new window @@ -94,6 +97,12 @@ void Events::eventDestroy(xcb_generic_event_t* event) { void Events::eventUnmapWindow(xcb_generic_event_t* event) { const auto E = reinterpret_cast(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); // 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) { const auto E = reinterpret_cast(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 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) { const auto E = reinterpret_cast(event); + RETURNIFBAR; + // mouse down! 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, @@ -379,6 +396,8 @@ void Events::eventButtonPress(xcb_generic_event_t* event) { void Events::eventButtonRelease(xcb_generic_event_t* event) { const auto E = reinterpret_cast(event); + RETURNIFBAR; + // ungrab the mouse ptr xcb_ungrab_pointer(g_pWindowManager->DisplayConnection, XCB_CURRENT_TIME); 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) { const auto E = reinterpret_cast(event); + RETURNIFBAR; + const auto KEYSYM = KeybindManager::getKeysymFromKeycode(E->detail); 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) { const auto E = reinterpret_cast(event); + RETURNIFBAR; + if (!g_pWindowManager->mouseKeyDown) return; // mouse up. @@ -463,4 +486,89 @@ void Events::eventExpose(xcb_generic_event_t* event) { const auto E = reinterpret_cast(event); // nothing +} + +void Events::eventClientMessage(xcb_generic_event_t* event) { + const auto E = reinterpret_cast(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); + } + } + + } \ No newline at end of file diff --git a/src/events/events.hpp b/src/events/events.hpp index 95d572d..3bec0ce 100644 --- a/src/events/events.hpp +++ b/src/events/events.hpp @@ -15,6 +15,7 @@ namespace Events { EVENT(Expose); EVENT(KeyPress); EVENT(MotionNotify); + EVENT(ClientMessage); // Bypass some events for floating windows CWindow* remapWindow(int, bool floating = false, int forcemonitor = -1); diff --git a/src/utilities/Tray.hpp b/src/utilities/Tray.hpp new file mode 100644 index 0000000..d253ed7 --- /dev/null +++ b/src/utilities/Tray.hpp @@ -0,0 +1,8 @@ +#pragma once + +class CTrayClient { +public: + uint32_t window = 0; + int XEVer = -1; + bool hidden = false; +}; \ No newline at end of file diff --git a/src/windowManager.cpp b/src/windowManager.cpp index 646a9ff..919b343 100644 --- a/src/windowManager.cpp +++ b/src/windowManager.cpp @@ -198,19 +198,52 @@ bool CWindowManager::handleEvent() { return false; 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); if (ev != NULL) { while (animationUtilBusy) { - ; // wait for it to finish + ; // wait for it to finish } // Set thread state, halt animations until done. mainThreadBusy = true; // 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: Events::eventEnter(ev); Debug::log(LOG, "Event dispatched ENTER"); @@ -241,7 +274,7 @@ bool CWindowManager::handleEvent() { break; case XCB_MOTION_NOTIFY: Events::eventMotionNotify(ev); - //Debug::log(LOG, "Event dispatched MOTION_NOTIFY"); // Spam!! + // Debug::log(LOG, "Event dispatched MOTION_NOTIFY"); // Spam!! break; case XCB_EXPOSE: Events::eventExpose(ev); @@ -251,39 +284,20 @@ bool CWindowManager::handleEvent() { Events::eventKeyPress(ev); Debug::log(LOG, "Event dispatched KEY_PRESS"); break; + case XCB_CLIENT_MESSAGE: + Events::eventClientMessage(ev); + Debug::log(LOG, "Event dispatched CLIENT_MESSAGE"); + break; 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)); break; } 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() { diff --git a/src/windowManager.hpp b/src/windowManager.hpp index 26a6fdd..87d80b7 100644 --- a/src/windowManager.hpp +++ b/src/windowManager.hpp @@ -16,6 +16,7 @@ #include "utilities/XCBProps.hpp" #include "ewmh/ewmh.hpp" #include "bar/Bar.hpp" +#include "utilities/Tray.hpp" #include "ipc/ipc.hpp" @@ -51,6 +52,8 @@ public: Vector2D lastKnownBarPosition = {-1,-1}; uint64_t barWindowID = 0; GThread* barThread; /* Well right now anything but the bar but lol */ + + std::vector trayclients; std::atomic mainThreadBusy = false; std::atomic animationUtilBusy = false; @@ -64,6 +67,7 @@ public: void setupManager(); bool handleEvent(); + void recieveEvent(); void refreshDirtyWindows(); void setFocusedWindow(xcb_drawable_t); @@ -111,7 +115,7 @@ public: void recalcAllWorkspaces(); - private: +private: // Internal WM functions that don't have to be exposed @@ -181,15 +185,13 @@ inline std::map HYPRATOMS = { HYPRATOM("WM_CLIENT_LEADER"), HYPRATOM("WM_TAKE_FOCUS"), 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_FRAME_EXTENTS"), HYPRATOM("_MOTIF_WM_HINTS"), 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")};