//
// ActionHandler.cc for pekwm
// Copyright (C) 2002-2005 Claes Nasten <pekdon{@}pekdon{.}net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//
#include "../config.h"
#include "ActionHandler.hh"
#include "PWinObj.hh"
#include "PDecor.hh"
#include "PMenu.hh"
#include "PScreen.hh"
#include "Frame.hh"
#include "Client.hh"
#include "Config.hh"
#include "CmdDialog.hh"
#include "Workspaces.hh"
#include "Viewport.hh"
#include "WindowManager.hh"
#include "Util.hh"
#include "RegexString.hh"
#ifdef HARBOUR
#include "Harbour.hh"
#endif // HARBOUR
#ifdef MENUS
#include "PDecor.hh"
#include "PMenu.hh"
#include "WORefMenu.hh"
#include "ActionMenu.hh"
#include "FrameListMenu.hh"
#include "DecorMenu.hh"
#ifdef HARBOUR
#include "HarbourMenu.hh"
#endif // HARBOUR
#endif // MENUS
#include <memory>
extern "C" {
#include <X11/keysym.h>
}
#ifdef DEBUG
#include <iostream>
using std::cerr;
using std::endl;
#endif // DEBUG
using std::auto_ptr;
using std::string;
using std::list;
using std::find;
ActionHandler *ActionHandler::_instance = NULL;
//! @brief ActionHandler constructor
ActionHandler::ActionHandler(WindowManager *wm) :
_wm(wm)
{
#ifdef DEBUG
if (_instance != NULL) {
cerr << __FILE__ << "@" << __LINE__ << ": "
<< "ActionHandler(" << this << ")::ActionHandler(" << wm << ")" << endl
<< " *** _instance allready set: " << _instance << endl;
}
#endif // DEBUG
_instance = this;
}
//! @brief ActionHandler destructor
ActionHandler::~ActionHandler(void)
{
_instance = NULL;
}
//! @brief Executes an ActionPerformed event.
void
ActionHandler::handleAction(const ActionPerformed &ap)
{
Client *client = NULL;
Frame *frame = NULL;
#ifdef MENUS
PMenu *menu = NULL;
#endif // MENUS
PDecor *decor = NULL;
bool matched = false;
// determine what type if any of the window object that is focused
if (ap.wo != NULL) {
if (ap.wo->getType() == PWinObj::WO_CLIENT) {
client = static_cast<Client*>(ap.wo);
frame = static_cast<Frame*>(client->getParent());
decor = static_cast<PDecor*>(frame);
} else if (ap.wo->getType() == PWinObj::WO_FRAME) {
frame = static_cast<Frame*>(ap.wo);
client = static_cast<Client*>(frame->getActiveChild());
decor = static_cast<PDecor*>(ap.wo);
#ifdef MENUS
} else if (ap.wo->getType() == PWinObj::WO_MENU) {
menu = static_cast<PMenu*>(ap.wo);
decor = static_cast<PDecor*>(ap.wo);
#endif // MENUS
} else {
decor = dynamic_cast<PDecor*>(ap.wo);
}
}
// go through the list of actions and execute them
list<Action>::const_iterator it = ap.ae.action_list.begin();
for (; it != ap.ae.action_list.end(); ++it, matched = false) {
// actions valid for all PWinObjs
if ((matched == false) && (ap.wo != NULL)) {
matched = true;
switch (it->getAction()) {
case ACTION_FOCUS:
ap.wo->giveInputFocus();
break;
case ACTION_UNFOCUS:
PWinObj::getRootPWinObj()->giveInputFocus();
break;
case ACTION_FOCUS_DIRECTIONAL:
actionFocusDirectional(ap.wo, DirectionType(it->getParamI(0)), it->getParamI(1));
break;
default:
matched = false;
break;
};
}
// actions valid for Clients and Frames
if ((matched == false) && (frame != NULL)) {
matched = true;
switch (it->getAction()) {
case ACTION_GROUPING_DRAG:
if (ap.type == MotionNotify)
frame->doGroupingDrag(ap.event.motion, client, it->getParamI(0));
break;
case ACTION_ACTIVATE_CLIENT:
if ((ap.type == ButtonPress) || (ap.type == ButtonRelease))
frame->activateChild(frame->getChildFromPos(ap.event.button->x));
break;
case ACTION_MAXFILL:
frame->setStateMaximized(STATE_SET,
it->getParamI(0), it->getParamI(1), true);
break;
case ACTION_GROW_DIRECTION:
frame->growDirection(it->getParamI(0));
break;
case ACTION_RESIZE:
if (ap.type == MotionNotify)
frame->doResize(ap.event.motion);
else
frame->doResize(BorderPosition(it->getParamI(0)));
break;
case ACTION_MOVE_RESIZE:
frame->doKeyboardMoveResize();
break;
case ACTION_CLOSE:
client->close();
break;
case ACTION_CLOSE_FRAME:
frame->close();
break;
case ACTION_KILL:
client->kill();
break;
case ACTION_RAISE:
if (it->getParamI(0) == true) {
_wm->familyRaiseLower(client, true);
} else {
frame->raise();
}
break;
case ACTION_LOWER:
if (it->getParamI(0) == true) {
_wm->familyRaiseLower(client, false);
} else {
frame->lower();
}
break;
case ACTION_ACTIVATE_OR_RAISE:
if ((ap.type == ButtonPress) || (ap.type == ButtonRelease)) {
if (ap.event.button->window == frame->getTitleWindow()) {
frame->activateChild(frame->getChildFromPos(ap.event.button->x));
}
}
if (frame->isFocused()) {
frame->raise();
} else {
ap.wo->giveInputFocus();
}
break;
case ACTION_MOVE_TO_EDGE:
frame->moveToEdge(OrientationType(it->getParamI(0)));
break;
case ACTION_ACTIVATE_CLIENT_REL:
frame->activateChildRel(it->getParamI(0));
break;
case ACTION_MOVE_CLIENT_REL:
frame->moveChildRel(it->getParamI(0));
break;
case ACTION_ACTIVATE_CLIENT_NUM:
frame->activateChildNum(it->getParamI(0));
break;
case ACTION_SEND_TO_WORKSPACE:
actionSendToWorkspace(decor, it->getParamI(0));
break;
case ACTION_DETACH:
frame->detachClient(client);
break;
case ACTION_ATTACH_MARKED:
_wm->attachMarked(frame);
break;
case ACTION_ATTACH_CLIENT_IN_NEXT_FRAME:
_wm->attachInNextPrevFrame(client, false, true);
break;
case ACTION_ATTACH_CLIENT_IN_PREV_FRAME:
_wm->attachInNextPrevFrame(client, false, false);
break;
case ACTION_ATTACH_FRAME_IN_NEXT_FRAME:
_wm->attachInNextPrevFrame(client, true, true);
break;
case ACTION_ATTACH_FRAME_IN_PREV_FRAME:
_wm->attachInNextPrevFrame(client, true, false);
break;
default:
matched = false;
break;
}
}
// Actions valid for Menus
#ifdef MENUS
if ((matched == false) && (menu != NULL)) {
matched = true;
switch (it->getAction()) {
// menu navigation
case ACTION_MENU_NEXT:
menu->selectNextItem();
break;
case ACTION_MENU_PREV:
menu->selectPrevItem();
break;
case ACTION_MENU_SELECT:
menu->exec(menu->getItemCurr());
// special case: execItem can cause an reload to be issued, if that's
// the case it causes the list (ae) to change and therefore
// it can't be used anymore
return;
break;
case ACTION_MENU_ENTER_SUBMENU:
if ((menu->getItemCurr() != NULL) &&
(menu->getItemCurr()->getWORef() != NULL) &&
(menu->getItemCurr()->getWORef()->getType() == PWinObj::WO_MENU)) {
menu->mapSubmenu(static_cast<PMenu*>(menu->getItemCurr()->getWORef()), true);
}
break;
case ACTION_MENU_LEAVE_SUBMENU:
menu->gotoParentMenu();
break;
case ACTION_CLOSE:
menu->unmapAll();
_wm->findWOAndFocus(NULL);
break;
default:
matched = false;
break;
}
}
#endif // MENUS
// actions valid for pdecor
if ((matched == false) && (decor != NULL)) {
matched = true;
switch (it->getAction()) {
case ACTION_MOVE:
decor->doMove((ap.type == MotionNotify) ? ap.event.motion : NULL);
break;
case ACTION_CLOSE:
decor->unmapWindow();
break;
case ACTION_WARP_TO_WORKSPACE:
actionWarpToWorkspace(decor, it->getParamI(0));
break;
case ACTION_WARP_TO_VIEWPORT:
actionWarpToViewport(decor, it->getParamI(0));
break;
default:
matched = false;
break;
}
}
// Actions valid from everywhere
if (matched == false) {
matched = true;
switch (it->getAction()) {
case ACTION_SET:
case ACTION_UNSET:
case ACTION_TOGGLE:
handleStateAction(*it, ap.wo, client, frame);
break;
case ACTION_NEXT_FRAME:
actionFocusToggle(ap.ae.sym, it->getParamI(0), 1, false);
break;
case ACTION_NEXT_FRAME_MRU:
actionFocusToggle(ap.ae.sym, it->getParamI(0), 1, true);
break;
case ACTION_PREV_FRAME:
actionFocusToggle(ap.ae.sym, it->getParamI(0), -1, false);
break;
case ACTION_PREV_FRAME_MRU:
actionFocusToggle(ap.ae.sym, it->getParamI(0), -1, true);
break;
case ACTION_GOTO_WORKSPACE:
// if the event was caused by a motion event ( dragging frame to the
// edge ) or enter event ( moving the pointer to the edge ) we'll want
// to warp the pointer
Workspaces::instance()->gotoWorkspace(it->getParamI(0),
((ap.type == MotionNotify) ||
(ap.type == EnterNotify)));
break;
case ACTION_VIEWPORT_MOVE_XY:
Workspaces::instance()->getActiveViewport()->move(it->getParamI(0), it->getParamI(1));
break;
case ACTION_VIEWPORT_MOVE_DRAG:
if (ap.type == MotionNotify) {
Workspaces::instance()->getActiveViewport()->moveDrag(ap.event.motion->x_root, ap.event.motion->y_root);
}
break;
case ACTION_VIEWPORT_MOVE_DIRECTION:
if (ap.type == KeyPress) {
Workspaces::instance()->getActiveViewport()->moveDirection(DirectionType(it->getParamI(0)), false);
} else {
Workspaces::instance()->getActiveViewport()->moveDirection(DirectionType(it->getParamI(0)), true);
}
break;
case ACTION_VIEWPORT_SCROLL:
Workspaces::instance()->getActiveViewport()->scroll(it->getParamI(0), it->getParamI(1));
break;
case ACTION_VIEWPORT_GOTO:
Workspaces::instance()->getActiveViewport()->gotoColRow((unsigned) it->getParamI(0), (unsigned) it->getParamI(1));
break;
case ACTION_FIND_CLIENT:
actionFindClient(it->getParamS());
break;
case ACTION_EXEC:
if (it->getParamS().size())
Util::forkExec(it->getParamS());
break;
#ifdef MENUS
case ACTION_SHOW_MENU:
actionShowMenu(MenuType(it->getParamI(0)), it->getParamI(1),
ap.type, client ? client : ap.wo);
break;
case ACTION_HIDE_ALL_MENUS:
_wm->hideAllMenus();
_wm->findWOAndFocus(NULL);
break;
#endif // MENUS
case ACTION_RELOAD:
_wm->reload();
// special case: reload causes the list (ae) to change and therefore
// it can't be used anymore
return;
break;
case ACTION_RESTART:
_wm->restart();
break;
case ACTION_RESTART_OTHER:
if (it->getParamS().size())
_wm->restart(it->getParamS());
break;
case ACTION_EXIT:
_wm->shutdown();
break;
case ACTION_SHOW_CMD_DIALOG:
if (_wm->getCmdDialog()->isMapped()) {
_wm->getCmdDialog()->unmapWindow();
} else {
_wm->getCmdDialog()->setWORef(client ? client : ap.wo);
_wm->getCmdDialog()->mapCenteredOnWORef();
_wm->getCmdDialog()->giveInputFocus();
}
break;
default:
matched = false;
break;
}
}
}
}
//! @brief Handles state actions
void
ActionHandler::handleStateAction(const Action &action, PWinObj *wo,
Client *client, Frame *frame)
{
StateAction sa = static_cast<StateAction>(action.getAction()); // convenience
bool matched = false;
// check for frame actions
if ((matched == false) && (frame != NULL)) {
matched = true;
switch (action.getParamI(0)) {
case ACTION_STATE_MAXIMIZED:
frame->setStateMaximized(sa, action.getParamI(1),
action.getParamI(2), false);
break;
case ACTION_STATE_FULLSCREEN:
frame->setStateFullscreen(sa);
break;
case ACTION_STATE_SHADED:
frame->setShaded(sa);
break;
case ACTION_STATE_STICKY:
frame->setStateSticky(sa);
break;
case ACTION_STATE_ALWAYS_ONTOP:
frame->setStateAlwaysOnTop(sa);
break;
case ACTION_STATE_ALWAYS_BELOW:
frame->setStateAlwaysBelow(sa);
break;
case ACTION_STATE_DECOR_BORDER:
frame->setStateDecorBorder(sa);
break;
case ACTION_STATE_DECOR_TITLEBAR:
frame->setStateDecorTitlebar(sa);
break;
case ACTION_STATE_ICONIFIED:
frame->setStateIconified(sa);
break;
case ACTION_STATE_TAGGED:
frame->setStateTagged(sa, action.getParamI(1));
break;
case ACTION_STATE_MARKED:
client->setStateMarked(sa);
break;
case ACTION_STATE_SKIP:
frame->setStateSkip(sa, action.getParamI(1));
break;
case ACTION_STATE_CFG_DENY:
client->setStateCfgDeny(sa, action.getParamI(1));
break;
case ACTION_STATE_DECOR:
frame->setDecorOverride(sa, action.getParamS());
break;
case ACTION_STATE_TITLE:
frame->setStateTitle(sa, client, action.getParamS());
break;
default:
matched = false;
break;
}
}
// check for menu actions
if ((matched == false) && (wo != NULL) &&
(wo->getType() == PWinObj::WO_MENU)) {
matched = true;
switch (action.getParamI(0)) {
case ACTION_STATE_STICKY:
wo->stick();
break;
default:
matched = false;
break;
}
}
if (matched == false) {
matched = true;
switch (action.getParamI(0)) {
case ACTION_STATE_GLOBAL_GROUPING:
_wm->setStateGlobalGrouping(sa);
break;
default:
matched = false;
break;
}
}
}
//! @brief Checks if motion threshold is within bounds.
bool
ActionHandler::checkAEThreshold(int x, int y, int x_t, int y_t, uint t)
{
if (((x > x_t) ? (x > (x_t + signed(t))) : (x < (x_t - signed(t)))) ||
((y > y_t) ? (y > (y_t + signed(t))) : (y < (y_t - signed(t))))) {
return true;
}
return false;
}
//! @brief Searches the actions list for an matching event
ActionEvent*
ActionHandler::findMouseAction(uint button, uint state, MouseEventType type,
std::list<ActionEvent> *actions)
{
if (actions == NULL)
return NULL;
state &= ~PScreen::instance()->getNumLock() &
~PScreen::instance()->getScrollLock() & ~LockMask;
state &= ~Button1Mask & ~Button2Mask & ~Button3Mask
& ~Button4Mask & ~Button5Mask;
list<ActionEvent>::iterator it(actions->begin());
for (; it != actions->end(); ++it) {
if ((it->type == unsigned(type)) &&
((it->mod == MOD_ANY) || (it->mod == state)) &&
((it->sym == BUTTON_ANY) || (it->sym == button))) {
return &*it;
}
}
return NULL;
}
//! @brief Searches for a client matching titles and makes it visible
void
ActionHandler::actionFindClient(const std::string &title)
{
if (title.size() == 0) {
return;
}
Client *client = findClientFromTitle(title);
if (client == NULL) {
return;
}
Frame *frame = static_cast<Frame*>(client->getParent());
// make sure it's visible
if (frame->isMapped() == false) {
if ((frame->isSticky() == false) &&
(frame->getWorkspace() != Workspaces::instance()->getActive())) {
Workspaces::instance()->setWorkspace(frame->getWorkspace(), false);
}
frame->mapWindow();
}
if (Workspaces::instance()->getActiveViewport()->isInside(frame) == false) {
Workspaces::instance()->getActiveViewport()->moveToWO(frame);
}
frame->activateChild(client);
frame->raise();
frame->giveInputFocus();
}
//! @brief Sends client to specified workspace
//! @param direction Workspace to send to, or special meaning relative space.
void
ActionHandler::actionSendToWorkspace(PDecor *decor, int direction)
{
switch (direction) {
case WORKSPACE_LEFT:
case WORKSPACE_PREV:
if (Workspaces::instance()->getActive() > 0) {
decor->setWorkspace(Workspaces::instance()->getActive() - 1);
} else if (static_cast<uint>(direction) == WORKSPACE_PREV) {
decor->setWorkspace(Workspaces::instance()->size() - 1);
}
break;
case WORKSPACE_NEXT:
case WORKSPACE_RIGHT:
if ((Workspaces::instance()->getActive() + 1) <
Workspaces::instance()->size()) {
decor->setWorkspace(Workspaces::instance()->getActive() + 1);
} else if (static_cast<uint>(direction) == WORKSPACE_NEXT) {
decor->setWorkspace(0);
}
break;
case WORKSPACE_LAST:
decor->setWorkspace(Workspaces::instance()->getPrevious());
break;
default:
decor->setWorkspace(direction);
break;
}
}
//! @brief
void
ActionHandler::actionWarpToWorkspace(PDecor *decor, uint direction)
{
// actually did move
if (Workspaces::instance()->gotoWorkspace(DirectionType(direction), true) == true) {
int x, y;
PScreen::instance()->getMousePosition(x, y);
decor->move(decor->getClickX() + x - decor->getPointerX(),
decor->getClickY() + y - decor->getPointerY());
decor->setWorkspace(Workspaces::instance()->getActive());
}
}
//! @brief
void
ActionHandler::actionWarpToViewport(PDecor *decor, uint direction)
{
Viewport *vp = Workspaces::instance()->getActiveViewport();
// actually did move
if (vp->moveDirection(DirectionType(direction)) == true) {
int x, y;
PScreen::instance()->getMousePosition(x, y);
decor->move(decor->getClickX() + x - decor->getPointerX(),
decor->getClickY() + y - decor->getPointerY());
}
}
//! @brief Tries to find the next/prev frame relative to the focused client
void
ActionHandler::actionFocusToggle(uint button, uint raise, int off, bool mru)
{
PMenu *p_menu;
if (mru) {
p_menu = createMRUMenu();
} else {
p_menu = createNextPrevMenu();
}
auto_ptr<PMenu> menu(p_menu);
// no clients in the list
if (menu->size() == 0) {
return;
}
// unable to grab keyboard
if (PScreen::instance()->grabKeyboard(PScreen::instance()->getRoot()) == false) {
return;
}
// find the focused window object
PWinObj *fo_wo = NULL;
if (PWinObj::getFocusedPWinObj() != NULL) {
if (PWinObj::getFocusedPWinObj()->getType() == PWinObj::WO_CLIENT) {
fo_wo = PWinObj::getFocusedPWinObj()->getParent();
list<PMenu::Item*>::iterator it(menu->m_begin());
for (; it != menu->m_end(); ++it) {
if ((*it)->getWORef() == fo_wo) {
menu->selectItem(it);
break;
}
}
fo_wo->setFocused(false);
} else {
#ifdef DEBUG
cerr << __FILE__ << "@" << __LINE__ << ": "
<< "ActionHandler(" << this << ")::actionFocusToggle("
<< button << "," << raise << "," << off << "," << mru << ")" << endl
<< " *** focused PWinObj != WO_FRAME" << endl;
#endif // DEBUG
}
}
if (Config::instance()->getShowFrameList()) {
menu->buildMenu();
Geometry head;
PScreen::instance()->getHeadInfo(PScreen::instance()->getCurrHead(), head);
menu->move(head.x + ((head.width - menu->getWidth()) / 2),
head.y + ((head.height - menu->getHeight()) / 2));
menu->setFocused(true);
menu->mapWindowRaised();
}
menu->selectItemRel(off);
fo_wo = menu->getItemCurr()->getWORef();
XEvent ev;
bool cycling = true;
while (cycling) {
if (fo_wo != NULL) {
fo_wo->setFocused(true);
if (Raise(raise) == ALWAYS_RAISE) {
fo_wo->raise();
}
}
XMaskEvent(PScreen::instance()->getDpy(), KeyPressMask|KeyReleaseMask, &ev);
if (ev.type == KeyPress) {
if (ev.xkey.keycode == button) {
if (fo_wo != NULL) {
fo_wo->setFocused(false);
}
menu->selectItemRel(off);
fo_wo = menu->getItemCurr()->getWORef();
} else {
XPutBackEvent (PScreen::instance()->getDpy(), &ev);
cycling = false;
}
} else if (ev.type == KeyRelease) {
if (IsModifierKey(XKeycodeToKeysym(PScreen::instance()->getDpy(),
ev.xkey.keycode, 0))) {
cycling = false;
}
} else {
XPutBackEvent(PScreen::instance()->getDpy(), &ev);
}
}
PScreen::instance()->ungrabKeyboard();
if (fo_wo != NULL) {
fo_wo->giveInputFocus();
}
if (Raise(raise) == END_RAISE) {
fo_wo->raise();
}
}
//! @brief Finds a window in direction and gives it focus
void
ActionHandler::actionFocusDirectional(PWinObj *wo, DirectionType dir, bool raise)
{
PWinObj *wo_focus =
Workspaces::instance()->findDirectional(wo, dir, SKIP_FOCUS_TOGGLE);
if (wo_focus != NULL) {
if (raise == true) {
wo_focus->raise();
}
wo_focus->giveInputFocus();
}
}
#ifdef MENUS
//! @brief Toggles visibility of menu of type m_type
void
ActionHandler::actionShowMenu(MenuType m_type, bool stick,
uint e_type, PWinObj *wo_ref)
{
PMenu *menu = _wm->getMenu(m_type);
if (menu == NULL) {
return;
}
if (menu->isMapped()) {
menu->unmapAll();
} else {
// if it's a WORefMenu, set referencing client
WORefMenu *wo_ref_menu = dynamic_cast<WORefMenu*>(menu);
if ((wo_ref_menu != NULL) &&
(wo_ref_menu->getMenuType() != ROOTMENU_TYPE)) {
wo_ref_menu->setWORef(wo_ref);
}
// mapping can fail because of empty menu, like iconmenu, so we check
menu->mapUnderMouse();
if (menu->isMapped()) {
menu->giveInputFocus();
if (stick) {
menu->setSticky(true);
}
// if we opened the menu with the keyboard, select item 0
if (e_type == KeyPress) {
menu->selectItemNum(0);
}
}
}
}
#endif // MENUS
//! @brief Creates a menu containing a list of Frames currently visible
PMenu*
ActionHandler::createNextPrevMenu(void)
{
ActionEvent ae; // empty ae, used when inserting
Viewport *vp = Workspaces::instance()->getActiveViewport();
PMenu *menu =
new PMenu(PScreen::instance()->getDpy(), _wm->getTheme(), "Windows");
list<Frame*>::iterator f_it(_wm->frame_begin());
for (; f_it != _wm->frame_end(); ++f_it) {
// if it's not hidden it's either sticky or on this workspace
if ((*f_it)->isMapped() && vp->isInside(*f_it) && (*f_it)->isFocusable() &&
((*f_it)->isSkip(SKIP_FOCUS_TOGGLE) == false)) {
menu->insert(static_cast<Client*>((*f_it)->getActiveChild())->getTitle()->getVisible(), ae, *f_it);
}
}
return menu;
}
//! @brief Creates a menu containing a list of Frames currently visible ( MRU order )
PMenu*
ActionHandler::createMRUMenu(void)
{
ActionEvent ae; // empty ae, used when inserting
Viewport *vp = Workspaces::instance()->getActiveViewport();
PMenu *menu =
new PMenu(PScreen::instance()->getDpy(), _wm->getTheme(), "MRU Windows");
Frame *fr;
list<PWinObj*>::reverse_iterator f_it = _wm->mru_rbegin();
for (; f_it != _wm->mru_rend(); ++f_it) {
fr = static_cast<Frame*>(*f_it);
// if it's not hidden it's either sticky or on this workspace
if (fr->isMapped() && vp->isInside(fr) && fr->isFocusable() &&
(fr->isSkip(SKIP_FOCUS_TOGGLE) == false)) {
menu->insert(static_cast<Client*>(fr->getActiveChild())->getTitle()->getVisible(), ae, fr);
}
}
return menu;
}
//! @brief Searches the client list for a client with a title matching title
Client*
ActionHandler::findClientFromTitle(const std::string &or_title)
{
RegexString o_rs;
if (o_rs.parse_match (or_title))
{
list<Client*>::iterator it (_wm->client_begin ());
for (; it != _wm->client_end (); ++it)
{
if (o_rs == (*it)->getTitle()->getReal())
return (*it);
}
}
return NULL;
}
syntax highlighted by Code2HTML, v. 0.9.1