From 138a3c2af1694c353531cebfb5342161af2f5b91 Mon Sep 17 00:00:00 2001
From: simonb <simonb>
Date: Sat, 4 Aug 2007 17:16:04 +0000
Subject: forward port systray fixes

---
 src/FbTk/FbWindow.cc |  8 ++++++++
 src/FbTk/FbWindow.hh |  3 +++
 src/SystemTray.cc    | 47 ++++++++++++++++++++++++++++++++++++-----------
 src/SystemTray.hh    |  8 ++++++--
 src/fluxbox.cc       |  2 ++
 5 files changed, 55 insertions(+), 13 deletions(-)

diff --git a/src/FbTk/FbWindow.cc b/src/FbTk/FbWindow.cc
index 2c2bb24..f8141cf 100644
--- a/src/FbTk/FbWindow.cc
+++ b/src/FbTk/FbWindow.cc
@@ -556,6 +556,14 @@ void FbWindow::deleteProperty(Atom property) {
     XDeleteProperty(display(), m_window, property);
 }
 
+void FbWindow::addToSaveSet() {
+    XAddToSaveSet(display(), m_window);
+}
+
+void FbWindow::removeFromSaveSet() {
+    XRemoveFromSaveSet(display(), m_window);
+}
+
 int FbWindow::screenNumber() const {
     return m_screen_num;
 }
diff --git a/src/FbTk/FbWindow.hh b/src/FbTk/FbWindow.hh
index a1b93cc..091fb48 100644
--- a/src/FbTk/FbWindow.hh
+++ b/src/FbTk/FbWindow.hh
@@ -165,6 +165,9 @@ public:
 
     std::string textProperty(Atom property) const;
 
+    void addToSaveSet();
+    void removeFromSaveSet();
+
     /// @return parent FbWindow
     const FbWindow *parent() const { return m_parent; }
     /// @return real X window
diff --git a/src/SystemTray.cc b/src/SystemTray.cc
index fdccda0..00d9b11 100644
--- a/src/SystemTray.cc
+++ b/src/SystemTray.cc
@@ -52,6 +52,7 @@ public:
     TrayWindow(Window win):FbTk::FbWindow(win), m_visible(false) {
         setEventMask(PropertyChangeMask);
     }
+
     bool isVisible() { return m_visible; }
     void show() {
         if (!m_visible) {
@@ -65,6 +66,7 @@ public:
             FbTk::FbWindow::hide();
         }
     }
+
 private:
     bool m_visible;
 };
@@ -132,9 +134,11 @@ SystemTray::SystemTray(const FbTk::FbWindow& parent, ButtonTheme& theme, BScreen
              SubstructureNotifyMask | SubstructureRedirectMask),
     m_theme(theme),
     m_screen(screen),
-    m_pixmap(0), m_num_visible_clients(0) {
-
+    m_pixmap(0), m_num_visible_clients(0),
+    m_selection_owner(m_window, 0, 0, 1, 1, SubstructureNotifyMask, false, false, CopyFromParent, InputOnly) {
+    
     FbTk::EventManager::instance()->add(*this, m_window);
+    FbTk::EventManager::instance()->add(*this, m_selection_owner);
     m_theme.reconfigSig().attach(this);
     screen.bgChangeSig().attach(this);
 
@@ -162,7 +166,7 @@ SystemTray::SystemTray(const FbTk::FbWindow& parent, ButtonTheme& theme, BScreen
     cerr<<__FILE__<<"(SystemTray(const FbTk::FbWindow)): SETTING OWNER!"<<endl;
 #endif // DEBUG
     // set owner
-    XSetSelectionOwner(disp, tray_atom, m_window.window(), CurrentTime);
+    XSetSelectionOwner(disp, tray_atom, m_selection_owner.window(), CurrentTime);
 
     m_handler.reset(new SystemTrayHandler(*this));
 
@@ -190,7 +194,20 @@ SystemTray::SystemTray(const FbTk::FbWindow& parent, ButtonTheme& theme, BScreen
 
 SystemTray::~SystemTray() {
     // remove us, else fluxbox might delete the memory too
-    Fluxbox::instance()->removeAtomHandler(m_handler.get());
+    Fluxbox* fluxbox = Fluxbox::instance();
+    fluxbox->removeAtomHandler(m_handler.get());
+    Display *disp = fluxbox->display();
+    // setup atom name to _NET_SYSTEM_TRAY_S<screen number>
+    char intbuff[16];
+    sprintf(intbuff, "%d", m_window.screenNumber());
+    string atom_name("_NET_SYSTEM_TRAY_S");
+    atom_name += intbuff; // append number
+
+    // get selection owner and see if it's free
+    Atom tray_atom = XInternAtom(disp, atom_name.c_str(), False);
+
+    // Properly give up selection.
+    XSetSelectionOwner(disp, tray_atom, None, CurrentTime);
     removeAllClients();
 
     if (m_pixmap)
@@ -323,10 +340,11 @@ void SystemTray::addClient(Window win) {
     FbTk::EventManager::instance()->add(*this, win);
     XChangeSaveSet(FbTk::App::instance()->display(), win, SetModeInsert);
     traywin->reparent(m_window, 0, 0);
+    traywin->addToSaveSet();
     showClient(traywin);
 }
 
-void SystemTray::removeClient(Window win) {
+void SystemTray::removeClient(Window win, bool destroyed) {
     ClientList::iterator tray_it = findClient(win);
     if (tray_it == m_clients.end())
         return;
@@ -336,7 +354,11 @@ void SystemTray::removeClient(Window win) {
 #endif // DEBUG
     TrayWindow *traywin = *tray_it;
     m_clients.erase(tray_it);
-    hideClient(traywin);
+    if (!destroyed) {
+        traywin->setEventMask(NoEventMask);
+        traywin->removeFromSaveSet();
+    }
+    hideClient(traywin, destroyed);
     delete traywin;
 }
 
@@ -346,9 +368,9 @@ void SystemTray::exposeEvent(XExposeEvent &event) {
 
 void SystemTray::handleEvent(XEvent &event) {
     if (event.type == DestroyNotify) {
-        removeClient(event.xdestroywindow.window);
+        removeClient(event.xdestroywindow.window, true);
     } else if (event.type == ReparentNotify && event.xreparent.parent != m_window.window()) {
-        removeClient(event.xreparent.window);
+        removeClient(event.xreparent.window, false);
     } else if (event.type == UnmapNotify && event.xany.send_event) {
         // we ignore server-generated events, which can occur
         // on restart. The ICCCM says that a client must send
@@ -443,20 +465,23 @@ void SystemTray::rearrangeClients() {
 void SystemTray::removeAllClients() {
     BScreen *screen = Fluxbox::instance()->findScreen(window().screenNumber());
     while (!m_clients.empty()) {
+        m_clients.back()->setEventMask(NoEventMask);
+        m_clients.back()->hide();
         if (screen)
             m_clients.back()->reparent(screen->rootWindow(), 0, 0);
-        m_clients.back()->hide();
+        m_clients.back()->removeFromSaveSet();
         delete m_clients.back();
         m_clients.pop_back();
     }
     m_num_visible_clients = 0;
 }
 
-void SystemTray::hideClient(TrayWindow *traywin) {
+void SystemTray::hideClient(TrayWindow *traywin, bool destroyed) {
     if (!traywin || !traywin->isVisible())
         return;
 
-    traywin->hide();
+    if (!destroyed)
+        traywin->hide();
     m_num_visible_clients--;
     rearrangeClients();
 }
diff --git a/src/SystemTray.hh b/src/SystemTray.hh
index 392ca11..557d1e4 100644
--- a/src/SystemTray.hh
+++ b/src/SystemTray.hh
@@ -60,7 +60,7 @@ public:
     void handleEvent(XEvent &event);
 
     void addClient(Window win);
-    void removeClient(Window win);
+    void removeClient(Window win, bool destroyed);
 
     unsigned int width() const;
     unsigned int height() const;
@@ -83,7 +83,7 @@ private:
 
     void rearrangeClients();
     void removeAllClients();
-    void hideClient(TrayWindow *traywin);
+    void hideClient(TrayWindow *traywin, bool destroyed = false);
     void showClient(TrayWindow *traywin);
 
     FbTk::FbWindow m_window;
@@ -95,6 +95,10 @@ private:
 
     ClientList m_clients;
     size_t m_num_visible_clients;
+
+    // gaim/pidgin seems to barf if the selection is not an independent window.
+    // I suspect it's an interacton with parent relationship and gdk window caching.
+    FbTk::FbWindow m_selection_owner;
 };
 
 #endif // SYSTEMTRAY_HH
diff --git a/src/fluxbox.cc b/src/fluxbox.cc
index 248c897..80d055b 100644
--- a/src/fluxbox.cc
+++ b/src/fluxbox.cc
@@ -254,6 +254,7 @@ Fluxbox::Fluxbox(int argc, char **argv, const char *dpy_name, const char *rcfile
     SignalHandler &sigh = SignalHandler::instance();
     sigh.registerHandler(SIGSEGV, this);
     sigh.registerHandler(SIGFPE, this);
+    sigh.registerHandler(SIGPIPE, this); // e.g. output sent to grep
     sigh.registerHandler(SIGTERM, this);
     sigh.registerHandler(SIGINT, this);
     sigh.registerHandler(SIGCHLD, this);
@@ -1059,6 +1060,7 @@ void Fluxbox::handleSignal(int signum) {
         break;
     case SIGFPE:
     case SIGINT:
+    case SIGPIPE:
     case SIGTERM:
         shutdown();
         break;
-- 
cgit v0.11.2