//
// KeyGrabber.hh for pekwm
// Copyright © 2003-2009 Claes Nästén <me@pekdon.net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//

#ifndef _KEYGRABBER_HH_
#define _KEYGRABBER_HH_

#include "config.h"

#include "pekwm.hh"

#include "Action.hh"
#include "CfgParser.hh"
#include "PWinObj.hh"

#include <string>

extern "C" {
#include <X11/Xlib.h>
}

//! @brief Key grabbing and matching routines with key chain support.
class KeyGrabber
{
public:
    //! @brief Key chain state information.
    class Chain
    {
    public:
        Chain(uint mod, uint key);
        ~Chain(void);

        void unload(void);

        //! @brief Returns modifier state Chain represents.
        inline uint getMod(void) const { return _mod; }
        //! @brief Returns key state Chain represents.
        inline uint getKey(void) const { return _key; }

        //! @brief Returns vector of Chains that follows.
        inline const vector<Chain*> &getChains(void) const { return _chains; }
        //! @brief Returns vector of Keys in chain.
        inline const vector<ActionEvent> &getKeys(void) const { return _keys; }

        //! @brief Adds chain to Chain vector.
        inline void addChain(Chain *chain) { _chains.push_back(chain); }
        //! @brief Adds action to Key vector.
        inline void addAction(const ActionEvent &key) { _keys.push_back(key); }

        Chain *findChain(XKeyEvent *ev, bool *matched);
        ActionEvent *findAction(XKeyEvent *ev, bool *matched);

    private:
        uint _mod, _key;

        vector<Chain*> _chains;
        vector<ActionEvent> _keys;
    };

    KeyGrabber(void);
    ~KeyGrabber(void);

    //! @brief Returns the KeyGrabber instance pointer.
    static KeyGrabber *instance(void) { return _instance; }

    bool load(const std::string &file, bool force=false);
    void grabKeys(Window win);
    void ungrabKeys(Window win);

    ActionEvent *findAction(XKeyEvent *ev, PWinObj::Type type, bool *matched);
    ActionEvent *findMoveResizeAction(XKeyEvent *ev);

private:
    void grabKey(Window win, uint mod, uint key);

    void parseGlobalChain(CfgParser::Entry *section, KeyGrabber::Chain *chain);
    void parseMoveResizeChain(CfgParser::Entry *section, KeyGrabber::Chain *chain);
    void parseInputDialogChain(CfgParser::Entry *section, KeyGrabber::Chain *chain);
    void parseMenuChain(CfgParser::Entry *section, KeyGrabber::Chain *chain);

    ActionEvent *findAction(XKeyEvent *ev, KeyGrabber::Chain *chain, bool *matched);

    TimeFiles _cfg_files;

    KeyGrabber::Chain _menu_chain;
    KeyGrabber::Chain _global_chain;
    KeyGrabber::Chain _moveresize_chain;
    KeyGrabber::Chain _input_dialog_chain;

    uint _num_lock;
    uint _scroll_lock;

    static KeyGrabber *_instance;
};

#endif // _KEYGRABBER_HH_
