• Main Page
  • Classes
  • Files
  • File List

COSXClipboard.cpp

00001 /*
00002  * synergy -- mouse and keyboard sharing utility
00003  * Copyright (C) 2012 Bolton Software Ltd.
00004  * Copyright (C) 2004 Chris Schoeneman
00005  * 
00006  * This package is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * found in the file COPYING that should have accompanied this file.
00009  * 
00010  * This package is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00017  */
00018 
00019 #include "COSXClipboard.h"
00020 #include "CClipboard.h"
00021 #include "COSXClipboardUTF16Converter.h"
00022 #include "COSXClipboardTextConverter.h"
00023 #include "CLog.h"
00024 #include "XArch.h"
00025 
00026 //
00027 // COSXClipboard
00028 //
00029 
00030 COSXClipboard::COSXClipboard() :
00031     m_time(0),
00032     m_pboard(NULL)
00033 {
00034     m_converters.push_back(new COSXClipboardUTF16Converter);
00035     m_converters.push_back(new COSXClipboardTextConverter);
00036 
00037     OSStatus createErr = PasteboardCreate(kPasteboardClipboard, &m_pboard);
00038     if (createErr != noErr) {
00039         LOG((CLOG_DEBUG "failed to create clipboard reference: error %i", createErr));
00040         LOG((CLOG_ERR "unable to connect to pasteboard, clipboard sharing disabled", createErr));
00041         m_pboard = NULL;
00042         return;
00043 
00044     }
00045 
00046     OSStatus syncErr = PasteboardSynchronize(m_pboard);
00047     if (syncErr != noErr) {
00048         LOG((CLOG_DEBUG "failed to syncronize clipboard: error %i", syncErr));
00049     }
00050 }
00051 
00052 COSXClipboard::~COSXClipboard()
00053 {
00054     clearConverters();
00055 }
00056 
00057     bool
00058 COSXClipboard::empty()
00059 {
00060     LOG((CLOG_DEBUG "emptying clipboard"));
00061     if (m_pboard == NULL)
00062         return false;
00063 
00064     OSStatus err = PasteboardClear(m_pboard);
00065     if (err != noErr) {
00066         LOG((CLOG_DEBUG "failed to clear clipboard: error %i", err));
00067         return false;
00068     }
00069 
00070     return true;
00071 }
00072 
00073     bool
00074 COSXClipboard::synchronize()
00075 {
00076     if (m_pboard == NULL)
00077         return false;
00078 
00079     PasteboardSyncFlags flags = PasteboardSynchronize(m_pboard);
00080     LOG((CLOG_DEBUG2 "flags: %x", flags));
00081 
00082     if (flags & kPasteboardModified) {
00083         return true;
00084     }
00085     return false;
00086 }    
00087 
00088     void
00089 COSXClipboard::add(EFormat format, const CString & data)
00090 {
00091     bool emptied = false;
00092     if (m_pboard == NULL)
00093         return;
00094 
00095     LOG((CLOG_DEBUG "add %d bytes to clipboard format: %d", data.size(), format));
00096 
00097     for (ConverterList::const_iterator index = m_converters.begin();
00098             index != m_converters.end(); ++index) {
00099 
00100         IOSXClipboardConverter* converter = *index;
00101 
00102         // skip converters for other formats
00103         if (converter->getFormat() == format) {
00104             CString osXData = converter->fromIClipboard(data);
00105             CFStringRef flavorType = converter->getOSXFormat();
00106             CFDataRef dataRef = CFDataCreate(kCFAllocatorDefault, (UInt8 *)osXData.data(), osXData.size());
00107 
00108             // integ tests showed that if you call add(...) twice, then the
00109             // second call will actually fail to set clipboard data. calling
00110             // empty() seems to solve this problem. but, only clear the clipboard
00111             // for the first converter, otherwise further converters will wipe out
00112             // what we just added.
00113             if (!emptied) {
00114                 empty();
00115                 emptied = true;
00116             }
00117             
00118             PasteboardPutItemFlavor(
00119                     m_pboard,
00120                     (PasteboardItemID) 0,
00121                     flavorType,
00122                     dataRef, 
00123                     kPasteboardFlavorNoFlags);
00124             LOG((CLOG_DEBUG "added %d bytes to clipboard format: %d", data.size(), format));
00125         }
00126     }
00127 }
00128 
00129 bool
00130 COSXClipboard::open(Time time) const 
00131 {
00132     if (m_pboard == NULL)
00133         return false;
00134 
00135     LOG((CLOG_DEBUG "opening clipboard"));
00136     m_time = time;
00137     return true;
00138 }
00139 
00140 void
00141 COSXClipboard::close() const
00142 {
00143     LOG((CLOG_DEBUG "closing clipboard"));
00144     /* not needed */
00145 }
00146 
00147 IClipboard::Time
00148 COSXClipboard::getTime() const
00149 {
00150     return m_time;
00151 }
00152 
00153 bool
00154 COSXClipboard::has(EFormat format) const
00155 {
00156     if (m_pboard == NULL)
00157         return false;
00158 
00159     PasteboardItemID item;
00160     PasteboardGetItemIdentifier(m_pboard, (CFIndex) 1, &item);
00161 
00162     for (ConverterList::const_iterator index = m_converters.begin();
00163             index != m_converters.end(); ++index) {
00164         IOSXClipboardConverter* converter = *index;
00165         if (converter->getFormat() == format) {
00166             PasteboardFlavorFlags flags;
00167             CFStringRef type = converter->getOSXFormat();
00168 
00169             OSStatus res;
00170 
00171             if ((res = PasteboardGetItemFlavorFlags(m_pboard, item, type, &flags)) == noErr) {
00172                 return true;
00173             }
00174         }
00175     }
00176 
00177     return false;
00178 }
00179 
00180 CString
00181 COSXClipboard::get(EFormat format) const
00182 {
00183     CFStringRef type;
00184     PasteboardItemID item;
00185     CString result;
00186 
00187     if (m_pboard == NULL)
00188         return result;
00189 
00190     PasteboardGetItemIdentifier(m_pboard, (CFIndex) 1, &item);
00191 
00192 
00193     // find the converter for the first clipboard format we can handle
00194     IOSXClipboardConverter* converter = NULL;
00195     for (ConverterList::const_iterator index = m_converters.begin();
00196             index != m_converters.end(); ++index) {
00197         converter = *index;
00198 
00199         PasteboardFlavorFlags flags;
00200         type = converter->getOSXFormat();
00201 
00202         if (converter->getFormat() == format &&
00203                 PasteboardGetItemFlavorFlags(m_pboard, item, type, &flags) == noErr) {
00204             break;
00205         }
00206         converter = NULL;
00207     }
00208 
00209     // if no converter then we don't recognize any formats
00210     if (converter == NULL) {
00211         LOG((CLOG_DEBUG "Unable to find converter for data"));
00212         return result;
00213     }
00214 
00215     // get the clipboard data.
00216     CFDataRef buffer = NULL;
00217     try {
00218         OSStatus err = PasteboardCopyItemFlavorData(m_pboard, item, type, &buffer);
00219 
00220         if (err != noErr) {
00221             throw err;
00222         }
00223 
00224         result = CString((char *) CFDataGetBytePtr(buffer), CFDataGetLength(buffer));
00225     }
00226     catch (OSStatus err) {
00227         LOG((CLOG_DEBUG "exception thrown in COSXClipboard::get MacError (%d)", err));
00228     }
00229     catch (...) {
00230         LOG((CLOG_DEBUG "unknown exception in COSXClipboard::get"));
00231         RETHROW_XTHREAD
00232     }
00233 
00234     if (buffer != NULL)
00235         CFRelease(buffer);
00236 
00237     return converter->toIClipboard(result);
00238 }
00239 
00240     void
00241 COSXClipboard::clearConverters()
00242 {
00243     if (m_pboard == NULL)
00244         return;
00245 
00246     for (ConverterList::iterator index = m_converters.begin();
00247             index != m_converters.end(); ++index) {
00248         delete *index;
00249     }
00250     m_converters.clear();
00251 }

Generated on Tue May 21 2013 00:00:05 for Synergy by  doxygen 1.7.1