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:
parent
6253ca6637
commit
e0a70cddf7
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue