Added SimpleObserver class.

This class works in the same way as the SimpleCommand class.
Use it with the makeObserver function.
It calls the receiver's member function when the subject sends
a signal.
This commit is contained in:
Henrik Kinnunen 2008-04-27 21:22:18 +02:00
parent 40e17b4d0e
commit 80b10f7772
8 changed files with 139 additions and 58 deletions

View file

@ -44,7 +44,7 @@ libFbTk_a_SOURCES = App.hh App.cc Color.cc Color.hh Command.hh \
StringUtil.hh StringUtil.cc Parser.hh Parser.cc \
RegExp.hh RegExp.cc \
FbString.hh FbString.cc \
Subject.hh Subject.cc Observer.hh Observer.cc \
Subject.hh Subject.cc Observer.hh Observer.cc SimpleObserver.hh \
Transparent.hh Transparent.cc \
FbPixmap.hh FbPixmap.cc \
FbDrawable.hh FbDrawable.cc \

View file

@ -0,0 +1,70 @@
// SimpleObserver.hh
// Copyright (c) 2008 Fluxbox Team (fluxgen at fluxbox dot org)
//
// 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.
#include "Observer.hh"
#include "SimpleCommand.hh"
namespace FbTk {
/** Functor for observers, instead of using this directly use makeObserver.
* Usage:
* @code
* class SomeClass {
* public:
* void doAction();
* };
*
* SomeClass some;
*
* Observer* obs = makeProxyObserver(some, &SomeClass::doAction);
* SomeSubject subj;
* subj.attach(obs);
* @endcode
*/
template <typename Receiver>
class SimpleObserver: public Observer {
public:
typedef void (Receiver::* Action)();
SimpleObserver(Receiver &r, Action a):
m_receiver(r), m_action(a) {
}
void update(Subject *changedSubj) {
(m_receiver.*m_action)();
}
private:
Receiver &m_receiver;
Action m_action;
};
// Helpers
/** Creates an observer that takes no arguments.
* @param receiver The receiving instance.
* @param action A function in the receiving class.
* @return allocated simple observer. @see SimpleObserver
*/
template <typename Receiver, typename Action>
Observer *makeObserver(Receiver &receiver, Action action) {
return new SimpleObserver<Receiver>( receiver, action );
}
}

View file

@ -1,5 +1,5 @@
// SendToMenu.cc for Fluxbox
// Copyright (c) 2003 - 2006 Henrik Kinnunen (fluxgen at fluxbox dot org)
// Copyright (c) 2003 - 2008 Henrik Kinnunen (fluxgen at fluxbox dot org)
// and Simon Bowden (rathnor at users.sourceforge.net)
//
// Permission is hereby granted, free of charge, to any person obtaining a
@ -31,6 +31,7 @@
#include "FbTk/MultiButtonMenuItem.hh"
#include "FbTk/Command.hh"
#include "FbTk/SimpleObserver.hh"
class SendToCmd: public FbTk::Command<void> {
public:
@ -54,24 +55,21 @@ SendToMenu::SendToMenu(BScreen &screen):
// workspace count signal
// workspace names signal
// current workspace signal
screen.workspaceCountSig().attach(this);
screen.workspaceNamesSig().attach(this);
screen.currentWorkspaceSig().attach(this);
m_rebuildObs = makeObserver(*this, &SendToMenu::rebuildMenu);
screen.workspaceCountSig().attach(m_rebuildObs);
screen.workspaceNamesSig().attach(m_rebuildObs);
screen.currentWorkspaceSig().attach(m_rebuildObs);
// no title for this menu, it should be a submenu in the window menu.
disableTitle();
// build menu
update(0);
// setup menu items
rebuildMenu();
}
void SendToMenu::update(FbTk::Subject *subj) {
if (subj != 0) {
if (subj == &(theme().reconfigSig())) {
// we got reconfig Theme signal, let base menu handle it
FbTk::Menu::update(subj);
return;
}
SendToMenu::~SendToMenu() {
delete m_rebuildObs;
}
}
void SendToMenu::rebuildMenu() {
// rebuild menu
removeAll();
@ -95,6 +93,7 @@ void SendToMenu::show() {
if (WindowCmd<void>::window() != 0) {
for (unsigned int i=0; i < numberOfItems(); ++i)
setItemEnabled(i, true);
// update the workspace for the current window
setItemEnabled(WindowCmd<void>::window()->workspaceNumber(), false);
updateMenu();
}

View file

@ -1,5 +1,5 @@
// SendToMenu.hh for Fluxbox
// Copyright (c) 2003 - 2006 Henrik Kinnunen (fluxgen at fluxbox dot org)
// Copyright (c) 2003 - 2008 Henrik Kinnunen (fluxgen at fluxbox dot org)
// and Simon Bowden (rathnor at users.sourceforge.net)
//
// Permission is hereby granted, free of charge, to any person obtaining a
@ -25,15 +25,28 @@
#include "FbMenu.hh"
namespace FbTk {
class Observer;
}
class BScreen;
/**
* Creates the "send to menu".
* Displays all the workspaces for which the current window can be sent to.
*/
class SendToMenu:public FbMenu {
public:
explicit SendToMenu(BScreen &win);
virtual ~SendToMenu() { }
/// @param screen the screen on which this menu should be created on.
explicit SendToMenu(BScreen &screen);
virtual ~SendToMenu();
/// @see FbTk::Menu
void show();
protected:
void update(FbTk::Subject *subj);
private:
/// Rebuild the menu from scratch.
void rebuildMenu();
/// listens to signals that makes this instance need to rebuild menu
FbTk::Observer *m_rebuildObs;
};
#endif // SENDTOMENU_HH

View file

@ -30,6 +30,7 @@
#include "WinClient.hh"
#include "Screen.hh"
#include "ButtonTheme.hh"
#include "SimpleObserver.hh"
#include <X11/Xutil.h>
#include <X11/Xatom.h>
@ -166,8 +167,10 @@ SystemTray::SystemTray(const FbTk::FbWindow& parent,
FbTk::EventManager::instance()->add(*this, m_window);
FbTk::EventManager::instance()->add(*this, m_selection_owner);
m_theme->reconfigSig().attach(this);
screen.bgChangeSig().attach(this);
// setup signals
m_observer.reset(makeObserver(*this, &SystemTray::update));
m_theme->reconfigSig().attach(m_observer.get());
screen.bgChangeSig().attach(m_observer.get());
Fluxbox* fluxbox = Fluxbox::instance();
Display *disp = fluxbox->display();
@ -216,7 +219,7 @@ SystemTray::SystemTray(const FbTk::FbWindow& parent,
XSendEvent(disp, root_window, false, StructureNotifyMask, &ce);
update(0);
update();
}
SystemTray::~SystemTray() {
@ -276,7 +279,7 @@ void SystemTray::hide() {
void SystemTray::show() {
update(0);
update();
m_window.show();
}
@ -470,7 +473,7 @@ void SystemTray::rearrangeClients() {
unsigned int trayw = m_num_visible_clients*h_rot0 + bw, trayh = h_rot0;
FbTk::translateSize(orientation(), trayw, trayh);
resize(trayw, trayh);
update(0);
update();
// move and resize clients
ClientList::iterator client_it = m_clients.begin();
@ -529,7 +532,7 @@ void SystemTray::showClient(TrayWindow *traywin) {
rearrangeClients();
}
void SystemTray::update(FbTk::Subject* subject) {
void SystemTray::update() {
if (!m_theme->texture().usePixmap()) {
m_window.setBackgroundColor(m_theme->texture().color());

View file

@ -25,12 +25,12 @@
#include "FbTk/FbWindow.hh"
#include "FbTk/EventHandler.hh"
#include "FbTk/Observer.hh"
#include "ToolTheme.hh"
#include "ToolbarItem.hh"
#include <list>
#include <memory>
class BScreen;
class ButtonTheme;
@ -39,9 +39,10 @@ class AtomHandler;
namespace FbTk {
template <class T> class ThemeProxy;
class Observer;
}
class SystemTray: public ToolbarItem, public FbTk::EventHandler, public FbTk::Observer {
class SystemTray: public ToolbarItem, public FbTk::EventHandler {
public:
explicit SystemTray(const FbTk::FbWindow &parent,
@ -75,7 +76,7 @@ public:
m_window.setBorderWidth(m_theme->border().width());
m_window.setBorderColor(m_theme->border().color());
m_window.setAlpha(alpha);
update(0);
update();
}
void updateSizing() { m_window.setBorderWidth(m_theme->border().width()); }
@ -85,7 +86,7 @@ public:
private:
void update(FbTk::Subject *subj);
void update();
typedef std::list<TrayWindow *> ClientList;
ClientList::iterator findClient(Window win);
@ -108,7 +109,7 @@ private:
// 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;
std::auto_ptr<FbTk::Observer> m_observer;
};
#endif // SYSTEMTRAY_HH

View file

@ -50,7 +50,7 @@
#include "FbTk/BoolMenuItem.hh"
#include "FbTk/IntMenuItem.hh"
#include "FbTk/Shape.hh"
#include "FbTk/SimpleObserver.hh"
// use GNU extensions
#ifndef _GNU_SOURCE
@ -240,11 +240,15 @@ Toolbar::Toolbar(BScreen &scrn, FbTk::XLayer &layer, size_t width):
m_shape(new FbTk::Shape(frame.window, 0)),
m_resize_lock(false) {
_FB_USES_NLS;
// NOTE: first subject is always the rearrangeItem !
m_observers.push_back(makeObserver(*this, &Toolbar::rearrangeItems));
// we need to get notified when the theme is reloaded
m_theme.reconfigSig().attach(this);
m_observers.push_back(makeObserver(*this, &Toolbar::reconfigure));
m_theme.reconfigSig().attach(m_observers.back());
screen().reconfigureSig().attach(m_observers.back()); // get this on antialias change
// listen to screen size changes
screen().resizeSig().attach(this);
screen().reconfigureSig().attach(this); // get this on antialias change
screen().resizeSig().attach(m_observers.back());
moveToLayer((*m_rc_layernum).getNum());
@ -370,6 +374,7 @@ void Toolbar::lower() {
}
void Toolbar::reconfigure() {
updateVisibleState();
if (!doAutoHide() && isHidden())
@ -426,7 +431,8 @@ void Toolbar::reconfigure() {
if (item == 0)
continue;
m_item_list.push_back(item);
item->resizeSig().attach(this);
// attach to first observer ( which must be rearrangeItems )
item->resizeSig().attach(m_observers[0]);
}
// show all items
@ -515,6 +521,11 @@ void Toolbar::reconfigure() {
// area to be reserved on screen
updateStrut();
#ifdef XINERAMA
if (m_xineramaheadmenu)
m_xineramaheadmenu->reloadHeads();
#endif // XINERAMA
}
@ -613,22 +624,6 @@ void Toolbar::handleEvent(XEvent &event) {
*/
}
void Toolbar::update(FbTk::Subject *subj) {
// either screen reconfigured, theme was reloaded
// or a tool resized itself
if (typeid(*subj) == typeid(ToolbarItem::ToolbarItemSubject))
rearrangeItems();
else
reconfigure();
#ifdef XINERAMA
if (subj == &m_screen.resizeSig() && m_xineramaheadmenu)
m_xineramaheadmenu->reloadHeads();
#endif // XINERAMA
}
void Toolbar::setPlacement(Toolbar::Placement where) {
// disable vertical toolbar

View file

@ -37,7 +37,6 @@
#include "FbTk/Timer.hh"
#include "FbTk/Resource.hh"
#include "FbTk/Observer.hh"
#include "FbTk/XLayer.hh"
#include "FbTk/XLayerItem.hh"
#include "FbTk/EventHandler.hh"
@ -57,7 +56,8 @@ class Shape;
/// The toolbar.
/// Handles iconbar, workspace name view and clock view
class Toolbar: public FbTk::EventHandler, public FbTk::Observer, public LayerObject {
class Toolbar: public FbTk::EventHandler,
public LayerObject {
public:
/// Toolbar placement on the screen
@ -99,8 +99,6 @@ public:
void reconfigure();
void setPlacement(Placement where);
void update(FbTk::Subject *subj);
int layerNumber() const { return const_cast<FbTk::XLayerItem &>(m_layeritem).getLayerNum(); }
const FbTk::Menu &menu() const { return m_toolbarmenu; }
@ -193,6 +191,8 @@ private:
StringList m_tools;
bool m_resize_lock; ///< to lock rearrangeItems or not
/// observers for various signals
std::vector<FbTk::Observer*> m_observers;
};