/*
 * synergy -- mouse and keyboard sharing utility
 * Copyright (C) 2002 Chris Schoeneman
 * Copyright (C) 2006 Knut St. Osmundsen
 *
 * This package is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * found in the file COPYING that should have accompanied this file.
 *
 * This package is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#ifndef CPMSCREEN_H
#define CPMSCREEN_H

#include "CPlatformScreen.h"
#include "CPMSynergyHook.h"
#include "CCondVar.h"
#include "CMutex.h"
#include "CString.h"
#define INCL_ERRORS
#define INCL_BASE
#define INCL_PM
#include <os2.h>


class CEventQueueTimer;
class CPMDesks;
class CPMKeyState;
class CPMScreenSaver;
class CThread;

//! Implementation of IPlatformScreen for PM
class CPMScreen : public CPlatformScreen {
public:
    CPMScreen(bool isPrimary);
    virtual ~CPMScreen();

    // IScreen overrides
    virtual void*       getEventTarget() const;
    virtual bool        getClipboard(ClipboardID id, IClipboard*) const;
    virtual void        getShape(SInt32& x, SInt32& y, SInt32& cx, SInt32& cy) const;
    virtual void        getCursorPos(SInt32& x, SInt32& y) const;

    // IPrimaryScreen overrides
    virtual void        reconfigure(UInt32 activeSides);
    virtual void        warpCursor(SInt32 x, SInt32 y);
    virtual UInt32      registerHotKey(KeyID key,
                            KeyModifierMask mask);
    virtual void        unregisterHotKey(UInt32 id);
    virtual void        fakeInputBegin();
    virtual void        fakeInputEnd();
    virtual SInt32      getJumpZoneSize() const;
    virtual bool        isAnyMouseButtonDown() const;
    virtual void        getCursorCenter(SInt32& x, SInt32& y) const;

    // ISecondaryScreen overrides
    virtual void        fakeMouseButton(ButtonID id, bool press) const;
    virtual void        fakeMouseMove(SInt32 x, SInt32 y) const;
    virtual void        fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const;
    virtual void        fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const;

    // IKeyState overrides
    virtual void        updateKeys();
    virtual void        fakeKeyDown(KeyID id, KeyModifierMask mask,
                            KeyButton button);
    virtual void        fakeKeyRepeat(KeyID id, KeyModifierMask mask,
                            SInt32 count, KeyButton button);
    virtual void        fakeKeyUp(KeyButton button);
    virtual void        fakeAllKeysUp();

    // IPlatformScreen overrides
    virtual void        enable();
    virtual void        disable();
    virtual void        enter();
    virtual bool        leave();
    virtual bool        setClipboard(ClipboardID, const IClipboard*);
    virtual void        checkClipboards();
    virtual void        openScreensaver(bool notify);
    virtual void        closeScreensaver();
    virtual void        screensaver(bool activate);
    virtual void        resetOptions();
    virtual void        setOptions(const COptionsList& options);
    virtual void        setSequenceNumber(UInt32);
    virtual bool        isPrimary() const;

protected:
    // IPlatformScreen overrides
    virtual void        handleSystemEvent(const CEvent&, void*);
    virtual void        updateButtons();
    virtual IKeyState*  getKeyState() const;

private:
    // initialization and shutdown operations
    HMODULE             openHookLibrary(const char* name);
    void                closeHookLibrary(HMODULE hookLibrary) const;
    HWND                createWindow(const char* name);
    void                destroyWindow(HWND) const;

    // fake message injection
    void                fakeMessage(ULONG msg, MPARAM mp1, MPARAM mp2) const;
    void                fakeMouseMessage(ULONG msg, MPARAM mp1) const;

    // convenience function to send events
    void                sendEvent(CEvent::Type type, void* = NULL);
    void                sendClipboardEvent(CEvent::Type type, ClipboardID id);

    // handle message before it gets dispatched.  returns true iff
    // the message should not be dispatched.
    bool                onPreDispatch(HWND, ULONG, MPARAM, MPARAM);

    // handle message before it gets dispatched.  returns true iff
    // the message should not be dispatched.
    bool                onPreDispatchPrimary(HWND, ULONG, MPARAM, MPARAM);

    // handle message.  returns true iff handled and optionally sets
    // \c *result (which defaults to 0).
    bool                onEvent(HWND, ULONG, MPARAM, MPARAM, MRESULT*);

    // message handlers
    bool                onMark(UInt32 mark);
    bool                onKey(USHORT fsFlags, UCHAR ucRepeat, UCHAR ucScanCode, USHORT usch, USHORT usvk);
    bool                onHotKey(MPARAM, MPARAM);
    bool                onMouseButton(ULONG msg, SInt32 ax, SInt32 ay);
    bool                onMouseMove(ULONG msg, SInt32 ax, SInt32 ay);
    bool                onClipboardChange();

    // warp cursor without discarding queued events
    void                warpCursorNoFlush(SInt32 x, SInt32 y);

    // discard posted messages
    void                nextMark();

    // test if event should be ignored
    bool                ignore() const;

    // update screen size cache
    void                updateScreenShape();

    // fix timer callback
    void                handleFixes(const CEvent&, void*);

    // enable/disable special key combinations so we can catch/pass them
    void                enableSpecialKeys(bool) const;

    // map a button event to a button ID
    ButtonID            mapButtonFromEvent(ULONG msg) const;

    // map a button event to a press (true) or release (false)
    bool                mapPressFromEvent(ULONG msg) const;

    // job to update the key state
    void                updateKeysCB(void*);

    // determine whether the mouse is hidden by the system and force
    // it to be displayed if user has entered this secondary screen.
    void                forceShowCursor();

    // forceShowCursor uses MouseKeys to show the cursor.  since we
    // don't actually want MouseKeys behavior we have to make sure
    // it applies when NumLock is in whatever state it's not in now.
    // this method does that.
    void                updateForceShowCursor();

    // our window proc
    static MRESULT EXPENTRY wndProc(HWND, ULONG, MPARAM, MPARAM);

private:
    struct CHotKeyItem {
    public:
        CHotKeyItem(ULONG vk, ULONG modifiers);

        ULONG           getVirtualKey() const;

        bool            operator<(const CHotKeyItem&) const;

    private:
        ULONG           m_keycode;
        ULONG           m_mask;
    };
    typedef std::map<UInt32, CHotKeyItem> HotKeyMap;
    typedef std::vector<UInt32> HotKeyIDList;
    typedef std::map<CHotKeyItem, UInt32> HotKeyToIDMap;

    // true if screen is being used as a primary screen, false otherwise
    bool                m_isPrimary;
    bool                m_isOnScreen;

    // screen shape stuff
    SInt32              m_x, m_y;
    SInt32              m_cx, m_cy;
    SInt32              m_xCenter, m_yCenter;

    // true if system appears to have multiple monitors
    bool                m_multimon;

    // last mouse position
    SInt32              m_xCursor, m_yCursor;

    // last clipboard
    UInt32              m_sequenceNumber;

    // used to discard queued messages that are no longer needed
    UInt32              m_mark;
    UInt32              m_markReceived;

    // the main loop's thread id, anchor block and message queue.
    int                 m_threadID;
    HAB                 m_hab;
    HMQ                 m_hmq;

    // screen saver stuff
    CPMScreenSaver*     m_screensaver;
    bool                m_screensaverNotify;
    bool                m_screensaverActive;

    // clipboard stuff.  our window is used mainly as a clipboard
    // owner and as a link in the clipboard viewer chain.
    HWND                m_window;
    HWND                m_nextClipboardWindow;
    bool                m_ownClipboard;

    // hook library stuff
    HMODULE             m_hmodHook;
    InitFunc            m_init;
    CleanupFunc         m_cleanup;
    SetSidesFunc        m_setSides;
    SetZoneFunc         m_setZone;
    SetModeFunc         m_setMode;
    FakeMsgFunc         m_fakeMsg;

    // keyboard stuff
    CPMKeyState*        m_keyState;

    // hot key stuff
    HotKeyMap           m_hotKeys;
    HotKeyIDList        m_oldHotKeyIDs;
    HotKeyToIDMap       m_hotKeyToIDMap;

    // map of button state
    bool                m_buttons[1 + kButtonExtra0 + 1];

    bool                m_hasMouse;
    bool                m_showingMouse;

    static CPMScreen*   s_screen;
};

/*
 * Local Variables:
 *  mode: c
 *  c-file-style: "k&r"
 *  c-basic-offset: 4
 *  tab-width: 4
 *  indent-tabs-mode: s
 * End:
 */

#endif
