diff --git a/include/modules/xworkspaces.hpp b/include/modules/xworkspaces.hpp index e1f52426..2d5447db 100644 --- a/include/modules/xworkspaces.hpp +++ b/include/modules/xworkspaces.hpp @@ -66,6 +66,7 @@ namespace modules { void rebuild_clientlist(); void rebuild_desktops(); void rebuild_desktop_states(); + void set_desktop_urgent(xcb_window_t window); bool input(string&& cmd); diff --git a/include/x11/atoms.hpp b/include/x11/atoms.hpp index 169dd12a..94aa806e 100644 --- a/include/x11/atoms.hpp +++ b/include/x11/atoms.hpp @@ -8,7 +8,7 @@ struct cached_atom { xcb_atom_t* atom; }; -extern cached_atom ATOMS[35]; +extern cached_atom ATOMS[36]; extern xcb_atom_t _NET_SUPPORTED; extern xcb_atom_t _NET_CURRENT_DESKTOP; @@ -45,3 +45,4 @@ extern xcb_atom_t _XSETROOT_ID; extern xcb_atom_t ESETROOT_PMAP_ID; extern xcb_atom_t _COMPTON_SHADOW; extern xcb_atom_t _NET_WM_WINDOW_OPACITY; +extern xcb_atom_t WM_HINTS; diff --git a/include/x11/ewmh.hpp b/include/x11/ewmh.hpp index 8591da9c..bced1347 100644 --- a/include/x11/ewmh.hpp +++ b/include/x11/ewmh.hpp @@ -27,6 +27,7 @@ namespace ewmh_util { xcb_window_t get_active_window(int screen = 0); void change_current_desktop(unsigned int desktop); + unsigned int get_desktop_from_window(xcb_window_t window); void set_wm_window_type(xcb_window_t win, vector types); diff --git a/include/x11/icccm.hpp b/include/x11/icccm.hpp index 4f85eb83..d27bbb93 100644 --- a/include/x11/icccm.hpp +++ b/include/x11/icccm.hpp @@ -12,6 +12,7 @@ namespace icccm_util { void set_wm_name(xcb_connection_t* c, xcb_window_t w, const char* wmname, size_t l, const char* wmclass, size_t l2); void set_wm_protocols(xcb_connection_t* c, xcb_window_t w, vector flags); + bool get_wm_urgency(xcb_connection_t* c, xcb_window_t w); } POLYBAR_NS_END diff --git a/src/modules/xworkspaces.cpp b/src/modules/xworkspaces.cpp index dfaf4141..7401eb5b 100644 --- a/src/modules/xworkspaces.cpp +++ b/src/modules/xworkspaces.cpp @@ -104,6 +104,10 @@ namespace modules { } else if (evt->atom == m_ewmh->_NET_CURRENT_DESKTOP) { m_current_desktop = ewmh_util::get_current_desktop(); rebuild_desktop_states(); + } else if (evt->atom == WM_HINTS) { + if (icccm_util::get_wm_urgency(m_connection, evt->window)) { + set_desktop_urgent(evt->window); + } } else { return; } @@ -133,6 +137,8 @@ namespace modules { std::set_difference( clients.begin(), clients.end(), m_clientlist.begin(), m_clientlist.end(), back_inserter(diff)); for (auto&& win : diff) { + // listen for wm_hint (urgency) changes + m_connection.ensure_event_mask(win, XCB_EVENT_MASK_PROPERTY_CHANGE); // track window m_clientlist.emplace_back(win); } @@ -215,6 +221,31 @@ namespace modules { } } + /** + * Find window and set corresponding desktop to urgent + */ + void xworkspaces_module::set_desktop_urgent(xcb_window_t window) { + auto desk = ewmh_util::get_desktop_from_window(window); + if(desk == m_current_desktop) + // ignore if current desktop is urgent + return; + for (auto&& v : m_viewports) { + for (auto&& d : v->desktops) { + if (d->index == desk && d->state != desktop_state::URGENT) { + d->state = desktop_state::URGENT; + + d->label = m_labels.at(d->state)->clone(); + d->label->reset_tokens(); + d->label->replace_token("%index%", to_string(d->index - d->offset + 1)); + d->label->replace_token("%name%", m_desktop_names[d->index]); + d->label->replace_token("%icon%", m_icons->get(m_desktop_names[d->index], DEFAULT_ICON)->get()); + return; + } + } + } + + } + /** * Fetch and parse data */ diff --git a/src/x11/atoms.cpp b/src/x11/atoms.cpp index 5fd98560..3145783f 100644 --- a/src/x11/atoms.cpp +++ b/src/x11/atoms.cpp @@ -38,9 +38,10 @@ xcb_atom_t _XSETROOT_ID; xcb_atom_t ESETROOT_PMAP_ID; xcb_atom_t _COMPTON_SHADOW; xcb_atom_t _NET_WM_WINDOW_OPACITY; +xcb_atom_t WM_HINTS; // clang-format off -cached_atom ATOMS[35] = { +cached_atom ATOMS[36] = { {"_NET_SUPPORTED", sizeof("_NET_SUPPORTED") - 1, &_NET_SUPPORTED}, {"_NET_CURRENT_DESKTOP", sizeof("_NET_CURRENT_DESKTOP") - 1, &_NET_CURRENT_DESKTOP}, {"_NET_ACTIVE_WINDOW", sizeof("_NET_ACTIVE_WINDOW") - 1, &_NET_ACTIVE_WINDOW}, @@ -76,5 +77,6 @@ cached_atom ATOMS[35] = { {"ESETROOT_PMAP_ID", sizeof("ESETROOT_PMAP_ID") - 1, &ESETROOT_PMAP_ID}, {"_COMPTON_SHADOW", sizeof("_COMPTON_SHADOW") - 1, &_COMPTON_SHADOW}, {"_NET_WM_WINDOW_OPACITY", sizeof("_NET_WM_WINDOW_OPACITY") - 1, &_NET_WM_WINDOW_OPACITY}, + {"WM_HINTS", sizeof("WM_HINTS") - 1, &WM_HINTS}, }; // clang-format on diff --git a/src/x11/ewmh.cpp b/src/x11/ewmh.cpp index 0d0f7972..1c4fb2f6 100644 --- a/src/x11/ewmh.cpp +++ b/src/x11/ewmh.cpp @@ -112,6 +112,13 @@ namespace ewmh_util { xcb_flush(conn->connection); } + unsigned int get_desktop_from_window(xcb_window_t window) { + auto conn = initialize().get(); + unsigned int desktop = XCB_NONE; + xcb_ewmh_get_wm_desktop_reply(conn, xcb_ewmh_get_wm_desktop(conn, window), &desktop, nullptr); + return desktop; + } + void set_wm_window_type(xcb_window_t win, vector types) { auto conn = initialize().get(); xcb_ewmh_set_wm_window_type(conn, win, types.size(), types.data()); diff --git a/src/x11/icccm.cpp b/src/x11/icccm.cpp index 2bb12f47..a6e292ee 100644 --- a/src/x11/icccm.cpp +++ b/src/x11/icccm.cpp @@ -29,6 +29,15 @@ namespace icccm_util { void set_wm_protocols(xcb_connection_t* c, xcb_window_t w, vector flags) { xcb_icccm_set_wm_protocols(c, w, WM_PROTOCOLS, flags.size(), flags.data()); } + + bool get_wm_urgency(xcb_connection_t* c, xcb_window_t w) { + xcb_icccm_wm_hints_t hints; + if (xcb_icccm_get_wm_hints_reply(c, xcb_icccm_get_wm_hints(c, w), &hints, NULL)) { + if(xcb_icccm_wm_hints_get_urgency(&hints) == XCB_ICCCM_WM_HINT_X_URGENCY) + return true; + } + return false; + } } POLYBAR_NS_END