diff options
author | Gregor Bollerhey <gbsoftware@arcor.de> | 2013-12-14 07:43:26 (GMT) |
---|---|---|
committer | Jan Sucan <jan@jansucan.com> | 2020-04-05 07:47:18 (GMT) |
commit | 7e762f0a972b7714f76a94e537dd65d0067f67b2 (patch) | |
tree | 86968d8a594d15513efffc42cc559a62797f4e7e | |
parent | 53fa0d6aaca3eb8a1fe8011e0e3d53cb85e1a772 (diff) | |
download | fluxbox-7e762f0a972b7714f76a94e537dd65d0067f67b2.zip fluxbox-7e762f0a972b7714f76a94e537dd65d0067f67b2.tar.bz2 |
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.
-rw-r--r-- | src/SystemTray.cc | 89 | ||||
-rw-r--r-- | src/SystemTray.hh | 7 |
2 files changed, 91 insertions, 5 deletions
diff --git a/src/SystemTray.cc b/src/SystemTray.cc index 4fa9da3..4b2cf56 100644 --- a/src/SystemTray.cc +++ b/src/SystemTray.cc | |||
@@ -37,6 +37,11 @@ | |||
37 | #include <X11/Xatom.h> | 37 | #include <X11/Xatom.h> |
38 | 38 | ||
39 | #include <string> | 39 | #include <string> |
40 | #include <sstream> | ||
41 | #include <vector> | ||
42 | #include <memory> | ||
43 | #include <algorithm> | ||
44 | #include <functional> | ||
40 | 45 | ||
41 | 46 | ||
42 | using std::string; | 47 | using std::string; |
@@ -161,7 +166,6 @@ public: | |||
161 | winclient.setEventMask(StructureNotifyMask | | 166 | winclient.setEventMask(StructureNotifyMask | |
162 | SubstructureNotifyMask | EnterWindowMask); | 167 | SubstructureNotifyMask | EnterWindowMask); |
163 | m_tray.addClient(winclient.window(), false); | 168 | m_tray.addClient(winclient.window(), false); |
164 | |||
165 | }; | 169 | }; |
166 | 170 | ||
167 | void updateWorkarea(BScreen &) { } | 171 | void updateWorkarea(BScreen &) { } |
@@ -192,7 +196,13 @@ SystemTray::SystemTray(const FbTk::FbWindow& parent, | |||
192 | m_theme(theme), | 196 | m_theme(theme), |
193 | m_screen(screen), | 197 | m_screen(screen), |
194 | m_pixmap(0), m_num_visible_clients(0), | 198 | m_pixmap(0), m_num_visible_clients(0), |
195 | m_selection_owner(m_window, 0, 0, 1, 1, SubstructureNotifyMask, false, false, CopyFromParent, InputOnly) { | 199 | m_selection_owner(m_window, 0, 0, 1, 1, SubstructureNotifyMask, false, false, CopyFromParent, InputOnly), |
200 | m_rc_systray_pinleft(screen.resourceManager(), | ||
201 | "", screen.name() + ".systray.pinLeft", | ||
202 | screen.altName() + ".Systray.PinLeft"), | ||
203 | m_rc_systray_pinright(screen.resourceManager(), | ||
204 | "", screen.name() + ".systray.pinRight", | ||
205 | screen.altName() + ".Systray.PinRight") { | ||
196 | 206 | ||
197 | FbTk::EventManager::instance()->add(*this, m_window); | 207 | FbTk::EventManager::instance()->add(*this, m_window); |
198 | FbTk::EventManager::instance()->add(*this, m_selection_owner); | 208 | FbTk::EventManager::instance()->add(*this, m_selection_owner); |
@@ -456,6 +466,9 @@ void SystemTray::handleEvent(XEvent &event) { | |||
456 | // check and see if we need to update it's size | 466 | // check and see if we need to update it's size |
457 | // and we must reposition and resize them to fit | 467 | // and we must reposition and resize them to fit |
458 | // our toolbar | 468 | // our toolbar |
469 | |||
470 | sortClients(); | ||
471 | |||
459 | ClientList::iterator it = findClient(event.xconfigure.window); | 472 | ClientList::iterator it = findClient(event.xconfigure.window); |
460 | if (it != m_clients.end()) { | 473 | if (it != m_clients.end()) { |
461 | if (static_cast<unsigned int>(event.xconfigure.width) != (*it)->width() || | 474 | if (static_cast<unsigned int>(event.xconfigure.width) != (*it)->width() || |
@@ -473,7 +486,6 @@ void SystemTray::handleEvent(XEvent &event) { | |||
473 | resizeSig().emit(); | 486 | resizeSig().emit(); |
474 | } | 487 | } |
475 | } | 488 | } |
476 | |||
477 | } else if (event.type == PropertyNotify) { | 489 | } else if (event.type == PropertyNotify) { |
478 | ClientList::iterator it = findClient(event.xproperty.window); | 490 | ClientList::iterator it = findClient(event.xproperty.window); |
479 | if (it != m_clients.end()) { | 491 | if (it != m_clients.end()) { |
@@ -484,8 +496,7 @@ void SystemTray::handleEvent(XEvent &event) { | |||
484 | hideClient(*it); | 496 | hideClient(*it); |
485 | } | 497 | } |
486 | } | 498 | } |
487 | } | 499 | } |
488 | |||
489 | } | 500 | } |
490 | 501 | ||
491 | void SystemTray::rearrangeClients() { | 502 | void SystemTray::rearrangeClients() { |
@@ -556,6 +567,74 @@ void SystemTray::showClient(TrayWindow *traywin) { | |||
556 | rearrangeClients(); | 567 | rearrangeClients(); |
557 | } | 568 | } |
558 | 569 | ||
570 | static std::string trim(const std::string& str) | ||
571 | { | ||
572 | const std::string whitespace(" \t"); | ||
573 | const auto strBegin = str.find_first_not_of(whitespace); | ||
574 | if (strBegin == std::string::npos) | ||
575 | return ""; // no content | ||
576 | |||
577 | const auto strEnd = str.find_last_not_of(whitespace); | ||
578 | const auto strRange = strEnd - strBegin + 1; | ||
579 | |||
580 | return str.substr(strBegin, strRange); | ||
581 | } | ||
582 | |||
583 | static void parse_order(const std::string s, std::vector<std::string> &out) { | ||
584 | std::stringstream ss(s); | ||
585 | std::string item; | ||
586 | |||
587 | while (std::getline(ss, item, ',')) | ||
588 | out.push_back(trim(item)); | ||
589 | } | ||
590 | |||
591 | static int client_to_ordinal(const std::vector<std::string> left, | ||
592 | const std::vector<std::string> right, | ||
593 | TrayWindow *i) { | ||
594 | |||
595 | std::unique_ptr<XClassHint> xclasshint (XAllocClassHint()); | ||
596 | if(XGetClassHint(Fluxbox::instance()->display(), | ||
597 | i->window(), xclasshint.get()) != BadWindow) | ||
598 | { | ||
599 | std::string classname(xclasshint.get()->res_class); | ||
600 | |||
601 | auto ix = std::find(left.begin(), left.end(), classname); | ||
602 | if (ix != left.end()) | ||
603 | return -(left.end()-ix); // the more left, the negative (<0) | ||
604 | else { | ||
605 | ix = std::find(right.begin(), right.end(), classname); | ||
606 | if (ix != right.end()) | ||
607 | // the more right, the positive (>0) | ||
608 | return ix-right.begin()+1; | ||
609 | } | ||
610 | } | ||
611 | |||
612 | // in neither list or invalid window (=0) | ||
613 | return 0; | ||
614 | } | ||
615 | |||
616 | static bool client_comperator(const std::vector<std::string> left, | ||
617 | const std::vector<std::string> right, | ||
618 | TrayWindow *item1, TrayWindow *item2) { | ||
619 | const int a = client_to_ordinal(left, right, item1); | ||
620 | const int b = client_to_ordinal(left, right, item2); | ||
621 | return a<b; | ||
622 | } | ||
623 | |||
624 | |||
625 | void SystemTray::sortClients() { | ||
626 | std::vector<std::string> pinleft, pinright; | ||
627 | |||
628 | parse_order(m_rc_systray_pinleft, pinleft); | ||
629 | parse_order(m_rc_systray_pinright, pinright); | ||
630 | |||
631 | m_clients.sort(std::bind(client_comperator, | ||
632 | pinleft, pinright, | ||
633 | std::placeholders::_1, std::placeholders::_2)); | ||
634 | |||
635 | rearrangeClients(); | ||
636 | } | ||
637 | |||
559 | void SystemTray::update() { | 638 | void SystemTray::update() { |
560 | 639 | ||
561 | if (!m_theme->texture().usePixmap()) { | 640 | if (!m_theme->texture().usePixmap()) { |
diff --git a/src/SystemTray.hh b/src/SystemTray.hh index 16e703e..b9fd75a 100644 --- a/src/SystemTray.hh +++ b/src/SystemTray.hh | |||
@@ -26,12 +26,14 @@ | |||
26 | #include "FbTk/FbWindow.hh" | 26 | #include "FbTk/FbWindow.hh" |
27 | #include "FbTk/EventHandler.hh" | 27 | #include "FbTk/EventHandler.hh" |
28 | #include "FbTk/Signal.hh" | 28 | #include "FbTk/Signal.hh" |
29 | #include "FbTk/Resource.hh" | ||
29 | 30 | ||
30 | #include "ToolTheme.hh" | 31 | #include "ToolTheme.hh" |
31 | #include "ToolbarItem.hh" | 32 | #include "ToolbarItem.hh" |
32 | 33 | ||
33 | #include <list> | 34 | #include <list> |
34 | #include <memory> | 35 | #include <memory> |
36 | #include <string> | ||
35 | 37 | ||
36 | class BScreen; | 38 | class BScreen; |
37 | class ButtonTheme; | 39 | class ButtonTheme; |
@@ -91,6 +93,7 @@ public: | |||
91 | 93 | ||
92 | private: | 94 | private: |
93 | void update(); | 95 | void update(); |
96 | void sortClients(); | ||
94 | 97 | ||
95 | class TrayWindow; | 98 | class TrayWindow; |
96 | typedef std::list<TrayWindow*> ClientList; | 99 | typedef std::list<TrayWindow*> ClientList; |
@@ -114,6 +117,10 @@ private: | |||
114 | // gaim/pidgin seems to barf if the selection is not an independent window. | 117 | // gaim/pidgin seems to barf if the selection is not an independent window. |
115 | // I suspect it's an interacton with parent relationship and gdk window caching. | 118 | // I suspect it's an interacton with parent relationship and gdk window caching. |
116 | FbTk::FbWindow m_selection_owner; | 119 | FbTk::FbWindow m_selection_owner; |
120 | |||
121 | // resources | ||
122 | FbTk::Resource<std::string> m_rc_systray_pinleft; | ||
123 | FbTk::Resource<std::string> m_rc_systray_pinright; | ||
117 | }; | 124 | }; |
118 | 125 | ||
119 | #endif // SYSTEMTRAY_HH | 126 | #endif // SYSTEMTRAY_HH |