checkpoint. adding support for unicode in clipboard.

This commit is contained in:
crs 2002-07-22 17:32:51 +00:00
parent 4c2cbb9f03
commit 643d0f1089
13 changed files with 966 additions and 97 deletions

530
base/CUnicode.cpp Normal file
View File

@ -0,0 +1,530 @@
#include "CUnicode.h"
#include <string.h>
//
// local utility functions
//
inline
static
UInt16
decode16(const UInt8* n)
{
union x16 {
UInt8 n8[2];
UInt16 n16;
} c;
c.n8[0] = n[0];
c.n8[1] = n[1];
return c.n16;
}
inline
static
UInt32
decode32(const UInt8* n)
{
union x32 {
UInt8 n8[4];
UInt32 n32;
} c;
c.n8[0] = n[0];
c.n8[1] = n[1];
c.n8[2] = n[2];
c.n8[3] = n[3];
return c.n32;
}
//
// CUnicode
//
UInt32 CUnicode::s_invalid = 0x0000ffff;
CString
CUnicode::UTF8ToUCS2(const CString& src)
{
// get size of input string and reserve some space in output.
// include UTF8's nul terminator.
UInt32 n = src.size() + 1;
CString dst;
dst.reserve(2 * n);
// convert each character
const UInt8* data = reinterpret_cast<const UInt8*>(src.c_str());
while (n > 0) {
UInt32 c = fromUTF8(data, n);
if (c != s_invalid && c < 0x0000ffff) {
UInt16 ucs2 = static_cast<UInt16>(c);
dst.append(reinterpret_cast<const char*>(&ucs2), 2);
}
}
return dst;
}
CString
CUnicode::UTF8ToUCS4(const CString& src)
{
// get size of input string and reserve some space in output.
// include UTF8's nul terminator.
UInt32 n = src.size() + 1;
CString dst;
dst.reserve(4 * n);
// convert each character
const UInt8* data = reinterpret_cast<const UInt8*>(src.c_str());
while (n > 0) {
UInt32 c = fromUTF8(data, n);
if (c != s_invalid) {
dst.append(reinterpret_cast<const char*>(&c), 4);
}
}
return dst;
}
CString
CUnicode::UTF8ToUTF16(const CString& src)
{
// get size of input string and reserve some space in output.
// include UTF8's nul terminator.
UInt32 n = src.size() + 1;
CString dst;
dst.reserve(2 * n);
// convert each character
const UInt8* data = reinterpret_cast<const UInt8*>(src.c_str());
while (n > 0) {
UInt32 c = fromUTF8(data, n);
if (c != s_invalid && c < 0x0010ffff) {
if (c < 0x00010000) {
UInt16 ucs2 = static_cast<UInt16>(c);
dst.append(reinterpret_cast<const char*>(&ucs2), 2);
}
else {
c -= 0x00010000;
UInt16 utf16h = static_cast<UInt16>(c >> 10) + 0xd800;
UInt16 utf16l = (static_cast<UInt16>(c) & 0x03ff) + 0xdc00;
dst.append(reinterpret_cast<const char*>(&utf16h), 2);
dst.append(reinterpret_cast<const char*>(&utf16l), 2);
}
}
}
return dst;
}
CString
CUnicode::UTF8ToUTF32(const CString& src)
{
// FIXME -- should ensure dst has no characters over U-0010FFFF
return UTF8ToUCS4(src);
}
CString
CUnicode::UCS2ToUTF8(const CString& src)
{
UInt32 n = src.size() >> 1;
return doUCS2ToUTF8(reinterpret_cast<const UInt8*>(src.data()), n);
}
CString
CUnicode::UCS4ToUTF8(const CString& src)
{
UInt32 n = src.size() >> 2;
return doUCS4ToUTF8(reinterpret_cast<const UInt8*>(src.data()), n);
}
CString
CUnicode::UTF16ToUTF8(const CString& src)
{
UInt32 n = src.size() >> 1;
return doUTF16ToUTF8(reinterpret_cast<const UInt8*>(src.data()), n);
}
CString
CUnicode::UTF32ToUTF8(const CString& src)
{
UInt32 n = src.size() >> 2;
return doUTF32ToUTF8(reinterpret_cast<const UInt8*>(src.data()), n);
}
CString
CUnicode::UTF8ToText(const CString& src)
{
// convert to wide char
wchar_t* tmp = UTF8ToWideChar(src);
// get length of multibyte string
mbstate_t state;
memset(&state, 0, sizeof(state));
const wchar_t* scratch = tmp;
size_t len = wcsrtombs(NULL, &scratch, 0, &state);
if (len == (size_t)-1) {
// invalid character in src
delete[] tmp;
return CString();
}
// convert to multibyte
scratch = tmp;
char* dst = new char[len + 1];
wcsrtombs(dst, &scratch, len + 1, &state);
CString text(dst);
// clean up
delete[] dst;
delete[] tmp;
return text;
}
CString
CUnicode::textToUTF8(const CString& src)
{
// get length of wide char string
mbstate_t state;
memset(&state, 0, sizeof(state));
const char* scratch = src.c_str();
size_t len = mbsrtowcs(NULL, &scratch, 0, &state);
if (len == (size_t)-1) {
// invalid character in src
return CString();
}
// convert multibyte to wide char
scratch = src.c_str();
wchar_t* dst = new wchar_t[len + 1];
mbsrtowcs(dst, &scratch, len + 1, &state);
// convert to UTF8
CString utf8 = wideCharToUTF8(dst);
// clean up
delete[] dst;
return utf8;
}
wchar_t*
CUnicode::UTF8ToWideChar(const CString& src)
{
// convert to platform's wide character encoding.
// note -- this must include a wide nul character (independent of
// the CString's nul character).
#if WINDOWS_LIKE
CString tmp = UTF8ToUCS16(src);
UInt32 size = tmp.size() >> 1;
#elif UNIX_LIKE
CString tmp = UTF8ToUCS4(src);
UInt32 size = tmp.size() >> 2;
#endif
// copy to a wchar_t array
wchar_t* dst = new wchar_t[size];
::memcpy(dst, src.data(), sizeof(wchar_t) * size);
return dst;
}
CString
CUnicode::wideCharToUTF8(const wchar_t* src)
{
// convert from platform's wide character encoding.
// note -- this must include a wide nul character (independent of
// the CString's nul character).
#if WINDOWS_LIKE
return doUCS16ToUTF8(reinterpret_cast<const UInt8*>(src), wcslen(src));
#elif UNIX_LIKE
return doUCS4ToUTF8(reinterpret_cast<const UInt8*>(src), wcslen(src));
#endif
}
CString
CUnicode::doUCS2ToUTF8(const UInt8* data, UInt32 n)
{
// make some space
CString dst;
dst.reserve(n);
// convert each character
for (; n > 0; data += 2, --n) {
UInt32 c = decode16(data);
toUTF8(dst, c);
}
// remove extra trailing nul
if (dst.size() > 0 && dst[dst.size() - 1] == '\0') {
dst.resize(dst.size() - 1);
}
return dst;
}
CString
CUnicode::doUCS4ToUTF8(const UInt8* data, UInt32 n)
{
// make some space
CString dst;
dst.reserve(n);
// convert each character
for (; n > 0; data += 4, --n) {
UInt32 c = decode32(data);
toUTF8(dst, c);
}
// remove extra trailing nul
if (dst.size() > 0 && dst[dst.size() - 1] == '\0') {
dst.resize(dst.size() - 1);
}
return dst;
}
CString
CUnicode::doUTF16ToUTF8(const UInt8* data, UInt32 n)
{
// make some space
CString dst;
dst.reserve(n);
// convert each character
for (; n > 0; data += 2, --n) {
UInt32 c = decode16(data);
if (c < 0x0000d800 || c > 0x0000dfff) {
toUTF8(dst, c);
}
else if (n == 1) {
// error -- missing second word
}
else if (c >= 0x0000d800 && c <= 0x0000dbff) {
UInt32 c2 = decode16(data);
data += 2;
--n;
if (c2 < 0x0000dc00 || c2 > 0x0000dfff) {
// error -- [d800,dbff] not followed by [dc00,dfff]
}
else {
c = (((c - 0x0000d800) << 10) | (c2 - 0x0000dc00)) + 0x00010000;
toUTF8(dst, c);
}
}
else {
// error -- [dc00,dfff] without leading [d800,dbff]
}
}
// remove extra trailing nul
if (dst.size() > 0 && dst[dst.size() - 1] == '\0') {
dst.resize(dst.size() - 1);
}
return dst;
}
CString
CUnicode::doUTF32ToUTF8(const UInt8* data, UInt32 n)
{
// FIXME -- should check that src has no characters over U-0010FFFF
return doUCS4ToUTF8(data, n);
}
UInt32
CUnicode::fromUTF8(const UInt8*& data, UInt32& n)
{
assert(data != NULL);
assert(n != 0);
// compute character encoding length, checking for overlong
// sequences (i.e. characters that don't use the shortest
// possible encoding).
UInt32 size;
if (data[0] < 0x80) {
// 0xxxxxxx
size = 1;
}
else if (data[0] < 0xc0) {
// 10xxxxxx -- in the middle of a multibyte character. skip
// until we find a start byte and return error.
do {
--n;
++data;
} while (n > 0 && (data[0] & 0xc0) == 0x80);
return s_invalid;
}
else if (data[0] < 0xe0) {
// 110xxxxx
size = 2;
}
else if (data[0] < 0xf0) {
// 1110xxxx
size = 3;
}
else if (data[0] < 0xf8) {
// 11110xxx
size = 4;
}
else if (data[0] < 0xfc) {
// 111110xx
size = 5;
}
else if (data[0] < 0xfe) {
// 1111110x
size = 6;
}
else {
// invalid sequence. dunno how many bytes to skip so skip one.
--n;
++data;
return s_invalid;
}
// make sure we have enough data
if (size > n) {
data += n;
n = 0;
return s_invalid;
}
// extract character
UInt32 c;
switch (size) {
case 1:
c = static_cast<UInt32>(data[0]);
break;
case 2:
c = ((static_cast<UInt32>(data[0]) & 0x1f) << 6) |
((static_cast<UInt32>(data[1]) & 0x3f) );
break;
case 3:
c = ((static_cast<UInt32>(data[0]) & 0x0f) << 12) |
((static_cast<UInt32>(data[1]) & 0x3f) << 6) |
((static_cast<UInt32>(data[2]) & 0x3f) );
break;
case 4:
c = ((static_cast<UInt32>(data[0]) & 0x07) << 18) |
((static_cast<UInt32>(data[1]) & 0x3f) << 12) |
((static_cast<UInt32>(data[1]) & 0x3f) << 6) |
((static_cast<UInt32>(data[1]) & 0x3f) );
break;
case 5:
c = ((static_cast<UInt32>(data[0]) & 0x03) << 24) |
((static_cast<UInt32>(data[1]) & 0x3f) << 18) |
((static_cast<UInt32>(data[1]) & 0x3f) << 12) |
((static_cast<UInt32>(data[1]) & 0x3f) << 6) |
((static_cast<UInt32>(data[1]) & 0x3f) );
break;
case 6:
c = ((static_cast<UInt32>(data[0]) & 0x01) << 30) |
((static_cast<UInt32>(data[1]) & 0x3f) << 24) |
((static_cast<UInt32>(data[1]) & 0x3f) << 18) |
((static_cast<UInt32>(data[1]) & 0x3f) << 12) |
((static_cast<UInt32>(data[1]) & 0x3f) << 6) |
((static_cast<UInt32>(data[1]) & 0x3f) );
break;
default:
assert(0 && "invalid size");
}
// update parameters
data += size;
n -= size;
// check for characters that didn't use the smallest possible encoding
static UInt32 s_minChar[] = {
0,
0x00000000,
0x00000080,
0x00000800,
0x00010000,
0x00200000,
0x04000000
};
if (c < s_minChar[size]) {
return s_invalid;
}
// check that all bytes after the first have the pattern 10xxxxxx.
UInt8 a = 0x80;
switch (size) {
case 6:
a |= data[5];
// fall through
case 5:
a |= data[4];
// fall through
case 4:
a |= data[3];
// fall through
case 3:
a |= data[2];
// fall through
case 2:
a |= data[1];
}
if ((a & 0xc0) != 0x80) {
return s_invalid;
}
return c;
}
void
CUnicode::toUTF8(CString& dst, const UInt32 c)
{
UInt8 data[6];
if (c < 0x00000080) {
data[0] = static_cast<UInt8>(c);
dst.append(reinterpret_cast<char*>(data), 1);
}
else if (c < 0x00000800) {
data[0] = static_cast<UInt8>((c >> 6) & 0x0000001f) + 0xc0;
data[1] = static_cast<UInt8>(c & 0x0000003f) + 0x80;
dst.append(reinterpret_cast<char*>(data), 2);
}
else if (c < 0x00010000) {
data[0] = static_cast<UInt8>((c >> 12) & 0x0000000f) + 0xe0;
data[1] = static_cast<UInt8>((c >> 6) & 0x0000003f) + 0x80;
data[2] = static_cast<UInt8>(c & 0x0000003f) + 0x80;
dst.append(reinterpret_cast<char*>(data), 3);
}
else if (c < 0x00200000) {
data[0] = static_cast<UInt8>((c >> 18) & 0x00000007) + 0xf0;
data[1] = static_cast<UInt8>((c >> 12) & 0x0000003f) + 0x80;
data[2] = static_cast<UInt8>((c >> 6) & 0x0000003f) + 0x80;
data[3] = static_cast<UInt8>(c & 0x0000003f) + 0x80;
dst.append(reinterpret_cast<char*>(data), 4);
}
else if (c < 0x04000000) {
data[0] = static_cast<UInt8>((c >> 24) & 0x00000003) + 0xf8;
data[1] = static_cast<UInt8>((c >> 18) & 0x0000003f) + 0x80;
data[2] = static_cast<UInt8>((c >> 12) & 0x0000003f) + 0x80;
data[3] = static_cast<UInt8>((c >> 6) & 0x0000003f) + 0x80;
data[4] = static_cast<UInt8>(c & 0x0000003f) + 0x80;
dst.append(reinterpret_cast<char*>(data), 5);
}
else if (c < 0x80000000) {
data[0] = static_cast<UInt8>((c >> 30) & 0x00000001) + 0xfc;
data[1] = static_cast<UInt8>((c >> 24) & 0x0000003f) + 0x80;
data[2] = static_cast<UInt8>((c >> 18) & 0x0000003f) + 0x80;
data[3] = static_cast<UInt8>((c >> 12) & 0x0000003f) + 0x80;
data[4] = static_cast<UInt8>((c >> 6) & 0x0000003f) + 0x80;
data[5] = static_cast<UInt8>(c & 0x0000003f) + 0x80;
dst.append(reinterpret_cast<char*>(data), 6);
}
else {
// invalid character
}
}

