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.
This commit is contained in:
parent
bb0790d794
commit
b23aba180f
2 changed files with 64 additions and 68 deletions
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue