Added support for multiple clipboards. This is mainly to
support both PRIMARY and CLIPBOARD selections on X windows.
This commit is contained in:
parent
428166fe85
commit
f9170eb139
|
@ -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);
|
||||
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);
|
||||
CProtocolUtil::writef(m_output, kMsgCClipboard, id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -318,7 +318,12 @@ void CClient::onLeave()
|
|||
|
||||
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()
|
||||
|
@ -345,45 +350,47 @@ void CClient::onQueryInfo()
|
|||
void CClient::onQueryClipboard()
|
||||
{
|
||||
// parse message
|
||||
ClipboardID id;
|
||||
UInt32 seqNum;
|
||||
CClipboard clipboard;
|
||||
{
|
||||
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
|
||||
m_screen->getClipboard(&clipboard);
|
||||
m_screen->getClipboard(id, &clipboard);
|
||||
|
||||
// marshall the data
|
||||
CString data = clipboard.marshall();
|
||||
|
||||
// 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);
|
||||
CProtocolUtil::writef(m_output, kMsgDClipboard, seqNum, &data);
|
||||
CProtocolUtil::writef(m_output, kMsgDClipboard, id, seqNum, &data);
|
||||
}
|
||||
}
|
||||
|
||||
void CClient::onSetClipboard()
|
||||
{
|
||||
ClipboardID id;
|
||||
CString data;
|
||||
{
|
||||
// parse message
|
||||
UInt32 seqNum;
|
||||
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
|
||||
CClipboard clipboard;
|
||||
clipboard.unmarshall(data);
|
||||
|
||||
// set screen's clipboard
|
||||
m_screen->setClipboard(&clipboard);
|
||||
m_screen->setClipboard(id, &clipboard);
|
||||
}
|
||||
|
||||
void CClient::onKeyDown()
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "CMutex.h"
|
||||
#include "CString.h"
|
||||
#include "BasicTypes.h"
|
||||
#include "ClipboardTypes.h"
|
||||
|
||||
class CNetworkAddress;
|
||||
class IInputStream;
|
||||
|
@ -20,7 +21,7 @@ class CClient {
|
|||
void run(const CNetworkAddress& serverAddress);
|
||||
|
||||
// handle events on client's screen
|
||||
void onClipboardChanged();
|
||||
void onClipboardChanged(ClipboardID);
|
||||
|
||||
// accessors
|
||||
|
||||
|
|
|
@ -63,7 +63,8 @@ void CXWindowsSecondaryScreen::run()
|
|||
// selection owner. report that to the server.
|
||||
if (lostClipboard(xevent.xselectionclear.selection,
|
||||
xevent.xselectionclear.time)) {
|
||||
m_client->onClipboardChanged();
|
||||
m_client->onClipboardChanged(getClipboardID(
|
||||
xevent.xselectionclear.selection));
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -260,16 +261,16 @@ void CXWindowsSecondaryScreen::mouseWheel(SInt32)
|
|||
}
|
||||
|
||||
void CXWindowsSecondaryScreen::setClipboard(
|
||||
const IClipboard* clipboard)
|
||||
ClipboardID id, const IClipboard* clipboard)
|
||||
{
|
||||
// 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
|
||||
setDisplayClipboard(NULL, m_window, CurrentTime);
|
||||
setDisplayClipboard(id, NULL, m_window, CurrentTime);
|
||||
}
|
||||
|
||||
void CXWindowsSecondaryScreen::getSize(
|
||||
|
@ -284,10 +285,10 @@ SInt32 CXWindowsSecondaryScreen::getJumpZoneSize() const
|
|||
}
|
||||
|
||||
void CXWindowsSecondaryScreen::getClipboard(
|
||||
IClipboard* clipboard) const
|
||||
ClipboardID id, IClipboard* clipboard) const
|
||||
{
|
||||
// FIXME -- don't use CurrentTime
|
||||
getDisplayClipboard(clipboard, m_window, CurrentTime);
|
||||
getDisplayClipboard(id, clipboard, m_window, CurrentTime);
|
||||
}
|
||||
|
||||
void CXWindowsSecondaryScreen::onOpenDisplay()
|
||||
|
|
|
@ -24,11 +24,11 @@ class CXWindowsSecondaryScreen : public CXWindowsScreen, public ISecondaryScreen
|
|||
virtual void mouseUp(ButtonID);
|
||||
virtual void mouseMove(SInt32 xAbsolute, SInt32 yAbsolute);
|
||||
virtual void mouseWheel(SInt32 delta);
|
||||
virtual void setClipboard(const IClipboard*);
|
||||
virtual void grabClipboard();
|
||||
virtual void setClipboard(ClipboardID, const IClipboard*);
|
||||
virtual void grabClipboard(ClipboardID);
|
||||
virtual void getSize(SInt32* width, SInt32* height) const;
|
||||
virtual SInt32 getJumpZoneSize() const;
|
||||
virtual void getClipboard(IClipboard*) const;
|
||||
virtual void getClipboard(ClipboardID, IClipboard*) const;
|
||||
|
||||
protected:
|
||||
// CXWindowsScreen overrides
|
||||
|
|
|
@ -43,9 +43,7 @@ else { wait(0); exit(1); }
|
|||
|
||||
CServer::CServer() : m_primary(NULL),
|
||||
m_active(NULL),
|
||||
m_primaryInfo(NULL),
|
||||
m_clipboardSeqNum(0),
|
||||
m_clipboardReady(false)
|
||||
m_primaryInfo(NULL)
|
||||
{
|
||||
m_socketFactory = 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));
|
||||
}
|
||||
|
||||
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);
|
||||
ClipboardInfo& clipboard = m_clipboards[id];
|
||||
|
||||
// client must be connected
|
||||
CScreenList::iterator index = m_screens.find(client);
|
||||
|
@ -165,74 +165,77 @@ void CServer::grabClipboard(const CString& client)
|
|||
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
|
||||
m_clipboardOwner = client;
|
||||
clipboard.m_clipboardOwner = client;
|
||||
|
||||
// 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
|
||||
// them as not having the data yet.
|
||||
for (index = m_screens.begin(); index != m_screens.end(); ++index) {
|
||||
if (index->first != client) {
|
||||
CScreenInfo* info = index->second;
|
||||
info->m_gotClipboard = false;
|
||||
info->m_gotClipboard[id] = false;
|
||||
if (info->m_protocol == NULL) {
|
||||
m_primary->grabClipboard();
|
||||
m_primary->grabClipboard(id);
|
||||
}
|
||||
else {
|
||||
info->m_protocol->sendGrabClipboard();
|
||||
info->m_protocol->sendGrabClipboard(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// increment the clipboard sequence number so we can identify the
|
||||
// clipboard query's response.
|
||||
++m_clipboardSeqNum;
|
||||
++clipboard.m_clipboardSeqNum;
|
||||
|
||||
// begin getting the clipboard data
|
||||
if (m_active->m_protocol == NULL) {
|
||||
// get clipboard immediately from primary screen
|
||||
m_primary->getClipboard(&m_clipboard);
|
||||
m_clipboardData = m_clipboard.marshall();
|
||||
m_clipboardReady = true;
|
||||
m_primary->getClipboard(id, &clipboard.m_clipboard);
|
||||
clipboard.m_clipboardData = clipboard.m_clipboard.marshall();
|
||||
clipboard.m_clipboardReady = true;
|
||||
}
|
||||
else {
|
||||
// clear out the clipboard since existing data is now out of date.
|
||||
if (m_clipboard.open()) {
|
||||
m_clipboard.close();
|
||||
if (clipboard.m_clipboard.open()) {
|
||||
clipboard.m_clipboard.close();
|
||||
}
|
||||
m_clipboardReady = false;
|
||||
clipboard.m_clipboardReady = false;
|
||||
|
||||
// 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)
|
||||
{
|
||||
// update the clipboard if the sequence number matches
|
||||
CLock lock(&m_mutex);
|
||||
if (seqNum == m_clipboardSeqNum) {
|
||||
ClipboardInfo& clipboard = m_clipboards[id];
|
||||
if (seqNum == clipboard.m_clipboardSeqNum) {
|
||||
// unmarshall into our clipboard buffer
|
||||
m_clipboardData = data;
|
||||
m_clipboard.unmarshall(m_clipboardData);
|
||||
m_clipboardReady = true;
|
||||
clipboard.m_clipboardData = data;
|
||||
clipboard.m_clipboard.unmarshall(clipboard.m_clipboardData);
|
||||
clipboard.m_clipboardReady = true;
|
||||
|
||||
// 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) {
|
||||
if (!m_active->m_gotClipboard[id]) {
|
||||
if (m_active->m_protocol == NULL) {
|
||||
m_primary->setClipboard(&m_clipboard);
|
||||
m_primary->setClipboard(id, &clipboard.m_clipboard);
|
||||
}
|
||||
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
|
||||
if (m_clipboardReady && !m_active->m_gotClipboard) {
|
||||
if (m_active->m_protocol == NULL) {
|
||||
m_primary->setClipboard(&m_clipboard);
|
||||
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;
|
||||
}
|
||||
else {
|
||||
m_active->m_protocol->sendClipboard(m_clipboardData);
|
||||
}
|
||||
m_active->m_gotClipboard = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -919,10 +926,13 @@ void CServer::openPrimaryScreen()
|
|||
|
||||
// set the clipboard owner to the primary screen and then get the
|
||||
// current clipboard data.
|
||||
m_primary->getClipboard(&m_clipboard);
|
||||
m_clipboardData = m_clipboard.marshall();
|
||||
m_clipboardReady = true;
|
||||
m_clipboardOwner = m_active->m_name;
|
||||
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
|
||||
ClipboardInfo& clipboard = m_clipboards[id];
|
||||
m_primary->getClipboard(id, &clipboard.m_clipboard);
|
||||
clipboard.m_clipboardData = clipboard.m_clipboard.marshall();
|
||||
clipboard.m_clipboardReady = true;
|
||||
clipboard.m_clipboardOwner = m_active->m_name;
|
||||
}
|
||||
}
|
||||
|
||||
void CServer::closePrimaryScreen()
|
||||
|
@ -1075,13 +1085,28 @@ CServer::CScreenInfo::CScreenInfo(const CString& name,
|
|||
m_name(name),
|
||||
m_protocol(protocol),
|
||||
m_width(0), m_height(0),
|
||||
m_zoneSize(0),
|
||||
m_gotClipboard(false)
|
||||
m_zoneSize(0)
|
||||
{
|
||||
// do nothing
|
||||
for (ClipboardID id = 0; id < kClipboardEnd; ++id)
|
||||
m_gotClipboard[id] = false;
|
||||
}
|
||||
|
||||
CServer::CScreenInfo::~CScreenInfo()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// CServer::ClipboardInfo
|
||||
//
|
||||
|
||||
CServer::ClipboardInfo::ClipboardInfo() :
|
||||
m_clipboard(),
|
||||
m_clipboardData(),
|
||||
m_clipboardOwner(),
|
||||
m_clipboardSeqNum(0),
|
||||
m_clipboardReady(false)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef CSERVER_H
|
||||
#define CSERVER_H
|
||||
|
||||
#include "ClipboardTypes.h"
|
||||
#include "KeyTypes.h"
|
||||
#include "MouseTypes.h"
|
||||
#include "CScreenMap.h"
|
||||
|
@ -43,13 +44,14 @@ class CServer {
|
|||
bool onMouseMovePrimary(SInt32 x, SInt32 y);
|
||||
void onMouseMoveSecondary(SInt32 dx, SInt32 dy);
|
||||
void onMouseWheel(SInt32 delta);
|
||||
void grabClipboard();
|
||||
void grabClipboard(ClipboardID);
|
||||
|
||||
// handle messages from clients
|
||||
void setInfo(const CString& clientName,
|
||||
SInt32 w, SInt32 h, SInt32 zoneSize);
|
||||
void grabClipboard(const CString& clientName);
|
||||
void setClipboard(UInt32 seqNum, const CString& data);
|
||||
void grabClipboard(ClipboardID, const CString& clientName);
|
||||
void setClipboard(ClipboardID,
|
||||
UInt32 seqNum, const CString& data);
|
||||
|
||||
// accessors
|
||||
|
||||
|
@ -95,7 +97,7 @@ class CServer {
|
|||
IServerProtocol* m_protocol;
|
||||
SInt32 m_width, m_height;
|
||||
SInt32 m_zoneSize;
|
||||
bool m_gotClipboard;
|
||||
bool m_gotClipboard[kClipboardEnd];
|
||||
};
|
||||
|
||||
// change the active screen
|
||||
|
@ -146,6 +148,17 @@ class CServer {
|
|||
private:
|
||||
typedef std::list<CThread*> CThreadList;
|
||||
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;
|
||||
|
||||
|
@ -165,11 +178,7 @@ class CServer {
|
|||
|
||||
CScreenMap m_screenMap;
|
||||
|
||||
CClipboard m_clipboard;
|
||||
CString m_clipboardData;
|
||||
CString m_clipboardOwner;
|
||||
UInt32 m_clipboardSeqNum;
|
||||
bool m_clipboardReady;
|
||||
ClipboardInfo m_clipboards[kClipboardEnd];
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -33,9 +33,9 @@ class CServerProtocol : public IServerProtocol {
|
|||
virtual void sendClose() = 0;
|
||||
virtual void sendEnter(SInt32 xAbs, SInt32 yAbs) = 0;
|
||||
virtual void sendLeave() = 0;
|
||||
virtual void sendClipboard(const CString&) = 0;
|
||||
virtual void sendGrabClipboard() = 0;
|
||||
virtual void sendQueryClipboard(UInt32 seqNum) = 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;
|
||||
|
|
|
@ -103,22 +103,24 @@ void CServerProtocol1_0::sendLeave()
|
|||
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()));
|
||||
CProtocolUtil::writef(getOutputStream(), kMsgDClipboard, 0, &data);
|
||||
log((CLOG_INFO "send clipboard %d to \"%s\" size=%d", id, getClient().c_str(), data.size()));
|
||||
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()));
|
||||
CProtocolUtil::writef(getOutputStream(), kMsgCClipboard);
|
||||
log((CLOG_INFO "send grab clipboard %d to \"%s\"", id, getClient().c_str()));
|
||||
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()));
|
||||
CProtocolUtil::writef(getOutputStream(), kMsgQClipboard, seqNum);
|
||||
log((CLOG_INFO "query clipboard %d to \"%s\"", id, getClient().c_str()));
|
||||
CProtocolUtil::writef(getOutputStream(), kMsgQClipboard, id, seqNum);
|
||||
}
|
||||
|
||||
void CServerProtocol1_0::sendScreenSaver(bool on)
|
||||
|
@ -194,15 +196,18 @@ void CServerProtocol1_0::recvInfo()
|
|||
|
||||
void CServerProtocol1_0::recvClipboard()
|
||||
{
|
||||
ClipboardID id;
|
||||
UInt32 seqNum;
|
||||
CString data;
|
||||
CProtocolUtil::readf(getInputStream(), kMsgDClipboard + 4, &seqNum, &data);
|
||||
log((CLOG_INFO "received client \"%s\" clipboard seqnum=%d, size=%d", getClient().c_str(), seqNum, data.size()));
|
||||
getServer()->setClipboard(seqNum, data);
|
||||
CProtocolUtil::readf(getInputStream(), kMsgDClipboard + 4, &id, &seqNum, &data);
|
||||
log((CLOG_INFO "received client \"%s\" clipboard %d seqnum=%d, size=%d", getClient().c_str(), id, seqNum, data.size()));
|
||||
getServer()->setClipboard(id, seqNum, data);
|
||||
}
|
||||
|
||||
void CServerProtocol1_0::recvGrabClipboard()
|
||||
{
|
||||
log((CLOG_INFO "received client \"%s\" grabbed clipboard", getClient().c_str()));
|
||||
getServer()->grabClipboard(getClient());
|
||||
ClipboardID id;
|
||||
CProtocolUtil::readf(getInputStream(), kMsgCClipboard + 4, &id);
|
||||
log((CLOG_INFO "received client \"%s\" grabbed clipboard %d", getClient().c_str(), id));
|
||||
getServer()->grabClipboard(id, getClient());
|
||||
}
|
||||
|
|
|
@ -18,9 +18,9 @@ class CServerProtocol1_0 : public CServerProtocol {
|
|||
virtual void sendClose();
|
||||
virtual void sendEnter(SInt32 xAbs, SInt32 yAbs);
|
||||
virtual void sendLeave();
|
||||
virtual void sendClipboard(const CString&);
|
||||
virtual void sendGrabClipboard();
|
||||
virtual void sendQueryClipboard(UInt32 seqNum);
|
||||
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);
|
||||
|
|
|
@ -137,7 +137,8 @@ void CXWindowsPrimaryScreen::run()
|
|||
// selection owner. report that to the server.
|
||||
if (lostClipboard(xevent.xselectionclear.selection,
|
||||
xevent.xselectionclear.time)) {
|
||||
m_server->grabClipboard();
|
||||
m_server->grabClipboard(getClipboardID(
|
||||
xevent.xselectionclear.selection));
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -270,7 +271,7 @@ void CXWindowsPrimaryScreen::leave()
|
|||
assert(result != GrabNotViewable);
|
||||
if (result != GrabSuccess) {
|
||||
log((CLOG_DEBUG "waiting to grab pointer"));
|
||||
CThread::sleep(0.25);
|
||||
CThread::sleep(0.1);
|
||||
}
|
||||
} while (result != GrabSuccess);
|
||||
log((CLOG_DEBUG "grabbed pointer"));
|
||||
|
@ -283,7 +284,7 @@ void CXWindowsPrimaryScreen::leave()
|
|||
// back off to avoid grab deadlock
|
||||
XUngrabPointer(display, CurrentTime);
|
||||
log((CLOG_DEBUG "ungrabbed pointer, waiting to grab keyboard"));
|
||||
CThread::sleep(0.25);
|
||||
CThread::sleep(0.1);
|
||||
}
|
||||
} while (result != GrabSuccess);
|
||||
log((CLOG_DEBUG "grabbed keyboard"));
|
||||
|
@ -323,16 +324,16 @@ void CXWindowsPrimaryScreen::warpCursorNoLock(
|
|||
}
|
||||
|
||||
void CXWindowsPrimaryScreen::setClipboard(
|
||||
const IClipboard* clipboard)
|
||||
ClipboardID id, const IClipboard* clipboard)
|
||||
{
|
||||
// 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
|
||||
setDisplayClipboard(NULL, m_window, CurrentTime);
|
||||
setDisplayClipboard(id, NULL, m_window, CurrentTime);
|
||||
}
|
||||
|
||||
void CXWindowsPrimaryScreen::getSize(
|
||||
|
@ -347,10 +348,10 @@ SInt32 CXWindowsPrimaryScreen::getJumpZoneSize() const
|
|||
}
|
||||
|
||||
void CXWindowsPrimaryScreen::getClipboard(
|
||||
IClipboard* clipboard) const
|
||||
ClipboardID id, IClipboard* clipboard) const
|
||||
{
|
||||
// FIXME -- don't use CurrentTime
|
||||
getDisplayClipboard(clipboard, m_window, CurrentTime);
|
||||
getDisplayClipboard(id, clipboard, m_window, CurrentTime);
|
||||
}
|
||||
|
||||
void CXWindowsPrimaryScreen::onOpenDisplay()
|
||||
|
|
|
@ -19,11 +19,11 @@ class CXWindowsPrimaryScreen : public CXWindowsScreen, public IPrimaryScreen {
|
|||
virtual void enter(SInt32 xAbsolute, SInt32 yAbsolute);
|
||||
virtual void leave();
|
||||
virtual void warpCursor(SInt32 xAbsolute, SInt32 yAbsolute);
|
||||
virtual void setClipboard(const IClipboard*);
|
||||
virtual void grabClipboard();
|
||||
virtual void setClipboard(ClipboardID, const IClipboard*);
|
||||
virtual void grabClipboard(ClipboardID);
|
||||
virtual void getSize(SInt32* width, SInt32* height) const;
|
||||
virtual SInt32 getJumpZoneSize() const;
|
||||
virtual void getClipboard(IClipboard*) const;
|
||||
virtual void getClipboard(ClipboardID, IClipboard*) const;
|
||||
|
||||
protected:
|
||||
// CXWindowsScreen overrides
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
// CXWindowsScreen
|
||||
//
|
||||
|
||||
static const Atom kClipboardSelection = XA_PRIMARY;
|
||||
static const UInt32 kMaxRequestSize = 4096;
|
||||
|
||||
CXWindowsScreen::CXWindowsScreen() :
|
||||
|
@ -66,6 +65,11 @@ void CXWindowsScreen::openDisplay()
|
|||
m_atomText = XInternAtom(m_display, "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
|
||||
onOpenDisplay();
|
||||
}
|
||||
|
@ -78,16 +82,19 @@ void CXWindowsScreen::closeDisplay()
|
|||
onCloseDisplay();
|
||||
|
||||
// clear out the clipboard request lists
|
||||
for (CRequestMap::iterator index = m_requests.begin();
|
||||
index != m_requests.end(); ++index) {
|
||||
CRequestList* list = index->second;
|
||||
for (CRequestList::iterator index2 = list->begin();
|
||||
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
|
||||
ClipboardInfo& clipboard = m_clipboards[id];
|
||||
for (CRequestMap::iterator index = clipboard.m_requests.begin();
|
||||
index != clipboard.m_requests.end(); ++index) {
|
||||
CRequestList* list = index->second;
|
||||
for (CRequestList::iterator index2 = list->begin();
|
||||
index2 != list->end(); ++index2) {
|
||||
delete *index2;
|
||||
delete *index2;
|
||||
}
|
||||
delete list;
|
||||
}
|
||||
delete list;
|
||||
clipboard.m_requests.clear();
|
||||
}
|
||||
m_requests.clear();
|
||||
|
||||
// close the display
|
||||
XCloseDisplay(m_display);
|
||||
|
@ -179,39 +186,50 @@ void CXWindowsScreen::doStop()
|
|||
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(
|
||||
Atom selection, Time timestamp)
|
||||
{
|
||||
if (selection == kClipboardSelection) {
|
||||
// note the time
|
||||
CLock lock(&m_mutex);
|
||||
m_lostClipboard = timestamp;
|
||||
log((CLOG_INFO "lost clipboard ownership at %d", timestamp));
|
||||
return true;
|
||||
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
|
||||
if (selection == m_atomClipboard[id]) {
|
||||
// note the time
|
||||
CLock lock(&m_mutex);
|
||||
m_clipboards[id].m_lostClipboard = timestamp;
|
||||
log((CLOG_INFO "lost clipboard %d ownership at %d", id, timestamp));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CXWindowsScreen::setDisplayClipboard(
|
||||
ClipboardID id,
|
||||
const IClipboard* clipboard,
|
||||
Window requestor, Time timestamp)
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
|
||||
XSetSelectionOwner(m_display, kClipboardSelection, requestor, timestamp);
|
||||
if (XGetSelectionOwner(m_display, kClipboardSelection) == requestor) {
|
||||
XSetSelectionOwner(m_display, m_atomClipboard[id], requestor, timestamp);
|
||||
if (XGetSelectionOwner(m_display, m_atomClipboard[id]) == requestor) {
|
||||
// we got the selection
|
||||
log((CLOG_INFO "grabbed clipboard at %d", timestamp));
|
||||
m_gotClipboard = timestamp;
|
||||
m_clipboards[id].m_gotClipboard = timestamp;
|
||||
|
||||
if (clipboard != NULL) {
|
||||
// save clipboard to serve requests
|
||||
CClipboard::copy(&m_clipboard, clipboard);
|
||||
CClipboard::copy(&m_clipboards[id].m_clipboard, clipboard);
|
||||
}
|
||||
else {
|
||||
// clear clipboard
|
||||
if (m_clipboard.open()) {
|
||||
m_clipboard.close();
|
||||
if (m_clipboards[id].m_clipboard.open()) {
|
||||
m_clipboards[id].m_clipboard.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -222,6 +240,7 @@ bool CXWindowsScreen::setDisplayClipboard(
|
|||
}
|
||||
|
||||
void CXWindowsScreen::getDisplayClipboard(
|
||||
ClipboardID id,
|
||||
IClipboard* clipboard,
|
||||
Window requestor, Time timestamp) const
|
||||
{
|
||||
|
@ -236,7 +255,7 @@ void CXWindowsScreen::getDisplayClipboard(
|
|||
// in particular, this prevents the event thread from stealing the
|
||||
// selection notify event we're expecting.
|
||||
CLock lock(&m_mutex);
|
||||
Atom selection = kClipboardSelection;
|
||||
Atom selection = m_atomClipboard[id];
|
||||
|
||||
// ask the selection for all the formats it has. some owners return
|
||||
// the TARGETS atom and some the ATOM atom when TARGETS is requested.
|
||||
|
@ -541,10 +560,13 @@ void CXWindowsScreen::addClipboardRequest(
|
|||
Atom selection, Atom target,
|
||||
Atom property, Time time)
|
||||
{
|
||||
// we can only own kClipboardSelection
|
||||
if (selection != kClipboardSelection) {
|
||||
// see if it's a selection we know about
|
||||
ClipboardID id;
|
||||
for (id = 0; id < kClipboardEnd; ++id)
|
||||
if (selection == m_atomClipboard[id])
|
||||
break;
|
||||
if (id == kClipboardEnd)
|
||||
return;
|
||||
}
|
||||
|
||||
// mutex the display
|
||||
CLock lock(&m_mutex);
|
||||
|
@ -554,16 +576,16 @@ void CXWindowsScreen::addClipboardRequest(
|
|||
if (target == m_atomMultiple) {
|
||||
// add a multiple request
|
||||
if (property != None) {
|
||||
success = sendClipboardMultiple(requestor, property, time);
|
||||
success = sendClipboardMultiple(id, requestor, property, time);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// handle remaining request formats
|
||||
success = sendClipboardData(requestor, target, property, time);
|
||||
success = sendClipboardData(id, requestor, target, property, time);
|
||||
}
|
||||
|
||||
// send success or failure
|
||||
sendNotify(requestor, target, success ? property : None, time);
|
||||
sendNotify(id, requestor, target, success ? property : None, time);
|
||||
}
|
||||
|
||||
void CXWindowsScreen::processClipboardRequest(
|
||||
|
@ -572,62 +594,71 @@ void CXWindowsScreen::processClipboardRequest(
|
|||
{
|
||||
CLock lock(&m_mutex);
|
||||
|
||||
// find the request list
|
||||
CRequestMap::iterator index = m_requests.find(requestor);
|
||||
if (index == m_requests.end()) {
|
||||
return;
|
||||
}
|
||||
CRequestList* list = index->second;
|
||||
assert(list != NULL);
|
||||
// check every clipboard
|
||||
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
|
||||
ClipboardInfo& clipboard = m_clipboards[id];
|
||||
|
||||
// find the property in the list
|
||||
CRequestList::iterator index2;
|
||||
for (index2 = list->begin(); index2 != list->end(); ++index2) {
|
||||
if ((*index2)->m_property == property) {
|
||||
break;
|
||||
// find the request list
|
||||
CRequestMap::iterator index = clipboard.m_requests.find(requestor);
|
||||
if (index == clipboard.m_requests.end()) {
|
||||
// this clipboard isn't servicing this requestor window
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (index2 == list->end()) {
|
||||
log((CLOG_WARN "received property event on unexpected property"));
|
||||
return;
|
||||
}
|
||||
CClipboardRequest* request = *index2;
|
||||
assert(request != NULL);
|
||||
CRequestList* list = index->second;
|
||||
assert(list != NULL);
|
||||
|
||||
// compute amount of data to send
|
||||
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;
|
||||
// find the property in the list
|
||||
CRequestList::iterator index2;
|
||||
for (index2 = list->begin(); index2 != list->end(); ++index2) {
|
||||
if ((*index2)->m_property == property) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
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
|
||||
count &= ~((request->m_size >> 3) - 1);
|
||||
}
|
||||
// compute amount of data to send
|
||||
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
|
||||
// FIXME -- handle Alloc errors (by returning false)
|
||||
XChangeProperty(m_display, request->m_requestor, request->m_property,
|
||||
// make it a multiple of the size
|
||||
count &= ~((request->m_size >> 3) - 1);
|
||||
}
|
||||
|
||||
// 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,
|
||||
PropModeReplace,
|
||||
reinterpret_cast<const unsigned char*>(
|
||||
request->m_data.data() + request->m_sent),
|
||||
count / (request->m_size >> 3));
|
||||
|
||||
// account for sent data
|
||||
request->m_sent += count;
|
||||
// account for sent data
|
||||
request->m_sent += count;
|
||||
|
||||
// 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
|
||||
// map. also stop watching the requestor for events.
|
||||
if (count == 0) {
|
||||
list->erase(index2);
|
||||
delete request;
|
||||
if (list->empty()) {
|
||||
m_requests.erase(index);
|
||||
delete list;
|
||||
// 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
|
||||
// map. also stop watching the requestor for events.
|
||||
if (count == 0) {
|
||||
list->erase(index2);
|
||||
delete request;
|
||||
if (list->empty()) {
|
||||
clipboard.m_requests.erase(index);
|
||||
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);
|
||||
|
||||
// find the request list
|
||||
CRequestMap::iterator index = m_requests.find(requestor);
|
||||
if (index == m_requests.end()) {
|
||||
return;
|
||||
}
|
||||
CRequestList* list = index->second;
|
||||
assert(list != NULL);
|
||||
// check every clipboard
|
||||
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
|
||||
ClipboardInfo& clipboard = m_clipboards[id];
|
||||
|
||||
// destroy every request in the list
|
||||
for (CRequestList::iterator index2 = list->begin();
|
||||
// find the request list
|
||||
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) {
|
||||
delete *index2;
|
||||
}
|
||||
delete *index2;
|
||||
}
|
||||
|
||||
// remove and destroy the list
|
||||
m_requests.erase(index);
|
||||
delete list;
|
||||
// remove and destroy the list
|
||||
clipboard.m_requests.erase(index);
|
||||
delete list;
|
||||
}
|
||||
|
||||
// note -- we don't stop watching the window for events because
|
||||
// we're called in response to the window being destroyed.
|
||||
}
|
||||
|
||||
bool CXWindowsScreen::sendClipboardData(
|
||||
ClipboardID id,
|
||||
Window requestor, Atom target,
|
||||
Atom property, Time time)
|
||||
{
|
||||
if (target == m_atomTargets) {
|
||||
return sendClipboardTargets(requestor, property, time);
|
||||
return sendClipboardTargets(id, requestor, property, time);
|
||||
}
|
||||
else if (target == m_atomTimestamp) {
|
||||
return sendClipboardTimestamp(requestor, property, time);
|
||||
return sendClipboardTimestamp(id, requestor, property, time);
|
||||
}
|
||||
else {
|
||||
// compute the type and size for the requested target and
|
||||
|
@ -675,10 +712,10 @@ bool CXWindowsScreen::sendClipboardData(
|
|||
int size = 0;
|
||||
CString data;
|
||||
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;
|
||||
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));
|
||||
|
||||
// get the appropriate list, creating it if necessary
|
||||
CRequestList* list = m_requests[requestor];
|
||||
CRequestList* list = m_clipboards[id].m_requests[requestor];
|
||||
if (list == NULL) {
|
||||
list = new CRequestList;
|
||||
m_requests[requestor] = list;
|
||||
m_clipboards[id].m_requests[requestor] = list;
|
||||
}
|
||||
|
||||
// create request object
|
||||
|
@ -718,7 +755,8 @@ bool CXWindowsScreen::sendClipboardData(
|
|||
// set property to INCR
|
||||
const UInt32 zero = 0;
|
||||
XChangeProperty(m_display, requestor, property,
|
||||
m_atomINCR, 8 * sizeof(zero),
|
||||
m_atomINCR,
|
||||
8 * sizeof(zero),
|
||||
PropModeReplace,
|
||||
reinterpret_cast<const unsigned char*>(&zero),
|
||||
1);
|
||||
|
@ -730,7 +768,8 @@ bool CXWindowsScreen::sendClipboardData(
|
|||
XChangeProperty(m_display, requestor, property,
|
||||
type, size,
|
||||
PropModeReplace,
|
||||
reinterpret_cast<const unsigned char*>(data.data()),
|
||||
reinterpret_cast<const unsigned char*>(
|
||||
data.data()),
|
||||
data.size() / (size >> 3));
|
||||
}
|
||||
return true;
|
||||
|
@ -739,6 +778,7 @@ bool CXWindowsScreen::sendClipboardData(
|
|||
}
|
||||
|
||||
bool CXWindowsScreen::sendClipboardMultiple(
|
||||
ClipboardID id,
|
||||
Window requestor,
|
||||
Atom property, Time time)
|
||||
{
|
||||
|
@ -768,7 +808,7 @@ bool CXWindowsScreen::sendClipboardMultiple(
|
|||
|
||||
// handle target
|
||||
if (property != None) {
|
||||
if (!sendClipboardData(requestor, target, property, time)) {
|
||||
if (!sendClipboardData(id, requestor, target, property, time)) {
|
||||
// couldn't handle target. change property to None.
|
||||
const Atom none = None;
|
||||
data.replace((2 * index + 1) * sizeof(Atom), sizeof(Atom),
|
||||
|
@ -786,15 +826,18 @@ bool CXWindowsScreen::sendClipboardMultiple(
|
|||
if (updated) {
|
||||
// FIXME -- handle Alloc errors (by returning false)
|
||||
XChangeProperty(m_display, requestor, property,
|
||||
m_atomAtomPair, 8 * sizeof(Atom),
|
||||
m_atomAtomPair,
|
||||
8 * sizeof(Atom),
|
||||
PropModeReplace,
|
||||
reinterpret_cast<const unsigned char*>(data.data()),
|
||||
reinterpret_cast<const unsigned char*>(
|
||||
data.data()),
|
||||
data.length());
|
||||
}
|
||||
|
||||
// send notify if any format was successful
|
||||
if (success) {
|
||||
sendNotify(requestor, m_atomMultiple, success ? property : None, time);
|
||||
sendNotify(id, requestor, m_atomMultiple,
|
||||
success ? property : None, time);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -802,6 +845,7 @@ bool CXWindowsScreen::sendClipboardMultiple(
|
|||
}
|
||||
|
||||
bool CXWindowsScreen::sendClipboardTargets(
|
||||
ClipboardID id,
|
||||
Window requestor,
|
||||
Atom property, Time /*time*/)
|
||||
{
|
||||
|
@ -809,7 +853,7 @@ bool CXWindowsScreen::sendClipboardTargets(
|
|||
|
||||
// count the number of targets, plus TARGETS and MULTIPLE
|
||||
SInt32 numTargets = 2;
|
||||
if (m_clipboard.has(IClipboard::kText)) {
|
||||
if (m_clipboards[id].m_clipboard.has(IClipboard::kText)) {
|
||||
numTargets += 2;
|
||||
}
|
||||
|
||||
|
@ -818,7 +862,7 @@ bool CXWindowsScreen::sendClipboardTargets(
|
|||
SInt32 count = 0;
|
||||
response[count++] = m_atomTargets;
|
||||
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_atomString;
|
||||
}
|
||||
|
@ -826,7 +870,8 @@ bool CXWindowsScreen::sendClipboardTargets(
|
|||
// send response (we assume we can transfer the entire list at once)
|
||||
// FIXME -- handle Alloc errors (by returning false)
|
||||
XChangeProperty(m_display, requestor, property,
|
||||
m_atomAtom, 8 * sizeof(Atom),
|
||||
m_atomAtom,
|
||||
8 * sizeof(Atom),
|
||||
PropModeReplace,
|
||||
reinterpret_cast<unsigned char*>(response),
|
||||
count);
|
||||
|
@ -838,6 +883,7 @@ bool CXWindowsScreen::sendClipboardTargets(
|
|||
}
|
||||
|
||||
bool CXWindowsScreen::sendClipboardTimestamp(
|
||||
ClipboardID id,
|
||||
Window requestor,
|
||||
Atom property, Time /*time*/)
|
||||
{
|
||||
|
@ -845,22 +891,24 @@ bool CXWindowsScreen::sendClipboardTimestamp(
|
|||
|
||||
// FIXME -- handle Alloc errors (by returning false)
|
||||
XChangeProperty(m_display, requestor, property,
|
||||
m_atomInteger, 8 * sizeof(m_gotClipboard),
|
||||
m_atomInteger,
|
||||
8 * sizeof(m_clipboards[id].m_gotClipboard),
|
||||
PropModeReplace,
|
||||
reinterpret_cast<unsigned char*>(&m_gotClipboard),
|
||||
reinterpret_cast<unsigned char*>(
|
||||
&m_clipboards[id].m_gotClipboard),
|
||||
1);
|
||||
return true;
|
||||
}
|
||||
|
||||
void CXWindowsScreen::sendNotify(
|
||||
Window requestor, Atom target,
|
||||
Atom property, Time time)
|
||||
ClipboardID id, Window requestor,
|
||||
Atom target, Atom property, Time time)
|
||||
{
|
||||
XEvent event;
|
||||
event.xselection.type = SelectionNotify;
|
||||
event.xselection.display = m_display;
|
||||
event.xselection.requestor = requestor;
|
||||
event.xselection.selection = kClipboardSelection;
|
||||
event.xselection.selection = m_atomClipboard[id];
|
||||
event.xselection.target = target;
|
||||
event.xselection.property = property;
|
||||
event.xselection.time = time;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "CClipboard.h"
|
||||
#include "CMutex.h"
|
||||
#include "BasicTypes.h"
|
||||
#include "ClipboardTypes.h"
|
||||
#include <X11/Xlib.h>
|
||||
#include <map>
|
||||
#include <list>
|
||||
|
@ -56,19 +57,25 @@ class CXWindowsScreen {
|
|||
// cause getEvent() to return false immediately and forever after
|
||||
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
|
||||
// a SelectionClear event). returns true iff we've actually lost
|
||||
// a selection we care about.
|
||||
bool lostClipboard(Atom selection, Time timestamp);
|
||||
|
||||
// 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);
|
||||
|
||||
// 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.
|
||||
void getDisplayClipboard(IClipboard* clipboard,
|
||||
void getDisplayClipboard(ClipboardID,
|
||||
IClipboard* clipboard,
|
||||
Window requestor, Time timestamp) const;
|
||||
|
||||
// add a selection request to the request list
|
||||
|
@ -120,18 +127,31 @@ class CXWindowsScreen {
|
|||
static Bool findPropertyNotify(Display*,
|
||||
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);
|
||||
bool sendClipboardMultiple(Window requestor,
|
||||
bool sendClipboardTargets(ClipboardID, Window requestor,
|
||||
Atom property, Time time);
|
||||
bool sendClipboardTargets(Window requestor,
|
||||
Atom property, Time time);
|
||||
bool sendClipboardTimestamp(Window requestor,
|
||||
Atom property, Time time);
|
||||
void sendNotify(Window requestor, Atom target,
|
||||
bool sendClipboardTimestamp(ClipboardID, Window requestor,
|
||||
Atom property, Time time);
|
||||
void sendNotify(ClipboardID, Window requestor,
|
||||
Atom target, Atom property, Time time);
|
||||
|
||||
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;
|
||||
int m_screen;
|
||||
Window m_root;
|
||||
|
@ -150,7 +170,11 @@ class CXWindowsScreen {
|
|||
Atom m_atomString;
|
||||
Atom m_atomText;
|
||||
Atom m_atomCompoundText;
|
||||
Atom m_atomClipboard[kClipboardEnd];
|
||||
|
||||
// clipboard info
|
||||
ClipboardInfo m_clipboards[kClipboardEnd];
|
||||
/*
|
||||
// the contents of our selection
|
||||
CClipboard m_clipboard;
|
||||
|
||||
|
@ -160,6 +184,7 @@ class CXWindowsScreen {
|
|||
|
||||
// the request queues
|
||||
CRequestMap m_requests;
|
||||
*/
|
||||
|
||||
// X is not thread safe
|
||||
CMutex m_mutex;
|
||||
|
|
|
@ -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
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "IInterface.h"
|
||||
#include "BasicTypes.h"
|
||||
#include "ClipboardTypes.h"
|
||||
|
||||
class CServer;
|
||||
class IClipboard;
|
||||
|
@ -49,7 +50,7 @@ class IPrimaryScreen : public IInterface {
|
|||
|
||||
// set the screen's clipboard contents. this is usually called
|
||||
// soon after an enter().
|
||||
virtual void setClipboard(const IClipboard*) = 0;
|
||||
virtual void setClipboard(ClipboardID, const IClipboard*) = 0;
|
||||
|
||||
/*
|
||||
// show or hide the screen saver
|
||||
|
@ -57,7 +58,7 @@ class IPrimaryScreen : public IInterface {
|
|||
*/
|
||||
|
||||
// synergy should own the clipboard
|
||||
virtual void grabClipboard() = 0;
|
||||
virtual void grabClipboard(ClipboardID) = 0;
|
||||
|
||||
// accessors
|
||||
|
||||
|
@ -75,7 +76,7 @@ class IPrimaryScreen : public IInterface {
|
|||
virtual SInt32 getJumpZoneSize() const = 0;
|
||||
|
||||
// get the screen's clipboard contents
|
||||
virtual void getClipboard(IClipboard*) const = 0;
|
||||
virtual void getClipboard(ClipboardID, IClipboard*) const = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "IInterface.h"
|
||||
#include "BasicTypes.h"
|
||||
#include "ClipboardTypes.h"
|
||||
#include "KeyTypes.h"
|
||||
#include "MouseTypes.h"
|
||||
|
||||
|
@ -52,7 +53,7 @@ class ISecondaryScreen : public IInterface {
|
|||
|
||||
// set the screen's clipboard contents. this is usually called
|
||||
// soon after an enter().
|
||||
virtual void setClipboard(const IClipboard*) = 0;
|
||||
virtual void setClipboard(ClipboardID, const IClipboard*) = 0;
|
||||
|
||||
/*
|
||||
// show or hide the screen saver
|
||||
|
@ -60,7 +61,7 @@ class ISecondaryScreen : public IInterface {
|
|||
*/
|
||||
|
||||
// take ownership of clipboard
|
||||
virtual void grabClipboard() = 0;
|
||||
virtual void grabClipboard(ClipboardID) = 0;
|
||||
|
||||
// accessors
|
||||
|
||||
|
@ -71,7 +72,7 @@ class ISecondaryScreen : public IInterface {
|
|||
virtual SInt32 getJumpZoneSize() const = 0;
|
||||
|
||||
// get the screen's clipboard contents
|
||||
virtual void getClipboard(IClipboard*) const = 0;
|
||||
virtual void getClipboard(ClipboardID, IClipboard*) const = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef ISERVERPROTOCOL_H
|
||||
#define ISERVERPROTOCOL_H
|
||||
|
||||
#include "ClipboardTypes.h"
|
||||
#include "KeyTypes.h"
|
||||
#include "MouseTypes.h"
|
||||
#include "IInterface.h"
|
||||
|
@ -25,9 +26,9 @@ class IServerProtocol : public IInterface {
|
|||
virtual void sendClose() = 0;
|
||||
virtual void sendEnter(SInt32 xAbs, SInt32 yAbs) = 0;
|
||||
virtual void sendLeave() = 0;
|
||||
virtual void sendClipboard(const CString&) = 0;
|
||||
virtual void sendGrabClipboard() = 0;
|
||||
virtual void sendQueryClipboard(UInt32 seqNum) = 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;
|
||||
|
|
|
@ -7,30 +7,101 @@
|
|||
static const SInt32 kMajorVersion = 0;
|
||||
static const SInt32 kMinorVersion = 1;
|
||||
|
||||
// message codes (trailing NUL is not part of code). codes are
|
||||
// grouped into:
|
||||
// commands -- request an action, no reply expected
|
||||
// queries -- request info
|
||||
// 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
|
||||
//
|
||||
// message codes (trailing NUL is not part of code). in comments, $n
|
||||
// refers to the n'th argument (counting from one). message codes are
|
||||
// always 4 bytes optionally followed by message specific parameters.
|
||||
//
|
||||
|
||||
static const char kMsgDKeyDown[] = "DKDN%2i%2i"; // server
|
||||
static const char kMsgDKeyRepeat[] = "DKRP%2i%2i%2i"; // server
|
||||
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
|
||||
//
|
||||
// command codes
|
||||
//
|
||||
|
||||
static const char kMsgQClipboard[] = "QCLP%4i"; // server
|
||||
static const char kMsgQInfo[] = "QINF"; // server
|
||||
// close connection; primary -> secondary
|
||||
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";
|
||||
|
||||
|
|
Loading…
Reference in New Issue