48
base/CUnicode.h Normal file
View File

@ -0,0 +1,48 @@
#ifndef CUNICODE_H
#define CUNICODE_H
#include "CString.h"
#include "BasicTypes.h"
#include <wchar.h>
class CUnicode {
public:
static CString UTF8ToUCS2(const CString&);
static CString UTF8ToUCS4(const CString&);
static CString UTF8ToUTF16(const CString&);
static CString UTF8ToUTF32(const CString&);
static CString UCS2ToUTF8(const CString&);
static CString UCS4ToUTF8(const CString&);
static CString UTF16ToUTF8(const CString&);
static CString UTF32ToUTF8(const CString&);
// convert UTF-8 to/from the current locale's encoding
static CString UTF8ToText(const CString&);
static CString textToUTF8(const CString&);
private:
// convert UTF8 to nul terminated wchar_t string (using whatever
// encoding is native to the platform). caller must delete[]
// the returned string.
static wchar_t* UTF8ToWideChar(const CString&);
// convert nul terminated wchar_t string (in platform's native
// encoding) to UTF8.
static CString wideCharToUTF8(const wchar_t*);
// internal conversion to UTF8
static CString doUCS2ToUTF8(const UInt8* src, UInt32 n);
static CString doUCS4ToUTF8(const UInt8* src, UInt32 n);
static CString doUTF16ToUTF8(const UInt8* src, UInt32 n);
static CString doUTF32ToUTF8(const UInt8* src, UInt32 n);
// convert characters to/from UTF8
static UInt32 fromUTF8(const UInt8*& src, UInt32& size);
static void toUTF8(CString& dst, const UInt32 c);
private:
static UInt32 s_invalid;
};
#endif

