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.
|
* 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,14 +193,14 @@ 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");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue