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);
|
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()
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
ClipboardInfo& clipboard = m_clipboards[id];
|
||||||
|
if (clipboard.m_clipboardReady && !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[id] = true;
|
||||||
}
|
}
|
||||||
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
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,8 +82,10 @@ 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];
|
||||||
|
for (CRequestMap::iterator index = clipboard.m_requests.begin();
|
||||||
|
index != clipboard.m_requests.end(); ++index) {
|
||||||
CRequestList* list = index->second;
|
CRequestList* list = index->second;
|
||||||
for (CRequestList::iterator index2 = list->begin();
|
for (CRequestList::iterator index2 = list->begin();
|
||||||
index2 != list->end(); ++index2) {
|
index2 != list->end(); ++index2) {
|
||||||
|
@ -87,7 +93,8 @@ void CXWindowsScreen::closeDisplay()
|
||||||
}
|
}
|
||||||
delete list;
|
delete list;
|
||||||
}
|
}
|
||||||
m_requests.clear();
|
clipboard.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) {
|
||||||
|
if (selection == m_atomClipboard[id]) {
|
||||||
// note the time
|
// note the time
|
||||||
CLock lock(&m_mutex);
|
CLock lock(&m_mutex);
|
||||||
m_lostClipboard = timestamp;
|
m_clipboards[id].m_lostClipboard = timestamp;
|
||||||
log((CLOG_INFO "lost clipboard ownership at %d", timestamp));
|
log((CLOG_INFO "lost clipboard %d ownership at %d", id, timestamp));
|
||||||
return true;
|
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,10 +594,15 @@ void CXWindowsScreen::processClipboardRequest(
|
||||||
{
|
{
|
||||||
CLock lock(&m_mutex);
|
CLock lock(&m_mutex);
|
||||||
|
|
||||||
|
// check every clipboard
|
||||||
|
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
|
||||||
|
ClipboardInfo& clipboard = m_clipboards[id];
|
||||||
|
|
||||||
// find the request list
|
// find the request list
|
||||||
CRequestMap::iterator index = m_requests.find(requestor);
|
CRequestMap::iterator index = clipboard.m_requests.find(requestor);
|
||||||
if (index == m_requests.end()) {
|
if (index == clipboard.m_requests.end()) {
|
||||||
return;
|
// this clipboard isn't servicing this requestor window
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
CRequestList* list = index->second;
|
CRequestList* list = index->second;
|
||||||
assert(list != NULL);
|
assert(list != NULL);
|
||||||
|
@ -588,8 +615,8 @@ void CXWindowsScreen::processClipboardRequest(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (index2 == list->end()) {
|
if (index2 == list->end()) {
|
||||||
log((CLOG_WARN "received property event on unexpected property"));
|
// this clipboard isn't waiting on this property
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
CClipboardRequest* request = *index2;
|
CClipboardRequest* request = *index2;
|
||||||
assert(request != NULL);
|
assert(request != NULL);
|
||||||
|
@ -624,11 +651,15 @@ void CXWindowsScreen::processClipboardRequest(
|
||||||
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CXWindowsScreen::destroyClipboardRequest(
|
void CXWindowsScreen::destroyClipboardRequest(
|
||||||
|
@ -636,10 +667,14 @@ void CXWindowsScreen::destroyClipboardRequest(
|
||||||
{
|
{
|
||||||
CLock lock(&m_mutex);
|
CLock lock(&m_mutex);
|
||||||
|
|
||||||
|
// check every clipboard
|
||||||
|
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
|
||||||
|
ClipboardInfo& clipboard = m_clipboards[id];
|
||||||
|
|
||||||
// find the request list
|
// find the request list
|
||||||
CRequestMap::iterator index = m_requests.find(requestor);
|
CRequestMap::iterator index = clipboard.m_requests.find(requestor);
|
||||||
if (index == m_requests.end()) {
|
if (index == clipboard.m_requests.end()) {
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
CRequestList* list = index->second;
|
CRequestList* list = index->second;
|
||||||
assert(list != NULL);
|
assert(list != NULL);
|
||||||
|
@ -651,22 +686,24 @@ void CXWindowsScreen::destroyClipboardRequest(
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 "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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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";
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue