From b23aba180ffe8f6af2a2955641b73f764f740f62 Mon Sep 17 00:00:00 2001
From: Gregor Bollerhey <gbsoftware@arcor.de>
Date: Wed, 8 Jan 2014 20:38:00 +0100
Subject: Icon order now is property of the SystemTray.

This way it is only parsed once in the constructor. Updating the
TrayWindow order is now a method which is called once when the icon is
created.

sortClients/rearrange is now only called on adding and removing icons.
---
 src/SystemTray.cc | 131 ++++++++++++++++++++++++++----------------------------
 src/SystemTray.hh |   1 +
 2 files changed, 64 insertions(+), 68 deletions(-)

diff --git a/src/SystemTray.cc b/src/SystemTray.cc
index af534f6..2d1b316 100644
--- a/src/SystemTray.cc
+++ b/src/SystemTray.cc
@@ -41,7 +41,6 @@
 #include <vector>
 #include <memory>
 #include <algorithm>
-#include <functional>
 
 
 using std::string;
@@ -84,6 +83,31 @@ void getScreenCoordinates(Window win, int x, int y, int &screen_x, int &screen_y
 
 static SystemTray *s_theoneandonly = 0;
 
+static std::string trim(const std::string& str)
+{
+    // removes trailing and leading whitespace from a string
+
+    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) {
+    // splits a comma seperated list and performs trimming
+
+    std::stringstream ss(s);
+    std::string item;
+
+    while (std::getline(ss, item, ','))
+        out.push_back(trim(item));
+}
+
 /// helper class for tray windows, so we dont call XDestroyWindow
 class SystemTray::TrayWindow : public FbTk::FbWindow {
 public:
@@ -91,6 +115,8 @@ public:
         setEventMask(PropertyChangeMask);
     }
 
+    void pinByClassname(const std::vector<std::string> left, const std::vector<std::string> right);
+
     bool isVisible() { return m_visible; }
     bool isXEmbedded() { return m_xembedded; }
     void show() {
@@ -133,6 +159,34 @@ private:
     bool m_xembedded; // using xembed protocol? (i.e. unmap when done)
 };
 
+void TrayWindow::pinByClassname(const std::vector<std::string> left,
+        const std::vector<std::string> right) {
+    // based on the parsed order list and a given window returns an
+    // ordinal used to sort the tray icons.
+
+    auto deleter = [](XClassHint *x){if(x) XFree(x);};
+
+    std::unique_ptr<XClassHint, decltype(deleter)>
+        xclasshint(XAllocClassHint(), deleter);
+
+    if(XGetClassHint(Fluxbox::instance()->display(),
+                this->window(), xclasshint.get()))
+    {
+        std::string classname(xclasshint.get()->res_class);
+
+        auto ix = std::find(left.begin(), left.end(), classname);
+        if (ix != left.end())
+            m_order = -(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)
+                m_order = ix-right.begin()+1;
+        }
+    }
+    // in neither list or invalid window (=0)
+}
+
 /// handles clientmessage event and notifies systemtray
 class SystemTrayHandler: public AtomHandler {
 public:
@@ -205,6 +259,9 @@ SystemTray::SystemTray(const FbTk::FbWindow& parent,
             "", screen.name() + ".systray.pinRight",
             screen.altName() + ".Systray.PinRight") {
 
+    parse_order(m_rc_systray_pinleft, m_pinleft);
+    parse_order(m_rc_systray_pinright, m_pinright);
+
     FbTk::EventManager::instance()->add(*this, m_window);
     FbTk::EventManager::instance()->add(*this, m_selection_owner);
     // setup signals
@@ -427,6 +484,9 @@ void SystemTray::addClient(Window win, bool using_xembed) {
 
     if (traywin->getMappedDefault())
         showClient(traywin);
+
+    traywin->pinByClassname(m_pinleft, m_pinright);
+    sortClients();
 }
 
 void SystemTray::removeClient(Window win, bool destroyed) {
@@ -444,6 +504,8 @@ void SystemTray::removeClient(Window win, bool destroyed) {
     }
     hideClient(traywin, destroyed);
     delete traywin;
+
+    sortClients();
 }
 
 void SystemTray::exposeEvent(XExposeEvent &event) {
@@ -468,8 +530,6 @@ void SystemTray::handleEvent(XEvent &event) {
         // 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() ||
@@ -568,73 +628,8 @@ void SystemTray::showClient(TrayWindow *traywin) {
     rearrangeClients();
 }
 
-static std::string trim(const std::string& str)
-{
-    // removes trailing and leading whitespace from a string
-
-    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) {
-    // splits a comma seperated list and performs trimming
-
-    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) {
-    // based on the parsed order list and a given window returns an
-    // ordinal used to sort the tray icons.
-
-    auto deleter = [](XClassHint *x){if(x) XFree(x);};
-
-    std::unique_ptr<XClassHint, decltype(deleter)>
-        xclasshint(XAllocClassHint(), deleter);
-
-    if(XGetClassHint(Fluxbox::instance()->display(),
-                i->window(), xclasshint.get()))
-    {
-        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;
-}
-
 void SystemTray::sortClients() {
-    std::vector<std::string> pinleft, pinright;
-
-    parse_order(m_rc_systray_pinleft, pinleft);
-    parse_order(m_rc_systray_pinright, pinright);
-
-    for(TrayWindow *i: m_clients)
-        i->m_order = client_to_ordinal(pinleft, pinright, i);
-
     m_clients.sort([](TrayWindow *a, TrayWindow *b){return a->m_order < b->m_order;});
-
     rearrangeClients();
 }
 
diff --git a/src/SystemTray.hh b/src/SystemTray.hh
index b9fd75a..c1485f6 100644
--- a/src/SystemTray.hh
+++ b/src/SystemTray.hh
@@ -121,6 +121,7 @@ private:
     // resources
     FbTk::Resource<std::string> m_rc_systray_pinleft;
     FbTk::Resource<std::string> m_rc_systray_pinright;
+    std::vector<std::string> m_pinleft, m_pinright;
 };
 
 #endif // SYSTEMTRAY_HH
-- 
cgit v0.11.2