barrier/lib/server/CServer.h
2010-06-20 17:38:51 +00:00

469 lines
14 KiB
C++

/*
* synergy-plus -- mouse and keyboard sharing utility
* Copyright (C) 2009 The Synergy+ Project
* Copyright (C) 2002 Chris Schoeneman
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CSERVER_H
#define CSERVER_H
#include "CConfig.h"
#include "CClipboard.h"
#include "ClipboardTypes.h"
#include "KeyTypes.h"
#include "MouseTypes.h"
#include "CEvent.h"
#include "CStopwatch.h"
#include "stdmap.h"
#include "stdset.h"
#include "stdvector.h"
#include "INode.h"
class CBaseClientProxy;
class CEventQueueTimer;
class CPrimaryClient;
class CInputFilter;
//! Synergy server
/*!
This class implements the top-level server algorithms for synergy.
*/
class CServer : public INode {
public:
//! Lock cursor to screen data
class CLockCursorToScreenInfo {
public:
enum State { kOff, kOn, kToggle };
static CLockCursorToScreenInfo* alloc(State state = kToggle);
public:
State m_state;
};
//! Switch to screen data
class CSwitchToScreenInfo {
public:
static CSwitchToScreenInfo* alloc(const CString& screen);
public:
// this is a C-string; this type is a variable size structure
char m_screen[1];
};
//! Switch in direction data
class CSwitchInDirectionInfo {
public:
static CSwitchInDirectionInfo* alloc(EDirection direction);
public:
EDirection m_direction;
};
//! Screen connected data
class CScreenConnectedInfo {
public:
CScreenConnectedInfo(CString screen) : m_screen(screen) { }
public:
CString m_screen; // was char[1]
};
//! Keyboard broadcast data
class CKeyboardBroadcastInfo {
public:
enum State { kOff, kOn, kToggle };
static CKeyboardBroadcastInfo* alloc(State state = kToggle);
static CKeyboardBroadcastInfo* alloc(State state,
const CString& screens);
public:
State m_state;
char m_screens[1];
};
/*!
Start the server with the configuration \p config and the primary
client (local screen) \p primaryClient. The client retains
ownership of \p primaryClient.
*/
CServer(const CConfig& config, CPrimaryClient* primaryClient);
~CServer();
//! @name manipulators
//@{
//! Set configuration
/*!
Change the server's configuration. Returns true iff the new
configuration was accepted (it must include the server's name).
This will disconnect any clients no longer in the configuration.
*/
bool setConfig(const CConfig&);
//! Add a client
/*!
Adds \p client to the server. The client is adopted and will be
destroyed when the client disconnects or is disconnected.
*/
void adoptClient(CBaseClientProxy* client);
//! Disconnect clients
/*!
Disconnect clients. This tells them to disconnect but does not wait
for them to actually do so. The server sends the disconnected event
when they're all disconnected (or immediately if none are connected).
The caller can also just destroy this object to force the disconnection.
*/
void disconnect();
//@}
//! @name accessors
//@{
//! Get number of connected clients
/*!
Returns the number of connected clients, including the server itself.
*/
UInt32 getNumClients() const;
//! Get the list of connected clients
/*!
Set the \c list to the names of the currently connected clients.
*/
void getClients(std::vector<CString>& list) const;
//! Get error event type
/*!
Returns the error event type. This is sent when the server fails
for some reason.
*/
static CEvent::Type getErrorEvent();
//! Get connected event type
/*!
Returns the connected event type. This is sent when a client screen
has connected. The event data is a \c CScreenConnectedInfo* that
indicates the connected screen.
*/
static CEvent::Type getConnectedEvent();
//! Get disconnected event type
/*!
Returns the disconnected event type. This is sent when all the
clients have disconnected.
*/
static CEvent::Type getDisconnectedEvent();
//! Get switch to screen event type
/*!
Returns the switch to screen event type. The server responds to this
by switching screens. The event data is a \c CSwitchToScreenInfo*
that indicates the target screen.
*/
static CEvent::Type getSwitchToScreenEvent();
//! Get switch in direction event type
/*!
Returns the switch in direction event type. The server responds to this
by switching screens. The event data is a \c CSwitchInDirectionInfo*
that indicates the target direction.
*/
static CEvent::Type getSwitchInDirectionEvent();
//! Get keyboard broadcast event type
/*!
Returns the keyboard broadcast event type. The server responds
to this by turning on keyboard broadcasting or turning it off. The
event data is a \c CKeyboardBroadcastInfo*.
*/
static CEvent::Type getKeyboardBroadcastEvent();
//! Get lock cursor event type
/*!
Returns the lock cursor event type. The server responds to this
by locking the cursor to the active screen or unlocking it. The
event data is a \c CLockCursorToScreenInfo*.
*/
static CEvent::Type getLockCursorToScreenEvent();
//@}
private:
// get canonical name of client
CString getName(const CBaseClientProxy*) const;
// get the sides of the primary screen that have neighbors
UInt32 getActivePrimarySides() const;
// returns true iff mouse should be locked to the current screen
// according to this object only, ignoring what the primary client
// says.
bool isLockedToScreenServer() const;
// returns true iff mouse should be locked to the current screen
// according to this object or the primary client.
bool isLockedToScreen() const;
// returns the jump zone of the client
SInt32 getJumpZoneSize(CBaseClientProxy*) const;
// change the active screen
void switchScreen(CBaseClientProxy*,
SInt32 x, SInt32 y, bool forScreenSaver);
// jump to screen
void jumpToScreen(CBaseClientProxy*);
// convert pixel position to fraction, using x or y depending on the
// direction.
float mapToFraction(CBaseClientProxy*, EDirection,
SInt32 x, SInt32 y) const;
// convert fraction to pixel position, writing only x or y depending
// on the direction.
void mapToPixel(CBaseClientProxy*, EDirection, float f,
SInt32& x, SInt32& y) const;
// returns true if the client has a neighbor anywhere along the edge
// indicated by the direction.
bool hasAnyNeighbor(CBaseClientProxy*, EDirection) const;
// lookup neighboring screen, mapping the coordinate independent of
// the direction to the neighbor's coordinate space.
CBaseClientProxy* getNeighbor(CBaseClientProxy*, EDirection,
SInt32& x, SInt32& y) const;
// lookup neighboring screen. given a position relative to the
// source screen, find the screen we should move onto and where.
// if the position is sufficiently far from the source then we
// cross multiple screens. if there is no suitable screen then
// return NULL and x,y are not modified.
CBaseClientProxy* mapToNeighbor(CBaseClientProxy*, EDirection,
SInt32& x, SInt32& y) const;
// adjusts x and y or neither to avoid ending up in a jump zone
// after entering the client in the given direction.
void avoidJumpZone(CBaseClientProxy*, EDirection,
SInt32& x, SInt32& y) const;
// test if a switch is permitted. this includes testing user
// options like switch delay and tracking any state required to
// implement them. returns true iff a switch is permitted.
bool isSwitchOkay(CBaseClientProxy* dst, EDirection,
SInt32 x, SInt32 y, SInt32 xActive, SInt32 yActive);
// update switch state due to a mouse move at \p x, \p y that
// doesn't switch screens.
void noSwitch(SInt32 x, SInt32 y);
// stop switch timers
void stopSwitch();
// start two tap switch timer
void startSwitchTwoTap();
// arm the two tap switch timer if \p x, \p y is outside the tap zone
void armSwitchTwoTap(SInt32 x, SInt32 y);
// stop the two tap switch timer
void stopSwitchTwoTap();
// returns true iff the two tap switch timer is started
bool isSwitchTwoTapStarted() const;
// returns true iff should switch because of two tap
bool shouldSwitchTwoTap() const;
// start delay switch timer
void startSwitchWait(SInt32 x, SInt32 y);
// stop delay switch timer
void stopSwitchWait();
// returns true iff the delay switch timer is started
bool isSwitchWaitStarted() const;
// returns the corner (EScreenSwitchCornerMasks) where x,y is on the
// given client. corners have the given size.
UInt32 getCorner(CBaseClientProxy*,
SInt32 x, SInt32 y, SInt32 size) const;
// stop relative mouse moves
void stopRelativeMoves();
// send screen options to \c client
void sendOptions(CBaseClientProxy* client) const;
// process options from configuration
void processOptions();
// event handlers
void handleShapeChanged(const CEvent&, void*);
void handleClipboardGrabbed(const CEvent&, void*);
void handleClipboardChanged(const CEvent&, void*);
void handleKeyDownEvent(const CEvent&, void*);
void handleKeyUpEvent(const CEvent&, void*);
void handleKeyRepeatEvent(const CEvent&, void*);
void handleButtonDownEvent(const CEvent&, void*);
void handleButtonUpEvent(const CEvent&, void*);
void handleMotionPrimaryEvent(const CEvent&, void*);
void handleMotionSecondaryEvent(const CEvent&, void*);
void handleWheelEvent(const CEvent&, void*);
void handleScreensaverActivatedEvent(const CEvent&, void*);
void handleScreensaverDeactivatedEvent(const CEvent&, void*);
void handleSwitchWaitTimeout(const CEvent&, void*);
void handleClientDisconnected(const CEvent&, void*);
void handleClientCloseTimeout(const CEvent&, void*);
void handleSwitchToScreenEvent(const CEvent&, void*);
void handleSwitchInDirectionEvent(const CEvent&, void*);
void handleKeyboardBroadcastEvent(const CEvent&,void*);
void handleLockCursorToScreenEvent(const CEvent&, void*);
void handleFakeInputBeginEvent(const CEvent&, void*);
void handleFakeInputEndEvent(const CEvent&, void*);
// event processing
void onClipboardChanged(CBaseClientProxy* sender,
ClipboardID id, UInt32 seqNum);
void onScreensaver(bool activated);
void onKeyDown(KeyID, KeyModifierMask, KeyButton,
const char* screens);
void onKeyUp(KeyID, KeyModifierMask, KeyButton,
const char* screens);
void onKeyRepeat(KeyID, KeyModifierMask, SInt32, KeyButton);
void onMouseDown(ButtonID);
void onMouseUp(ButtonID);
bool onMouseMovePrimary(SInt32 x, SInt32 y);
void onMouseMoveSecondary(SInt32 dx, SInt32 dy);
void onMouseWheel(SInt32 xDelta, SInt32 yDelta);
// add client to list and attach event handlers for client
bool addClient(CBaseClientProxy*);
// remove client from list and detach event handlers for client
bool removeClient(CBaseClientProxy*);
// close a client
void closeClient(CBaseClientProxy*, const char* msg);
// close clients not in \p config
void closeClients(const CConfig& config);
// close all clients whether they've completed the handshake or not,
// except the primary client
void closeAllClients();
// remove clients from internal state
void removeActiveClient(CBaseClientProxy*);
void removeOldClient(CBaseClientProxy*);
// force the cursor off of \p client
void forceLeaveClient(CBaseClientProxy* client);
private:
class CClipboardInfo {
public:
CClipboardInfo();
public:
CClipboard m_clipboard;
CString m_clipboardData;
CString m_clipboardOwner;
UInt32 m_clipboardSeqNum;
};
// the primary screen client
CPrimaryClient* m_primaryClient;
// all clients (including the primary client) indexed by name
typedef std::map<CString, CBaseClientProxy*> CClientList;
typedef std::set<CBaseClientProxy*> CClientSet;
CClientList m_clients;
CClientSet m_clientSet;
// all old connections that we're waiting to hangup
typedef std::map<CBaseClientProxy*, CEventQueueTimer*> COldClients;
COldClients m_oldClients;
// the client with focus
CBaseClientProxy* m_active;
// the sequence number of enter messages
UInt32 m_seqNum;
// current mouse position (in absolute screen coordinates) on
// whichever screen is active
SInt32 m_x, m_y;
// last mouse deltas. this is needed to smooth out double tap
// on win32 which reports bogus mouse motion at the edge of
// the screen when using low level hooks, synthesizing motion
// in the opposite direction the mouse actually moved.
SInt32 m_xDelta, m_yDelta;
SInt32 m_xDelta2, m_yDelta2;
// current configuration
CConfig m_config;
// input filter (from m_config);
CInputFilter* m_inputFilter;
// clipboard cache
CClipboardInfo m_clipboards[kClipboardEnd];
// state saved when screen saver activates
CBaseClientProxy* m_activeSaver;
SInt32 m_xSaver, m_ySaver;
// common state for screen switch tests. all tests are always
// trying to reach the same screen in the same direction.
EDirection m_switchDir;
CBaseClientProxy* m_switchScreen;
// state for delayed screen switching
double m_switchWaitDelay;
CEventQueueTimer* m_switchWaitTimer;
SInt32 m_switchWaitX, m_switchWaitY;
// state for double-tap screen switching
double m_switchTwoTapDelay;
CStopwatch m_switchTwoTapTimer;
bool m_switchTwoTapEngaged;
bool m_switchTwoTapArmed;
SInt32 m_switchTwoTapZone;
// relative mouse move option
bool m_relativeMoves;
// flag whether or not we have broadcasting enabled and the screens to
// which we should send broadcasted keys.
bool m_keyboardBroadcasting;
CString m_keyboardBroadcastingScreens;
// screen locking (former scroll lock)
bool m_lockedToScreen;
static CEvent::Type s_errorEvent;
static CEvent::Type s_connectedEvent;
static CEvent::Type s_disconnectedEvent;
static CEvent::Type s_switchToScreen;
static CEvent::Type s_switchInDirection;
static CEvent::Type s_keyboardBroadcast;
static CEvent::Type s_lockCursorToScreen;
};
#endif