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 /src | |
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.
Diffstat (limited to 'src')
-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 |