View File

@ -8,12 +8,14 @@ libbase_a_SOURCES = \
CLog.cpp \ CLog.cpp \
CStopwatch.cpp \ CStopwatch.cpp \
CString.cpp \ CString.cpp \
CUnicode.cpp \
XBase.cpp \ XBase.cpp \
BasicTypes.h \ BasicTypes.h \
CFunctionJob.h \ CFunctionJob.h \
CLog.h \ CLog.h \
CStopwatch.h \ CStopwatch.h \
CString.h \ CString.h \
CUnicode.h \
IInterface.h \ IInterface.h \
IJob.h \ IJob.h \
TMethodJob.h \ TMethodJob.h \

View File

@ -1,4 +1,7 @@
#include "CXWindowsClipboard.h" #include "CXWindowsClipboard.h"
#include "CXWindowsClipboardTextConverter.h"
#include "CXWindowsClipboardUCS2Converter.h"
#include "CXWindowsClipboardUTF8Converter.h"
#include "CXWindowsUtil.h" #include "CXWindowsUtil.h"
#include "CThread.h" #include "CThread.h"
#include "CLog.h" #include "CLog.h"
@ -52,6 +55,20 @@ CXWindowsClipboard::CXWindowsClipboard(Display* display,
break; break;
} }
// add converters
m_converters.push_back(new CXWindowsClipboardUTF8Converter(m_display,
"text/plain;charset=UTF-8"));
m_converters.push_back(new CXWindowsClipboardUTF8Converter(m_display,
"UTF8_STRING"));
m_converters.push_back(new CXWindowsClipboardUCS2Converter(m_display,
"text/plain;charset=ISO-10646-UCS-2"));
m_converters.push_back(new CXWindowsClipboardUCS2Converter(m_display,
"text/unicode"));
m_converters.push_back(new CXWindowsClipboardTextConverter(m_display,
"text/plain"));
m_converters.push_back(new CXWindowsClipboardTextConverter(m_display,
"STRING"));
// we have no data // we have no data
clearCache(); clearCache();
} }
@ -59,6 +76,7 @@ CXWindowsClipboard::CXWindowsClipboard(Display* display,
CXWindowsClipboard::~CXWindowsClipboard() CXWindowsClipboard::~CXWindowsClipboard()
{ {
clearReplies(); clearReplies();
clearConverters();
} }
void void
@ -132,9 +150,17 @@ CXWindowsClipboard::addSimpleRequest(Window requestor,
else if (target == m_atomTimestamp) { else if (target == m_atomTimestamp) {
type = getTimestampData(data, &format); type = getTimestampData(data, &format);
} }
else if (target == m_atomString || else {
target == m_atomText) { IXWindowsClipboardConverter* converter = getConverter(target);
type = getStringData(data, &format); IClipboard::EFormat clipboardFormat = converter->getFormat();
if (!m_added[clipboardFormat]) {
type = None;
}
else {
type = converter->getAtom();
format = converter->getDataSize();
data = converter->fromIClipboard(m_data[clipboardFormat]);
}
} }
if (type != None) { if (type != None) {
@ -334,17 +360,41 @@ CXWindowsClipboard::get(EFormat format) const
return m_data[format]; return m_data[format];
} }
IClipboard::EFormat void
CXWindowsClipboard::getFormat(Atom src) const CXWindowsClipboard::clearConverters()
{ {
// FIXME -- handle more formats (especially mime-type-like formats for (ConverterList::iterator index = m_converters.begin();
// and various character encodings like unicode). index != m_converters.end(); ++index) {
if (src == m_atomString || delete *index;
src == m_atomText /*||
src == m_atomCompoundText*/) {
return IClipboard::kText;
} }
return IClipboard::kNumFormats; m_converters.clear();
}
IXWindowsClipboardConverter*
CXWindowsClipboard::getConverter(Atom target, bool onlyIfNotAdded) const
{
IXWindowsClipboardConverter* converter = NULL;
for (ConverterList::const_iterator index = m_converters.begin();
index != m_converters.end(); ++index) {
converter = *index;
if (converter->getAtom() == target) {
break;
}
}
if (converter == NULL) {
log((CLOG_DEBUG1 " no converter for target %d", target));
return NULL;
}
// optionally skip already handled targets
if (onlyIfNotAdded) {
if (m_added[converter->getFormat()]) {
log((CLOG_DEBUG1 " skipping handled format %d", converter->getFormat()));
return NULL;
}
}
return converter;
} }
void void
@ -438,44 +488,29 @@ CXWindowsClipboard::icccmFillCache()
const Atom* targets = reinterpret_cast<const Atom*>(data.data()); const Atom* targets = reinterpret_cast<const Atom*>(data.data());
const UInt32 numTargets = data.size() / sizeof(Atom); const UInt32 numTargets = data.size() / sizeof(Atom);
for (UInt32 i = 0; i < numTargets; ++i) { for (UInt32 i = 0; i < numTargets; ++i) {
// determine the expected clipboard format // see if we have a converter for this target
Atom target = targets[i]; Atom target = targets[i];
IClipboard::EFormat expectedFormat = getFormat(target); IXWindowsClipboardConverter* converter = getConverter(target, true);
if (expectedFormat == IClipboard::kNumFormats) { if (converter == NULL) {
log((CLOG_DEBUG1 " no format for target %d", target));
continue;
}
log((CLOG_DEBUG1 " source target %d -> %d", target, expectedFormat));
// skip already handled targets
if (m_added[expectedFormat]) {
log((CLOG_DEBUG1 " skipping handled format %d", expectedFormat));
continue; continue;
} }
// get the data
Atom actualTarget; Atom actualTarget;
CString targetData; CString targetData;
if (!icccmGetSelection(target, &actualTarget, &targetData)) { if (!icccmGetSelection(target, &actualTarget, &targetData)) {
log((CLOG_DEBUG1 " no data for target", target)); log((CLOG_DEBUG1 " no data for target", target));
continue; continue;
} }
logc(actualTarget != target, (CLOG_DEBUG1 " actual target is %d", actualTarget)); if (actualTarget != target) {
log((CLOG_DEBUG1 " expected (%d) and actual (%d) targets differ", target, actualTarget));
// use the actual format, not the expected
IClipboard::EFormat actualFormat = getFormat(actualTarget);
if (actualFormat == IClipboard::kNumFormats) {
log((CLOG_DEBUG1 " no format for target %d", actualTarget));
continue;
}
if (m_added[actualFormat]) {
log((CLOG_DEBUG1 " skipping handled format %d", actualFormat));
continue; continue;
} }
// add to clipboard and note we've done it // add to clipboard and note we've done it
m_data[actualFormat] = targetData; m_data[converter->getFormat()] = converter->toIClipboard(targetData);
m_added[actualFormat] = true; m_added[converter->getFormat()] = true;
log((CLOG_DEBUG " added format %d for target %d", actualFormat, target)); log((CLOG_DEBUG " added format %d for target %d", converter->getFormat(), target));
} }
} }
@ -676,42 +711,36 @@ CXWindowsClipboard::motifFillCache()
continue; continue;
} }
// determine the expected clipboard format
Atom target = motifFormat->m_type;
IClipboard::EFormat expectedFormat = getFormat(target);
if (expectedFormat == IClipboard::kNumFormats) {
log((CLOG_DEBUG1 " no format for target %d", target));
continue;
}
log((CLOG_DEBUG1 " source target %d -> %d", target, expectedFormat));
// skip already handled targets // see if we have a converter for this target
if (m_added[expectedFormat]) { Atom target = motifFormat->m_type;
log((CLOG_DEBUG1 " skipping handled format %d", expectedFormat)); IXWindowsClipboardConverter* converter = getConverter(target, true);
if (converter == NULL) {
continue; continue;
} }
// get the data (finally) // get the data (finally)
SInt32 length = motifFormat->m_length; SInt32 length = motifFormat->m_length;
sprintf(name, "_MOTIF_CLIP_ITEM_%d", motifFormat->m_data); sprintf(name, "_MOTIF_CLIP_ITEM_%d", motifFormat->m_data);
Atom atomData = XInternAtom(m_display, name, False); Atom atomData = XInternAtom(m_display, name, False), atomTarget;
data = ""; CString targetData;
if (!CXWindowsUtil::getWindowProperty(m_display, root, if (!CXWindowsUtil::getWindowProperty(m_display, root,
atomData, &data, atomData, &targetData,
&target, &format, False)) { &atomTarget, &format, False)) {
log((CLOG_DEBUG1 " no data for target", target));
continue; continue;
} }
if (target != atomData) { if (atomTarget != atomData) {
continue; continue;
} }
// truncate data to length specified in the format // truncate data to length specified in the format
data.erase(length); targetData.erase(length);
// add to clipboard and note we've done it // add to clipboard and note we've done it
m_data[expectedFormat] = data; m_data[converter->getFormat()] = converter->toIClipboard(targetData);
m_added[expectedFormat] = true; m_added[converter->getFormat()] = true;
log((CLOG_DEBUG " added format %d for target %d", expectedFormat, motifFormat->m_type)); log((CLOG_DEBUG " added format %d for target %d", converter->getFormat(), target));
} }
} }
@ -1061,7 +1090,7 @@ CXWindowsClipboard::getTargetsData(CString& data, int* format) const
{ {
assert(format != NULL); assert(format != NULL);
// construct response // add standard targets
Atom atom; Atom atom;
atom = m_atomTargets; atom = m_atomTargets;
data.append(reinterpret_cast<char*>(&atom), sizeof(Atom)); data.append(reinterpret_cast<char*>(&atom), sizeof(Atom));
@ -1069,12 +1098,18 @@ CXWindowsClipboard::getTargetsData(CString& data, int* format) const
data.append(reinterpret_cast<char*>(&atom), sizeof(Atom)); data.append(reinterpret_cast<char*>(&atom), sizeof(Atom));
atom = m_atomTimestamp; atom = m_atomTimestamp;
data.append(reinterpret_cast<char*>(&atom), sizeof(Atom)); data.append(reinterpret_cast<char*>(&atom), sizeof(Atom));
if (m_added[kText]) {
atom = m_atomString; // add targets we can convert to
data.append(reinterpret_cast<char*>(&atom), sizeof(Atom)); for (ConverterList::const_iterator index = m_converters.begin();
atom = m_atomText; index != m_converters.end(); ++index) {
IXWindowsClipboardConverter* converter = *index;
// skip formats we don't have
if (!m_added[converter->getFormat()]) {
atom = converter->getAtom();
data.append(reinterpret_cast<char*>(&atom), sizeof(Atom)); data.append(reinterpret_cast<char*>(&atom), sizeof(Atom));
} }
}
*format = 32; *format = 32;
return m_atomTargets; return m_atomTargets;
@ -1092,21 +1127,6 @@ CXWindowsClipboard::getTimestampData(CString& data, int* format) const
return m_atomTimestamp; return m_atomTimestamp;
} }
Atom
CXWindowsClipboard::getStringData(CString& data, int* format) const
{
assert(format != NULL);
if (m_added[kText]) {
data = m_data[kText];
*format = 8;
return m_atomString;
}
else {
return None;
}
}
// //
// CXWindowsClipboard::CICCCMGetClipboard // CXWindowsClipboard::CICCCMGetClipboard

