summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog3
-rw-r--r--src/SystemTray.cc126
-rw-r--r--src/SystemTray.hh6
3 files changed, 103 insertions, 32 deletions
diff --git a/ChangeLog b/ChangeLog
index dfc029d..37f91ea 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,8 @@
1 (Format: Year/Month/Day) 1 (Format: Year/Month/Day)
2Changes for 1.0rc3: 2Changes for 1.0rc3:
3*07/02/22:
4 * Make systemtray support XEMBED protocol (Mark)
5 Systemtray.cc/hh
3*07/02/21: 6*07/02/21:
4 * Buttons should only run a command if the mouse was clicked down on the 7 * Buttons should only run a command if the mouse was clicked down on the
5 same button, e.g. bug #1437864 (Mark) 8 same button, e.g. bug #1437864 (Mark)
diff --git a/src/SystemTray.cc b/src/SystemTray.cc
index ecbdd4f..98a726a 100644
--- a/src/SystemTray.cc
+++ b/src/SystemTray.cc
@@ -49,7 +49,24 @@ using std::dec;
49/// helper class for tray windows, so we dont call XDestroyWindow 49/// helper class for tray windows, so we dont call XDestroyWindow
50class TrayWindow: public FbTk::FbWindow { 50class TrayWindow: public FbTk::FbWindow {
51public: 51public:
52 TrayWindow(Window win):FbTk::FbWindow(win) { } 52 TrayWindow(Window win):FbTk::FbWindow(win), m_visible(false) {
53 setEventMask(PropertyChangeMask);
54 }
55 bool isVisible() { return m_visible; }
56 void show() {
57 if (!m_visible) {
58 m_visible = true;
59 FbTk::FbWindow::show();
60 }
61 }
62 void hide() {
63 if (m_visible) {
64 m_visible = false;
65 FbTk::FbWindow::hide();
66 }
67 }
68private:
69 bool m_visible;
53}; 70};
54 71
55/// handles clientmessage event and notifies systemtray 72/// handles clientmessage event and notifies systemtray
@@ -115,7 +132,7 @@ SystemTray::SystemTray(const FbTk::FbWindow& parent, ButtonTheme& theme, BScreen
115 SubstructureNotifyMask | SubstructureRedirectMask), 132 SubstructureNotifyMask | SubstructureRedirectMask),
116 m_theme(theme), 133 m_theme(theme),
117 m_screen(screen), 134 m_screen(screen),
118 m_pixmap(0) { 135 m_pixmap(0), m_num_visible_clients(0) {
119 136
120 FbTk::EventManager::instance()->add(*this, m_window); 137 FbTk::EventManager::instance()->add(*this, m_window);
121 m_theme.reconfigSig().attach(this); 138 m_theme.reconfigSig().attach(this);
@@ -189,10 +206,9 @@ void SystemTray::resize(unsigned int width, unsigned int height) {
189 if (width != m_window.width() || 206 if (width != m_window.width() ||
190 height != m_window.height()) { 207 height != m_window.height()) {
191 m_window.resize(width, height); 208 m_window.resize(width, height);
192 if (!m_clients.empty()) { 209 if (m_num_visible_clients)
193 rearrangeClients(); 210 rearrangeClients();
194 resizeSig().notify(); 211 resizeSig().notify();
195 }
196 } 212 }
197} 213}
198 214
@@ -201,10 +217,9 @@ void SystemTray::moveResize(int x, int y,
201 if (width != m_window.width() || 217 if (width != m_window.width() ||
202 height != m_window.height()) { 218 height != m_window.height()) {
203 m_window.moveResize(x, y, width, height); 219 m_window.moveResize(x, y, width, height);
204 if (!m_clients.empty()) { 220 if (m_num_visible_clients)
205 rearrangeClients(); 221 rearrangeClients();
206 resizeSig().notify(); 222 resizeSig().notify();
207 }
208 } else { 223 } else {
209 move(x, y); 224 move(x, y);
210 } 225 }
@@ -224,14 +239,14 @@ unsigned int SystemTray::width() const {
224 if (orientation() == FbTk::ROT90 || orientation() == FbTk::ROT270) 239 if (orientation() == FbTk::ROT90 || orientation() == FbTk::ROT270)
225 return m_window.width(); 240 return m_window.width();
226 241
227 return m_clients.size()* (height() - 2 * m_theme.border().width()); 242 return m_num_visible_clients * (height() - 2 * m_theme.border().width());
228} 243}
229 244
230unsigned int SystemTray::height() const { 245unsigned int SystemTray::height() const {
231 if (orientation() == FbTk::ROT0 || orientation() == FbTk::ROT180) 246 if (orientation() == FbTk::ROT0 || orientation() == FbTk::ROT180)
232 return m_window.height(); 247 return m_window.height();
233 248
234 return m_clients.size()* (width() - 2 * m_theme.border().width()); 249 return m_num_visible_clients * (width() - 2 * m_theme.border().width());
235} 250}
236 251
237unsigned int SystemTray::borderWidth() const { 252unsigned int SystemTray::borderWidth() const {
@@ -297,26 +312,18 @@ void SystemTray::addClient(Window win) {
297 return; 312 return;
298 } 313 }
299 314
300 FbTk::FbWindow *traywin = new TrayWindow(win); 315 TrayWindow *traywin = new TrayWindow(win);
301 316
302#ifdef DEBUG 317#ifdef DEBUG
303 cerr<<"SystemTray::addClient(Window): 0x"<<hex<<win<<dec<<endl; 318 cerr<<"SystemTray::addClient(Window): 0x"<<hex<<win<<dec<<endl;
304#endif // DEBUG 319#endif // DEBUG
305 if (m_clients.empty())
306 show();
307 320
308 m_clients.push_back(traywin); 321 m_clients.push_back(traywin);
309 FbTk::EventManager::instance()->add(*this, win); 322 FbTk::EventManager::instance()->add(*this, win);
310 FbTk::EventManager::instance()->addParent(*this, window()); 323 FbTk::EventManager::instance()->addParent(*this, window());
311 XChangeSaveSet(FbTk::App::instance()->display(), win, SetModeInsert); 324 XChangeSaveSet(FbTk::App::instance()->display(), win, SetModeInsert);
312 traywin->reparent(m_window, 0, 0); 325 traywin->reparent(m_window, 0, 0);
313 traywin->show(); 326 showClient(traywin);
314
315
316#ifdef DEBUG
317 cerr<<"SystemTray: number of clients = "<<m_clients.size()<<endl;
318#endif // DEBUG
319 rearrangeClients();
320} 327}
321 328
322void SystemTray::removeClient(Window win) { 329void SystemTray::removeClient(Window win) {
@@ -327,15 +334,10 @@ void SystemTray::removeClient(Window win) {
327#ifdef DEBUG 334#ifdef DEBUG
328 cerr<<__FILE__<<"(SystemTray::removeClient(Window)): 0x"<<hex<<win<<dec<<endl; 335 cerr<<__FILE__<<"(SystemTray::removeClient(Window)): 0x"<<hex<<win<<dec<<endl;
329#endif // DEBUG 336#endif // DEBUG
330 FbTk::FbWindow *traywin = *tray_it; 337 TrayWindow *traywin = *tray_it;
331 m_clients.erase(tray_it); 338 m_clients.erase(tray_it);
339 hideClient(traywin);
332 delete traywin; 340 delete traywin;
333 resize(width(), height());
334 rearrangeClients();
335 if (m_clients.empty()) {
336 // so we send notify signal to parent
337 resizeSig().notify();
338 }
339} 341}
340 342
341void SystemTray::exposeEvent(XExposeEvent &event) { 343void SystemTray::exposeEvent(XExposeEvent &event) {
@@ -345,11 +347,15 @@ void SystemTray::exposeEvent(XExposeEvent &event) {
345void SystemTray::handleEvent(XEvent &event) { 347void SystemTray::handleEvent(XEvent &event) {
346 if (event.type == DestroyNotify) { 348 if (event.type == DestroyNotify) {
347 removeClient(event.xdestroywindow.window); 349 removeClient(event.xdestroywindow.window);
350 } else if (event.type == ReparentNotify && event.xreparent.parent != m_window.window()) {
351 removeClient(event.xreparent.window);
348 } else if (event.type == UnmapNotify && event.xany.send_event) { 352 } else if (event.type == UnmapNotify && event.xany.send_event) {
349 // we ignore server-generated events, which can occur 353 // we ignore server-generated events, which can occur
350 // on restart. The ICCCM says that a client must send 354 // on restart. The ICCCM says that a client must send
351 // a synthetic event for the withdrawn state 355 // a synthetic event for the withdrawn state
352 removeClient(event.xunmap.window); 356 ClientList::iterator it = findClient(event.xunmap.window);
357 if (it != m_clients.end())
358 hideClient(*it);
353 } else if (event.type == ConfigureNotify) { 359 } else if (event.type == ConfigureNotify) {
354 // we got configurenotify from an client 360 // we got configurenotify from an client
355 // check and see if we need to update it's size 361 // check and see if we need to update it's size
@@ -373,6 +379,38 @@ void SystemTray::handleEvent(XEvent &event) {
373 } 379 }
374 } 380 }
375 381
382 } else if (event.type == PropertyNotify) {
383 ClientList::iterator it = findClient(event.xproperty.window);
384 if (it != m_clients.end()) {
385 Atom embed_info = XInternAtom(FbTk::App::instance()->display(),"_XEMBED_INFO",false);
386 if (event.xproperty.atom == embed_info) {
387
388/* Flags for _XEMBED_INFO */
389#define XEMBED_MAPPED (1 << 0)
390
391 TrayWindow *traywin = *it;
392 Atom actual_type;
393 int actual_format;
394 unsigned long nitems, bytes_after;
395 unsigned long *prop;
396 if (traywin->property(embed_info, 0l, 2l, false, embed_info,
397 &actual_type, &actual_format, &nitems, &bytes_after,
398 (unsigned char **) &prop)) {
399
400 bool mapped = (bool)(static_cast<unsigned long>(prop[1]) & XEMBED_MAPPED);
401 XFree(static_cast<void *>(prop));
402
403#ifdef DEBUG
404 cerr<<__FILE__<<"(SystemTray::handleEvent(XEvent)): XEMBED_MAPPED = "<<mapped<<endl;
405#endif // DEBUG
406
407 if (mapped)
408 showClient(traywin);
409 else
410 hideClient(traywin);
411 }
412 }
413 }
376 } 414 }
377} 415}
378 416
@@ -380,7 +418,7 @@ void SystemTray::rearrangeClients() {
380 unsigned int w_rot0 = width(), h_rot0 = height(); 418 unsigned int w_rot0 = width(), h_rot0 = height();
381 const unsigned int bw = m_theme.border().width(); 419 const unsigned int bw = m_theme.border().width();
382 FbTk::translateSize(orientation(), w_rot0, h_rot0); 420 FbTk::translateSize(orientation(), w_rot0, h_rot0);
383 unsigned int trayw = m_clients.size()*h_rot0 + bw, trayh = h_rot0; 421 unsigned int trayw = m_num_visible_clients*h_rot0 + bw, trayh = h_rot0;
384 FbTk::translateSize(orientation(), trayw, trayh); 422 FbTk::translateSize(orientation(), trayw, trayh);
385 resize(trayw, trayh); 423 resize(trayw, trayh);
386 update(0); 424 update(0);
@@ -389,9 +427,11 @@ void SystemTray::rearrangeClients() {
389 ClientList::iterator client_it = m_clients.begin(); 427 ClientList::iterator client_it = m_clients.begin();
390 ClientList::iterator client_it_end = m_clients.end(); 428 ClientList::iterator client_it_end = m_clients.end();
391 int next_x = bw; 429 int next_x = bw;
392 for (; client_it != client_it_end; 430 for (; client_it != client_it_end; ++client_it) {
393 ++client_it, next_x += h_rot0+bw) { 431 if (!(*client_it)->isVisible())
432 continue;
394 int x = next_x, y = bw; 433 int x = next_x, y = bw;
434 next_x += h_rot0+bw;
395 translateCoords(orientation(), x, y, w_rot0, h_rot0); 435 translateCoords(orientation(), x, y, w_rot0, h_rot0);
396 translatePosition(orientation(), x, y, h_rot0, h_rot0, 0); 436 translatePosition(orientation(), x, y, h_rot0, h_rot0, 0);
397 437
@@ -409,6 +449,28 @@ void SystemTray::removeAllClients() {
409 delete m_clients.back(); 449 delete m_clients.back();
410 m_clients.pop_back(); 450 m_clients.pop_back();
411 } 451 }
452 m_num_visible_clients = 0;
453}
454
455void SystemTray::hideClient(TrayWindow *traywin) {
456 if (!traywin || !traywin->isVisible())
457 return;
458
459 traywin->hide();
460 m_num_visible_clients--;
461 rearrangeClients();
462}
463
464void SystemTray::showClient(TrayWindow *traywin) {
465 if (!traywin || traywin->isVisible())
466 return;
467
468 if (!m_num_visible_clients)
469 show();
470
471 traywin->show();
472 m_num_visible_clients++;
473 rearrangeClients();
412} 474}
413 475
414void SystemTray::update(FbTk::Subject* subject) { 476void SystemTray::update(FbTk::Subject* subject) {
@@ -432,6 +494,8 @@ void SystemTray::update(FbTk::Subject* subject) {
432 494
433 // maybe not the best solution (yet), force a refresh of the 495 // maybe not the best solution (yet), force a refresh of the
434 // background of the client 496 // background of the client
497 if (!(*client_it)->isVisible())
498 continue;
435 (*client_it)->hide(); 499 (*client_it)->hide();
436 (*client_it)->show(); 500 (*client_it)->show();
437 } 501 }
diff --git a/src/SystemTray.hh b/src/SystemTray.hh
index 8be1cd8..0d4afc8 100644
--- a/src/SystemTray.hh
+++ b/src/SystemTray.hh
@@ -37,6 +37,7 @@
37 37
38#include <list> 38#include <list>
39 39
40class TrayWindow;
40class AtomHandler; 41class AtomHandler;
41 42
42class SystemTray: public ToolbarItem, public FbTk::EventHandler, public FbTk::Observer { 43class SystemTray: public ToolbarItem, public FbTk::EventHandler, public FbTk::Observer {
@@ -77,11 +78,13 @@ private:
77 78
78 void update(FbTk::Subject *subj); 79 void update(FbTk::Subject *subj);
79 80
80 typedef std::list<FbTk::FbWindow *> ClientList; 81 typedef std::list<TrayWindow *> ClientList;
81 ClientList::iterator findClient(Window win); 82 ClientList::iterator findClient(Window win);
82 83
83 void rearrangeClients(); 84 void rearrangeClients();
84 void removeAllClients(); 85 void removeAllClients();
86 void hideClient(TrayWindow *traywin);
87 void showClient(TrayWindow *traywin);
85 88
86 FbTk::FbWindow m_window; 89 FbTk::FbWindow m_window;
87 ButtonTheme& m_theme; 90 ButtonTheme& m_theme;
@@ -91,6 +94,7 @@ private:
91 std::auto_ptr<AtomHandler> m_handler; 94 std::auto_ptr<AtomHandler> m_handler;
92 95
93 ClientList m_clients; 96 ClientList m_clients;
97 size_t m_num_visible_clients;
94}; 98};
95 99
96#endif // SYSTEMTRAY_HH 100#endif // SYSTEMTRAY_HH