barrier/platform/CXWindowsClipboard.h
2002-07-24 17:30:32 +00:00

312 lines
8.3 KiB
C++

#ifndef CXWINDOWSCLIPBOARD_H
#define CXWINDOWSCLIPBOARD_H
#include "IClipboard.h"
#include "ClipboardTypes.h"
#include "stdmap.h"
#include "stdlist.h"
#include "stdvector.h"
#if defined(X_DISPLAY_MISSING)
# error X11 is required to build synergy
#else
# include <X11/Xlib.h>
#endif
class IXWindowsClipboardConverter;
class CXWindowsClipboard : public IClipboard {
public:
CXWindowsClipboard(Display*, Window, ClipboardID);
virtual ~CXWindowsClipboard();
// tell clipboard it lost ownership
void lost(Time);
// add a selection request to the request list. if the given
// owner window isn't this clipboard's window then this simply
// sends a failure event to the requestor.
void addRequest(Window owner,
Window requestor, Atom target,
::Time time, Atom property);
// continue processing a selection request. returns true if the
// request was handled, false if the request was unknown.
bool processRequest(Window requestor,
::Time time, Atom property);
// terminate a selection request. returns true iff the request
// was known and handled.
bool destroyRequest(Window requestor);
// get the clipboard's window
Window getWindow() const;
// get the clipboard selection atom
Atom getSelection() const;
// IClipboard overrides
virtual bool empty();
virtual void add(EFormat, const CString& data);
virtual bool open(Time) const;
virtual void close() const;
virtual Time getTime() const;
virtual bool has(EFormat) const;
virtual CString get(EFormat) const;
private:
// remove all converters from our list
void clearConverters();
// get the converter for a clipboard format. returns NULL if no
// suitable converter. iff onlyIfNotAdded is true then also
// return NULL if a suitable converter was found but we already
// have data of the converter's clipboard format.
IXWindowsClipboardConverter*
getConverter(Atom target,
bool onlyIfNotAdded = false) const;
// convert target atom to clipboard format
EFormat getFormat(Atom target) const;
// add a non-MULTIPLE request. does not verify that the selection
// was owned at the given time. returns true if the conversion
// could be performed, false otherwise. in either case, the
// reply is inserted.
bool addSimpleRequest(
Window requestor, Atom target,
::Time time, Atom property);
// if not already checked then see if the cache is stale and, if so,
// clear it. this has the side effect of updating m_timeOwned.
void checkCache() const;
// clear the cache, resetting the cached flag and the added flag for
// each format.
void clearCache() const;
void doClearCache();
// cache all formats of the selection
void fillCache() const;
void doFillCache();
//
// helper classes
//
// read an ICCCM conforming selection
class CICCCMGetClipboard {
public:
CICCCMGetClipboard(Window requestor, Time time, Atom property);
~CICCCMGetClipboard();
// convert the given selection to the given type. returns
// true iff the conversion was successful or the conversion
// cannot be performed (in which case *actualTarget == None).
bool readClipboard(Display* display,
Atom selection, Atom target,
Atom* actualTarget, CString* data);
private:
bool processEvent(Display* display, XEvent* event);
private:
Window m_requestor;
Time m_time;
Atom m_property;
bool m_incr;
bool m_failed;
bool m_done;
// true iff we've received the selection notify
bool m_reading;
// the converted selection data
CString* m_data;
// the actual type of the data. if this is None then the
// selection owner cannot convert to the requested type.
Atom* m_actualTarget;
public:
// true iff the selection owner didn't follow ICCCM conventions
bool m_error;
};
// Motif structure IDs
enum { kMotifClipFormat = 1, kMotifClipItem, kMotifClipHeader };
// _MOTIF_CLIP_HEADER structure
class CMotifClipHeader {
public:
SInt32 m_id; // kMotifClipHeader
SInt32 m_pad1[3];
SInt32 m_item;
SInt32 m_pad2[4];
SInt32 m_numItems;
SInt32 m_pad3[3];
Window m_selectionOwner;
SInt32 m_pad4[2];
};
// Motif clip item structure
class CMotifClipItem {
public:
SInt32 m_id; // kMotifClipItem
SInt32 m_pad1[5];
SInt32 m_size;
SInt32 m_numFormats;
SInt32 m_numDeletedFormats;
SInt32 m_pad2[6];
};
// Motif clip format structure
class CMotifClipFormat {
public:
SInt32 m_id; // kMotifClipFormat
SInt32 m_pad1[6];
SInt32 m_length;
SInt32 m_data;
Atom m_type;
SInt32 m_pad2[1];
int m_deleted;
SInt32 m_pad3[4];
};
// stores data needed to respond to a selection request
class CReply {
public:
CReply(Window, Atom target, ::Time);
CReply(Window, Atom target, ::Time, Atom property,
const CString& data, Atom type, int format);
public:
// information about the request
Window m_requestor;
Atom m_target;
::Time m_time;
Atom m_property;
// true iff we've sent the notification for this reply
bool m_replied;
// true iff the reply has sent its last message
bool m_done;
// the data to send and its type and format
CString m_data;
Atom m_type;
int m_format;
// index of next byte in m_data to send
UInt32 m_ptr;
};
typedef std::list<CReply*> CReplyList;
typedef std::map<Window, CReplyList> CReplyMap;
typedef std::map<Window, long> CReplyEventMask;
// ICCCM interoperability methods
void icccmFillCache();
bool icccmGetSelection(Atom target,
Atom* actualTarget, CString* data) const;
Time icccmGetTime() const;
// motif interoperability methods
bool motifLockClipboard() const;
void motifUnlockClipboard() const;
bool motifOwnsClipboard() const;
void motifFillCache();
bool motifGetSelection(const CMotifClipFormat*,
Atom* actualTarget, CString* data) const;
Time motifGetTime() const;
// reply methods
bool insertMultipleReply(Window, ::Time, Atom);
void insertReply(CReply*);
void pushReplies();
void pushReplies(CReplyMap::iterator,
CReplyList&, CReplyList::iterator);
bool sendReply(CReply*);
void clearReplies();
void clearReplies(CReplyList&);
void sendNotify(Window requestor, Atom selection,
Atom target, Atom property, Time time);
bool wasOwnedAtTime(::Time) const;
// data conversion methods
Atom getTargetsData(CString&, int* format) const;
Atom getTimestampData(CString&, int* format) const;
private:
typedef std::vector<IXWindowsClipboardConverter*> ConverterList;
Display* m_display;
Window m_window;
ClipboardID m_id;
Atom m_selection;
mutable bool m_open;
mutable Time m_time;
bool m_owner;
mutable Time m_timeOwned;
Time m_timeLost;
// true iff open and clipboard owned by a motif app
mutable bool m_motif;
// the added/cached clipboard data
mutable bool m_checkCache;
bool m_cached;
Time m_cacheTime;
bool m_added[kNumFormats];
CString m_data[kNumFormats];
// conversion request replies
CReplyMap m_replies;
CReplyEventMask m_eventMasks;
// clipboard format converters
ConverterList m_converters;
// atoms we'll need
Atom m_atomTargets;
Atom m_atomMultiple;
Atom m_atomTimestamp;
Atom m_atomInteger;
Atom m_atomAtom;
Atom m_atomAtomPair;
Atom m_atomData;
Atom m_atomINCR;
Atom m_atomMotifClipLock;
Atom m_atomMotifClipHeader;
Atom m_atomMotifClipAccess;
Atom m_atomGDKSelection;
};
class IXWindowsClipboardConverter : public IInterface {
public:
// accessors
// return the clipboard format this object converts from/to
virtual IClipboard::EFormat
getFormat() const = 0;
// return the atom representing the X selection format that
// this object converts from/to
virtual Atom getAtom() const = 0;
// return the size (in bits) of data elements returned by
// toIClipboard().
virtual int getDataSize() const = 0;
// convert from the IClipboard format to the X selection format.
// the input data must be in the IClipboard format returned by
// getFormat(). the return data will be in the X selection
// format returned by getAtom().
virtual CString fromIClipboard(const CString&) const = 0;
// convert from the X selection format to the IClipboard format
// (i.e., the reverse of fromIClipboard()).
virtual CString toIClipboard(const CString&) const = 0;
};
#endif