View File

@ -5,12 +5,15 @@
#include "ClipboardTypes.h" #include "ClipboardTypes.h"
#include "stdmap.h" #include "stdmap.h"
#include "stdlist.h" #include "stdlist.h"
#include "stdvector.h"
#if defined(X_DISPLAY_MISSING) #if defined(X_DISPLAY_MISSING)
# error X11 is required to build synergy # error X11 is required to build synergy
#else #else
# include <X11/Xlib.h> # include <X11/Xlib.h>
#endif #endif
class IXWindowsClipboardConverter;
class CXWindowsClipboard : public IClipboard { class CXWindowsClipboard : public IClipboard {
public: public:
CXWindowsClipboard(Display*, Window, ClipboardID); CXWindowsClipboard(Display*, Window, ClipboardID);
@ -51,6 +54,17 @@ public:
virtual CString get(EFormat) const; virtual CString get(EFormat) const;
private: private:
// remove all converters from our list
void clearConverters();
// get the converter for a clipboard format. returns NULL if no
// suitable converter. iff onlyIfNotAdded is true then also
// return NULL if a suitable converter was found but we already
// have data of the converter's clipboard format.
IXWindowsClipboardConverter*
getConverter(Atom target,
bool onlyIfNotAdded = false) const;
// convert target atom to clipboard format // convert target atom to clipboard format
EFormat getFormat(Atom target) const; EFormat getFormat(Atom target) const;
@ -218,9 +232,10 @@ private:
// data conversion methods // data conversion methods
Atom getTargetsData(CString&, int* format) const; Atom getTargetsData(CString&, int* format) const;
Atom getTimestampData(CString&, int* format) const; Atom getTimestampData(CString&, int* format) const;
Atom getStringData(CString&, int* format) const;
private: private:
typedef std::vector<IXWindowsClipboardConverter*> ConverterList;
Display* m_display; Display* m_display;
Window m_window; Window m_window;
ClipboardID m_id; ClipboardID m_id;
@ -245,6 +260,9 @@ private:
CReplyMap m_replies; CReplyMap m_replies;
CReplyEventMask m_eventMasks; CReplyEventMask m_eventMasks;
// clipboard format converters
ConverterList m_converters;
// atoms we'll need // atoms we'll need
Atom m_atomTargets; Atom m_atomTargets;
Atom m_atomMultiple; Atom m_atomMultiple;
@ -263,4 +281,31 @@ private:
Atom m_atomGDKSelection; Atom m_atomGDKSelection;
}; };
class IXWindowsClipboardConverter : public IInterface {
public:
// accessors
// return the clipboard format this object converts from/to
virtual IClipboard::EFormat
getFormat() const = 0;
// return the atom representing the X selection format that
// this object converts from/to
virtual Atom getAtom() const = 0;
// return the size (in bits) of data elements returned by
// toIClipboard().
virtual int getDataSize() const = 0;
// convert from the IClipboard format to the X selection format.
// the input data must be in the IClipboard format returned by
// getFormat(). the return data will be in the X selection
// format returned by getAtom().
virtual CString fromIClipboard(const CString&) const = 0;
// convert from the X selection format to the IClipboard format
// (i.e., the reverse of fromIClipboard()).
virtual CString toIClipboard(const CString&) const = 0;
};
#endif #endif

