mirror of
https://github.com/hyprwm/Hypr.git
synced 2024-12-24 02:19:49 +01:00
Added a tray module
This commit is contained in:
parent
b897a1b64e
commit
2ca2ddfd2e
9 changed files with 442 additions and 49 deletions
|
@ -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$
|
||||
}
|
||||
|
||||
|
|
251
src/bar/Bar.cpp
251
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;
|
||||
}
|
||||
}
|
|
@ -7,6 +7,8 @@
|
|||
#include "BarCommands.hpp"
|
||||
#include <chrono>
|
||||
|
||||
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<int> openWorkspaces;
|
||||
EXPOSED_MEMBER(CurrentWorkspace, int, i);
|
||||
|
@ -77,6 +83,12 @@ private:
|
|||
int getTextHalfY();
|
||||
|
||||
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.
|
||||
|
|
|
@ -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
|
||||
#define CONTAINS(s, f) s.find(f) != std::string::npos
|
||||
|
||||
#define RETURNIFBAR if (g_pWindowManager->statusBar) return;
|
||||
#define RETURNIFMAIN if (!g_pWindowManager->statusBar) return;
|
|
@ -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<xcb_enter_notify_event_t*>(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<xcb_leave_notify_event_t*>(event);
|
||||
|
||||
RETURNIFBAR;
|
||||
|
||||
//
|
||||
}
|
||||
|
||||
void Events::eventDestroy(xcb_generic_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);
|
||||
|
||||
// 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<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);
|
||||
|
||||
// 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<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
|
||||
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<xcb_button_press_event_t*>(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<xcb_button_release_event_t*>(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<xcb_key_press_event_t*>(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<xcb_motion_notify_event_t*>(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<xcb_expose_event_t*>(event);
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
|
8
src/utilities/Tray.hpp
Normal file
8
src/utilities/Tray.hpp
Normal file
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
class CTrayClient {
|
||||
public:
|
||||
uint32_t window = 0;
|
||||
int XEVer = -1;
|
||||
bool hidden = false;
|
||||
};
|
|
@ -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() {
|
||||
|
|
|
@ -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<CTrayClient> trayclients;
|
||||
|
||||
std::atomic<bool> mainThreadBusy = false;
|
||||
std::atomic<bool> 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<std::string, xcb_atom_t> 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")};
|
||||
|
|
Loading…
Reference in a new issue