2009-02-27 11:54:59 +00:00
|
|
|
/*
|
|
|
|
* synergy -- mouse and keyboard sharing utility
|
|
|
|
* Copyright (C) 2004 Chris Schoeneman
|
|
|
|
*
|
|
|
|
* This package is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* found in the file COPYING that should have accompanied this file.
|
|
|
|
*
|
|
|
|
* This package is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "COSXClipboard.h"
|
|
|
|
#include "COSXClipboardUTF16Converter.h"
|
|
|
|
#include "COSXClipboardTextConverter.h"
|
|
|
|
#include "CLog.h"
|
|
|
|
#include "XArch.h"
|
|
|
|
|
|
|
|
//
|
|
|
|
// COSXClipboard
|
|
|
|
//
|
|
|
|
|
|
|
|
COSXClipboard::COSXClipboard() :
|
|
|
|
m_time(0),
|
2009-04-24 09:14:03 +00:00
|
|
|
m_pboard(NULL)
|
2009-02-27 11:54:59 +00:00
|
|
|
{
|
|
|
|
m_converters.push_back(new COSXClipboardUTF16Converter);
|
|
|
|
m_converters.push_back(new COSXClipboardTextConverter);
|
|
|
|
}
|
|
|
|
|
|
|
|
COSXClipboard::~COSXClipboard()
|
|
|
|
{
|
|
|
|
clearConverters();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
COSXClipboard::empty()
|
|
|
|
{
|
|
|
|
LOG((CLOG_DEBUG "empty clipboard"));
|
2009-04-24 09:14:03 +00:00
|
|
|
assert(m_pboard != NULL);
|
2009-02-27 11:54:59 +00:00
|
|
|
|
2009-04-24 09:14:03 +00:00
|
|
|
OSStatus err = PasteboardClear(m_pboard);
|
2009-02-27 11:54:59 +00:00
|
|
|
if (err != noErr) {
|
|
|
|
LOG((CLOG_DEBUG "failed to grab clipboard"));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-04-24 09:14:03 +00:00
|
|
|
|
2009-02-27 11:54:59 +00:00
|
|
|
// we own the clipboard
|
2009-04-24 09:14:03 +00:00
|
|
|
UInt8 claimString[] = {'s', 'y', 'n', 'e'};
|
|
|
|
CFDataRef claimData = CFDataCreate(kCFAllocatorDefault, claimString, 4);
|
|
|
|
|
|
|
|
err = PasteboardPutItemFlavor(
|
|
|
|
m_pboard,
|
|
|
|
0,
|
2009-02-27 11:54:59 +00:00
|
|
|
getOwnershipFlavor(),
|
2009-04-24 09:14:03 +00:00
|
|
|
claimData,
|
|
|
|
kPasteboardFlavorNoFlags);
|
2009-02-27 11:54:59 +00:00
|
|
|
if (err != noErr) {
|
2009-04-24 09:14:03 +00:00
|
|
|
LOG((CLOG_DEBUG "failed to grab clipboard (%d)", err));
|
2009-02-27 11:54:59 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
COSXClipboard::add(EFormat format, const CString & data)
|
|
|
|
{
|
|
|
|
LOG((CLOG_DEBUG "add %d bytes to clipboard format: %d", data.size(), format));
|
|
|
|
|
|
|
|
for (ConverterList::const_iterator index = m_converters.begin();
|
|
|
|
index != m_converters.end(); ++index) {
|
|
|
|
|
|
|
|
IOSXClipboardConverter* converter = *index;
|
|
|
|
|
|
|
|
// skip converters for other formats
|
|
|
|
if (converter->getFormat() == format) {
|
|
|
|
CString osXData = converter->fromIClipboard(data);
|
2009-04-24 09:14:03 +00:00
|
|
|
CFStringRef flavorType = converter->getOSXFormat();
|
|
|
|
CFDataRef data_ref = CFDataCreate(kCFAllocatorDefault, (UInt8 *)osXData.data(), osXData.size());
|
2009-02-27 11:54:59 +00:00
|
|
|
|
2009-04-24 09:14:03 +00:00
|
|
|
PasteboardPutItemFlavor(
|
|
|
|
m_pboard,
|
|
|
|
(PasteboardItemID) 1,
|
2009-02-27 11:54:59 +00:00
|
|
|
flavorType,
|
2009-04-24 09:14:03 +00:00
|
|
|
data_ref,
|
|
|
|
kPasteboardFlavorNoFlags);
|
|
|
|
LOG((CLOG_DEBUG "added %d bytes to clipboard format: %d", data.size(), format));
|
2009-02-27 11:54:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
COSXClipboard::open(Time time) const
|
|
|
|
{
|
|
|
|
LOG((CLOG_DEBUG "open clipboard"));
|
|
|
|
m_time = time;
|
2009-04-24 09:14:03 +00:00
|
|
|
OSStatus err = PasteboardCreate(kPasteboardClipboard, &m_pboard);
|
2009-02-27 11:54:59 +00:00
|
|
|
return (err == noErr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
COSXClipboard::close() const
|
|
|
|
{
|
|
|
|
LOG((CLOG_DEBUG "close clipboard"));
|
2009-04-24 09:14:03 +00:00
|
|
|
m_pboard = NULL;
|
2009-02-27 11:54:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
IClipboard::Time
|
|
|
|
COSXClipboard::getTime() const
|
|
|
|
{
|
|
|
|
return m_time;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
COSXClipboard::has(EFormat format) const
|
|
|
|
{
|
2009-04-24 09:14:03 +00:00
|
|
|
assert(m_pboard != NULL);
|
2009-02-27 11:54:59 +00:00
|
|
|
|
|
|
|
for (ConverterList::const_iterator index = m_converters.begin();
|
|
|
|
index != m_converters.end(); ++index) {
|
|
|
|
IOSXClipboardConverter* converter = *index;
|
|
|
|
if (converter->getFormat() == format) {
|
2009-04-24 09:14:03 +00:00
|
|
|
PasteboardFlavorFlags* flags = NULL;
|
|
|
|
CFStringRef type = converter->getOSXFormat();
|
2009-02-27 11:54:59 +00:00
|
|
|
|
2009-04-24 09:14:03 +00:00
|
|
|
if (PasteboardGetItemFlavorFlags(m_pboard, (void *)1, type, flags) == noErr) {
|
2009-02-27 11:54:59 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
CString
|
|
|
|
COSXClipboard::get(EFormat format) const
|
|
|
|
{
|
|
|
|
CString result;
|
2009-04-24 09:14:03 +00:00
|
|
|
CFStringRef type;
|
2009-02-27 11:54:59 +00:00
|
|
|
|
|
|
|
// find the converter for the first clipboard format we can handle
|
|
|
|
IOSXClipboardConverter* converter = NULL;
|
|
|
|
for (ConverterList::const_iterator index = m_converters.begin();
|
|
|
|
index != m_converters.end(); ++index) {
|
|
|
|
converter = *index;
|
|
|
|
|
2009-04-24 09:14:03 +00:00
|
|
|
PasteboardFlavorFlags* flags = NULL;
|
|
|
|
type = converter->getOSXFormat();
|
2009-02-27 11:54:59 +00:00
|
|
|
|
|
|
|
if (converter->getFormat() == format &&
|
2009-04-24 09:14:03 +00:00
|
|
|
PasteboardGetItemFlavorFlags(m_pboard, (void *)1, type, flags) == noErr) {
|
2009-02-27 11:54:59 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
converter = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if no converter then we don't recognize any formats
|
|
|
|
if (converter == NULL) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get the clipboard data.
|
2009-04-24 09:14:03 +00:00
|
|
|
CFDataRef buffer = NULL;
|
2009-02-27 11:54:59 +00:00
|
|
|
try {
|
2009-04-24 09:14:03 +00:00
|
|
|
OSStatus err = PasteboardCopyItemFlavorData(m_pboard, (void *)1,
|
|
|
|
type, &buffer);
|
|
|
|
|
2009-02-27 11:54:59 +00:00
|
|
|
if (err != noErr) {
|
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
|
2009-04-24 09:14:03 +00:00
|
|
|
result = CString((char *) CFDataGetBytePtr(buffer), CFDataGetLength(buffer));
|
2009-02-27 11:54:59 +00:00
|
|
|
}
|
|
|
|
catch (OSStatus err) {
|
|
|
|
LOG((CLOG_DEBUG "exception thrown in COSXClipboard::get MacError (%d)", err));
|
|
|
|
}
|
|
|
|
catch (...) {
|
|
|
|
LOG((CLOG_DEBUG "unknown exception in COSXClipboard::get"));
|
|
|
|
RETHROW_XTHREAD
|
|
|
|
}
|
2009-04-24 09:14:03 +00:00
|
|
|
|
|
|
|
if (buffer != NULL)
|
|
|
|
CFRelease(buffer);
|
2009-02-27 11:54:59 +00:00
|
|
|
|
|
|
|
return converter->toIClipboard(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
COSXClipboard::clearConverters()
|
|
|
|
{
|
|
|
|
for (ConverterList::iterator index = m_converters.begin();
|
|
|
|
index != m_converters.end(); ++index) {
|
|
|
|
delete *index;
|
|
|
|
}
|
|
|
|
m_converters.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
COSXClipboard::isOwnedBySynergy()
|
|
|
|
{
|
2009-04-24 09:14:03 +00:00
|
|
|
PasteboardFlavorFlags flags;
|
|
|
|
PasteboardRef pboard;
|
|
|
|
OSStatus err = PasteboardCreate(kPasteboardClipboard, &pboard);
|
2009-02-27 11:54:59 +00:00
|
|
|
if (err == noErr) {
|
2009-04-24 09:14:03 +00:00
|
|
|
err = PasteboardGetItemFlavorFlags(pboard, 0, getOwnershipFlavor() , &flags);
|
2009-02-27 11:54:59 +00:00
|
|
|
}
|
|
|
|
return (err == noErr);
|
|
|
|
}
|
|
|
|
|
2009-04-24 09:14:03 +00:00
|
|
|
CFStringRef
|
2009-02-27 11:54:59 +00:00
|
|
|
COSXClipboard::getOwnershipFlavor()
|
|
|
|
{
|
2009-04-24 09:14:03 +00:00
|
|
|
return CFSTR("Syne");
|
2009-02-27 11:54:59 +00:00
|
|
|
}
|
2009-04-24 09:14:03 +00:00
|
|
|
|