all repos — fluxbox @ 7e762f0a972b7714f76a94e537dd65d0067f67b2

custom fork of the fluxbox windowmanager

Make systray icon pinning available.

The user options screenname.systray.pinLeft and
screenname.systray.pinRight in .fluxbox/init are read as comma sperated
list of window classnames.

While preserving the order of the lists, systray icons are sorted so
that pinLeft'ed classnames appear left and vice versa.
Gregor Bollerhey gbsoftware@arcor.de
commit

7e762f0a972b7714f76a94e537dd65d0067f67b2

parent

53fa0d6aaca3eb8a1fe8011e0e3d53cb85e1a772

2 files changed, 91 insertions(+), 5 deletions(-)

jump to
M src/SystemTray.ccsrc/SystemTray.cc

@@ -37,6 +37,11 @@ #include <X11/Xutil.h>

#include <X11/Xatom.h> #include <string> +#include <sstream> +#include <vector> +#include <memory> +#include <algorithm> +#include <functional> using std::string;

@@ -161,7 +166,6 @@ return;

winclient.setEventMask(StructureNotifyMask | SubstructureNotifyMask | EnterWindowMask); m_tray.addClient(winclient.window(), false); - }; void updateWorkarea(BScreen &) { }

@@ -192,7 +196,13 @@ SubstructureNotifyMask | SubstructureRedirectMask),

m_theme(theme), m_screen(screen), m_pixmap(0), m_num_visible_clients(0), - m_selection_owner(m_window, 0, 0, 1, 1, SubstructureNotifyMask, false, false, CopyFromParent, InputOnly) { + m_selection_owner(m_window, 0, 0, 1, 1, SubstructureNotifyMask, false, false, CopyFromParent, InputOnly), + m_rc_systray_pinleft(screen.resourceManager(), + "", screen.name() + ".systray.pinLeft", + screen.altName() + ".Systray.PinLeft"), + m_rc_systray_pinright(screen.resourceManager(), + "", screen.name() + ".systray.pinRight", + screen.altName() + ".Systray.PinRight") { FbTk::EventManager::instance()->add(*this, m_window); FbTk::EventManager::instance()->add(*this, m_selection_owner);

@@ -456,6 +466,9 @@ // we got configurenotify from an client

// check and see if we need to update it's size // and we must reposition and resize them to fit // our toolbar + + sortClients(); + ClientList::iterator it = findClient(event.xconfigure.window); if (it != m_clients.end()) { if (static_cast<unsigned int>(event.xconfigure.width) != (*it)->width() ||

@@ -473,7 +486,6 @@ // done inside this loop, because otherwise we can get into nasty looping

resizeSig().emit(); } } - } else if (event.type == PropertyNotify) { ClientList::iterator it = findClient(event.xproperty.window); if (it != m_clients.end()) {

@@ -484,8 +496,7 @@ else

hideClient(*it); } } - } - + } } void SystemTray::rearrangeClients() {

@@ -553,6 +564,74 @@ show();

traywin->show(); m_num_visible_clients++; + rearrangeClients(); +} + +static std::string trim(const std::string& str) +{ + const std::string whitespace(" \t"); + const auto strBegin = str.find_first_not_of(whitespace); + if (strBegin == std::string::npos) + return ""; // no content + + const auto strEnd = str.find_last_not_of(whitespace); + const auto strRange = strEnd - strBegin + 1; + + return str.substr(strBegin, strRange); +} + +static void parse_order(const std::string s, std::vector<std::string> &out) { + std::stringstream ss(s); + std::string item; + + while (std::getline(ss, item, ',')) + out.push_back(trim(item)); +} + +static int client_to_ordinal(const std::vector<std::string> left, + const std::vector<std::string> right, + TrayWindow *i) { + + std::unique_ptr<XClassHint> xclasshint (XAllocClassHint()); + if(XGetClassHint(Fluxbox::instance()->display(), + i->window(), xclasshint.get()) != BadWindow) + { + std::string classname(xclasshint.get()->res_class); + + auto ix = std::find(left.begin(), left.end(), classname); + if (ix != left.end()) + return -(left.end()-ix); // the more left, the negative (<0) + else { + ix = std::find(right.begin(), right.end(), classname); + if (ix != right.end()) + // the more right, the positive (>0) + return ix-right.begin()+1; + } + } + + // in neither list or invalid window (=0) + return 0; +} + +static bool client_comperator(const std::vector<std::string> left, + const std::vector<std::string> right, + TrayWindow *item1, TrayWindow *item2) { + const int a = client_to_ordinal(left, right, item1); + const int b = client_to_ordinal(left, right, item2); + return a<b; +} + + +void SystemTray::sortClients() { + std::vector<std::string> pinleft, pinright; + + parse_order(m_rc_systray_pinleft, pinleft); + parse_order(m_rc_systray_pinright, pinright); + + m_clients.sort(std::bind(client_comperator, + pinleft, pinright, + std::placeholders::_1, std::placeholders::_2)); + rearrangeClients(); }
M src/SystemTray.hhsrc/SystemTray.hh

@@ -26,12 +26,14 @@

#include "FbTk/FbWindow.hh" #include "FbTk/EventHandler.hh" #include "FbTk/Signal.hh" +#include "FbTk/Resource.hh" #include "ToolTheme.hh" #include "ToolbarItem.hh" #include <list> #include <memory> +#include <string> class BScreen; class ButtonTheme;

@@ -91,6 +93,7 @@ static bool doesControl(Window win);

private: void update(); + void sortClients(); class TrayWindow; typedef std::list<TrayWindow*> ClientList;

@@ -114,6 +117,10 @@

// gaim/pidgin seems to barf if the selection is not an independent window. // I suspect it's an interacton with parent relationship and gdk window caching. FbTk::FbWindow m_selection_owner; + + // resources + FbTk::Resource<std::string> m_rc_systray_pinleft; + FbTk::Resource<std::string> m_rc_systray_pinright; }; #endif // SYSTEMTRAY_HH