View File

@ -0,0 +1,48 @@
#include "CXWindowsClipboardTextConverter.h"
#include "CUnicode.h"
//
// CXWindowsClipboardTextConverter
//
CXWindowsClipboardTextConverter::CXWindowsClipboardTextConverter(
Display* display, const char* name) :
m_atom(XInternAtom(display, name, False))
{
// do nothing
}
CXWindowsClipboardTextConverter::~CXWindowsClipboardTextConverter()
{
// do nothing
}
IClipboard::EFormat
CXWindowsClipboardTextConverter::getFormat() const
{
return IClipboard::kText;
}
Atom
CXWindowsClipboardTextConverter::getAtom() const
{
return m_atom;
}
int
CXWindowsClipboardTextConverter::getDataSize() const
{
return 8;
}
CString
CXWindowsClipboardTextConverter::fromIClipboard(const CString& data) const
{
return CUnicode::UTF8ToText(data);
}
CString
CXWindowsClipboardTextConverter::toIClipboard(const CString& data) const
{
return CUnicode::textToUTF8(data);
}

View File

@ -0,0 +1,23 @@
#ifndef CXWINDOWSCLIPBOARDTEXTCONVERTER_H
#define CXWINDOWSCLIPBOARDTEXTCONVERTER_H
#include "CXWindowsClipboard.h"
class CXWindowsClipboardTextConverter : public IXWindowsClipboardConverter {
public:
CXWindowsClipboardTextConverter(Display* display, const char* name);
virtual ~CXWindowsClipboardTextConverter();
// IXWindowsClipboardConverter overrides
virtual IClipboard::EFormat
getFormat() const;
virtual Atom getAtom() const;
virtual int getDataSize() const;
virtual CString fromIClipboard(const CString&) const;
virtual CString toIClipboard(const CString&) const;
private:
Atom m_atom;
};
#endif

