Added support for multiple clipboards. This is mainly to

support both PRIMARY and CLIPBOARD selections on X windows.
This commit is contained in:
crs 2002-04-27 14:19:53 +00:00
parent 428166fe85
commit f9170eb139
18 changed files with 468 additions and 251 deletions

View File

@ -85,14 +85,14 @@ void CClient::run(const CNetworkAddress& serverAddress)
} }
} }
void CClient::onClipboardChanged() void CClient::onClipboardChanged(ClipboardID id)
{ {
log((CLOG_DEBUG "sending clipboard changed")); log((CLOG_DEBUG "sending clipboard %d changed", id));
CLock lock(&m_mutex); CLock lock(&m_mutex);
if (m_output != NULL) { if (m_output != NULL) {
// m_output can be NULL if the screen calls this method // m_output can be NULL if the screen calls this method
// before we've gotten around to connecting to the server. // before we've gotten around to connecting to the server.
CProtocolUtil::writef(m_output, kMsgCClipboard); CProtocolUtil::writef(m_output, kMsgCClipboard, id);
} }
} }
@ -318,7 +318,12 @@ void CClient::onLeave()
void CClient::onGrabClipboard() void CClient::onGrabClipboard()
{ {
m_screen->grabClipboard(); ClipboardID id;
{
CLock lock(&m_mutex);
CProtocolUtil::readf(m_input, kMsgCClipboard + 4, &id);
}
m_screen->grabClipboard(id);
} }
void CClient::onScreenSaver() void CClient::onScreenSaver()
@ -345,45 +350,47 @@ void CClient::onQueryInfo()
void CClient::onQueryClipboard() void CClient::onQueryClipboard()
{ {
// parse message // parse message
ClipboardID id;
UInt32 seqNum; UInt32 seqNum;
CClipboard clipboard; CClipboard clipboard;
{ {
CLock lock(&m_mutex); CLock lock(&m_mutex);
CProtocolUtil::readf(m_input, kMsgQClipboard + 4, &seqNum); CProtocolUtil::readf(m_input, kMsgQClipboard + 4, &id, &seqNum);
} }
log((CLOG_DEBUG "received query clipboard seqnum=%d", seqNum)); log((CLOG_DEBUG "received query clipboard %d seqnum=%d", id, seqNum));
// get screen's clipboard data // get screen's clipboard data
m_screen->getClipboard(&clipboard); m_screen->getClipboard(id, &clipboard);
// marshall the data // marshall the data
CString data = clipboard.marshall(); CString data = clipboard.marshall();
// send it // send it
log((CLOG_DEBUG "sending clipboard seqnum=%d, size=%d", seqNum, data.size())); log((CLOG_DEBUG "sending clipboard %d seqnum=%d, size=%d", id, seqNum, data.size()));
{ {
CLock lock(&m_mutex); CLock lock(&m_mutex);
CProtocolUtil::writef(m_output, kMsgDClipboard, seqNum, &data); CProtocolUtil::writef(m_output, kMsgDClipboard, id, seqNum, &data);
} }
} }
void CClient::onSetClipboard() void CClient::onSetClipboard()
{ {
ClipboardID id;
CString data; CString data;
{ {
// parse message // parse message
UInt32 seqNum; UInt32 seqNum;
CLock lock(&m_mutex); CLock lock(&m_mutex);
CProtocolUtil::readf(m_input, kMsgDClipboard + 4, &seqNum, &data); CProtocolUtil::readf(m_input, kMsgDClipboard + 4, &id, &seqNum, &data);
} }
log((CLOG_DEBUG "received clipboard size=%d", data.size())); log((CLOG_DEBUG "received clipboard %d size=%d", id, data.size()));
// unmarshall // unmarshall
CClipboard clipboard; CClipboard clipboard;
clipboard.unmarshall(data); clipboard.unmarshall(data);
// set screen's clipboard // set screen's clipboard
m_screen->setClipboard(&clipboard); m_screen->setClipboard(id, &clipboard);
} }
void CClient::onKeyDown() void CClient::onKeyDown()

View File

@ -4,6 +4,7 @@
#include "CMutex.h" #include "CMutex.h"
#include "CString.h" #include "CString.h"
#include "BasicTypes.h" #include "BasicTypes.h"
#include "ClipboardTypes.h"
class CNetworkAddress; class CNetworkAddress;
class IInputStream; class IInputStream;
@ -20,7 +21,7 @@ class CClient {
void run(const CNetworkAddress& serverAddress); void run(const CNetworkAddress& serverAddress);
// handle events on client's screen // handle events on client's screen
void onClipboardChanged(); void onClipboardChanged(ClipboardID);
// accessors // accessors

View File

@ -63,7 +63,8 @@ void CXWindowsSecondaryScreen::run()
// selection owner. report that to the server. // selection owner. report that to the server.
if (lostClipboard(xevent.xselectionclear.selection, if (lostClipboard(xevent.xselectionclear.selection,
xevent.xselectionclear.time)) { xevent.xselectionclear.time)) {
m_client->onClipboardChanged(); m_client->onClipboardChanged(getClipboardID(
xevent.xselectionclear.selection));
} }
break; break;
@ -260,16 +261,16 @@ void CXWindowsSecondaryScreen::mouseWheel(SInt32)
} }
void CXWindowsSecondaryScreen::setClipboard( void CXWindowsSecondaryScreen::setClipboard(
const IClipboard* clipboard) ClipboardID id, const IClipboard* clipboard)
{ {
// FIXME -- don't use CurrentTime // FIXME -- don't use CurrentTime
setDisplayClipboard(clipboard, m_window, CurrentTime); setDisplayClipboard(id, clipboard, m_window, CurrentTime);
} }
void CXWindowsSecondaryScreen::grabClipboard() void CXWindowsSecondaryScreen::grabClipboard(ClipboardID id)
{ {
// FIXME -- don't use CurrentTime // FIXME -- don't use CurrentTime
setDisplayClipboard(NULL, m_window, CurrentTime); setDisplayClipboard(id, NULL, m_window, CurrentTime);
} }
void CXWindowsSecondaryScreen::getSize( void CXWindowsSecondaryScreen::getSize(
@ -284,10 +285,10 @@ SInt32 CXWindowsSecondaryScreen::getJumpZoneSize() const
} }
void CXWindowsSecondaryScreen::getClipboard( void CXWindowsSecondaryScreen::getClipboard(
IClipboard* clipboard) const ClipboardID id, IClipboard* clipboard) const
{ {
// FIXME -- don't use CurrentTime // FIXME -- don't use CurrentTime
getDisplayClipboard(clipboard, m_window, CurrentTime); getDisplayClipboard(id, clipboard, m_window, CurrentTime);
} }
void CXWindowsSecondaryScreen::onOpenDisplay() void CXWindowsSecondaryScreen::onOpenDisplay()

View File

@ -24,11 +24,11 @@ class CXWindowsSecondaryScreen : public CXWindowsScreen, public ISecondaryScreen
virtual void mouseUp(ButtonID); virtual void mouseUp(ButtonID);
virtual void mouseMove(SInt32 xAbsolute, SInt32 yAbsolute); virtual void mouseMove(SInt32 xAbsolute, SInt32 yAbsolute);
virtual void mouseWheel(SInt32 delta); virtual void mouseWheel(SInt32 delta);
virtual void setClipboard(const IClipboard*); virtual void setClipboard(ClipboardID, const IClipboard*);
virtual void grabClipboard(); virtual void grabClipboard(ClipboardID);
virtual void getSize(SInt32* width, SInt32* height) const; virtual void getSize(SInt32* width, SInt32* height) const;
virtual SInt32 getJumpZoneSize() const; virtual SInt32 getJumpZoneSize() const;
virtual void getClipboard(IClipboard*) const; virtual void getClipboard(ClipboardID, IClipboard*) const;
protected: protected:
// CXWindowsScreen overrides // CXWindowsScreen overrides

View File

@ -43,9 +43,7 @@ else { wait(0); exit(1); }
CServer::CServer() : m_primary(NULL), CServer::CServer() : m_primary(NULL),
m_active(NULL), m_active(NULL),
m_primaryInfo(NULL), m_primaryInfo(NULL)
m_clipboardSeqNum(0),
m_clipboardReady(false)
{ {
m_socketFactory = NULL; m_socketFactory = NULL;
m_securityFactory = NULL; m_securityFactory = NULL;
@ -150,14 +148,16 @@ void CServer::setInfo(const CString& client,
log((CLOG_NOTE "client \"%s\" size=%dx%d zone=%d", client.c_str(), w, h, zoneSize)); log((CLOG_NOTE "client \"%s\" size=%dx%d zone=%d", client.c_str(), w, h, zoneSize));
} }
void CServer::grabClipboard() void CServer::grabClipboard(ClipboardID id)
{ {
grabClipboard(m_primaryInfo->m_name); grabClipboard(id, m_primaryInfo->m_name);
} }
void CServer::grabClipboard(const CString& client) void CServer::grabClipboard(
ClipboardID id, const CString& client)
{ {
CLock lock(&m_mutex); CLock lock(&m_mutex);
ClipboardInfo& clipboard = m_clipboards[id];
// client must be connected // client must be connected
CScreenList::iterator index = m_screens.find(client); CScreenList::iterator index = m_screens.find(client);
@ -165,74 +165,77 @@ void CServer::grabClipboard(const CString& client)
throw XBadClient(); throw XBadClient();
} }
log((CLOG_NOTE "client \"%s\" grabbed clipboard from \"%s\"", client.c_str(), m_clipboardOwner.c_str())); log((CLOG_NOTE "client \"%s\" grabbed clipboard %d from \"%s\"", client.c_str(), id, clipboard.m_clipboardOwner.c_str()));
// save the clipboard owner // save the clipboard owner
m_clipboardOwner = client; clipboard.m_clipboardOwner = client;
// mark client as having the clipboard data // mark client as having the clipboard data
index->second->m_gotClipboard = true; index->second->m_gotClipboard[id] = true;
// tell all other clients to take ownership of clipboard and mark // tell all other clients to take ownership of clipboard and mark
// them as not having the data yet. // them as not having the data yet.
for (index = m_screens.begin(); index != m_screens.end(); ++index) { for (index = m_screens.begin(); index != m_screens.end(); ++index) {
if (index->first != client) { if (index->first != client) {
CScreenInfo* info = index->second; CScreenInfo* info = index->second;
info->m_gotClipboard = false; info->m_gotClipboard[id] = false;
if (info->m_protocol == NULL) { if (info->m_protocol == NULL) {
m_primary->grabClipboard(); m_primary->grabClipboard(id);
} }
else { else {
info->m_protocol->sendGrabClipboard(); info->m_protocol->sendGrabClipboard(id);
} }
} }
} }
// increment the clipboard sequence number so we can identify the // increment the clipboard sequence number so we can identify the
// clipboard query's response. // clipboard query's response.
++m_clipboardSeqNum; ++clipboard.m_clipboardSeqNum;
// begin getting the clipboard data // begin getting the clipboard data
if (m_active->m_protocol == NULL) { if (m_active->m_protocol == NULL) {
// get clipboard immediately from primary screen // get clipboard immediately from primary screen
m_primary->getClipboard(&m_clipboard); m_primary->getClipboard(id, &clipboard.m_clipboard);
m_clipboardData = m_clipboard.marshall(); clipboard.m_clipboardData = clipboard.m_clipboard.marshall();
m_clipboardReady = true; clipboard.m_clipboardReady = true;
} }
else { else {
// clear out the clipboard since existing data is now out of date. // clear out the clipboard since existing data is now out of date.
if (m_clipboard.open()) { if (clipboard.m_clipboard.open()) {
m_clipboard.close(); clipboard.m_clipboard.close();
} }
m_clipboardReady = false; clipboard.m_clipboardReady = false;
// send request but don't wait for reply // send request but don't wait for reply
m_active->m_protocol->sendQueryClipboard(m_clipboardSeqNum); m_active->m_protocol->sendQueryClipboard(id,
clipboard.m_clipboardSeqNum);
} }
} }
void CServer::setClipboard( void CServer::setClipboard(ClipboardID id,
UInt32 seqNum, const CString& data) UInt32 seqNum, const CString& data)
{ {
// update the clipboard if the sequence number matches // update the clipboard if the sequence number matches
CLock lock(&m_mutex); CLock lock(&m_mutex);
if (seqNum == m_clipboardSeqNum) { ClipboardInfo& clipboard = m_clipboards[id];
if (seqNum == clipboard.m_clipboardSeqNum) {
// unmarshall into our clipboard buffer // unmarshall into our clipboard buffer
m_clipboardData = data; clipboard.m_clipboardData = data;
m_clipboard.unmarshall(m_clipboardData); clipboard.m_clipboard.unmarshall(clipboard.m_clipboardData);
m_clipboardReady = true; clipboard.m_clipboardReady = true;
// if the active client doesn't have the clipboard data // if the active client doesn't have the clipboard data
// (and it won't unless the client is the one sending us // (and it won't unless the client is the one sending us
// the data) then send the data now. // the data) then send the data now.
if (!m_active->m_gotClipboard) { if (!m_active->m_gotClipboard[id]) {
if (m_active->m_protocol == NULL) { if (m_active->m_protocol == NULL) {
m_primary->setClipboard(&m_clipboard); m_primary->setClipboard(id, &clipboard.m_clipboard);
} }
else { else {
m_active->m_protocol->sendClipboard(m_clipboardData); m_active->m_protocol->sendClipboard(id,
clipboard.m_clipboardData);
} }
m_active->m_gotClipboard = true; m_active->m_gotClipboard[id] = true;
} }
} }
} }
@ -509,14 +512,18 @@ void CServer::switchScreen(CScreenInfo* dst,
} }
// send the clipboard data if we haven't done so yet // send the clipboard data if we haven't done so yet
if (m_clipboardReady && !m_active->m_gotClipboard) { for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
if (m_active->m_protocol == NULL) { ClipboardInfo& clipboard = m_clipboards[id];
m_primary->setClipboard(&m_clipboard); 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;
} }
else {
m_active->m_protocol->sendClipboard(m_clipboardData);
}
m_active->m_gotClipboard = true;
} }
} }
else { else {
@ -919,10 +926,13 @@ void CServer::openPrimaryScreen()
// set the clipboard owner to the primary screen and then get the // set the clipboard owner to the primary screen and then get the
// current clipboard data. // current clipboard data.
m_primary->getClipboard(&m_clipboard); for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
m_clipboardData = m_clipboard.marshall(); ClipboardInfo& clipboard = m_clipboards[id];
m_clipboardReady = true; m_primary->getClipboard(id, &clipboard.m_clipboard);
m_clipboardOwner = m_active->m_name; clipboard.m_clipboardData = clipboard.m_clipboard.marshall();
clipboard.m_clipboardReady = true;
clipboard.m_clipboardOwner = m_active->m_name;
}
} }
void CServer::closePrimaryScreen() void CServer::closePrimaryScreen()
@ -1075,13 +1085,28 @@ CServer::CScreenInfo::CScreenInfo(const CString& name,
m_name(name), m_name(name),
m_protocol(protocol), m_protocol(protocol),
m_width(0), m_height(0), m_width(0), m_height(0),
m_zoneSize(0), m_zoneSize(0)
m_gotClipboard(false)
{ {
// do nothing for (ClipboardID id = 0; id < kClipboardEnd; ++id)
m_gotClipboard[id] = false;
} }
CServer::CScreenInfo::~CScreenInfo() CServer::CScreenInfo::~CScreenInfo()
{ {
// do nothing // do nothing
} }
//
// CServer::ClipboardInfo
//
CServer::ClipboardInfo::ClipboardInfo() :
m_clipboard(),
m_clipboardData(),
m_clipboardOwner(),
m_clipboardSeqNum(0),
m_clipboardReady(false)
{
// do nothing
}

View File

@ -1,6 +1,7 @@
#ifndef CSERVER_H #ifndef CSERVER_H
#define CSERVER_H #define CSERVER_H
#include "ClipboardTypes.h"
#include "KeyTypes.h" #include "KeyTypes.h"
#include "MouseTypes.h" #include "MouseTypes.h"
#include "CScreenMap.h" #include "CScreenMap.h"
@ -43,13 +44,14 @@ class CServer {
bool onMouseMovePrimary(SInt32 x, SInt32 y); bool onMouseMovePrimary(SInt32 x, SInt32 y);
void onMouseMoveSecondary(SInt32 dx, SInt32 dy); void onMouseMoveSecondary(SInt32 dx, SInt32 dy);
void onMouseWheel(SInt32 delta); void onMouseWheel(SInt32 delta);
void grabClipboard(); void grabClipboard(ClipboardID);
// handle messages from clients // handle messages from clients
void setInfo(const CString& clientName, void setInfo(const CString& clientName,
SInt32 w, SInt32 h, SInt32 zoneSize); SInt32 w, SInt32 h, SInt32 zoneSize);
void grabClipboard(const CString& clientName); void grabClipboard(ClipboardID, const CString& clientName);
void setClipboard(UInt32 seqNum, const CString& data); void setClipboard(ClipboardID,
UInt32 seqNum, const CString& data);
// accessors // accessors
@ -95,7 +97,7 @@ class CServer {
IServerProtocol* m_protocol; IServerProtocol* m_protocol;
SInt32 m_width, m_height; SInt32 m_width, m_height;
SInt32 m_zoneSize; SInt32 m_zoneSize;
bool m_gotClipboard; bool m_gotClipboard[kClipboardEnd];
}; };
// change the active screen // change the active screen
@ -146,6 +148,17 @@ class CServer {
private: private:
typedef std::list<CThread*> CThreadList; typedef std::list<CThread*> CThreadList;
typedef std::map<CString, CScreenInfo*> CScreenList; typedef std::map<CString, CScreenInfo*> CScreenList;
class ClipboardInfo {
public:
ClipboardInfo();
public:
CClipboard m_clipboard;
CString m_clipboardData;
CString m_clipboardOwner;
UInt32 m_clipboardSeqNum;
bool m_clipboardReady;
};
CMutex m_mutex; CMutex m_mutex;
@ -165,11 +178,7 @@ class CServer {
CScreenMap m_screenMap; CScreenMap m_screenMap;
CClipboard m_clipboard; ClipboardInfo m_clipboards[kClipboardEnd];
CString m_clipboardData;
CString m_clipboardOwner;
UInt32 m_clipboardSeqNum;
bool m_clipboardReady;
}; };
#endif #endif

View File

@ -33,9 +33,9 @@ class CServerProtocol : public IServerProtocol {
virtual void sendClose() = 0; virtual void sendClose() = 0;
virtual void sendEnter(SInt32 xAbs, SInt32 yAbs) = 0; virtual void sendEnter(SInt32 xAbs, SInt32 yAbs) = 0;
virtual void sendLeave() = 0; virtual void sendLeave() = 0;
virtual void sendClipboard(const CString&) = 0; virtual void sendClipboard(ClipboardID, const CString&) = 0;
virtual void sendGrabClipboard() = 0; virtual void sendGrabClipboard(ClipboardID) = 0;
virtual void sendQueryClipboard(UInt32 seqNum) = 0; virtual void sendQueryClipboard(ClipboardID, UInt32 seqNum) = 0;
virtual void sendScreenSaver(bool on) = 0; virtual void sendScreenSaver(bool on) = 0;
virtual void sendKeyDown(KeyID, KeyModifierMask) = 0; virtual void sendKeyDown(KeyID, KeyModifierMask) = 0;
virtual void sendKeyRepeat(KeyID, KeyModifierMask, SInt32 count) = 0; virtual void sendKeyRepeat(KeyID, KeyModifierMask, SInt32 count) = 0;

View File

@ -103,22 +103,24 @@ void CServerProtocol1_0::sendLeave()
CProtocolUtil::writef(getOutputStream(), kMsgCLeave); CProtocolUtil::writef(getOutputStream(), kMsgCLeave);
} }
void CServerProtocol1_0::sendClipboard(const CString& data) void CServerProtocol1_0::sendClipboard(
ClipboardID id, const CString& data)
{ {
log((CLOG_INFO "send clipboard to \"%s\" size=%d", getClient().c_str(), data.size())); log((CLOG_INFO "send clipboard %d to \"%s\" size=%d", id, getClient().c_str(), data.size()));
CProtocolUtil::writef(getOutputStream(), kMsgDClipboard, 0, &data); CProtocolUtil::writef(getOutputStream(), kMsgDClipboard, id, 0, &data);
} }
void CServerProtocol1_0::sendGrabClipboard() void CServerProtocol1_0::sendGrabClipboard(ClipboardID id)
{ {
log((CLOG_INFO "send grab clipboard to \"%s\"", getClient().c_str())); log((CLOG_INFO "send grab clipboard %d to \"%s\"", id, getClient().c_str()));
CProtocolUtil::writef(getOutputStream(), kMsgCClipboard); CProtocolUtil::writef(getOutputStream(), kMsgCClipboard, id);
} }
void CServerProtocol1_0::sendQueryClipboard(UInt32 seqNum) void CServerProtocol1_0::sendQueryClipboard(
ClipboardID id, UInt32 seqNum)
{ {
log((CLOG_INFO "query clipboard to \"%s\"", getClient().c_str())); log((CLOG_INFO "query clipboard %d to \"%s\"", id, getClient().c_str()));
CProtocolUtil::writef(getOutputStream(), kMsgQClipboard, seqNum); CProtocolUtil::writef(getOutputStream(), kMsgQClipboard, id, seqNum);
} }
void CServerProtocol1_0::sendScreenSaver(bool on) void CServerProtocol1_0::sendScreenSaver(bool on)
@ -194,15 +196,18 @@ void CServerProtocol1_0::recvInfo()
void CServerProtocol1_0::recvClipboard() void CServerProtocol1_0::recvClipboard()
{ {
ClipboardID id;
UInt32 seqNum; UInt32 seqNum;
CString data; CString data;
CProtocolUtil::readf(getInputStream(), kMsgDClipboard + 4, &seqNum, &data); CProtocolUtil::readf(getInputStream(), kMsgDClipboard + 4, &id, &seqNum, &data);
log((CLOG_INFO "received client \"%s\" clipboard seqnum=%d, size=%d", getClient().c_str(), seqNum, data.size())); log((CLOG_INFO "received client \"%s\" clipboard %d seqnum=%d, size=%d", getClient().c_str(), id, seqNum, data.size()));
getServer()->setClipboard(seqNum, data); getServer()->setClipboard(id, seqNum, data);
} }
void CServerProtocol1_0::recvGrabClipboard() void CServerProtocol1_0::recvGrabClipboard()
{ {
log((CLOG_INFO "received client \"%s\" grabbed clipboard", getClient().c_str())); ClipboardID id;
getServer()->grabClipboard(getClient()); CProtocolUtil::readf(getInputStream(), kMsgCClipboard + 4, &id);
log((CLOG_INFO "received client \"%s\" grabbed clipboard %d", getClient().c_str(), id));
getServer()->grabClipboard(id, getClient());
} }

