checkpoint. changed protocol to better handle clipboards. now
sending a sequence number with enter messages. screens use that sequence number in clipboard grab and data messages. the server uses the sequence number to order messages across clients. also changed secondary screens to send clipboard updates on leaving (or when grab occurs when not active) instead of on a query from the server. primary effectively does the same. the query message has been removed.
This commit is contained in:
parent
3be014f8f5
commit
c5f6b34d85
|
@ -30,7 +30,9 @@ CClient::CClient(const CString& clientName) :
|
|||
m_name(clientName),
|
||||
m_input(NULL),
|
||||
m_output(NULL),
|
||||
m_screen(NULL)
|
||||
m_screen(NULL),
|
||||
m_active(false),
|
||||
m_seqNum(0)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
@ -92,7 +94,29 @@ void CClient::onClipboardChanged(ClipboardID id)
|
|||
if (m_output != NULL) {
|
||||
// m_output can be NULL if the screen calls this method
|
||||
// before we've gotten around to connecting to the server.
|
||||
CProtocolUtil::writef(m_output, kMsgCClipboard, id);
|
||||
CProtocolUtil::writef(m_output, kMsgCClipboard, id, m_seqNum);
|
||||
}
|
||||
|
||||
// we now own the clipboard and it has not been sent to the server
|
||||
m_ownClipboard[id] = true;
|
||||
m_timeClipboard[id] = 0;
|
||||
|
||||
// if we're not the active screen then send the clipboard now,
|
||||
// otherwise we'll until we leave.
|
||||
if (!m_active) {
|
||||
// get clipboard
|
||||
CClipboard clipboard;
|
||||
m_screen->getClipboard(id, &clipboard);
|
||||
|
||||
// save new time
|
||||
m_timeClipboard[id] = clipboard.getTime();
|
||||
|
||||
// marshall the data
|
||||
CString data = clipboard.marshall();
|
||||
|
||||
// send data
|
||||
log((CLOG_DEBUG "sending clipboard %d seqnum=%d, size=%d", id, m_seqNum, data.size()));
|
||||
CProtocolUtil::writef(m_output, kMsgDClipboard, id, m_seqNum, &data);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -230,9 +254,6 @@ void CClient::runSession(void*)
|
|||
else if (memcmp(code, kMsgQInfo, 4) == 0) {
|
||||
onQueryInfo();
|
||||
}
|
||||
else if (memcmp(code, kMsgQClipboard, 4) == 0) {
|
||||
onQueryClipboard();
|
||||
}
|
||||
else if (memcmp(code, kMsgDClipboard, 4) == 0) {
|
||||
onSetClipboard();
|
||||
}
|
||||
|
@ -271,6 +292,18 @@ void CClient::openSecondaryScreen()
|
|||
{
|
||||
assert(m_screen == NULL);
|
||||
|
||||
// not active
|
||||
m_active = false;
|
||||
|
||||
// reset last sequence number
|
||||
m_seqNum = 0;
|
||||
|
||||
// reset clipboard state
|
||||
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
|
||||
m_ownClipboard[id] = false;
|
||||
m_timeClipboard[id] = 0;
|
||||
}
|
||||
|
||||
// open screen
|
||||
log((CLOG_DEBUG1 "creating secondary screen"));
|
||||
#if defined(CONFIG_PLATFORM_WIN32)
|
||||
|
@ -306,22 +339,61 @@ void CClient::onEnter()
|
|||
SInt16 x, y;
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
CProtocolUtil::readf(m_input, kMsgCEnter + 4, &x, &y);
|
||||
CProtocolUtil::readf(m_input, kMsgCEnter + 4, &x, &y, &m_seqNum);
|
||||
m_active = true;
|
||||
}
|
||||
m_screen->enter(x, y);
|
||||
}
|
||||
|
||||
void CClient::onLeave()
|
||||
{
|
||||
// tell screen we're leaving
|
||||
m_screen->leave();
|
||||
|
||||
// no longer the active screen
|
||||
CLock lock(&m_mutex);
|
||||
m_active = false;
|
||||
|
||||
// send clipboards that we own and that have changed
|
||||
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
|
||||
if (m_ownClipboard[id]) {
|
||||
// get clipboard data. set the clipboard time to the last
|
||||
// clipboard time before getting the data from the screen
|
||||
// as the screen may detect an unchanged clipboard and
|
||||
// avoid copying the data.
|
||||
CClipboard clipboard;
|
||||
if (clipboard.open(m_timeClipboard[id]))
|
||||
clipboard.close();
|
||||
m_screen->getClipboard(id, &clipboard);
|
||||
|
||||
// check time
|
||||
if (m_timeClipboard[id] == 0 ||
|
||||
clipboard.getTime() != m_timeClipboard[id]) {
|
||||
// save new time
|
||||
m_timeClipboard[id] = clipboard.getTime();
|
||||
|
||||
// marshall the data
|
||||
CString data = clipboard.marshall();
|
||||
|
||||
// send data
|
||||
log((CLOG_DEBUG "sending clipboard %d seqnum=%d, size=%d", id, m_seqNum, data.size()));
|
||||
CProtocolUtil::writef(m_output,
|
||||
kMsgDClipboard, id, m_seqNum, &data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CClient::onGrabClipboard()
|
||||
{
|
||||
ClipboardID id;
|
||||
UInt32 seqNum;
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
CProtocolUtil::readf(m_input, kMsgCClipboard + 4, &id);
|
||||
CProtocolUtil::readf(m_input, kMsgCClipboard + 4, &id, &seqNum);
|
||||
|
||||
// we no longer own the clipboard
|
||||
m_ownClipboard[id] = false;
|
||||
}
|
||||
m_screen->grabClipboard(id);
|
||||
}
|
||||
|
@ -347,32 +419,6 @@ void CClient::onQueryInfo()
|
|||
CProtocolUtil::writef(m_output, kMsgDInfo, w, h, zoneSize);
|
||||
}
|
||||
|
||||
void CClient::onQueryClipboard()
|
||||
{
|
||||
// parse message
|
||||
ClipboardID id;
|
||||
UInt32 seqNum;
|
||||
CClipboard clipboard;
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
CProtocolUtil::readf(m_input, kMsgQClipboard + 4, &id, &seqNum);
|
||||
}
|
||||
log((CLOG_DEBUG "received query clipboard %d seqnum=%d", id, seqNum));
|
||||
|
||||
// get screen's clipboard data
|
||||
m_screen->getClipboard(id, &clipboard);
|
||||
|
||||
// marshall the data
|
||||
CString data = clipboard.marshall();
|
||||
|
||||
// send it
|
||||
log((CLOG_DEBUG "sending clipboard %d seqnum=%d, size=%d", id, seqNum, data.size()));
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
CProtocolUtil::writef(m_output, kMsgDClipboard, id, seqNum, &data);
|
||||
}
|
||||
}
|
||||
|
||||
void CClient::onSetClipboard()
|
||||
{
|
||||
ClipboardID id;
|
||||
|
@ -387,7 +433,7 @@ void CClient::onSetClipboard()
|
|||
|
||||
// unmarshall
|
||||
CClipboard clipboard;
|
||||
clipboard.unmarshall(data);
|
||||
clipboard.unmarshall(data, 0);
|
||||
|
||||
// set screen's clipboard
|
||||
m_screen->setClipboard(id, &clipboard);
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "CString.h"
|
||||
#include "BasicTypes.h"
|
||||
#include "ClipboardTypes.h"
|
||||
#include "IClipboard.h"
|
||||
|
||||
class CNetworkAddress;
|
||||
class IInputStream;
|
||||
|
@ -39,7 +40,6 @@ class CClient {
|
|||
void onGrabClipboard();
|
||||
void onScreenSaver();
|
||||
void onQueryInfo();
|
||||
void onQueryClipboard();
|
||||
void onSetClipboard();
|
||||
void onKeyDown();
|
||||
void onKeyRepeat();
|
||||
|
@ -56,6 +56,10 @@ class CClient {
|
|||
IOutputStream* m_output;
|
||||
ISecondaryScreen* m_screen;
|
||||
const CNetworkAddress* m_serverAddress;
|
||||
bool m_active;
|
||||
UInt32 m_seqNum;
|
||||
bool m_ownClipboard[kClipboardEnd];
|
||||
IClipboard::Time m_timeClipboard[kClipboardEnd];
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -43,7 +43,8 @@ else { wait(0); exit(1); }
|
|||
|
||||
CServer::CServer() : m_primary(NULL),
|
||||
m_active(NULL),
|
||||
m_primaryInfo(NULL)
|
||||
m_primaryInfo(NULL),
|
||||
m_seqNum(0)
|
||||
{
|
||||
m_socketFactory = NULL;
|
||||
m_securityFactory = NULL;
|
||||
|
@ -94,6 +95,11 @@ void CServer::run()
|
|||
}
|
||||
}
|
||||
|
||||
void CServer::quit()
|
||||
{
|
||||
m_primary->stop();
|
||||
}
|
||||
|
||||
void CServer::setScreenMap(const CScreenMap& screenMap)
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
|
@ -150,35 +156,43 @@ void CServer::setInfo(const CString& client,
|
|||
|
||||
void CServer::grabClipboard(ClipboardID id)
|
||||
{
|
||||
grabClipboard(id, m_primaryInfo->m_name);
|
||||
grabClipboard(id, 0, m_primaryInfo->m_name);
|
||||
}
|
||||
|
||||
void CServer::grabClipboard(
|
||||
ClipboardID id, const CString& client)
|
||||
ClipboardID id, UInt32 seqNum,
|
||||
const CString& client)
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
ClipboardInfo& clipboard = m_clipboards[id];
|
||||
CClipboardInfo& clipboard = m_clipboards[id];
|
||||
|
||||
// client must be connected
|
||||
// screen must be connected
|
||||
CScreenList::iterator index = m_screens.find(client);
|
||||
if (index == m_screens.end()) {
|
||||
throw XBadClient();
|
||||
}
|
||||
|
||||
// ignore grab if sequence number is old. always allow primary
|
||||
// screen to grab.
|
||||
if (client != m_primaryInfo->m_name &&
|
||||
seqNum < clipboard.m_clipboardSeqNum) {
|
||||
log((CLOG_INFO "ignored client \"%s\" grab of clipboard %d", client.c_str(), id));
|
||||
return;
|
||||
}
|
||||
|
||||
// mark screen as owning clipboard
|
||||
log((CLOG_NOTE "client \"%s\" grabbed clipboard %d from \"%s\"", client.c_str(), id, clipboard.m_clipboardOwner.c_str()));
|
||||
|
||||
// save the clipboard owner
|
||||
clipboard.m_clipboardOwner = client;
|
||||
clipboard.m_clipboardSeqNum = seqNum;
|
||||
|
||||
// mark client as having the clipboard data
|
||||
// no screens have the new clipboard except the sender
|
||||
clearGotClipboard(id);
|
||||
index->second->m_gotClipboard[id] = true;
|
||||
|
||||
// tell all other clients to take ownership of clipboard and mark
|
||||
// them as not having the data yet.
|
||||
// tell all other screens to take ownership of clipboard
|
||||
for (index = m_screens.begin(); index != m_screens.end(); ++index) {
|
||||
if (index->first != client) {
|
||||
CScreenInfo* info = index->second;
|
||||
info->m_gotClipboard[id] = false;
|
||||
if (info->m_protocol == NULL) {
|
||||
m_primary->grabClipboard(id);
|
||||
}
|
||||
|
@ -188,11 +202,8 @@ void CServer::grabClipboard(
|
|||
}
|
||||
}
|
||||
|
||||
// increment the clipboard sequence number so we can identify the
|
||||
// clipboard query's response.
|
||||
++clipboard.m_clipboardSeqNum;
|
||||
|
||||
// begin getting the clipboard data
|
||||
// get the clipboard data if primary has it, otherwise mark the
|
||||
// clipboard data as unknown.
|
||||
if (m_active->m_protocol == NULL) {
|
||||
// get clipboard immediately from primary screen
|
||||
m_primary->getClipboard(id, &clipboard.m_clipboard);
|
||||
|
@ -201,43 +212,42 @@ void CServer::grabClipboard(
|
|||
}
|
||||
else {
|
||||
// clear out the clipboard since existing data is now out of date.
|
||||
if (clipboard.m_clipboard.open()) {
|
||||
if (clipboard.m_clipboard.open(0)) {
|
||||
clipboard.m_clipboard.close();
|
||||
}
|
||||
clipboard.m_clipboardReady = false;
|
||||
|
||||
// send request but don't wait for reply
|
||||
m_active->m_protocol->sendQueryClipboard(id,
|
||||
clipboard.m_clipboardSeqNum);
|
||||
}
|
||||
}
|
||||
|
||||
void CServer::setClipboard(ClipboardID id,
|
||||
UInt32 seqNum, const CString& data)
|
||||
{
|
||||
// update the clipboard if the sequence number matches
|
||||
CLock lock(&m_mutex);
|
||||
ClipboardInfo& clipboard = m_clipboards[id];
|
||||
if (seqNum == clipboard.m_clipboardSeqNum) {
|
||||
// unmarshall into our clipboard buffer
|
||||
clipboard.m_clipboardData = data;
|
||||
clipboard.m_clipboard.unmarshall(clipboard.m_clipboardData);
|
||||
clipboard.m_clipboardReady = true;
|
||||
CClipboardInfo& clipboard = m_clipboards[id];
|
||||
|
||||
// if the active client doesn't have the clipboard data
|
||||
// (and it won't unless the client is the one sending us
|
||||
// the data) then send the data now.
|
||||
if (!m_active->m_gotClipboard[id]) {
|
||||
if (m_active->m_protocol == NULL) {
|
||||
m_primary->setClipboard(id, &clipboard.m_clipboard);
|
||||
}
|
||||
else {
|
||||
m_active->m_protocol->sendClipboard(id,
|
||||
clipboard.m_clipboardData);
|
||||
}
|
||||
m_active->m_gotClipboard[id] = true;
|
||||
// ignore update if sequence number is old
|
||||
if (seqNum < clipboard.m_clipboardSeqNum) {
|
||||
log((CLOG_INFO "ignored client \"%s\" update of clipboard %d", clipboard.m_clipboardOwner.c_str(), id));
|
||||
return;
|
||||
}
|
||||
|
||||
// unmarshall into our clipboard buffer
|
||||
log((CLOG_NOTE "client \"%s\" updated clipboard %d", clipboard.m_clipboardOwner.c_str(), id));
|
||||
clipboard.m_clipboardReady = true;
|
||||
clipboard.m_clipboardData = data;
|
||||
clipboard.m_clipboard.unmarshall(clipboard.m_clipboardData, 0);
|
||||
|
||||
// all screens have an out-of-date clipboard except the sender
|
||||
clearGotClipboard(id);
|
||||
CScreenList::const_iterator index =
|
||||
m_screens.find(clipboard.m_clipboardOwner);
|
||||
if (index != m_screens.end()) {
|
||||
index->second->m_gotClipboard[id] = true;
|
||||
}
|
||||
|
||||
// send the new clipboard to the active screen (will do nothing if
|
||||
// the active screen is the one sending the new clipboard)
|
||||
sendClipboard(id);
|
||||
}
|
||||
|
||||
bool CServer::onCommandKey(KeyID /*id*/,
|
||||
|
@ -492,8 +502,19 @@ void CServer::switchScreen(CScreenInfo* dst,
|
|||
// since that's a waste of time we skip that and just warp the
|
||||
// mouse.
|
||||
if (m_active != dst) {
|
||||
// note if we're leaving the primary screen
|
||||
const bool leavingPrimary = (m_active->m_protocol == NULL);
|
||||
|
||||
// if leaving the primary screen then update the clipboards
|
||||
// that it owns
|
||||
if (leavingPrimary) {
|
||||
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
|
||||
updatePrimaryClipboard(id);
|
||||
}
|
||||
}
|
||||
|
||||
// leave active screen
|
||||
if (m_active->m_protocol == NULL) {
|
||||
if (leavingPrimary) {
|
||||
m_primary->leave();
|
||||
}
|
||||
else {
|
||||
|
@ -503,27 +524,20 @@ void CServer::switchScreen(CScreenInfo* dst,
|
|||
// cut over
|
||||
m_active = dst;
|
||||
|
||||
// increment enter sequence number
|
||||
++m_seqNum;
|
||||
|
||||
// enter new screen
|
||||
if (m_active->m_protocol == NULL) {
|
||||
m_primary->enter(x, y);
|
||||
}
|
||||
else {
|
||||
m_active->m_protocol->sendEnter(x, y);
|
||||
m_active->m_protocol->sendEnter(x, y, m_seqNum);
|
||||
}
|
||||
|
||||
// send the clipboard data if we haven't done so yet
|
||||
// send the clipboard data to new active screen
|
||||
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
|
||||
ClipboardInfo& clipboard = m_clipboards[id];
|
||||
if (clipboard.m_clipboardReady && !m_active->m_gotClipboard[id]) {
|
||||
if (m_active->m_protocol == NULL) {
|
||||
m_primary->setClipboard(id, &clipboard.m_clipboard);
|
||||
}
|
||||
else {
|
||||
m_active->m_protocol->sendClipboard(id,
|
||||
clipboard.m_clipboardData);
|
||||
}
|
||||
m_active->m_gotClipboard[id] = true;
|
||||
}
|
||||
sendClipboard(id);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -889,9 +903,57 @@ void CServer::handshakeClient(void* vsocket)
|
|||
}
|
||||
}
|
||||
|
||||
void CServer::quit()
|
||||
void CServer::clearGotClipboard(ClipboardID id)
|
||||
{
|
||||
m_primary->stop();
|
||||
for (CScreenList::const_iterator index = m_screens.begin();
|
||||
index != m_screens.end(); ++index) {
|
||||
index->second->m_gotClipboard[id] = false;
|
||||
}
|
||||
}
|
||||
|
||||
void CServer::sendClipboard(ClipboardID id)
|
||||
{
|
||||
// do nothing if clipboard was already sent
|
||||
if (!m_active->m_gotClipboard[id]) {
|
||||
CClipboardInfo& clipboard = m_clipboards[id];
|
||||
if (clipboard.m_clipboardReady) {
|
||||
// send it
|
||||
if (m_active->m_protocol == NULL) {
|
||||
m_primary->setClipboard(id, &clipboard.m_clipboard);
|
||||
}
|
||||
else {
|
||||
m_active->m_protocol->sendClipboard(id,
|
||||
clipboard.m_clipboardData);
|
||||
}
|
||||
|
||||
// clipboard has been sent
|
||||
m_active->m_gotClipboard[id] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CServer::updatePrimaryClipboard(ClipboardID id)
|
||||
{
|
||||
CClipboardInfo& clipboard = m_clipboards[id];
|
||||
|
||||
// if leaving primary and the primary owns the clipboard
|
||||
// then update it.
|
||||
if (clipboard.m_clipboardOwner == m_primaryInfo->m_name) {
|
||||
assert(clipboard.m_clipboardReady == true);
|
||||
|
||||
// save clipboard time
|
||||
IClipboard::Time time = clipboard.m_clipboard.getTime();
|
||||
|
||||
// update
|
||||
m_primary->getClipboard(id, &clipboard.m_clipboard);
|
||||
|
||||
// if clipboard changed then other screens have an
|
||||
// out-of-date clipboard.
|
||||
if (time != clipboard.m_clipboard.getTime()) {
|
||||
clearGotClipboard(id);
|
||||
m_primaryInfo->m_gotClipboard[id] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME -- use factory to create screen
|
||||
|
@ -904,6 +966,9 @@ void CServer::openPrimaryScreen()
|
|||
{
|
||||
assert(m_primary == NULL);
|
||||
|
||||
// reset sequence number
|
||||
m_seqNum = 0;
|
||||
|
||||
// open screen
|
||||
log((CLOG_DEBUG1 "creating primary screen"));
|
||||
#if defined(CONFIG_PLATFORM_WIN32)
|
||||
|
@ -927,7 +992,7 @@ void CServer::openPrimaryScreen()
|
|||
// set the clipboard owner to the primary screen and then get the
|
||||
// current clipboard data.
|
||||
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
|
||||
ClipboardInfo& clipboard = m_clipboards[id];
|
||||
CClipboardInfo& clipboard = m_clipboards[id];
|
||||
m_primary->getClipboard(id, &clipboard.m_clipboard);
|
||||
clipboard.m_clipboardData = clipboard.m_clipboard.marshall();
|
||||
clipboard.m_clipboardReady = true;
|
||||
|
@ -1098,10 +1163,10 @@ CServer::CScreenInfo::~CScreenInfo()
|
|||
|
||||
|
||||
//
|
||||
// CServer::ClipboardInfo
|
||||
// CServer::CClipboardInfo
|
||||
//
|
||||
|
||||
CServer::ClipboardInfo::ClipboardInfo() :
|
||||
CServer::CClipboardInfo::CClipboardInfo() :
|
||||
m_clipboard(),
|
||||
m_clipboardData(),
|
||||
m_clipboardOwner(),
|
||||
|
|
|
@ -49,7 +49,8 @@ class CServer {
|
|||
// handle messages from clients
|
||||
void setInfo(const CString& clientName,
|
||||
SInt32 w, SInt32 h, SInt32 zoneSize);
|
||||
void grabClipboard(ClipboardID, const CString& clientName);
|
||||
void grabClipboard(ClipboardID,
|
||||
UInt32 seqNum, const CString& clientName);
|
||||
void setClipboard(ClipboardID,
|
||||
UInt32 seqNum, const CString& data);
|
||||
|
||||
|
@ -126,6 +127,15 @@ class CServer {
|
|||
void openPrimaryScreen();
|
||||
void closePrimaryScreen();
|
||||
|
||||
// clear gotClipboard flags in all screens
|
||||
void clearGotClipboard(ClipboardID);
|
||||
|
||||
// send clipboard to the active screen if it doesn't already have it
|
||||
void sendClipboard(ClipboardID);
|
||||
|
||||
// update the clipboard if owned by the primary screen
|
||||
void updatePrimaryClipboard(ClipboardID);
|
||||
|
||||
// cancel running threads
|
||||
void cleanupThreads();
|
||||
|
||||
|
@ -148,9 +158,9 @@ class CServer {
|
|||
private:
|
||||
typedef std::list<CThread*> CThreadList;
|
||||
typedef std::map<CString, CScreenInfo*> CScreenList;
|
||||
class ClipboardInfo {
|
||||
class CClipboardInfo {
|
||||
public:
|
||||
ClipboardInfo();
|
||||
CClipboardInfo();
|
||||
|
||||
public:
|
||||
CClipboard m_clipboard;
|
||||
|
@ -174,11 +184,14 @@ class CServer {
|
|||
CScreenInfo* m_active;
|
||||
CScreenInfo* m_primaryInfo;
|
||||
|
||||
// the sequence number of enter messages
|
||||
UInt32 m_seqNum;
|
||||
|
||||
SInt32 m_x, m_y;
|
||||
|
||||
CScreenMap m_screenMap;
|
||||
|
||||
ClipboardInfo m_clipboards[kClipboardEnd];
|
||||
CClipboardInfo m_clipboards[kClipboardEnd];
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -31,11 +31,10 @@ class CServerProtocol : public IServerProtocol {
|
|||
virtual void run() = 0;
|
||||
virtual void queryInfo() = 0;
|
||||
virtual void sendClose() = 0;
|
||||
virtual void sendEnter(SInt32 xAbs, SInt32 yAbs) = 0;
|
||||
virtual void sendEnter(SInt32 xAbs, SInt32 yAbs, UInt32 seqNum) = 0;
|
||||
virtual void sendLeave() = 0;
|
||||
virtual void sendClipboard(ClipboardID, const CString&) = 0;
|
||||
virtual void sendGrabClipboard(ClipboardID) = 0;
|
||||
virtual void sendQueryClipboard(ClipboardID, UInt32 seqNum) = 0;
|
||||
virtual void sendScreenSaver(bool on) = 0;
|
||||
virtual void sendKeyDown(KeyID, KeyModifierMask) = 0;
|
||||
virtual void sendKeyRepeat(KeyID, KeyModifierMask, SInt32 count) = 0;
|
||||
|
|
|
@ -91,10 +91,10 @@ void CServerProtocol1_0::sendClose()
|
|||
}
|
||||
|
||||
void CServerProtocol1_0::sendEnter(
|
||||
SInt32 xAbs, SInt32 yAbs)
|
||||
SInt32 xAbs, SInt32 yAbs, UInt32 seqNum)
|
||||
{
|
||||
log((CLOG_DEBUG1 "send enter to \"%s\", %d,%d", getClient().c_str(), xAbs, yAbs));
|
||||
CProtocolUtil::writef(getOutputStream(), kMsgCEnter, xAbs, yAbs);
|
||||
log((CLOG_DEBUG1 "send enter to \"%s\", %d,%d %d", getClient().c_str(), xAbs, yAbs, seqNum));
|
||||
CProtocolUtil::writef(getOutputStream(), kMsgCEnter, xAbs, yAbs, seqNum);
|
||||
}
|
||||
|
||||
void CServerProtocol1_0::sendLeave()
|
||||
|
@ -113,14 +113,7 @@ void CServerProtocol1_0::sendClipboard(
|
|||
void CServerProtocol1_0::sendGrabClipboard(ClipboardID id)
|
||||
{
|
||||
log((CLOG_DEBUG "send grab clipboard %d to \"%s\"", id, getClient().c_str()));
|
||||
CProtocolUtil::writef(getOutputStream(), kMsgCClipboard, id);
|
||||
}
|
||||
|
||||
void CServerProtocol1_0::sendQueryClipboard(
|
||||
ClipboardID id, UInt32 seqNum)
|
||||
{
|
||||
log((CLOG_DEBUG "query clipboard %d to \"%s\"", id, getClient().c_str()));
|
||||
CProtocolUtil::writef(getOutputStream(), kMsgQClipboard, id, seqNum);
|
||||
CProtocolUtil::writef(getOutputStream(), kMsgCClipboard, id, 0);
|
||||
}
|
||||
|
||||
void CServerProtocol1_0::sendScreenSaver(bool on)
|
||||
|
@ -207,7 +200,8 @@ void CServerProtocol1_0::recvClipboard()
|
|||
void CServerProtocol1_0::recvGrabClipboard()
|
||||
{
|
||||
ClipboardID id;
|
||||
CProtocolUtil::readf(getInputStream(), kMsgCClipboard + 4, &id);
|
||||
log((CLOG_DEBUG "received client \"%s\" grabbed clipboard %d", getClient().c_str(), id));
|
||||
getServer()->grabClipboard(id, getClient());
|
||||
UInt32 seqNum;
|
||||
CProtocolUtil::readf(getInputStream(), kMsgCClipboard + 4, &id, &seqNum);
|
||||
log((CLOG_DEBUG "received client \"%s\" grabbed clipboard %d seqnum=%d", getClient().c_str(), id, seqNum));
|
||||
getServer()->grabClipboard(id, seqNum, getClient());
|
||||
}
|
||||
|
|
|
@ -16,11 +16,10 @@ class CServerProtocol1_0 : public CServerProtocol {
|
|||
virtual void run();
|
||||
virtual void queryInfo();
|
||||
virtual void sendClose();
|
||||
virtual void sendEnter(SInt32 xAbs, SInt32 yAbs);
|
||||
virtual void sendEnter(SInt32 xAbs, SInt32 yAbs, UInt32 seqNum);
|
||||
virtual void sendLeave();
|
||||
virtual void sendClipboard(ClipboardID, const CString&);
|
||||
virtual void sendGrabClipboard(ClipboardID);
|
||||
virtual void sendQueryClipboard(ClipboardID, UInt32 seqNum);
|
||||
virtual void sendScreenSaver(bool on);
|
||||
virtual void sendKeyDown(KeyID, KeyModifierMask);
|
||||
virtual void sendKeyRepeat(KeyID, KeyModifierMask, SInt32 count);
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
|
||||
CClipboard::CClipboard()
|
||||
{
|
||||
// do nothing
|
||||
open(0);
|
||||
close();
|
||||
}
|
||||
|
||||
CClipboard::~CClipboard()
|
||||
|
@ -14,13 +15,17 @@ CClipboard::~CClipboard()
|
|||
// do nothing
|
||||
}
|
||||
|
||||
bool CClipboard::open()
|
||||
bool CClipboard::open(Time time)
|
||||
{
|
||||
// clear all data
|
||||
for (SInt32 index = 0; index < kNumFormats; ++index) {
|
||||
m_data[index] = "";
|
||||
m_added[index] = false;
|
||||
}
|
||||
|
||||
// save time
|
||||
m_time = time;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -35,6 +40,11 @@ void CClipboard::add(EFormat format, const CString& data)
|
|||
m_added[format] = true;
|
||||
}
|
||||
|
||||
CClipboard::Time CClipboard::getTime() const
|
||||
{
|
||||
return m_time;
|
||||
}
|
||||
|
||||
bool CClipboard::has(EFormat format) const
|
||||
{
|
||||
return m_added[format];
|
||||
|
@ -47,7 +57,19 @@ CString CClipboard::get(EFormat format) const
|
|||
|
||||
void CClipboard::copy(IClipboard* dst, const IClipboard* src)
|
||||
{
|
||||
if (dst->open()) {
|
||||
assert(dst != NULL);
|
||||
assert(src != NULL);
|
||||
|
||||
copy(dst, src, src->getTime());
|
||||
}
|
||||
|
||||
void CClipboard::copy(IClipboard* dst,
|
||||
const IClipboard* src, Time time)
|
||||
{
|
||||
assert(dst != NULL);
|
||||
assert(src != NULL);
|
||||
|
||||
if (dst->open(time)) {
|
||||
for (SInt32 format = 0; format != IClipboard::kNumFormats; ++format) {
|
||||
IClipboard::EFormat eFormat = (IClipboard::EFormat)format;
|
||||
if (src->has(eFormat)) {
|
||||
|
@ -58,12 +80,12 @@ void CClipboard::copy(IClipboard* dst, const IClipboard* src)
|
|||
}
|
||||
}
|
||||
|
||||
void CClipboard::unmarshall(const CString& data)
|
||||
void CClipboard::unmarshall(const CString& data, Time time)
|
||||
{
|
||||
const char* index = data.data();
|
||||
|
||||
// clear existing data
|
||||
open();
|
||||
open(time);
|
||||
|
||||
// read the number of formats
|
||||
const UInt32 numFormats = readUInt32(index);
|
||||
|
|
|
@ -16,7 +16,7 @@ class CClipboard : public IClipboard {
|
|||
// manipulators
|
||||
|
||||
// unmarshall clipboard data
|
||||
void unmarshall(const CString& data);
|
||||
void unmarshall(const CString& data, Time);
|
||||
|
||||
// accessors
|
||||
|
||||
|
@ -24,9 +24,10 @@ class CClipboard : public IClipboard {
|
|||
CString marshall() const;
|
||||
|
||||
// IClipboard overrides
|
||||
virtual bool open();
|
||||
virtual bool open(Time);
|
||||
virtual void close();
|
||||
virtual void add(EFormat, const CString& data);
|
||||
virtual Time getTime() const;
|
||||
virtual bool has(EFormat) const;
|
||||
virtual CString get(EFormat) const;
|
||||
|
||||
|
@ -34,14 +35,17 @@ class CClipboard : public IClipboard {
|
|||
|
||||
// transfer all the data in one clipboard to another. the
|
||||
// clipboards can be of any concrete clipboard type (and
|
||||
// they don't have to be the same type).
|
||||
// they don't have to be the same type). this also sets
|
||||
// the timestamp to time, if provided, or the time in src.
|
||||
static void copy(IClipboard* dst, const IClipboard* src);
|
||||
static void copy(IClipboard* dst, const IClipboard* src, Time);
|
||||
|
||||
private:
|
||||
UInt32 readUInt32(const char*) const;
|
||||
void writeUInt32(CString*, UInt32) const;
|
||||
|
||||
private:
|
||||
Time m_time;
|
||||
bool m_added[kNumFormats];
|
||||
CString m_data[kNumFormats];
|
||||
};
|
||||
|
|
|
@ -222,16 +222,15 @@ bool CXWindowsScreen::setDisplayClipboard(
|
|||
if (XGetSelectionOwner(m_display, m_atomClipboard[id]) == requestor) {
|
||||
// we got the selection
|
||||
log((CLOG_INFO "grabbed clipboard at %d", timestamp));
|
||||
m_clipboards[id].m_gotClipboard = timestamp;
|
||||
m_clipboards[id].m_lostClipboard = CurrentTime;
|
||||
|
||||
if (clipboard != NULL) {
|
||||
// save clipboard to serve requests
|
||||
CClipboard::copy(&m_clipboards[id].m_clipboard, clipboard);
|
||||
CClipboard::copy(&m_clipboards[id].m_clipboard,
|
||||
clipboard, timestamp);
|
||||
}
|
||||
else {
|
||||
// clear clipboard
|
||||
if (m_clipboards[id].m_clipboard.open()) {
|
||||
if (m_clipboards[id].m_clipboard.open(timestamp)) {
|
||||
m_clipboards[id].m_clipboard.close();
|
||||
}
|
||||
}
|
||||
|
@ -250,8 +249,10 @@ void CXWindowsScreen::getDisplayClipboard(
|
|||
assert(clipboard != NULL);
|
||||
assert(requestor != None);
|
||||
|
||||
// FIXME -- don't update clipboard object if clipboard hasn't changed
|
||||
|
||||
// clear the clipboard object
|
||||
if (!clipboard->open())
|
||||
if (!clipboard->open(timestamp))
|
||||
return;
|
||||
|
||||
// block others from using the display while we get the clipboard.
|
||||
|
@ -904,12 +905,12 @@ bool CXWindowsScreen::sendClipboardTimestamp(
|
|||
log((CLOG_DEBUG1 "handling clipboard request for TIMESTAMP"));
|
||||
|
||||
// FIXME -- handle Alloc errors (by returning false)
|
||||
Time time = m_clipboards[id].m_clipboard.getTime();
|
||||
XChangeProperty(m_display, requestor, property,
|
||||
m_atomInteger,
|
||||
8 * sizeof(m_clipboards[id].m_gotClipboard),
|
||||
32,
|
||||
PropModeReplace,
|
||||
reinterpret_cast<unsigned char*>(
|
||||
&m_clipboards[id].m_gotClipboard),
|
||||
reinterpret_cast<unsigned char*>(time),
|
||||
1);
|
||||
return true;
|
||||
}
|
||||
|
@ -935,7 +936,7 @@ bool CXWindowsScreen::wasOwnedAtTime(
|
|||
const CClipboardInfo& clipboard = m_clipboards[id];
|
||||
|
||||
// not owned if we've never owned the selection
|
||||
if (clipboard.m_gotClipboard == CurrentTime)
|
||||
if (clipboard.m_clipboard.getTime() == CurrentTime)
|
||||
return false;
|
||||
|
||||
// if time is CurrentTime then return true if we still own the
|
||||
|
@ -953,8 +954,8 @@ bool CXWindowsScreen::wasOwnedAtTime(
|
|||
return false;
|
||||
|
||||
// compare time to range
|
||||
Time duration = clipboard.m_lostClipboard - clipboard.m_gotClipboard;
|
||||
Time when = time - clipboard.m_gotClipboard;
|
||||
Time duration = clipboard.m_lostClipboard - clipboard.m_clipboard.getTime();
|
||||
Time when = time - clipboard.m_clipboard.getTime();
|
||||
return (/*when >= 0 &&*/ when < duration);
|
||||
}
|
||||
|
||||
|
@ -1001,7 +1002,6 @@ Time CXWindowsScreen::getCurrentTimeNoLock(
|
|||
|
||||
CXWindowsScreen::CClipboardInfo::CClipboardInfo() :
|
||||
m_clipboard(),
|
||||
m_gotClipboard(CurrentTime),
|
||||
m_lostClipboard(CurrentTime),
|
||||
m_requests()
|
||||
{
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
#ifndef CXWINDOWSSCREEN_H
|
||||
#define CXWINDOWSSCREEN_H
|
||||
|
||||
#include "CClipboard.h"
|
||||
#include "CMutex.h"
|
||||
#include "BasicTypes.h"
|
||||
#include "ClipboardTypes.h"
|
||||
#include "CClipboard.h"
|
||||
#include "CMutex.h"
|
||||
#include <X11/Xlib.h>
|
||||
#include <map>
|
||||
#include <list>
|
||||
|
@ -74,6 +74,7 @@ class CXWindowsScreen {
|
|||
// copy the clipboard contents to clipboard. requestor must be a
|
||||
// valid window; it will be used to receive the transfer. timestamp
|
||||
// should be the timestamp of the provoking event and not CurrentTime.
|
||||
// if force is false then only update clipboard
|
||||
void getDisplayClipboard(ClipboardID,
|
||||
IClipboard* clipboard,
|
||||
Window requestor, Time timestamp) const;
|
||||
|
@ -149,11 +150,10 @@ class CXWindowsScreen {
|
|||
CClipboardInfo();
|
||||
|
||||
public:
|
||||
// the contents of the clipboard
|
||||
// the contents of the clipboard and the time we got it
|
||||
CClipboard m_clipboard;
|
||||
|
||||
// when we got the clipboard and when we lost it
|
||||
Time m_gotClipboard;
|
||||
// when we lost the clipboard
|
||||
Time m_lostClipboard;
|
||||
|
||||
// the request queues
|
||||
|
|
|
@ -8,6 +8,13 @@ class CString;
|
|||
|
||||
class IClipboard : public IInterface {
|
||||
public:
|
||||
// timestamp type. timestamps are in milliseconds from some
|
||||
// arbitrary starting time. timestamps will wrap around to 0
|
||||
// after about 49 3/4 days.
|
||||
typedef UInt32 Time;
|
||||
|
||||
// known clipboard formats. kNumFormats must be last and
|
||||
// formats must be sequential starting from zero.
|
||||
enum EFormat { kText, kNumFormats };
|
||||
|
||||
// manipulators
|
||||
|
@ -16,8 +23,10 @@ class IClipboard : public IInterface {
|
|||
// only add() may be called between an open() and its
|
||||
// corresponding close(). if open() returns false then
|
||||
// the clipboard could not be opened or grabbed; do not
|
||||
// call close() in that case.
|
||||
virtual bool open() = 0;
|
||||
// call close() in that case. iff open() returns true it
|
||||
// should have saved the timestamp. the timestamp should
|
||||
// be zero before the first successful open.
|
||||
virtual bool open(Time) = 0;
|
||||
|
||||
// close the clipboard. close() must match a preceding open().
|
||||
// this signals that the clipboard has been filled with all the
|
||||
|
@ -33,6 +42,9 @@ class IClipboard : public IInterface {
|
|||
|
||||
// accessors
|
||||
|
||||
// returns the timestamp passed to the last successful open().
|
||||
virtual Time getTime() const = 0;
|
||||
|
||||
// returns true iff the clipboard contains data in the given
|
||||
// format.
|
||||
virtual bool has(EFormat) const = 0;
|
||||
|
|
|
@ -75,7 +75,9 @@ class IPrimaryScreen : public IInterface {
|
|||
// get the size of jump zone
|
||||
virtual SInt32 getJumpZoneSize() const = 0;
|
||||
|
||||
// get the screen's clipboard contents
|
||||
// get the screen's clipboard contents. the implementation can
|
||||
// and should avoid setting the clipboard object if the screen's
|
||||
// clipboard hasn't changed.
|
||||
virtual void getClipboard(ClipboardID, IClipboard*) const = 0;
|
||||
};
|
||||
|
||||
|
|
|
@ -24,11 +24,10 @@ class IServerProtocol : public IInterface {
|
|||
|
||||
// send various messages to client
|
||||
virtual void sendClose() = 0;
|
||||
virtual void sendEnter(SInt32 xAbs, SInt32 yAbs) = 0;
|
||||
virtual void sendEnter(SInt32 xAbs, SInt32 yAbs, UInt32 seqNum) = 0;
|
||||
virtual void sendLeave() = 0;
|
||||
virtual void sendClipboard(ClipboardID, const CString&) = 0;
|
||||
virtual void sendGrabClipboard(ClipboardID) = 0;
|
||||
virtual void sendQueryClipboard(ClipboardID, UInt32 seqNum) = 0;
|
||||
virtual void sendScreenSaver(bool on) = 0;
|
||||
virtual void sendKeyDown(KeyID, KeyModifierMask) = 0;
|
||||
virtual void sendKeyRepeat(KeyID, KeyModifierMask, SInt32 count) = 0;
|
||||
|
|
|
@ -22,17 +22,26 @@ static const char kMsgCClose[] = "CBYE";
|
|||
|
||||
// enter screen: primary -> secondary
|
||||
// entering screen at screen position $1 = x, $2 = y. x,y are
|
||||
// absolute screen coordinates.
|
||||
static const char kMsgCEnter[] = "CINN%2i%2i";
|
||||
// absolute screen coordinates. $3 = sequence number, which is
|
||||
// used to order messages between screens. the secondary screen
|
||||
// must return this number with some messages.
|
||||
static const char kMsgCEnter[] = "CINN%2i%2i%4i";
|
||||
|
||||
// leave screen: primary -> secondary
|
||||
// leaving screen
|
||||
// leaving screen. the secondary screen should send clipboard
|
||||
// data in response to this message for those clipboards that
|
||||
// it has grabbed (i.e. has sent a kMsgCClipboard for and has
|
||||
// not received a kMsgCClipboard for with a greater sequence
|
||||
// number) and that were grabbed or have changed since the
|
||||
// last leave.
|
||||
static const char kMsgCLeave[] = "COUT";
|
||||
|
||||
// grab clipboard: primary <-> secondary
|
||||
// sent by screen when some other app on that screen grabs a
|
||||
// clipboard. $1 = the clipboard identifier.
|
||||
static const char kMsgCClipboard[] = "CCLP%1i";
|
||||
// clipboard. $1 = the clipboard identifier, $2 = sequence number.
|
||||
// secondary screens must use the sequence number passed in the
|
||||
// most recent kMsgCEnter. the primary always sends 0.
|
||||
static const char kMsgCClipboard[] = "CCLP%1i%4i";
|
||||
|
||||
// screensaver change: primary -> secondary
|
||||
// screensaver on primary has started ($1 == 1) or closed ($1 == 0)
|
||||
|
@ -73,9 +82,9 @@ static const char kMsgDMouseWheel[] = "DMWM%2i";
|
|||
|
||||
// clipboard data: primary <-> secondary
|
||||
// $2 = sequence number, $3 = clipboard data. the sequence number
|
||||
// is 0 when sent by the primary. the secondary sends this message
|
||||
// in response to a kMsgQClipboard and uses the sequence number from
|
||||
// that message. $1 = clipboard identifier.
|
||||
// is 0 when sent by the primary. secondary screens should use the
|
||||
// sequence number from the most recent kMsgCEnter. $1 = clipboard
|
||||
// identifier.
|
||||
static const char kMsgDClipboard[] = "DCLP%1i%4i%s";
|
||||
|
||||
// client data: secondary -> primary
|
||||
|
@ -88,12 +97,6 @@ static const char kMsgDInfo[] = "DINF%2i%2i%2i";
|
|||
// query codes
|
||||
//
|
||||
|
||||
// query clipboard: primary -> secondary
|
||||
// $2 = sequence number. the sequence number is an arbitrary value
|
||||
// used by primary to identify the kMsgDClipboard response to a
|
||||
// query. $1 = clipboard identifier.
|
||||
static const char kMsgQClipboard[] = "QCLP%1i%4i";
|
||||
|
||||
// query screen info: primary -> secondary
|
||||
// client should reply with a kMsgDInfo.
|
||||
static const char kMsgQInfo[] = "QINF";
|
||||
|
|
Loading…
Reference in New Issue