View File

@ -0,0 +1,48 @@
#include "CXWindowsClipboardUCS2Converter.h"
#include "CUnicode.h"
//
// CXWindowsClipboardUCS2Converter
//
CXWindowsClipboardUCS2Converter::CXWindowsClipboardUCS2Converter(
Display* display, const char* name) :
m_atom(XInternAtom(display, name, False))
{
// do nothing
}
CXWindowsClipboardUCS2Converter::~CXWindowsClipboardUCS2Converter()
{
// do nothing
}
IClipboard::EFormat
CXWindowsClipboardUCS2Converter::getFormat() const
{
return IClipboard::kText;
}
Atom
CXWindowsClipboardUCS2Converter::getAtom() const
{
return m_atom;
}
int
CXWindowsClipboardUCS2Converter::getDataSize() const
{
return 16;
}
CString
CXWindowsClipboardUCS2Converter::fromIClipboard(const CString& data) const
{
return CUnicode::UTF8ToUCS2(data);
}
CString
CXWindowsClipboardUCS2Converter::toIClipboard(const CString& data) const
{
return CUnicode::UCS2ToUTF8(data);
}

View File

@ -0,0 +1,23 @@
#ifndef CXWINDOWSCLIPBOARDUCS2CONVERTER_H
#define CXWINDOWSCLIPBOARDUCS2CONVERTER_H
#include "CXWindowsClipboard.h"
class CXWindowsClipboardUCS2Converter : public IXWindowsClipboardConverter {
public:
CXWindowsClipboardUCS2Converter(Display* display, const char* name);
virtual ~CXWindowsClipboardUCS2Converter();
// IXWindowsClipboardConverter overrides
virtual IClipboard::EFormat
getFormat() const;
virtual Atom getAtom() const;
virtual int getDataSize() const;
virtual CString fromIClipboard(const CString&) const;
virtual CString toIClipboard(const CString&) const;
private:
Atom m_atom;
};
#endif

