all repos — fluxbox @ 9d69d8b94eea3c59ac5e600b1e641f6764f0d81a

custom fork of the fluxbox windowmanager

systray
fluxgen fluxgen
commit

9d69d8b94eea3c59ac5e600b1e641f6764f0d81a

parent

779a0f4707bc249969feaed33af0567ca0250f28

2 files changed, 363 insertions(+), 0 deletions(-)

jump to
A src/SystemTray.cc

@@ -0,0 +1,287 @@

+// SystemTray.cc +// Copyright (c) 2003 Henrik Kinnunen (fluxgen at users.sourceforge.net) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +// $Id: SystemTray.cc,v 1.1 2003/08/15 13:48:50 fluxgen Exp $ + +#include "SystemTray.hh" + +#include "FbTk/EventManager.hh" + +#include "AtomHandler.hh" +#include "fluxbox.hh" + +#include <iostream> +#include <string> + +using namespace std; + +/// helper class for tray windows, so we dont call XDestroyWindow +class TrayWindow: public FbTk::FbWindow { +public: + TrayWindow(Window win):FbTk::FbWindow(win) { } +}; + +/// handles clientmessage event and notifies systemtray +class SystemTrayHandler: public AtomHandler { +public: + SystemTrayHandler(SystemTray &tray):m_tray(tray) { + } + // client message is the only thing we care about + bool checkClientMessage(const XClientMessageEvent &ce, + BScreen * screen, WinClient * const winclient) { + return m_tray.clientMessage(ce); + } + + void initForScreen(BScreen &screen) { }; + void setupFrame(FluxboxWindow &win) { }; + void setupClient(WinClient &winclient) { }; + + void updateClientList(BScreen &screen) { }; + void updateWorkspaceNames(BScreen &screen) { }; + void updateCurrentWorkspace(BScreen &screen) { }; + void updateWorkspaceCount(BScreen &screen) { }; + + void updateFrameClose(FluxboxWindow &win) { }; + void updateClientClose(WinClient &winclient) { }; + void updateWorkspace(FluxboxWindow &win) { }; + void updateState(FluxboxWindow &win) { }; + void updateHints(FluxboxWindow &win) { }; + void updateLayer(FluxboxWindow &win) { }; + + virtual bool propertyNotify(WinClient &winclient, Atom the_property) { return false; } + +private: + SystemTray &m_tray; +}; + +SystemTray::SystemTray(const FbTk::FbWindow &parent): + ToolbarItem(ToolbarItem::FIXED), + m_window(parent, 0, 0, 1, 1, ExposureMask | ButtonPressMask | ButtonReleaseMask | + SubstructureNotifyMask | SubstructureRedirectMask) { + + FbTk::EventManager::instance()->add(*this, m_window); + + // setup atom name to _NET_SYSTEM_TRAY_S<screen number> + char intbuff[16]; + sprintf(intbuff, "%d", m_window.screenNumber()); + std::string atom_name("_NET_SYSTEM_TRAY_S"); + atom_name += intbuff; // append number + + Display *disp = FbTk::App::instance()->display(); + + // get selection owner and see if it's free + Atom tray_atom = XInternAtom(disp, atom_name.c_str(), False); + Window owner = XGetSelectionOwner(disp, tray_atom); + if (owner != 0) + return; // the're can't be more than one owner + + // ok, it was free. Lets set owner +#ifdef DEBUG + cerr<<__FILE__<<"("<<__FUNCTION__<<"): SETTING OWNER!"<<endl; +#endif // DEBUG + // set owner + XSetSelectionOwner(disp, tray_atom, m_window.window(), CurrentTime); + m_handler.reset(new SystemTrayHandler(*this)); + Fluxbox::instance()->addAtomHandler(m_handler.get()); + Window root_window = RootWindow(disp, m_window.screenNumber()); + + // send selection owner msg + XEvent ce; + ce.xclient.type = ClientMessage; + ce.xclient.message_type = XInternAtom(disp, "MANAGER", False); + ce.xclient.display = disp; + ce.xclient.window = root_window; + ce.xclient.format = 32; + ce.xclient.data.l[0] = CurrentTime; // timestamp + ce.xclient.data.l[1] = tray_atom; // manager selection atom + ce.xclient.data.l[2] = m_window.window(); // the window owning the selection + ce.xclient.data.l[3] = 0l; // selection specific data + ce.xclient.data.l[4] = 0l; // selection specific data + + XSendEvent(disp, root_window, false, StructureNotifyMask, &ce); + + +} + +SystemTray::~SystemTray() { + // remove us, else fluxbox might delete the memory too + Fluxbox::instance()->removeAtomHandler(m_handler.get()); + removeAllClients(); +} + +void SystemTray::move(int x, int y) { + m_window.move(x, y); +} + +void SystemTray::resize(unsigned int width, unsigned int height) { + if (width != m_window.width() || + height != m_window.height()) { + m_window.resize(SystemTray::width(), height); + rearrangeClients(); + } +} + +void SystemTray::moveResize(int x, int y, + unsigned int width, unsigned int height) { + move(x, y); + resize(width, height); +} + +void SystemTray::hide() { + m_window.hide(); +} + +void SystemTray::show() { + m_window.show(); +} + +unsigned int SystemTray::width() const { + return m_clients.size()*height(); //*m_tray_width; +} + +unsigned int SystemTray::height() const { + return m_window.height(); +} + +unsigned int SystemTray::borderWidth() const { + return m_window.borderWidth(); +} + +bool SystemTray::clientMessage(const XClientMessageEvent &event) { + static const int SYSTEM_TRAY_REQUEST_DOCK = 0; + static const int SYSTEM_TRAY_BEGIN_MESSAGE = 1; + static const int SYSTEM_TRAY_CANCEL_MESSAGE = 2; + + if (event.message_type == + XInternAtom(FbTk::App::instance()->display(), "_NET_SYSTEM_TRAY_OPCODE", False)) { + + int type = event.data.l[1]; + if (type == SYSTEM_TRAY_REQUEST_DOCK) { +#ifdef DEBUG + cerr<<__FILE__<<": REQUEST DOCK"<<endl; +#endif // DEBUG + addClient(event.data.l[2]); + } +#ifdef DEBUG + else if (type == SYSTEM_TRAY_BEGIN_MESSAGE) + cerr<<"BEGIN MESSAGE"<<endl; + else if (type == SYSTEM_TRAY_CANCEL_MESSAGE) + cerr<<"CANCEL MESSAGE"<<endl; +#endif // DEBUG + + return true; + } + + return false; +} + +SystemTray::ClientList::iterator SystemTray::findClient(Window win) { + + ClientList::iterator it = m_clients.begin(); + ClientList::iterator it_end = m_clients.end(); + for (; it != it_end; ++it) { + if ((*it)->window() == win) + break; + } + + return it; +} + +void SystemTray::addClient(Window win) { + if (win == 0) + return; + + ClientList::iterator it = findClient(win); + if (it != m_clients.end()) + return; + +#ifdef DEBUG + cerr<<__FILE__<<"("<<__FUNCTION__<<"): 0x"<<hex<<win<<dec<<endl; +#endif // DEBUG + + FbTk::FbWindow *traywin = new TrayWindow(win); + m_clients.push_back(traywin); + FbTk::EventManager::instance()->add(*this, win); + XChangeSaveSet(FbTk::App::instance()->display(), win, SetModeInsert); + traywin->reparent(m_window, 0, 0); + traywin->show(); + + resize(width(), m_clients.size()*height()); + + rearrangeClients(); +} + +void SystemTray::removeClient(Window win) { + ClientList::iterator tray_it = findClient(win); + if (tray_it == m_clients.end()) + return; + +#ifdef DEBUG + cerr<<__FILE__<<"("<<__FUNCTION__<<"): 0x"<<hex<<win<<dec<<endl; +#endif // DEBUG + + FbTk::FbWindow *traywin = *tray_it; + m_clients.erase(tray_it); + delete traywin; + resize(width(), height()); + rearrangeClients(); +} + +void SystemTray::exposeEvent(XExposeEvent &event) { + m_window.clear(); +} + +void SystemTray::handleEvent(XEvent &event) { + if (event.type == DestroyNotify) + removeClient(event.xdestroywindow.window); + else if (event.type == ConfigureNotify) { + // we got configurenotify from an client + // check and see if we need to update it's size + ClientList::iterator it = findClient(event.xconfigure.window); + if (it != m_clients.end()) { + if (static_cast<unsigned int>(event.xconfigure.width) != (*it)->width() || + static_cast<unsigned int>(event.xconfigure.height) != (*it)->height()) + (*it)->resize((*it)->width(), (*it)->height()); + } + } +} + +void SystemTray::rearrangeClients() { + // resize clients + ClientList::iterator client_it = m_clients.begin(); + ClientList::iterator client_it_end = m_clients.end(); + int next_x = 0; + for (; client_it != client_it_end; ++client_it, next_x += height()) { + (*client_it)->moveResize(next_x, 0, height(), height()); + +#ifdef DEBUG + cerr<<__FILE__<<"("<<__FUNCTION__<<"): "<<(*client_it)->width()<<", "<<(*client_it)->height()<<endl; +#endif // DEBUG + } +} + +void SystemTray::removeAllClients() { + while (!m_clients.empty()) { + m_clients.back()->hide(); + delete m_clients.back(); + m_clients.pop_back(); + } +}
A src/SystemTray.hh

@@ -0,0 +1,76 @@

+// SystemTray.hh +// Copyright (c) 2003 Henrik Kinnunen (fluxgen at users.sourceforge.net) +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +// $Id: SystemTray.hh,v 1.1 2003/08/15 13:48:50 fluxgen Exp $ + +#ifndef SYSTEMTRAY_HH +#define SYSTEMTRAY_HH + + +#include "FbTk/FbWindow.hh" +#include "FbTk/EventHandler.hh" + +#include "ToolbarItem.hh" + +#include <X11/Xlib.h> + +#include <list> + +class AtomHandler; + +class SystemTray: public ToolbarItem, public FbTk::EventHandler { +public: + + explicit SystemTray(const FbTk::FbWindow &parent); + ~SystemTray(); + + void move(int x, int y); + void resize(unsigned int width, unsigned int height); + void moveResize(int x, int y, + unsigned int width, unsigned int height); + void show(); + void hide(); + + bool clientMessage(const XClientMessageEvent &event); + void exposeEvent(XExposeEvent &event); + void handleEvent(XEvent &event); + + unsigned int width() const; + unsigned int height() const; + unsigned int borderWidth() const; + +private: + typedef std::list<FbTk::FbWindow *> ClientList; + ClientList::iterator findClient(Window win); + void addClient(Window win); + void removeClient(Window win); + void renderTheme(); + void rearrangeClients(); + void removeAllClients(); + + FbTk::FbWindow m_window; + + std::auto_ptr<AtomHandler> m_handler; + + ClientList m_clients; +}; + +#endif // SYSTEMTRAY_HH