/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012 Bolton Software Ltd. * Copyright (C) 2002 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file COPYING that should have accompanied this file. * * This package is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef CXWINDOWSCLIPBOARD_H #define CXWINDOWSCLIPBOARD_H #include "IClipboard.h" #include "ClipboardTypes.h" #include "stdmap.h" #include "stdlist.h" #include "stdvector.h" #if X_DISPLAY_MISSING # error X11 is required to build synergy #else # include #endif class IXWindowsClipboardConverter; //! X11 clipboard implementation class CXWindowsClipboard : public IClipboard { public: /*! Use \c window as the window that owns or interacts with the clipboard identified by \c id. */ CXWindowsClipboard(Display*, Window window, ClipboardID id); virtual ~CXWindowsClipboard(); //! Notify clipboard was lost /*! Tells clipboard it lost ownership at the given time. */ void lost(Time); //! Add clipboard request /*! Adds 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); //! Process clipboard request /*! Continues 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); //! Cancel clipboard request /*! Terminate a selection request. Returns true iff the request was known and handled. */ bool destroyRequest(Window requestor); //! Get window /*! Returns the clipboard's window (passed the c'tor). */ Window getWindow() const; //! Get selection atom /*! Returns the selection atom that identifies the clipboard to X11 (e.g. XA_PRIMARY). */ 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; // atoms needed for the protocol Atom m_atomNone; // NONE, not None Atom m_atomIncr; // 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]; SInt32 m_selectionOwner; // a Window 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; SInt32 m_type; // an Atom SInt32 m_pad2[1]; SInt32 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 CReplyList; typedef std::map CReplyMap; typedef std::map 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 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; }; //! Clipboard format converter interface /*! This interface defines the methods common to all X11 clipboard format converters. */ class IXWindowsClipboardConverter : public IInterface { public: //! @name accessors //@{ //! Get clipboard format /*! Return the clipboard format this object converts from/to. */ virtual IClipboard::EFormat getFormat() const = 0; //! Get X11 format atom /*! Return the atom representing the X selection format that this object converts from/to. */ virtual Atom getAtom() const = 0; //! Get X11 property datum size /*! Return the size (in bits) of data elements returned by toIClipboard(). */ virtual int getDataSize() const = 0; //! Convert from IClipboard format /*! 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 to IClipboard format /*! Convert from the X selection format to the IClipboard format (i.e., the reverse of fromIClipboard()). */ virtual CString toIClipboard(const CString&) const = 0; //@} }; #endif