View File

@ -0,0 +1,47 @@
#include "CXWindowsClipboardUTF8Converter.h"
//
// CXWindowsClipboardUTF8Converter
//
CXWindowsClipboardUTF8Converter::CXWindowsClipboardUTF8Converter(
Display* display, const char* name) :
m_atom(XInternAtom(display, name, False))
{
// do nothing
}
CXWindowsClipboardUTF8Converter::~CXWindowsClipboardUTF8Converter()
{
// do nothing
}
IClipboard::EFormat
CXWindowsClipboardUTF8Converter::getFormat() const
{
return IClipboard::kText;
}
Atom
CXWindowsClipboardUTF8Converter::getAtom() const
{
return m_atom;
}
int
CXWindowsClipboardUTF8Converter::getDataSize() const
{
return 8;
}
CString
CXWindowsClipboardUTF8Converter::fromIClipboard(const CString& data) const
{
return data;
}
CString
CXWindowsClipboardUTF8Converter::toIClipboard(const CString& data) const
{
return data;
}

View File

@ -0,0 +1,23 @@
#ifndef CXWINDOWSCLIPBOARDUTF8CONVERTER_H
#define CXWINDOWSCLIPBOARDUTF8CONVERTER_H
#include "CXWindowsClipboard.h"
class CXWindowsClipboardUTF8Converter : public IXWindowsClipboardConverter {
public:
CXWindowsClipboardUTF8Converter(Display* display, const char* name);
virtual ~CXWindowsClipboardUTF8Converter();
// IXWindowsClipboardConverter overrides
virtual IClipboard::EFormat
getFormat() const;
virtual Atom getAtom() const;
virtual int getDataSize() const;
virtual CString fromIClipboard(const CString&) const;
virtual CString toIClipboard(const CString&) const;
private:
Atom m_atom;
};
#endif