View File

@ -18,9 +18,9 @@ class CServerProtocol1_0 : public CServerProtocol {
virtual void sendClose(); virtual void sendClose();
virtual void sendEnter(SInt32 xAbs, SInt32 yAbs); virtual void sendEnter(SInt32 xAbs, SInt32 yAbs);
virtual void sendLeave(); virtual void sendLeave();
virtual void sendClipboard(const CString&); virtual void sendClipboard(ClipboardID, const CString&);
virtual void sendGrabClipboard(); virtual void sendGrabClipboard(ClipboardID);
virtual void sendQueryClipboard(UInt32 seqNum); virtual void sendQueryClipboard(ClipboardID, UInt32 seqNum);
virtual void sendScreenSaver(bool on); virtual void sendScreenSaver(bool on);
virtual void sendKeyDown(KeyID, KeyModifierMask); virtual void sendKeyDown(KeyID, KeyModifierMask);
virtual void sendKeyRepeat(KeyID, KeyModifierMask, SInt32 count); virtual void sendKeyRepeat(KeyID, KeyModifierMask, SInt32 count);

View File

@ -137,7 +137,8 @@ void CXWindowsPrimaryScreen::run()
// selection owner. report that to the server. // selection owner. report that to the server.
if (lostClipboard(xevent.xselectionclear.selection, if (lostClipboard(xevent.xselectionclear.selection,
xevent.xselectionclear.time)) { xevent.xselectionclear.time)) {
m_server->grabClipboard(); m_server->grabClipboard(getClipboardID(
xevent.xselectionclear.selection));
} }
break; break;
@ -270,7 +271,7 @@ void CXWindowsPrimaryScreen::leave()
assert(result != GrabNotViewable); assert(result != GrabNotViewable);
if (result != GrabSuccess) { if (result != GrabSuccess) {
log((CLOG_DEBUG "waiting to grab pointer")); log((CLOG_DEBUG "waiting to grab pointer"));
CThread::sleep(0.25); CThread::sleep(0.1);
} }
} while (result != GrabSuccess); } while (result != GrabSuccess);
log((CLOG_DEBUG "grabbed pointer")); log((CLOG_DEBUG "grabbed pointer"));
@ -283,7 +284,7 @@ void CXWindowsPrimaryScreen::leave()
// back off to avoid grab deadlock // back off to avoid grab deadlock
XUngrabPointer(display, CurrentTime); XUngrabPointer(display, CurrentTime);
log((CLOG_DEBUG "ungrabbed pointer, waiting to grab keyboard")); log((CLOG_DEBUG "ungrabbed pointer, waiting to grab keyboard"));
CThread::sleep(0.25); CThread::sleep(0.1);
} }
} while (result != GrabSuccess); } while (result != GrabSuccess);
log((CLOG_DEBUG "grabbed keyboard")); log((CLOG_DEBUG "grabbed keyboard"));
@ -323,16 +324,16 @@ void CXWindowsPrimaryScreen::warpCursorNoLock(
} }
void CXWindowsPrimaryScreen::setClipboard( void CXWindowsPrimaryScreen::setClipboard(
const IClipboard* clipboard) ClipboardID id, const IClipboard* clipboard)
{ {
// FIXME -- don't use CurrentTime // FIXME -- don't use CurrentTime
setDisplayClipboard(clipboard, m_window, CurrentTime); setDisplayClipboard(id, clipboard, m_window, CurrentTime);
} }
void CXWindowsPrimaryScreen::grabClipboard() void CXWindowsPrimaryScreen::grabClipboard(ClipboardID id)
{ {
// FIXME -- don't use CurrentTime // FIXME -- don't use CurrentTime
setDisplayClipboard(NULL, m_window, CurrentTime); setDisplayClipboard(id, NULL, m_window, CurrentTime);
} }
void CXWindowsPrimaryScreen::getSize( void CXWindowsPrimaryScreen::getSize(
@ -347,10 +348,10 @@ SInt32 CXWindowsPrimaryScreen::getJumpZoneSize() const
} }
void CXWindowsPrimaryScreen::getClipboard( void CXWindowsPrimaryScreen::getClipboard(
IClipboard* clipboard) const ClipboardID id, IClipboard* clipboard) const
{ {
// FIXME -- don't use CurrentTime // FIXME -- don't use CurrentTime
getDisplayClipboard(clipboard, m_window, CurrentTime); getDisplayClipboard(id, clipboard, m_window, CurrentTime);
} }
void CXWindowsPrimaryScreen::onOpenDisplay() void CXWindowsPrimaryScreen::onOpenDisplay()

