diff options
-rw-r--r-- | ChangeLog | 3 | ||||
-rw-r--r-- | src/SystemTray.cc | 126 | ||||
-rw-r--r-- | src/SystemTray.hh | 6 |
3 files changed, 103 insertions, 32 deletions
@@ -1,5 +1,8 @@ | |||
1 | (Format: Year/Month/Day) | 1 | (Format: Year/Month/Day) |
2 | Changes for 1.0rc3: | 2 | Changes 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 |
50 | class TrayWindow: public FbTk::FbWindow { | 50 | class TrayWindow: public FbTk::FbWindow { |
51 | public: | 51 | public: |
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 | } | ||
68 | private: | ||
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 | ||
230 | unsigned int SystemTray::height() const { | 245 | unsigned 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 | ||
237 | unsigned int SystemTray::borderWidth() const { | 252 | unsigned 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 | ||
322 | void SystemTray::removeClient(Window win) { | 329 | void 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 | ||
341 | void SystemTray::exposeEvent(XExposeEvent &event) { | 343 | void SystemTray::exposeEvent(XExposeEvent &event) { |
@@ -345,11 +347,15 @@ void SystemTray::exposeEvent(XExposeEvent &event) { | |||
345 | void SystemTray::handleEvent(XEvent &event) { | 347 | void 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 | |||
455 | void SystemTray::hideClient(TrayWindow *traywin) { | ||
456 | if (!traywin || !traywin->isVisible()) | ||
457 | return; | ||
458 | |||
459 | traywin->hide(); | ||
460 | m_num_visible_clients--; | ||
461 | rearrangeClients(); | ||
462 | } | ||
463 | |||
464 | void 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 | ||
414 | void SystemTray::update(FbTk::Subject* subject) { | 476 | void 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 | ||
40 | class TrayWindow; | ||
40 | class AtomHandler; | 41 | class AtomHandler; |
41 | 42 | ||
42 | class SystemTray: public ToolbarItem, public FbTk::EventHandler, public FbTk::Observer { | 43 | class 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 |