View File

@ -7,12 +7,18 @@ noinst_LIBRARIES = libplatform.a
libplatform_a_SOURCES = \ libplatform_a_SOURCES = \
CPlatform.cpp \ CPlatform.cpp \
CXWindowsClipboard.cpp \ CXWindowsClipboard.cpp \
CXWindowsClipboardTextConverter.cpp \
CXWindowsClipboardUCS2Converter.cpp \
CXWindowsClipboardUTF8Converter.cpp \
CXWindowsScreen.cpp \ CXWindowsScreen.cpp \
CXWindowsScreenSaver.cpp \ CXWindowsScreenSaver.cpp \
CXWindowsUtil.cpp \ CXWindowsUtil.cpp \
CPlatform.h \ CPlatform.h \
CUnixPlatform.h \ CUnixPlatform.h \
CXWindowsClipboard.h \ CXWindowsClipboard.h \
CXWindowsClipboardTextConverter.h \
CXWindowsClipboardUCS2Converter.h \
CXWindowsClipboardUTF8Converter.h \
CXWindowsScreen.h \ CXWindowsScreen.h \
CXWindowsScreenSaver.h \ CXWindowsScreenSaver.h \
CXWindowsUtil.h \ CXWindowsUtil.h \

View File

@ -13,7 +13,13 @@ public:
typedef UInt32 Time; typedef UInt32 Time;
// known clipboard formats. kNumFormats must be last and // known clipboard formats. kNumFormats must be last and
// formats must be sequential starting from zero. // formats must be sequential starting from zero. clipboard
// data set via add() and retrieved via get() is in one of
// these formats. platform dependent clipboard subclasses
// can and should present any suitable formats derivable
// from these formats (e.g. UCS-16 encoded unicode).
//
// kText: UTF-8 encoded unicode (ISO-10646), newline is LF
enum EFormat { kText, kNumFormats }; enum EFormat { kText, kNumFormats };
// manipulators // manipulators