checkpoint. trying to fix a delay when sending clipboards on X.

This commit is contained in:
crs 2002-06-20 13:35:28 +00:00
parent c4fea1c32b
commit 3d27de39bb
2 changed files with 76 additions and 74 deletions

View File

@ -2,7 +2,7 @@
#include "CXWindowsUtil.h" #include "CXWindowsUtil.h"
#include "CThread.h" #include "CThread.h"
#include "CLog.h" #include "CLog.h"
#include "TMethodJob.h" #include "CStopwatch.h"
#include <cstdio> #include <cstdio>
#include <X11/Xatom.h> #include <X11/Xatom.h>
@ -79,7 +79,7 @@ CXWindowsClipboard::addRequest(Window owner, Window requestor,
// at the given time. // at the given time.
bool success = false; bool success = false;
if (owner == m_window) { if (owner == m_window) {
log((CLOG_DEBUG "request for clipboard %d, target %d by 0x%08x (property=%d)", m_selection, target, requestor, property)); log((CLOG_DEBUG1 "request for clipboard %d, target %d by 0x%08x (property=%d)", m_selection, target, requestor, property));
if (wasOwnedAtTime(time)) { if (wasOwnedAtTime(time)) {
if (target == m_atomMultiple) { if (target == m_atomMultiple) {
// add a multiple request. property may not be None // add a multiple request. property may not be None
@ -96,13 +96,13 @@ CXWindowsClipboard::addRequest(Window owner, Window requestor,
} }
} }
else { else {
log((CLOG_DEBUG "failed, not owned at time %d", time)); log((CLOG_DEBUG1 "failed, not owned at time %d", time));
} }
} }
if (!success) { if (!success) {
// send failure // send failure
log((CLOG_DEBUG "failed")); log((CLOG_DEBUG1 "failed"));
insertReply(new CReply(requestor, target, time)); insertReply(new CReply(requestor, target, time));
} }
@ -138,14 +138,14 @@ CXWindowsClipboard::addSimpleRequest(Window requestor,
if (type != None) { if (type != None) {
// success // success
log((CLOG_DEBUG "success")); log((CLOG_DEBUG1 "success"));
insertReply(new CReply(requestor, target, time, insertReply(new CReply(requestor, target, time,
property, data, type, format)); property, data, type, format));
return true; return true;
} }
else { else {
// failure // failure
log((CLOG_DEBUG "failed")); log((CLOG_DEBUG1 "failed"));
insertReply(new CReply(requestor, target, time)); insertReply(new CReply(requestor, target, time));
return false; return false;
} }
@ -286,24 +286,9 @@ CXWindowsClipboard::open(Time time) const
m_open = true; m_open = true;
m_time = time; m_time = time;
// get the time the clipboard ownership was taken by the current // be sure to flush the cache later if it's dirty
// owner. m_checkCache = true;
if (m_motif) { checkCache();
m_timeOwned = motifGetTime();
}
else {
m_timeOwned = icccmGetTime();
}
// if we can't get the time then use the time passed to us
if (m_timeOwned == 0) {
m_timeOwned = m_time;
}
// if the cache is dirty then flush it
if (m_timeOwned != m_cacheTime) {
clearCache();
}
return true; return true;
} }
@ -327,6 +312,7 @@ CXWindowsClipboard::close() const
IClipboard::Time IClipboard::Time
CXWindowsClipboard::getTime() const CXWindowsClipboard::getTime() const
{ {
checkCache();
return m_timeOwned; return m_timeOwned;
} }
@ -361,6 +347,34 @@ CXWindowsClipboard::getFormat(Atom src) const
return IClipboard::kNumFormats; return IClipboard::kNumFormats;
} }
void
CXWindowsClipboard::checkCache() const
{
if (!m_checkCache) {
return;
}
m_checkCache = false;
// get the time the clipboard ownership was taken by the current
// owner.
if (m_motif) {
m_timeOwned = motifGetTime();
}
else {
m_timeOwned = icccmGetTime();
}
// if we can't get the time then use the time passed to us
if (m_timeOwned == 0) {
m_timeOwned = m_time;
}
// if the cache is dirty then flush it
if (m_timeOwned != m_cacheTime) {
clearCache();
}
}
void void
CXWindowsClipboard::clearCache() const CXWindowsClipboard::clearCache() const
{ {
@ -370,6 +384,7 @@ CXWindowsClipboard::clearCache() const
void void
CXWindowsClipboard::doClearCache() CXWindowsClipboard::doClearCache()
{ {
m_checkCache = false;
m_cached = false; m_cached = false;
for (SInt32 index = 0; index < kNumFormats; ++index) { for (SInt32 index = 0; index < kNumFormats; ++index) {
m_data[index] = ""; m_data[index] = "";
@ -381,6 +396,7 @@ void
CXWindowsClipboard::fillCache() const CXWindowsClipboard::fillCache() const
{ {
// get the selection data if not already cached // get the selection data if not already cached
checkCache();
if (!m_cached) { if (!m_cached) {
const_cast<CXWindowsClipboard*>(this)->doFillCache(); const_cast<CXWindowsClipboard*>(this)->doFillCache();
} }
@ -395,6 +411,7 @@ CXWindowsClipboard::doFillCache()
else { else {
icccmFillCache(); icccmFillCache();
} }
m_checkCache = false;
m_cached = true; m_cached = true;
m_cacheTime = m_timeOwned; m_cacheTime = m_timeOwned;
} }
@ -1007,6 +1024,7 @@ bool
CXWindowsClipboard::wasOwnedAtTime(::Time time) const CXWindowsClipboard::wasOwnedAtTime(::Time time) const
{ {
// not owned if we've never owned the selection // not owned if we've never owned the selection
checkCache();
if (m_timeOwned == 0) { if (m_timeOwned == 0) {
return false; return false;
} }
@ -1066,6 +1084,7 @@ CXWindowsClipboard::getTimestampData(CString& data, int* format) const
assert(format != NULL); assert(format != NULL);
assert(sizeof(m_timeOwned) == 4); assert(sizeof(m_timeOwned) == 4);
checkCache();
data.append(reinterpret_cast<const char*>(&m_timeOwned), 4); data.append(reinterpret_cast<const char*>(&m_timeOwned), 4);
*format = 32; *format = 32;
return m_atomTimestamp; return m_atomTimestamp;
@ -1129,9 +1148,6 @@ CXWindowsClipboard::CICCCMGetClipboard::readClipboard(Display* display,
*m_actualTarget = None; *m_actualTarget = None;
*m_data = ""; *m_data = "";
// get timeout atom
m_timeout = XInternAtom(display, "SYNERGY_TIMEOUT", False);
// delete target property // delete target property
XDeleteProperty(display, m_requestor, m_property); XDeleteProperty(display, m_requestor, m_property);
@ -1145,21 +1161,36 @@ CXWindowsClipboard::CICCCMGetClipboard::readClipboard(Display* display,
XConvertSelection(display, selection, target, XConvertSelection(display, selection, target,
m_property, m_requestor, m_time); m_property, m_requestor, m_time);
// process selection events. have a separate thread send us an // Xlib inexplicably omits the ability to wait for an event with
// event after a timeout so we don't get locked up by badly // a timeout. (it's inexplicable because there's no portable way
// behaved selection owners. // to do it.) we'll poll until we have what we're looking for or
CThread timer(new TMethodJob<CXWindowsClipboard::CICCCMGetClipboard>( // a timeout expires. we use a timeout so we don't get locked up
this, // by badly behaved selection owners.
&CXWindowsClipboard::CICCCMGetClipboard::timeout,
display));
XEvent xevent; XEvent xevent;
SInt32 lastPending = 0;
CStopwatch timeout(true);
static const double s_timeout = 0.2; // FIXME -- is this too short?
while (!m_done && !m_failed) { while (!m_done && !m_failed) {
// process events // fail if timeout has expired
XIfEvent(display, &xevent, if (timeout.getTime() < s_timeout) {
m_failed = true;
break;
}
// get how many events are pending now
SInt32 pending = XPending(display);
// process events if there are more otherwise sleep
if (pending > lastPending) {
lastPending = pending;
XCheckIfEvent(display, &xevent,
&CXWindowsClipboard::CICCCMGetClipboard::eventPredicate, &CXWindowsClipboard::CICCCMGetClipboard::eventPredicate,
reinterpret_cast<XPointer>(this)); reinterpret_cast<XPointer>(this));
} }
timer.cancel(); else {
CThread::sleep(0.01);
}
}
// restore mask // restore mask
XSelectInput(display, m_requestor, attr.your_event_mask); XSelectInput(display, m_requestor, attr.your_event_mask);
@ -1216,17 +1247,6 @@ CXWindowsClipboard::CICCCMGetClipboard::doEventPredicate(
// otherwise not interested // otherwise not interested
return false; return false;
case ClientMessage:
// done if this is the timeout message
if (xevent->xclient.window == m_requestor &&
xevent->xclient.message_type == m_timeout) {
m_failed = true;
return true;
}
// otherwise not interested
return false;
default: default:
// not interested // not interested
return false; return false;
@ -1314,24 +1334,6 @@ CXWindowsClipboard::CICCCMGetClipboard::eventPredicate(
return self->doEventPredicate(display, xevent) ? True : False; return self->doEventPredicate(display, xevent) ? True : False;
} }
void
CXWindowsClipboard::CICCCMGetClipboard::timeout(void* vdisplay)
{
// wait
CThread::sleep(0.2); // FIXME -- is this too short?
// send wake up
Display* display = reinterpret_cast<Display*>(vdisplay);
XEvent event;
event.xclient.type = ClientMessage;
event.xclient.display = display;
event.xclient.window = m_requestor;
event.xclient.message_type = m_timeout;
event.xclient.format = 8;
CXWindowsUtil::CErrorLock lock;
XSendEvent(display, m_requestor, False, 0, &event);
}
// //
// CXWindowsClipboard::CReply // CXWindowsClipboard::CReply

View File

@ -62,6 +62,10 @@ private:
Window requestor, Atom target, Window requestor, Atom target,
::Time time, Atom property); ::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 // clear the cache, resetting the cached flag and the added flag for
// each format. // each format.
void clearCache() const; void clearCache() const;
@ -84,7 +88,6 @@ private:
bool motifOwnsClipboard() const; bool motifOwnsClipboard() const;
Time motifGetTime() const; Time motifGetTime() const;
void motifFillCache(); void motifFillCache();
// FIXME
// //
// helper classes // helper classes
@ -109,7 +112,6 @@ private:
static Bool eventPredicate(Display* display, static Bool eventPredicate(Display* display,
XEvent* event, XEvent* event,
XPointer arg); XPointer arg);
void timeout(void*);
private: private:
Window m_requestor; Window m_requestor;
@ -129,9 +131,6 @@ private:
// selection owner cannot convert to the requested type. // selection owner cannot convert to the requested type.
Atom* m_actualTarget; Atom* m_actualTarget;
// property used in event to wake up event loop
Atom m_timeout;
public: public:
// true iff the selection owner didn't follow ICCCM conventions // true iff the selection owner didn't follow ICCCM conventions
bool m_error; bool m_error;
@ -240,6 +239,7 @@ private:
mutable bool m_motif; mutable bool m_motif;
// the added/cached clipboard data // the added/cached clipboard data
mutable bool m_checkCache;
bool m_cached; bool m_cached;
Time m_cacheTime; Time m_cacheTime;
bool m_added[kNumFormats]; bool m_added[kNumFormats];