diff options
-rw-r--r-- | src/SystemTray.cc | 125 | ||||
-rw-r--r-- | src/SystemTray.hh | 5 |
2 files changed, 84 insertions, 46 deletions
diff --git a/src/SystemTray.cc b/src/SystemTray.cc index 00d9b11..eac0ea4 100644 --- a/src/SystemTray.cc +++ b/src/SystemTray.cc | |||
@@ -49,11 +49,12 @@ 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), m_visible(false) { | 52 | TrayWindow(Window win, bool using_xembed):FbTk::FbWindow(win), m_visible(false), m_xembedded(using_xembed) { |
53 | setEventMask(PropertyChangeMask); | 53 | setEventMask(PropertyChangeMask); |
54 | } | 54 | } |
55 | 55 | ||
56 | bool isVisible() { return m_visible; } | 56 | bool isVisible() { return m_visible; } |
57 | bool isXEmbedded() { return m_xembedded; } | ||
57 | void show() { | 58 | void show() { |
58 | if (!m_visible) { | 59 | if (!m_visible) { |
59 | m_visible = true; | 60 | m_visible = true; |
@@ -67,8 +68,33 @@ public: | |||
67 | } | 68 | } |
68 | } | 69 | } |
69 | 70 | ||
71 | /* Flags for _XEMBED_INFO */ | ||
72 | #define XEMBED_MAPPED (1 << 0) | ||
73 | |||
74 | bool getMappedDefault() const { | ||
75 | Atom actual_type; | ||
76 | int actual_format; | ||
77 | unsigned long nitems, bytes_after; | ||
78 | unsigned long *prop; | ||
79 | bool mapped = false; | ||
80 | Atom embed_info = SystemTray::getXEmbedInfoAtom(); | ||
81 | if (property(embed_info, 0l, 2l, false, embed_info, | ||
82 | &actual_type, &actual_format, &nitems, &bytes_after, | ||
83 | (unsigned char **) &prop) && prop != 0) { | ||
84 | mapped = (bool)(static_cast<unsigned long>(prop[1]) & XEMBED_MAPPED); | ||
85 | XFree(static_cast<void *>(prop)); | ||
86 | |||
87 | #ifdef DEBUG | ||
88 | cerr<<__FILE__<<"(SystemTray::TrayWindow::getMappedDefault(): XEMBED_MAPPED = "<<mapped<<endl; | ||
89 | #endif // DEBUG | ||
90 | |||
91 | } | ||
92 | return true; | ||
93 | } | ||
94 | |||
70 | private: | 95 | private: |
71 | bool m_visible; | 96 | bool m_visible; |
97 | bool m_xembedded; // using xembed protocol? (i.e. unmap when done) | ||
72 | }; | 98 | }; |
73 | 99 | ||
74 | /// handles clientmessage event and notifies systemtray | 100 | /// handles clientmessage event and notifies systemtray |
@@ -104,7 +130,7 @@ public: | |||
104 | return; | 130 | return; |
105 | winclient.setEventMask(StructureNotifyMask | | 131 | winclient.setEventMask(StructureNotifyMask | |
106 | SubstructureNotifyMask | EnterWindowMask); | 132 | SubstructureNotifyMask | EnterWindowMask); |
107 | m_tray.addClient(winclient.window()); | 133 | m_tray.addClient(winclient.window(), false); |
108 | 134 | ||
109 | }; | 135 | }; |
110 | 136 | ||
@@ -183,7 +209,7 @@ SystemTray::SystemTray(const FbTk::FbWindow& parent, ButtonTheme& theme, BScreen | |||
183 | ce.xclient.format = 32; | 209 | ce.xclient.format = 32; |
184 | ce.xclient.data.l[0] = CurrentTime; // timestamp | 210 | ce.xclient.data.l[0] = CurrentTime; // timestamp |
185 | ce.xclient.data.l[1] = tray_atom; // manager selection atom | 211 | ce.xclient.data.l[1] = tray_atom; // manager selection atom |
186 | ce.xclient.data.l[2] = m_window.window(); // the window owning the selection | 212 | ce.xclient.data.l[2] = m_selection_owner.window(); // the window owning the selection |
187 | ce.xclient.data.l[3] = 0l; // selection specific data | 213 | ce.xclient.data.l[3] = 0l; // selection specific data |
188 | ce.xclient.data.l[4] = 0l; // selection specific data | 214 | ce.xclient.data.l[4] = 0l; // selection specific data |
189 | 215 | ||
@@ -275,9 +301,9 @@ bool SystemTray::clientMessage(const XClientMessageEvent &event) { | |||
275 | static const int SYSTEM_TRAY_REQUEST_DOCK = 0; | 301 | static const int SYSTEM_TRAY_REQUEST_DOCK = 0; |
276 | // static const int SYSTEM_TRAY_BEGIN_MESSAGE = 1; | 302 | // static const int SYSTEM_TRAY_BEGIN_MESSAGE = 1; |
277 | // static const int SYSTEM_TRAY_CANCEL_MESSAGE = 2; | 303 | // static const int SYSTEM_TRAY_CANCEL_MESSAGE = 2; |
304 | static Atom systray_opcode_atom = XInternAtom(FbTk::App::instance()->display(), "_NET_SYSTEM_TRAY_OPCODE", False); | ||
278 | 305 | ||
279 | if (event.message_type == | 306 | if (event.message_type == systray_opcode_atom) { |
280 | XInternAtom(FbTk::App::instance()->display(), "_NET_SYSTEM_TRAY_OPCODE", False)) { | ||
281 | 307 | ||
282 | int type = event.data.l[1]; | 308 | int type = event.data.l[1]; |
283 | if (type == SYSTEM_TRAY_REQUEST_DOCK) { | 309 | if (type == SYSTEM_TRAY_REQUEST_DOCK) { |
@@ -285,7 +311,7 @@ bool SystemTray::clientMessage(const XClientMessageEvent &event) { | |||
285 | cerr<<"SystemTray::clientMessage(const XClientMessageEvent): SYSTEM_TRAY_REQUEST_DOCK"<<endl; | 311 | cerr<<"SystemTray::clientMessage(const XClientMessageEvent): SYSTEM_TRAY_REQUEST_DOCK"<<endl; |
286 | cerr<<"window = event.data.l[2] = "<<event.data.l[2]<<endl; | 312 | cerr<<"window = event.data.l[2] = "<<event.data.l[2]<<endl; |
287 | #endif // DEBUG | 313 | #endif // DEBUG |
288 | addClient(event.data.l[2]); | 314 | addClient(event.data.l[2], true); |
289 | } | 315 | } |
290 | /* | 316 | /* |
291 | else if (type == SYSTEM_TRAY_BEGIN_MESSAGE) | 317 | else if (type == SYSTEM_TRAY_BEGIN_MESSAGE) |
@@ -312,7 +338,7 @@ SystemTray::ClientList::iterator SystemTray::findClient(Window win) { | |||
312 | return it; | 338 | return it; |
313 | } | 339 | } |
314 | 340 | ||
315 | void SystemTray::addClient(Window win) { | 341 | void SystemTray::addClient(Window win, bool using_xembed) { |
316 | if (win == 0) | 342 | if (win == 0) |
317 | return; | 343 | return; |
318 | 344 | ||
@@ -320,17 +346,17 @@ void SystemTray::addClient(Window win) { | |||
320 | if (it != m_clients.end()) | 346 | if (it != m_clients.end()) |
321 | return; | 347 | return; |
322 | 348 | ||
349 | Display *disp = Fluxbox::instance()->display(); | ||
323 | // make sure we have the same screen number | 350 | // make sure we have the same screen number |
324 | XWindowAttributes attr; | 351 | XWindowAttributes attr; |
325 | attr.screen = 0; | 352 | attr.screen = 0; |
326 | if (XGetWindowAttributes(FbTk::App::instance()->display(), | 353 | if (XGetWindowAttributes(disp, win, &attr) != 0 && |
327 | win, &attr) != 0 && | ||
328 | attr.screen != 0 && | 354 | attr.screen != 0 && |
329 | XScreenNumberOfScreen(attr.screen) != window().screenNumber()) { | 355 | XScreenNumberOfScreen(attr.screen) != window().screenNumber()) { |
330 | return; | 356 | return; |
331 | } | 357 | } |
332 | 358 | ||
333 | TrayWindow *traywin = new TrayWindow(win); | 359 | TrayWindow *traywin = new TrayWindow(win, using_xembed); |
334 | 360 | ||
335 | #ifdef DEBUG | 361 | #ifdef DEBUG |
336 | cerr<<"SystemTray::addClient(Window): 0x"<<hex<<win<<dec<<endl; | 362 | cerr<<"SystemTray::addClient(Window): 0x"<<hex<<win<<dec<<endl; |
@@ -338,10 +364,31 @@ void SystemTray::addClient(Window win) { | |||
338 | 364 | ||
339 | m_clients.push_back(traywin); | 365 | m_clients.push_back(traywin); |
340 | FbTk::EventManager::instance()->add(*this, win); | 366 | FbTk::EventManager::instance()->add(*this, win); |
341 | XChangeSaveSet(FbTk::App::instance()->display(), win, SetModeInsert); | ||
342 | traywin->reparent(m_window, 0, 0); | 367 | traywin->reparent(m_window, 0, 0); |
343 | traywin->addToSaveSet(); | 368 | traywin->addToSaveSet(); |
344 | showClient(traywin); | 369 | |
370 | if (using_xembed) { | ||
371 | static Atom xembed_atom = XInternAtom(disp, "_XEMBED", False); | ||
372 | |||
373 | #define XEMBED_EMBEDDED_NOTIFY 0 | ||
374 | // send embedded message | ||
375 | XEvent ce; | ||
376 | ce.xclient.type = ClientMessage; | ||
377 | ce.xclient.message_type = xembed_atom; | ||
378 | ce.xclient.display = disp; | ||
379 | ce.xclient.window = win; | ||
380 | ce.xclient.format = 32; | ||
381 | ce.xclient.data.l[0] = CurrentTime; // timestamp | ||
382 | ce.xclient.data.l[1] = XEMBED_EMBEDDED_NOTIFY; | ||
383 | ce.xclient.data.l[2] = 0l; // The protocol version we support | ||
384 | ce.xclient.data.l[3] = m_window.window(); // the window owning the selection | ||
385 | ce.xclient.data.l[4] = 0l; // unused | ||
386 | |||
387 | XSendEvent(disp, win, false, NoEventMask, &ce); | ||
388 | } | ||
389 | |||
390 | if (traywin->getMappedDefault()) | ||
391 | showClient(traywin); | ||
345 | } | 392 | } |
346 | 393 | ||
347 | void SystemTray::removeClient(Window win, bool destroyed) { | 394 | void SystemTray::removeClient(Window win, bool destroyed) { |
@@ -404,36 +451,15 @@ void SystemTray::handleEvent(XEvent &event) { | |||
404 | } else if (event.type == PropertyNotify) { | 451 | } else if (event.type == PropertyNotify) { |
405 | ClientList::iterator it = findClient(event.xproperty.window); | 452 | ClientList::iterator it = findClient(event.xproperty.window); |
406 | if (it != m_clients.end()) { | 453 | if (it != m_clients.end()) { |
407 | Atom embed_info = XInternAtom(FbTk::App::instance()->display(),"_XEMBED_INFO",false); | 454 | if (event.xproperty.atom == getXEmbedInfoAtom()) { |
408 | if (event.xproperty.atom == embed_info) { | 455 | if ((*it)->getMappedDefault()) |
409 | 456 | showClient(*it); | |
410 | /* Flags for _XEMBED_INFO */ | 457 | else |
411 | #define XEMBED_MAPPED (1 << 0) | 458 | hideClient(*it); |
412 | |||
413 | TrayWindow *traywin = *it; | ||
414 | Atom actual_type; | ||
415 | int actual_format; | ||
416 | unsigned long nitems, bytes_after; | ||
417 | unsigned long *prop; | ||
418 | if (traywin->property(embed_info, 0l, 2l, false, embed_info, | ||
419 | &actual_type, &actual_format, &nitems, &bytes_after, | ||
420 | (unsigned char **) &prop)) { | ||
421 | |||
422 | bool mapped = (bool)(static_cast<unsigned long>(prop[1]) & XEMBED_MAPPED); | ||
423 | XFree(static_cast<void *>(prop)); | ||
424 | |||
425 | #ifdef DEBUG | ||
426 | cerr<<__FILE__<<"(SystemTray::handleEvent(XEvent)): XEMBED_MAPPED = "<<mapped<<endl; | ||
427 | #endif // DEBUG | ||
428 | |||
429 | if (mapped) | ||
430 | showClient(traywin); | ||
431 | else | ||
432 | hideClient(traywin); | ||
433 | } | ||
434 | } | 459 | } |
435 | } | 460 | } |
436 | } | 461 | } |
462 | |||
437 | } | 463 | } |
438 | 464 | ||
439 | void SystemTray::rearrangeClients() { | 465 | void SystemTray::rearrangeClients() { |
@@ -465,12 +491,16 @@ void SystemTray::rearrangeClients() { | |||
465 | void SystemTray::removeAllClients() { | 491 | void SystemTray::removeAllClients() { |
466 | BScreen *screen = Fluxbox::instance()->findScreen(window().screenNumber()); | 492 | BScreen *screen = Fluxbox::instance()->findScreen(window().screenNumber()); |
467 | while (!m_clients.empty()) { | 493 | while (!m_clients.empty()) { |
468 | m_clients.back()->setEventMask(NoEventMask); | 494 | TrayWindow * traywin = m_clients.back(); |
469 | m_clients.back()->hide(); | 495 | traywin->setEventMask(NoEventMask); |
496 | |||
497 | if (traywin->isXEmbedded()) | ||
498 | traywin->hide(); | ||
499 | |||
470 | if (screen) | 500 | if (screen) |
471 | m_clients.back()->reparent(screen->rootWindow(), 0, 0); | 501 | traywin->reparent(screen->rootWindow(), 0, 0, false); |
472 | m_clients.back()->removeFromSaveSet(); | 502 | traywin->removeFromSaveSet(); |
473 | delete m_clients.back(); | 503 | delete traywin; |
474 | m_clients.pop_back(); | 504 | m_clients.pop_back(); |
475 | } | 505 | } |
476 | m_num_visible_clients = 0; | 506 | m_num_visible_clients = 0; |
@@ -524,3 +554,8 @@ void SystemTray::update(FbTk::Subject* subject) { | |||
524 | } | 554 | } |
525 | 555 | ||
526 | } | 556 | } |
557 | |||
558 | Atom SystemTray::getXEmbedInfoAtom() { | ||
559 | static Atom theatom = XInternAtom(Fluxbox::instance()->display(), "_XEMBED_INFO", False); | ||
560 | return theatom; | ||
561 | } | ||
diff --git a/src/SystemTray.hh b/src/SystemTray.hh index 557d1e4..e5c1f8c 100644 --- a/src/SystemTray.hh +++ b/src/SystemTray.hh | |||
@@ -59,7 +59,7 @@ public: | |||
59 | void exposeEvent(XExposeEvent &event); | 59 | void exposeEvent(XExposeEvent &event); |
60 | void handleEvent(XEvent &event); | 60 | void handleEvent(XEvent &event); |
61 | 61 | ||
62 | void addClient(Window win); | 62 | void addClient(Window win, bool using_xembed); |
63 | void removeClient(Window win, bool destroyed); | 63 | void removeClient(Window win, bool destroyed); |
64 | 64 | ||
65 | unsigned int width() const; | 65 | unsigned int width() const; |
@@ -74,6 +74,8 @@ public: | |||
74 | 74 | ||
75 | void parentMoved() { m_window.parentMoved(); } | 75 | void parentMoved() { m_window.parentMoved(); } |
76 | 76 | ||
77 | static Atom getXEmbedInfoAtom(); | ||
78 | |||
77 | private: | 79 | private: |
78 | 80 | ||
79 | void update(FbTk::Subject *subj); | 81 | void update(FbTk::Subject *subj); |
@@ -99,6 +101,7 @@ private: | |||
99 | // gaim/pidgin seems to barf if the selection is not an independent window. | 101 | // gaim/pidgin seems to barf if the selection is not an independent window. |
100 | // I suspect it's an interacton with parent relationship and gdk window caching. | 102 | // I suspect it's an interacton with parent relationship and gdk window caching. |
101 | FbTk::FbWindow m_selection_owner; | 103 | FbTk::FbWindow m_selection_owner; |
104 | |||
102 | }; | 105 | }; |
103 | 106 | ||
104 | #endif // SYSTEMTRAY_HH | 107 | #endif // SYSTEMTRAY_HH |