aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/SystemTray.cc125
-rw-r--r--src/SystemTray.hh5
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
50class TrayWindow: public FbTk::FbWindow { 50class TrayWindow: public FbTk::FbWindow {
51public: 51public:
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
70private: 95private:
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
315void SystemTray::addClient(Window win) { 341void 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
347void SystemTray::removeClient(Window win, bool destroyed) { 394void 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
439void SystemTray::rearrangeClients() { 465void SystemTray::rearrangeClients() {
@@ -465,12 +491,16 @@ void SystemTray::rearrangeClients() {
465void SystemTray::removeAllClients() { 491void 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
558Atom SystemTray::getXEmbedInfoAtom() {
559static Atom theatom = XInternAtom(Fluxbox::instance()->display(), "_XEMBED_INFO", False);
560return 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
77private: 79private:
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