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

View File

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