View File

@ -19,11 +19,11 @@ class CXWindowsPrimaryScreen : public CXWindowsScreen, public IPrimaryScreen {
virtual void enter(SInt32 xAbsolute, SInt32 yAbsolute); virtual void enter(SInt32 xAbsolute, SInt32 yAbsolute);
virtual void leave(); virtual void leave();
virtual void warpCursor(SInt32 xAbsolute, SInt32 yAbsolute); virtual void warpCursor(SInt32 xAbsolute, SInt32 yAbsolute);
virtual void setClipboard(const IClipboard*); virtual void setClipboard(ClipboardID, const IClipboard*);
virtual void grabClipboard(); virtual void grabClipboard(ClipboardID);
virtual void getSize(SInt32* width, SInt32* height) const; virtual void getSize(SInt32* width, SInt32* height) const;
virtual SInt32 getJumpZoneSize() const; virtual SInt32 getJumpZoneSize() const;
virtual void getClipboard(IClipboard*) const; virtual void getClipboard(ClipboardID, IClipboard*) const;
protected: protected:
// CXWindowsScreen overrides // CXWindowsScreen overrides

View File

@ -14,7 +14,6 @@
// CXWindowsScreen // CXWindowsScreen
// //
static const Atom kClipboardSelection = XA_PRIMARY;
static const UInt32 kMaxRequestSize = 4096; static const UInt32 kMaxRequestSize = 4096;
CXWindowsScreen::CXWindowsScreen() : CXWindowsScreen::CXWindowsScreen() :
@ -66,6 +65,11 @@ void CXWindowsScreen::openDisplay()
m_atomText = XInternAtom(m_display, "TEXT", False); m_atomText = XInternAtom(m_display, "TEXT", False);
m_atomCompoundText = XInternAtom(m_display, "COMPOUND_TEXT", False); m_atomCompoundText = XInternAtom(m_display, "COMPOUND_TEXT", False);
// clipboard atoms
m_atomClipboard[kClipboardClipboard] =
XInternAtom(m_display, "CLIPBOARD", False);
m_atomClipboard[kClipboardSelection] = XA_PRIMARY;
// let subclass prep display // let subclass prep display
onOpenDisplay(); onOpenDisplay();
} }
@ -78,16 +82,19 @@ void CXWindowsScreen::closeDisplay()
onCloseDisplay(); onCloseDisplay();
// clear out the clipboard request lists // clear out the clipboard request lists
for (CRequestMap::iterator index = m_requests.begin(); for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
index != m_requests.end(); ++index) { ClipboardInfo& clipboard = m_clipboards[id];
CRequestList* list = index->second; for (CRequestMap::iterator index = clipboard.m_requests.begin();
for (CRequestList::iterator index2 = list->begin(); index != clipboard.m_requests.end(); ++index) {
CRequestList* list = index->second;
for (CRequestList::iterator index2 = list->begin();
index2 != list->end(); ++index2) { index2 != list->end(); ++index2) {
delete *index2; delete *index2;
}
delete list;
} }
delete list; clipboard.m_requests.clear();
} }
m_requests.clear();
// close the display // close the display
XCloseDisplay(m_display); XCloseDisplay(m_display);
@ -179,39 +186,50 @@ void CXWindowsScreen::doStop()
m_stop = true; m_stop = true;
} }
ClipboardID CXWindowsScreen::getClipboardID(Atom selection)
{
for (ClipboardID id = 0; id < kClipboardEnd; ++id)
if (selection == m_atomClipboard[id])
return id;
return kClipboardEnd;
}
bool CXWindowsScreen::lostClipboard( bool CXWindowsScreen::lostClipboard(
Atom selection, Time timestamp) Atom selection, Time timestamp)
{ {
if (selection == kClipboardSelection) { for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
// note the time if (selection == m_atomClipboard[id]) {
CLock lock(&m_mutex); // note the time
m_lostClipboard = timestamp; CLock lock(&m_mutex);
log((CLOG_INFO "lost clipboard ownership at %d", timestamp)); m_clipboards[id].m_lostClipboard = timestamp;
return true; log((CLOG_INFO "lost clipboard %d ownership at %d", id, timestamp));
return true;
}
} }
return false; return false;
} }
bool CXWindowsScreen::setDisplayClipboard( bool CXWindowsScreen::setDisplayClipboard(
ClipboardID id,
const IClipboard* clipboard, const IClipboard* clipboard,
Window requestor, Time timestamp) Window requestor, Time timestamp)
{ {
CLock lock(&m_mutex); CLock lock(&m_mutex);
XSetSelectionOwner(m_display, kClipboardSelection, requestor, timestamp); XSetSelectionOwner(m_display, m_atomClipboard[id], requestor, timestamp);
if (XGetSelectionOwner(m_display, kClipboardSelection) == requestor) { if (XGetSelectionOwner(m_display, m_atomClipboard[id]) == requestor) {
// we got the selection // we got the selection
log((CLOG_INFO "grabbed clipboard at %d", timestamp)); log((CLOG_INFO "grabbed clipboard at %d", timestamp));
m_gotClipboard = timestamp; m_clipboards[id].m_gotClipboard = timestamp;
if (clipboard != NULL) { if (clipboard != NULL) {
// save clipboard to serve requests // save clipboard to serve requests
CClipboard::copy(&m_clipboard, clipboard); CClipboard::copy(&m_clipboards[id].m_clipboard, clipboard);
} }
else { else {
// clear clipboard // clear clipboard
if (m_clipboard.open()) { if (m_clipboards[id].m_clipboard.open()) {
m_clipboard.close(); m_clipboards[id].m_clipboard.close();
} }
} }
@ -222,6 +240,7 @@ bool CXWindowsScreen::setDisplayClipboard(
} }
void CXWindowsScreen::getDisplayClipboard( void CXWindowsScreen::getDisplayClipboard(
ClipboardID id,
IClipboard* clipboard, IClipboard* clipboard,
Window requestor, Time timestamp) const Window requestor, Time timestamp) const
{ {
@ -236,7 +255,7 @@ void CXWindowsScreen::getDisplayClipboard(
// in particular, this prevents the event thread from stealing the // in particular, this prevents the event thread from stealing the
// selection notify event we're expecting. // selection notify event we're expecting.
CLock lock(&m_mutex); CLock lock(&m_mutex);
Atom selection = kClipboardSelection; Atom selection = m_atomClipboard[id];
// ask the selection for all the formats it has. some owners return // ask the selection for all the formats it has. some owners return
// the TARGETS atom and some the ATOM atom when TARGETS is requested. // the TARGETS atom and some the ATOM atom when TARGETS is requested.
@ -541,10 +560,13 @@ void CXWindowsScreen::addClipboardRequest(
Atom selection, Atom target, Atom selection, Atom target,
Atom property, Time time) Atom property, Time time)
{ {
// we can only own kClipboardSelection // see if it's a selection we know about
if (selection != kClipboardSelection) { ClipboardID id;
for (id = 0; id < kClipboardEnd; ++id)
if (selection == m_atomClipboard[id])
break;
if (id == kClipboardEnd)
return; return;
}
// mutex the display // mutex the display
CLock lock(&m_mutex); CLock lock(&m_mutex);
@ -554,16 +576,16 @@ void CXWindowsScreen::addClipboardRequest(
if (target == m_atomMultiple) { if (target == m_atomMultiple) {
// add a multiple request // add a multiple request
if (property != None) { if (property != None) {
success = sendClipboardMultiple(requestor, property, time); success = sendClipboardMultiple(id, requestor, property, time);
} }
} }
else { else {
// handle remaining request formats // handle remaining request formats
success = sendClipboardData(requestor, target, property, time); success = sendClipboardData(id, requestor, target, property, time);
} }
// send success or failure // send success or failure
sendNotify(requestor, target, success ? property : None, time); sendNotify(id, requestor, target, success ? property : None, time);
} }
void CXWindowsScreen::processClipboardRequest( void CXWindowsScreen::processClipboardRequest(
@ -572,62 +594,71 @@ void CXWindowsScreen::processClipboardRequest(
{ {
CLock lock(&m_mutex); CLock lock(&m_mutex);
// find the request list // check every clipboard
CRequestMap::iterator index = m_requests.find(requestor); for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
if (index == m_requests.end()) { ClipboardInfo& clipboard = m_clipboards[id];
return;
}
CRequestList* list = index->second;
assert(list != NULL);
// find the property in the list // find the request list
CRequestList::iterator index2; CRequestMap::iterator index = clipboard.m_requests.find(requestor);
for (index2 = list->begin(); index2 != list->end(); ++index2) { if (index == clipboard.m_requests.end()) {
if ((*index2)->m_property == property) { // this clipboard isn't servicing this requestor window
break; continue;
} }
} CRequestList* list = index->second;
if (index2 == list->end()) { assert(list != NULL);
log((CLOG_WARN "received property event on unexpected property"));
return;
}
CClipboardRequest* request = *index2;
assert(request != NULL);
// compute amount of data to send // find the property in the list
assert(request->m_sent <= request->m_data.size()); CRequestList::iterator index2;
UInt32 count = request->m_data.size() - request->m_sent; for (index2 = list->begin(); index2 != list->end(); ++index2) {
if (count > kMaxRequestSize) { if ((*index2)->m_property == property) {
// limit maximum chunk size break;
count = kMaxRequestSize; }
}
if (index2 == list->end()) {
// this clipboard isn't waiting on this property
continue;
}
CClipboardRequest* request = *index2;
assert(request != NULL);
// make it a multiple of the size // compute amount of data to send
count &= ~((request->m_size >> 3) - 1); assert(request->m_sent <= request->m_data.size());
} UInt32 count = request->m_data.size() - request->m_sent;
if (count > kMaxRequestSize) {
// limit maximum chunk size
count = kMaxRequestSize;
// send more data // make it a multiple of the size
// FIXME -- handle Alloc errors (by returning false) count &= ~((request->m_size >> 3) - 1);
XChangeProperty(m_display, request->m_requestor, request->m_property, }
// send more data
// FIXME -- handle Alloc errors (by returning false)
XChangeProperty(m_display, request->m_requestor, request->m_property,
request->m_type, request->m_size, request->m_type, request->m_size,
PropModeReplace, PropModeReplace,
reinterpret_cast<const unsigned char*>( reinterpret_cast<const unsigned char*>(
request->m_data.data() + request->m_sent), request->m_data.data() + request->m_sent),
count / (request->m_size >> 3)); count / (request->m_size >> 3));
// account for sent data // account for sent data
request->m_sent += count; request->m_sent += count;
// if we sent zero bytes then we're done sending this data. remove // if we sent zero bytes then we're done sending this data. remove
// it from the list and, if the list is empty, the list from the // it from the list and, if the list is empty, the list from the
// map. also stop watching the requestor for events. // map. also stop watching the requestor for events.
if (count == 0) { if (count == 0) {
list->erase(index2); list->erase(index2);
delete request; delete request;
if (list->empty()) { if (list->empty()) {
m_requests.erase(index); clipboard.m_requests.erase(index);
delete list; delete list;
}
XSelectInput(m_display, requestor, NoEventMask);
} }
XSelectInput(m_display, requestor, NoEventMask);
// request has been serviced
break;
} }
} }
@ -636,37 +667,43 @@ void CXWindowsScreen::destroyClipboardRequest(
{ {
CLock lock(&m_mutex); CLock lock(&m_mutex);
// find the request list // check every clipboard
CRequestMap::iterator index = m_requests.find(requestor); for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
if (index == m_requests.end()) { ClipboardInfo& clipboard = m_clipboards[id];
return;
}
CRequestList* list = index->second;
assert(list != NULL);
// destroy every request in the list // find the request list
for (CRequestList::iterator index2 = list->begin(); CRequestMap::iterator index = clipboard.m_requests.find(requestor);
if (index == clipboard.m_requests.end()) {
continue;
}
CRequestList* list = index->second;
assert(list != NULL);
// destroy every request in the list
for (CRequestList::iterator index2 = list->begin();
index2 != list->end(); ++index2) { index2 != list->end(); ++index2) {
delete *index2; delete *index2;
} }
// remove and destroy the list // remove and destroy the list
m_requests.erase(index); clipboard.m_requests.erase(index);
delete list; delete list;
}
// note -- we don't stop watching the window for events because // note -- we don't stop watching the window for events because
// we're called in response to the window being destroyed. // we're called in response to the window being destroyed.
} }
bool CXWindowsScreen::sendClipboardData( bool CXWindowsScreen::sendClipboardData(
ClipboardID id,
Window requestor, Atom target, Window requestor, Atom target,
Atom property, Time time) Atom property, Time time)
{ {
if (target == m_atomTargets) { if (target == m_atomTargets) {
return sendClipboardTargets(requestor, property, time); return sendClipboardTargets(id, requestor, property, time);
} }
else if (target == m_atomTimestamp) { else if (target == m_atomTimestamp) {
return sendClipboardTimestamp(requestor, property, time); return sendClipboardTimestamp(id, requestor, property, time);
} }
else { else {
// compute the type and size for the requested target and // compute the type and size for the requested target and
@ -675,10 +712,10 @@ bool CXWindowsScreen::sendClipboardData(
int size = 0; int size = 0;
CString data; CString data;
if (target == m_atomText || target == m_atomString) { if (target == m_atomText || target == m_atomString) {
if (m_clipboard.has(IClipboard::kText)) { if (m_clipboards[id].m_clipboard.has(IClipboard::kText)) {
type = m_atomString; type = m_atomString;
size = 8; size = 8;
data = m_clipboard.get(IClipboard::kText); data = m_clipboards[id].m_clipboard.get(IClipboard::kText);
} }
} }
@ -691,10 +728,10 @@ bool CXWindowsScreen::sendClipboardData(
log((CLOG_DEBUG "handling clipboard request for %d as INCR", target)); log((CLOG_DEBUG "handling clipboard request for %d as INCR", target));
// get the appropriate list, creating it if necessary // get the appropriate list, creating it if necessary
CRequestList* list = m_requests[requestor]; CRequestList* list = m_clipboards[id].m_requests[requestor];
if (list == NULL) { if (list == NULL) {
list = new CRequestList; list = new CRequestList;
m_requests[requestor] = list; m_clipboards[id].m_requests[requestor] = list;
} }
// create request object // create request object
@ -718,7 +755,8 @@ bool CXWindowsScreen::sendClipboardData(
// set property to INCR // set property to INCR
const UInt32 zero = 0; const UInt32 zero = 0;
XChangeProperty(m_display, requestor, property, XChangeProperty(m_display, requestor, property,
m_atomINCR, 8 * sizeof(zero), m_atomINCR,
8 * sizeof(zero),
PropModeReplace, PropModeReplace,
reinterpret_cast<const unsigned char*>(&zero), reinterpret_cast<const unsigned char*>(&zero),
1); 1);
@ -730,7 +768,8 @@ bool CXWindowsScreen::sendClipboardData(
XChangeProperty(m_display, requestor, property, XChangeProperty(m_display, requestor, property,
type, size, type, size,
PropModeReplace, PropModeReplace,
reinterpret_cast<const unsigned char*>(data.data()), reinterpret_cast<const unsigned char*>(
data.data()),
data.size() / (size >> 3)); data.size() / (size >> 3));
} }
return true; return true;
@ -739,6 +778,7 @@ bool CXWindowsScreen::sendClipboardData(
} }
bool CXWindowsScreen::sendClipboardMultiple( bool CXWindowsScreen::sendClipboardMultiple(
ClipboardID id,
Window requestor, Window requestor,
Atom property, Time time) Atom property, Time time)
{ {
@ -768,7 +808,7 @@ bool CXWindowsScreen::sendClipboardMultiple(
// handle target // handle target
if (property != None) { if (property != None) {
if (!sendClipboardData(requestor, target, property, time)) { if (!sendClipboardData(id, requestor, target, property, time)) {
// couldn't handle target. change property to None. // couldn't handle target. change property to None.
const Atom none = None; const Atom none = None;
data.replace((2 * index + 1) * sizeof(Atom), sizeof(Atom), data.replace((2 * index + 1) * sizeof(Atom), sizeof(Atom),
@ -786,15 +826,18 @@ bool CXWindowsScreen::sendClipboardMultiple(
if (updated) { if (updated) {
// FIXME -- handle Alloc errors (by returning false) // FIXME -- handle Alloc errors (by returning false)
XChangeProperty(m_display, requestor, property, XChangeProperty(m_display, requestor, property,
m_atomAtomPair, 8 * sizeof(Atom), m_atomAtomPair,
8 * sizeof(Atom),
PropModeReplace, PropModeReplace,
reinterpret_cast<const unsigned char*>(data.data()), reinterpret_cast<const unsigned char*>(
data.data()),
data.length()); data.length());
} }
// send notify if any format was successful // send notify if any format was successful
if (success) { if (success) {
sendNotify(requestor, m_atomMultiple, success ? property : None, time); sendNotify(id, requestor, m_atomMultiple,
success ? property : None, time);
return true; return true;
} }
@ -802,6 +845,7 @@ bool CXWindowsScreen::sendClipboardMultiple(
} }
bool CXWindowsScreen::sendClipboardTargets( bool CXWindowsScreen::sendClipboardTargets(
ClipboardID id,
Window requestor, Window requestor,
Atom property, Time /*time*/) Atom property, Time /*time*/)
{ {
@ -809,7 +853,7 @@ bool CXWindowsScreen::sendClipboardTargets(
// count the number of targets, plus TARGETS and MULTIPLE // count the number of targets, plus TARGETS and MULTIPLE
SInt32 numTargets = 2; SInt32 numTargets = 2;
if (m_clipboard.has(IClipboard::kText)) { if (m_clipboards[id].m_clipboard.has(IClipboard::kText)) {
numTargets += 2; numTargets += 2;
} }
@ -818,7 +862,7 @@ bool CXWindowsScreen::sendClipboardTargets(
SInt32 count = 0; SInt32 count = 0;
response[count++] = m_atomTargets; response[count++] = m_atomTargets;
response[count++] = m_atomMultiple; response[count++] = m_atomMultiple;
if (m_clipboard.has(IClipboard::kText)) { if (m_clipboards[id].m_clipboard.has(IClipboard::kText)) {
response[count++] = m_atomText; response[count++] = m_atomText;
response[count++] = m_atomString; response[count++] = m_atomString;
} }
@ -826,7 +870,8 @@ bool CXWindowsScreen::sendClipboardTargets(
// send response (we assume we can transfer the entire list at once) // send response (we assume we can transfer the entire list at once)
// FIXME -- handle Alloc errors (by returning false) // FIXME -- handle Alloc errors (by returning false)
XChangeProperty(m_display, requestor, property, XChangeProperty(m_display, requestor, property,
m_atomAtom, 8 * sizeof(Atom), m_atomAtom,
8 * sizeof(Atom),
PropModeReplace, PropModeReplace,
reinterpret_cast<unsigned char*>(response), reinterpret_cast<unsigned char*>(response),
count); count);
@ -838,6 +883,7 @@ bool CXWindowsScreen::sendClipboardTargets(
} }
bool CXWindowsScreen::sendClipboardTimestamp( bool CXWindowsScreen::sendClipboardTimestamp(
ClipboardID id,
Window requestor, Window requestor,
Atom property, Time /*time*/) Atom property, Time /*time*/)
{ {
@ -845,22 +891,24 @@ bool CXWindowsScreen::sendClipboardTimestamp(
// FIXME -- handle Alloc errors (by returning false) // FIXME -- handle Alloc errors (by returning false)
XChangeProperty(m_display, requestor, property, XChangeProperty(m_display, requestor, property,
m_atomInteger, 8 * sizeof(m_gotClipboard), m_atomInteger,
8 * sizeof(m_clipboards[id].m_gotClipboard),
PropModeReplace, PropModeReplace,
reinterpret_cast<unsigned char*>(&m_gotClipboard), reinterpret_cast<unsigned char*>(
&m_clipboards[id].m_gotClipboard),
1); 1);
return true; return true;
} }
void CXWindowsScreen::sendNotify( void CXWindowsScreen::sendNotify(
Window requestor, Atom target, ClipboardID id, Window requestor,
Atom property, Time time) Atom target, Atom property, Time time)
{ {
XEvent event; XEvent event;
event.xselection.type = SelectionNotify; event.xselection.type = SelectionNotify;
event.xselection.display = m_display; event.xselection.display = m_display;
event.xselection.requestor = requestor; event.xselection.requestor = requestor;
event.xselection.selection = kClipboardSelection; event.xselection.selection = m_atomClipboard[id];
event.xselection.target = target; event.xselection.target = target;
event.xselection.property = property; event.xselection.property = property;
event.xselection.time = time; event.xselection.time = time;

View File

@ -4,6 +4,7 @@
#include "CClipboard.h" #include "CClipboard.h"
#include "CMutex.h" #include "CMutex.h"
#include "BasicTypes.h" #include "BasicTypes.h"
#include "ClipboardTypes.h"
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <map> #include <map>
#include <list> #include <list>
@ -56,19 +57,25 @@ class CXWindowsScreen {
// cause getEvent() to return false immediately and forever after // cause getEvent() to return false immediately and forever after
void doStop(); void doStop();
// determine the clipboard from the X selection. returns
// kClipboardEnd if no such clipboard.
ClipboardID getClipboardID(Atom selection);
// call when we lose the clipboard ownership (i.e. when we receive // call when we lose the clipboard ownership (i.e. when we receive
// a SelectionClear event). returns true iff we've actually lost // a SelectionClear event). returns true iff we've actually lost
// a selection we care about. // a selection we care about.
bool lostClipboard(Atom selection, Time timestamp); bool lostClipboard(Atom selection, Time timestamp);
// set the contents of the clipboard (i.e. primary selection) // set the contents of the clipboard (i.e. primary selection)
bool setDisplayClipboard(const IClipboard* clipboard, bool setDisplayClipboard(ClipboardID,
const IClipboard* clipboard,
Window requestor, Time timestamp); Window requestor, Time timestamp);
// copy the clipboard contents to clipboard. requestor must be a // copy the clipboard contents to clipboard. requestor must be a
// valid window; it will be used to receive the transfer. timestamp // valid window; it will be used to receive the transfer. timestamp
// should be the timestamp of the provoking event and not CurrentTime. // should be the timestamp of the provoking event and not CurrentTime.
void getDisplayClipboard(IClipboard* clipboard, void getDisplayClipboard(ClipboardID,
IClipboard* clipboard,
Window requestor, Time timestamp) const; Window requestor, Time timestamp) const;
// add a selection request to the request list // add a selection request to the request list
@ -120,18 +127,31 @@ class CXWindowsScreen {
static Bool findPropertyNotify(Display*, static Bool findPropertyNotify(Display*,
XEvent* xevent, XPointer arg); XEvent* xevent, XPointer arg);
bool sendClipboardData(Window requestor, Atom target, bool sendClipboardData(ClipboardID, Window requestor,
Atom target, Atom property, Time time);
bool sendClipboardMultiple(ClipboardID, Window requestor,
Atom property, Time time); Atom property, Time time);
bool sendClipboardMultiple(Window requestor, bool sendClipboardTargets(ClipboardID, Window requestor,
Atom property, Time time); Atom property, Time time);
bool sendClipboardTargets(Window requestor, bool sendClipboardTimestamp(ClipboardID, Window requestor,
Atom property, Time time);
bool sendClipboardTimestamp(Window requestor,
Atom property, Time time);
void sendNotify(Window requestor, Atom target,
Atom property, Time time); Atom property, Time time);
void sendNotify(ClipboardID, Window requestor,
Atom target, Atom property, Time time);
private: private:
class ClipboardInfo {
public:
// the contents of the clipboard
CClipboard m_clipboard;
// when we got the clipboard and when we lost it
Time m_gotClipboard;
Time m_lostClipboard;
// the request queues
CRequestMap m_requests;
};
Display* m_display; Display* m_display;
int m_screen; int m_screen;
Window m_root; Window m_root;
@ -150,7 +170,11 @@ class CXWindowsScreen {
Atom m_atomString; Atom m_atomString;
Atom m_atomText; Atom m_atomText;
Atom m_atomCompoundText; Atom m_atomCompoundText;
Atom m_atomClipboard[kClipboardEnd];
// clipboard info
ClipboardInfo m_clipboards[kClipboardEnd];
/*
// the contents of our selection // the contents of our selection
CClipboard m_clipboard; CClipboard m_clipboard;
@ -160,6 +184,7 @@ class CXWindowsScreen {
// the request queues // the request queues
CRequestMap m_requests; CRequestMap m_requests;
*/
// X is not thread safe // X is not thread safe
CMutex m_mutex; CMutex m_mutex;

21
synergy/ClipboardTypes.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef CLIPBOARDTYPES_H
#define CLIPBOARDTYPES_H
#include "BasicTypes.h"
// type to hold a clipboard identifier
typedef UInt8 ClipboardID;
// clipboard identifiers. kClipboardClipboard is what is normally
// considered the clipboard (e.g. the cut/copy/paste menu items
// affect it). kClipboardSelection is the selection on those
// platforms that can treat the selection as a clipboard (e.g. X
// windows). clipboard identifiers must be sequential starting
// at zero.
static const ClipboardID kClipboardClipboard = 0;
static const ClipboardID kClipboardSelection = 1;
// the number of clipboards (i.e. one greater than the last clipboard id)
static const ClipboardID kClipboardEnd = 2;
#endif

View File

@ -3,6 +3,7 @@
#include "IInterface.h" #include "IInterface.h"
#include "BasicTypes.h" #include "BasicTypes.h"
#include "ClipboardTypes.h"
class CServer; class CServer;
class IClipboard; class IClipboard;
@ -49,7 +50,7 @@ class IPrimaryScreen : public IInterface {
// set the screen's clipboard contents. this is usually called // set the screen's clipboard contents. this is usually called
// soon after an enter(). // soon after an enter().
virtual void setClipboard(const IClipboard*) = 0; virtual void setClipboard(ClipboardID, const IClipboard*) = 0;
/* /*
// show or hide the screen saver // show or hide the screen saver
@ -57,7 +58,7 @@ class IPrimaryScreen : public IInterface {
*/ */
// synergy should own the clipboard // synergy should own the clipboard
virtual void grabClipboard() = 0; virtual void grabClipboard(ClipboardID) = 0;
// accessors // accessors
@ -75,7 +76,7 @@ class IPrimaryScreen : public IInterface {
virtual SInt32 getJumpZoneSize() const = 0; virtual SInt32 getJumpZoneSize() const = 0;
// get the screen's clipboard contents // get the screen's clipboard contents
virtual void getClipboard(IClipboard*) const = 0; virtual void getClipboard(ClipboardID, IClipboard*) const = 0;
}; };
#endif #endif

View File

@ -3,6 +3,7 @@
#include "IInterface.h" #include "IInterface.h"
#include "BasicTypes.h" #include "BasicTypes.h"
#include "ClipboardTypes.h"
#include "KeyTypes.h" #include "KeyTypes.h"
#include "MouseTypes.h" #include "MouseTypes.h"
@ -52,7 +53,7 @@ class ISecondaryScreen : public IInterface {
// set the screen's clipboard contents. this is usually called // set the screen's clipboard contents. this is usually called
// soon after an enter(). // soon after an enter().
virtual void setClipboard(const IClipboard*) = 0; virtual void setClipboard(ClipboardID, const IClipboard*) = 0;
/* /*
// show or hide the screen saver // show or hide the screen saver
@ -60,7 +61,7 @@ class ISecondaryScreen : public IInterface {
*/ */
// take ownership of clipboard // take ownership of clipboard
virtual void grabClipboard() = 0; virtual void grabClipboard(ClipboardID) = 0;
// accessors // accessors
@ -71,7 +72,7 @@ class ISecondaryScreen : public IInterface {
virtual SInt32 getJumpZoneSize() const = 0; virtual SInt32 getJumpZoneSize() const = 0;
// get the screen's clipboard contents // get the screen's clipboard contents
virtual void getClipboard(IClipboard*) const = 0; virtual void getClipboard(ClipboardID, IClipboard*) const = 0;
}; };
#endif #endif

View File

@ -1,6 +1,7 @@
#ifndef ISERVERPROTOCOL_H #ifndef ISERVERPROTOCOL_H
#define ISERVERPROTOCOL_H #define ISERVERPROTOCOL_H
#include "ClipboardTypes.h"
#include "KeyTypes.h" #include "KeyTypes.h"
#include "MouseTypes.h" #include "MouseTypes.h"
#include "IInterface.h" #include "IInterface.h"
@ -25,9 +26,9 @@ class IServerProtocol : public IInterface {
virtual void sendClose() = 0; virtual void sendClose() = 0;
virtual void sendEnter(SInt32 xAbs, SInt32 yAbs) = 0; virtual void sendEnter(SInt32 xAbs, SInt32 yAbs) = 0;
virtual void sendLeave() = 0; virtual void sendLeave() = 0;
virtual void sendClipboard(const CString&) = 0; virtual void sendClipboard(ClipboardID, const CString&) = 0;
virtual void sendGrabClipboard() = 0; virtual void sendGrabClipboard(ClipboardID) = 0;
virtual void sendQueryClipboard(UInt32 seqNum) = 0; virtual void sendQueryClipboard(ClipboardID, UInt32 seqNum) = 0;
virtual void sendScreenSaver(bool on) = 0; virtual void sendScreenSaver(bool on) = 0;
virtual void sendKeyDown(KeyID, KeyModifierMask) = 0; virtual void sendKeyDown(KeyID, KeyModifierMask) = 0;
virtual void sendKeyRepeat(KeyID, KeyModifierMask, SInt32 count) = 0; virtual void sendKeyRepeat(KeyID, KeyModifierMask, SInt32 count) = 0;

View File

@ -7,30 +7,101 @@
static const SInt32 kMajorVersion = 0; static const SInt32 kMajorVersion = 0;
static const SInt32 kMinorVersion = 1; static const SInt32 kMinorVersion = 1;
// message codes (trailing NUL is not part of code). codes are //
// grouped into: // message codes (trailing NUL is not part of code). in comments, $n
// commands -- request an action, no reply expected // refers to the n'th argument (counting from one). message codes are
// queries -- request info // always 4 bytes optionally followed by message specific parameters.
// data -- send info //
// errors -- notify of error
static const char kMsgCClose[] = "CBYE"; // server
static const char kMsgCEnter[] = "CINN%2i%2i"; // server
static const char kMsgCLeave[] = "COUT"; // server
static const char kMsgCClipboard[] = "CCLP"; // server/client
static const char kMsgCScreenSaver[] = "CSEC%1i"; // server
static const char kMsgDKeyDown[] = "DKDN%2i%2i"; // server //
static const char kMsgDKeyRepeat[] = "DKRP%2i%2i%2i"; // server // command codes
static const char kMsgDKeyUp[] = "DKUP%2i%2i"; // server //
static const char kMsgDMouseDown[] = "DMDN%1i"; // server
static const char kMsgDMouseUp[] = "DMUP%1i"; // server
static const char kMsgDMouseMove[] = "DMMV%2i%2i"; // server
static const char kMsgDMouseWheel[] = "DMWM%2i"; // server
static const char kMsgDClipboard[] = "DCLP%4i%s"; // server/client
static const char kMsgDInfo[] = "DINF%2i%2i%2i"; // client
static const char kMsgQClipboard[] = "QCLP%4i"; // server // close connection; primary -> secondary
static const char kMsgQInfo[] = "QINF"; // server 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";
// leave screen: primary -> secondary
// leaving screen
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";
// screensaver change: primary -> secondary
// screensaver on primary has started ($1 == 1) or closed ($1 == 0)
static const char kMsgCScreenSaver[] = "CSEC%1i";
//
// data codes
//
// key pressed: primary -> secondary
// $1 = KeyID, $2 = KeyModifierMask
static const char kMsgDKeyDown[] = "DKDN%2i%2i";
// key auto-repeat: primary -> secondary
// $1 = KeyID, $2 = KeyModifierMask, $3 = number of repeats
static const char kMsgDKeyRepeat[] = "DKRP%2i%2i%2i";
// key released: primary -> secondary
// $1 = KeyID, $2 = KeyModifierMask
static const char kMsgDKeyUp[] = "DKUP%2i%2i";
// mouse button pressed: primary -> secondary
// $1 = ButtonID
static const char kMsgDMouseDown[] = "DMDN%1i";
// mouse button released: primary -> secondary
// $1 = ButtonID
static const char kMsgDMouseUp[] = "DMUP%1i";
// mouse moved: primary -> secondary
// $1 = x, $2 = y. x,y are absolute screen coordinates.
static const char kMsgDMouseMove[] = "DMMV%2i%2i";
// mouse button pressed: primary -> secondary
// $1 = delta
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.
static const char kMsgDClipboard[] = "DCLP%1i%4i%s";
// client data: seconary -> primary
// $1 = seconary screen width in pixels, $2 = screen height, $3 =
// size of warp zone.
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";
//
// error codes
//
static const char kMsgEIncompatible[] = "EICV"; static const char kMsgEIncompatible[] = "EICV";