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. * GNU General Public License for more details.
*/ */
#include "CClipboard.h"
#include "COSXClipboard.h" #include "COSXClipboard.h"
#include "COSXClipboardUTF16Converter.h" #include "COSXClipboardUTF16Converter.h"
#include "COSXClipboardTextConverter.h" #include "COSXClipboardTextConverter.h"
@ -28,6 +29,20 @@ COSXClipboard::COSXClipboard() :
{ {
m_converters.push_back(new COSXClipboardUTF16Converter); m_converters.push_back(new COSXClipboardUTF16Converter);
m_converters.push_back(new COSXClipboardTextConverter); 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() COSXClipboard::~COSXClipboard()
@ -35,44 +50,47 @@ COSXClipboard::~COSXClipboard()
clearConverters(); clearConverters();
} }
bool bool
COSXClipboard::empty() COSXClipboard::empty()
{ {
LOG((CLOG_DEBUG "empty clipboard")); LOG((CLOG_DEBUG "emptying clipboard"));
assert(m_pboard != NULL); if (m_pboard == NULL)
return false;
OSStatus err = PasteboardClear(m_pboard); OSStatus err = PasteboardClear(m_pboard);
if (err != noErr) { if (err != noErr) {
LOG((CLOG_DEBUG "failed to grab clipboard")); LOG((CLOG_DEBUG "failed to clear clipboard: error %i", err));
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));
return false; return false;
} }
return true; 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) 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)); LOG((CLOG_DEBUG "add %d bytes to clipboard format: %d", data.size(), format));
for (ConverterList::const_iterator index = m_converters.begin(); for (ConverterList::const_iterator index = m_converters.begin();
index != m_converters.end(); ++index) { index != m_converters.end(); ++index) {
IOSXClipboardConverter* converter = *index; IOSXClipboardConverter* converter = *index;
@ -80,15 +98,15 @@ COSXClipboard::add(EFormat format, const CString & data)
if (converter->getFormat() == format) { if (converter->getFormat() == format) {
CString osXData = converter->fromIClipboard(data); CString osXData = converter->fromIClipboard(data);
CFStringRef flavorType = converter->getOSXFormat(); CFStringRef flavorType = converter->getOSXFormat();
CFDataRef data_ref = CFDataCreate(kCFAllocatorDefault, (UInt8 *)osXData.data(), osXData.size()); CFDataRef dataRef = CFDataCreate(kCFAllocatorDefault, (UInt8 *)osXData.data(), osXData.size());
PasteboardPutItemFlavor( PasteboardPutItemFlavor(
m_pboard, m_pboard,
(PasteboardItemID) 1, (PasteboardItemID) 0,
flavorType, flavorType,
data_ref, dataRef,
kPasteboardFlavorNoFlags); kPasteboardFlavorNoFlags);
LOG((CLOG_DEBUG "added %d bytes to clipboard format: %d", data.size(), format)); 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 bool
COSXClipboard::open(Time time) const COSXClipboard::open(Time time) const
{ {
LOG((CLOG_DEBUG "open clipboard")); if (m_pboard == NULL)
return false;
LOG((CLOG_DEBUG "opening clipboard"));
m_time = time; m_time = time;
OSStatus err = PasteboardCreate(kPasteboardClipboard, &m_pboard); return true;
return (err == noErr);
} }
void void
COSXClipboard::close() const COSXClipboard::close() const
{ {
LOG((CLOG_DEBUG "close clipboard")); LOG((CLOG_DEBUG "closing clipboard"));
m_pboard = NULL; /* not needed */
} }
IClipboard::Time IClipboard::Time
@ -118,16 +138,22 @@ COSXClipboard::getTime() const
bool bool
COSXClipboard::has(EFormat format) const 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(); for (ConverterList::const_iterator index = m_converters.begin();
index != m_converters.end(); ++index) { index != m_converters.end(); ++index) {
IOSXClipboardConverter* converter = *index; IOSXClipboardConverter* converter = *index;
if (converter->getFormat() == format) { if (converter->getFormat() == format) {
PasteboardFlavorFlags* flags = NULL; PasteboardFlavorFlags flags;
CFStringRef type = converter->getOSXFormat(); 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; return true;
} }
} }
@ -139,20 +165,27 @@ COSXClipboard::has(EFormat format) const
CString CString
COSXClipboard::get(EFormat format) const COSXClipboard::get(EFormat format) const
{ {
CFStringRef type;
PasteboardItemID item;
CString result; 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 // find the converter for the first clipboard format we can handle
IOSXClipboardConverter* converter = NULL; IOSXClipboardConverter* converter = NULL;
for (ConverterList::const_iterator index = m_converters.begin(); for (ConverterList::const_iterator index = m_converters.begin();
index != m_converters.end(); ++index) { index != m_converters.end(); ++index) {
converter = *index; converter = *index;
PasteboardFlavorFlags* flags = NULL; PasteboardFlavorFlags flags;
type = converter->getOSXFormat(); type = converter->getOSXFormat();
if (converter->getFormat() == format && if (converter->getFormat() == format &&
PasteboardGetItemFlavorFlags(m_pboard, (void *)1, type, flags) == noErr) { PasteboardGetItemFlavorFlags(m_pboard, item, type, &flags) == noErr) {
break; break;
} }
converter = NULL; converter = NULL;
@ -160,15 +193,15 @@ COSXClipboard::get(EFormat format) const
// if no converter then we don't recognize any formats // if no converter then we don't recognize any formats
if (converter == NULL) { if (converter == NULL) {
LOG((CLOG_DEBUG "Unable to find converter for data"));
return result; return result;
} }
// get the clipboard data. // get the clipboard data.
CFDataRef buffer = NULL; CFDataRef buffer = NULL;
try { try {
OSStatus err = PasteboardCopyItemFlavorData(m_pboard, (void *)1, OSStatus err = PasteboardCopyItemFlavorData(m_pboard, item, type, &buffer);
type, &buffer);
if (err != noErr) { if (err != noErr) {
throw err; throw err;
} }
@ -183,37 +216,21 @@ COSXClipboard::get(EFormat format) const
RETHROW_XTHREAD RETHROW_XTHREAD
} }
if (buffer != NULL) if (buffer != NULL)
CFRelease(buffer); CFRelease(buffer);
return converter->toIClipboard(result); return converter->toIClipboard(result);
} }
void void
COSXClipboard::clearConverters() COSXClipboard::clearConverters()
{ {
if (m_pboard == NULL)
return;
for (ConverterList::iterator index = m_converters.begin(); for (ConverterList::iterator index = m_converters.begin();
index != m_converters.end(); ++index) { index != m_converters.end(); ++index) {
delete *index; delete *index;
} }
m_converters.clear(); 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 bool has(EFormat) const;
virtual CString get(EFormat) const; virtual CString get(EFormat) const;
bool synchronize();
private: private:
void clearConverters(); void clearConverters();
static CFStringRef
getOwnershipFlavor();
private: private:
typedef std::vector<IOSXClipboardConverter*> ConverterList; typedef std::vector<IOSXClipboardConverter*> ConverterList;
mutable Time m_time; mutable Time m_time;
ConverterList m_converters; ConverterList m_converters;
mutable PasteboardRef m_pboard; PasteboardRef m_pboard;
}; };
//! Clipboard format converter interface //! Clipboard format converter interface

View File

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

View File

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