Revamped OSX clipboard handling to rely on the pasteboard synchronization built into the API, rather than attempting to roll our own.

This brings back clipboard sharing functionality under my environment; I'll be posting a call to test to the appropriate ticket.

Ref: Issue #67
This commit is contained in:
Edward Carrel 2009-11-25 11:09:37 +00:00
parent 6253ca6637
commit e0a70cddf7
4 changed files with 103 additions and 105 deletions

View File

@ -12,6 +12,7 @@
* GNU General Public License for more details.
*/
#include "CClipboard.h"
#include "COSXClipboard.h"
#include "COSXClipboardUTF16Converter.h"
#include "COSXClipboardTextConverter.h"
@ -28,6 +29,20 @@ COSXClipboard::COSXClipboard() :
{
m_converters.push_back(new COSXClipboardUTF16Converter);
m_converters.push_back(new COSXClipboardTextConverter);
OSStatus createErr = PasteboardCreate(kPasteboardClipboard, &m_pboard);
if (createErr != noErr) {
LOG((CLOG_DEBUG "failed to create clipboard reference: error %i", createErr));
LOG((CLOG_ERR "Unable to connect to pasteboard. Clipboard sharing disabled.", createErr));
m_pboard = NULL;
return;
}
OSStatus syncErr = PasteboardSynchronize(m_pboard);
if (syncErr != noErr) {
LOG((CLOG_DEBUG "failed to syncronize clipboard: error %i", syncErr));
}
}
COSXClipboard::~COSXClipboard()
@ -35,44 +50,47 @@ COSXClipboard::~COSXClipboard()
clearConverters();
}
bool
bool
COSXClipboard::empty()
{
LOG((CLOG_DEBUG "empty clipboard"));
assert(m_pboard != NULL);
LOG((CLOG_DEBUG "emptying clipboard"));
if (m_pboard == NULL)
return false;
OSStatus err = PasteboardClear(m_pboard);
if (err != noErr) {
LOG((CLOG_DEBUG "failed to grab clipboard"));
return false;
}
// we own the clipboard
UInt8 claimString[] = {'s', 'y', 'n', 'e'};
CFDataRef claimData = CFDataCreate(kCFAllocatorDefault, claimString, 4);
err = PasteboardPutItemFlavor(
m_pboard,
0,
getOwnershipFlavor(),
claimData,
kPasteboardFlavorNoFlags);
if (err != noErr) {
LOG((CLOG_DEBUG "failed to grab clipboard (%d)", err));
LOG((CLOG_DEBUG "failed to clear clipboard: error %i", err));
return false;
}
return true;
}
void
bool
COSXClipboard::synchronize()
{
if (m_pboard == NULL)
return false;
PasteboardSyncFlags flags = PasteboardSynchronize(m_pboard);
LOG((CLOG_DEBUG1 "flags: %x", flags));
if (flags & kPasteboardModified) {
return true;
}
return false;
}
void
COSXClipboard::add(EFormat format, const CString & data)
{
if (m_pboard == NULL)
return;
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) {
index != m_converters.end(); ++index) {
IOSXClipboardConverter* converter = *index;
@ -80,15 +98,15 @@ COSXClipboard::add(EFormat format, const CString & data)
if (converter->getFormat() == format) {
CString osXData = converter->fromIClipboard(data);
CFStringRef flavorType = converter->getOSXFormat();
CFDataRef data_ref = CFDataCreate(kCFAllocatorDefault, (UInt8 *)osXData.data(), osXData.size());
CFDataRef dataRef = CFDataCreate(kCFAllocatorDefault, (UInt8 *)osXData.data(), osXData.size());
PasteboardPutItemFlavor(
m_pboard,
(PasteboardItemID) 1,
flavorType,
data_ref,
kPasteboardFlavorNoFlags);
LOG((CLOG_DEBUG "added %d bytes to clipboard format: %d", data.size(), format));
m_pboard,
(PasteboardItemID) 0,
flavorType,
dataRef,
kPasteboardFlavorNoFlags);
LOG((CLOG_DEBUG "added %d bytes to clipboard format: %d", data.size(), format));
}
}
}
@ -96,17 +114,19 @@ COSXClipboard::add(EFormat format, const CString & data)
bool
COSXClipboard::open(Time time) const
{
LOG((CLOG_DEBUG "open clipboard"));
if (m_pboard == NULL)
return false;
LOG((CLOG_DEBUG "opening clipboard"));
m_time = time;
OSStatus err = PasteboardCreate(kPasteboardClipboard, &m_pboard);
return (err == noErr);
return true;
}
void
COSXClipboard::close() const
{
LOG((CLOG_DEBUG "close clipboard"));
m_pboard = NULL;
LOG((CLOG_DEBUG "closing clipboard"));
/* not needed */
}
IClipboard::Time
@ -118,16 +138,22 @@ COSXClipboard::getTime() const
bool
COSXClipboard::has(EFormat format) const
{
assert(m_pboard != NULL);
if (m_pboard == NULL)
return false;
PasteboardItemID item;
PasteboardGetItemIdentifier(m_pboard, (CFIndex) 1, &item);
for (ConverterList::const_iterator index = m_converters.begin();
index != m_converters.end(); ++index) {
index != m_converters.end(); ++index) {
IOSXClipboardConverter* converter = *index;
if (converter->getFormat() == format) {
PasteboardFlavorFlags* flags = NULL;
PasteboardFlavorFlags flags;
CFStringRef type = converter->getOSXFormat();
if (PasteboardGetItemFlavorFlags(m_pboard, (void *)1, type, flags) == noErr) {
OSStatus res;
if ((res = PasteboardGetItemFlavorFlags(m_pboard, item, type, &flags)) == noErr) {
return true;
}
}
@ -139,20 +165,27 @@ COSXClipboard::has(EFormat format) const
CString
COSXClipboard::get(EFormat format) const
{
CFStringRef type;
PasteboardItemID item;
CString result;
CFStringRef type;
if (m_pboard == NULL)
return result;
PasteboardGetItemIdentifier(m_pboard, (CFIndex) 1, &item);
// 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) {
index != m_converters.end(); ++index) {
converter = *index;
PasteboardFlavorFlags* flags = NULL;
PasteboardFlavorFlags flags;
type = converter->getOSXFormat();
if (converter->getFormat() == format &&
PasteboardGetItemFlavorFlags(m_pboard, (void *)1, type, flags) == noErr) {
PasteboardGetItemFlavorFlags(m_pboard, item, type, &flags) == noErr) {
break;
}
converter = NULL;
@ -160,15 +193,15 @@ COSXClipboard::get(EFormat format) const
// if no converter then we don't recognize any formats
if (converter == NULL) {
LOG((CLOG_DEBUG "Unable to find converter for data"));
return result;
}
// get the clipboard data.
CFDataRef buffer = NULL;
CFDataRef buffer = NULL;
try {
OSStatus err = PasteboardCopyItemFlavorData(m_pboard, (void *)1,
type, &buffer);
OSStatus err = PasteboardCopyItemFlavorData(m_pboard, item, type, &buffer);
if (err != noErr) {
throw err;
}
@ -183,37 +216,21 @@ COSXClipboard::get(EFormat format) const
RETHROW_XTHREAD
}
if (buffer != NULL)
CFRelease(buffer);
if (buffer != NULL)
CFRelease(buffer);
return converter->toIClipboard(result);
}
void
void
COSXClipboard::clearConverters()
{
if (m_pboard == NULL)
return;
for (ConverterList::iterator index = m_converters.begin();
index != m_converters.end(); ++index) {
index != m_converters.end(); ++index) {
delete *index;
}
m_converters.clear();
}
bool
COSXClipboard::isOwnedBySynergy()
{
PasteboardFlavorFlags flags;
PasteboardRef pboard;
OSStatus err = PasteboardCreate(kPasteboardClipboard, &pboard);
if (err == noErr) {
err = PasteboardGetItemFlavorFlags(pboard, 0, getOwnershipFlavor() , &flags);
}
return (err == noErr);
}
CFStringRef
COSXClipboard::getOwnershipFlavor()
{
return CFSTR("Syne");
}

View File

@ -39,17 +39,16 @@ public:
virtual bool has(EFormat) const;
virtual CString get(EFormat) const;
bool synchronize();
private:
void clearConverters();
static CFStringRef
getOwnershipFlavor();
private:
typedef std::vector<IOSXClipboardConverter*> ConverterList;
mutable Time m_time;
ConverterList m_converters;
mutable PasteboardRef m_pboard;
PasteboardRef m_pboard;
};
//! Clipboard format converter interface

View File

@ -185,8 +185,7 @@ COSXScreen::getEventTarget() const
bool
COSXScreen::getClipboard(ClipboardID, IClipboard* dst) const
{
COSXClipboard src;
CClipboard::copy(dst, &src);
CClipboard::copy(dst, &m_pasteboard);
return true;
}
@ -643,41 +642,22 @@ COSXScreen::leave()
bool
COSXScreen::setClipboard(ClipboardID, const IClipboard* src)
{
COSXClipboard dst;
if (src != NULL) {
// save clipboard data
if (!CClipboard::copy(&dst, src)) {
return false;
}
}
else {
// assert clipboard ownership
if (!dst.open(0)) {
return false;
}
dst.empty();
dst.close();
}
checkClipboards();
return true;
if(src != NULL) {
LOG((CLOG_DEBUG "setting clipboard"));
CClipboard::copy(&m_pasteboard, src);
}
return true;
}
void
COSXScreen::checkClipboards()
{
// check if clipboard ownership changed
if (!COSXClipboard::isOwnedBySynergy()) {
if (m_ownClipboard) {
LOG((CLOG_DEBUG "clipboard changed: lost ownership"));
m_ownClipboard = false;
sendClipboardEvent(getClipboardGrabbedEvent(), kClipboardClipboard);
sendClipboardEvent(getClipboardGrabbedEvent(), kClipboardSelection);
}
}
else if (!m_ownClipboard) {
LOG((CLOG_DEBUG "clipboard changed: synergy owned"));
m_ownClipboard = true;
}
LOG((CLOG_DEBUG1 "checking clipboard"));
if (m_pasteboard.synchronize()) {
LOG((CLOG_DEBUG "clipboard changed"));
sendClipboardEvent(getClipboardGrabbedEvent(), kClipboardClipboard);
sendClipboardEvent(getClipboardGrabbedEvent(), kClipboardSelection);
}
}
void
@ -1629,4 +1609,4 @@ COSXScreen::handleCGInputEvent(CGEventTapProxy proxy,
} else {
return NULL;
}
}
}

View File

@ -16,6 +16,7 @@
#define COSXSCREEN_H
#include <Carbon/Carbon.h>
#include "COSXClipboard.h"
#include "CPlatformScreen.h"
#include "stdmap.h"
#include "stdvector.h"
@ -205,6 +206,7 @@ private:
COSXKeyState* m_keyState;
// clipboards
COSXClipboard m_pasteboard;
UInt32 m_sequenceNumber;
// screen saver stuff