From 3d27de39bb4ec75e3428f14aef3bf333bc27d2c8 Mon Sep 17 00:00:00 2001 From: crs Date: Thu, 20 Jun 2002 13:35:28 +0000 Subject: [PATCH] checkpoint. trying to fix a delay when sending clipboards on X. --- platform/CXWindowsClipboard.cpp | 140 ++++++++++++++++---------------- platform/CXWindowsClipboard.h | 10 +-- 2 files changed, 76 insertions(+), 74 deletions(-) diff --git a/platform/CXWindowsClipboard.cpp b/platform/CXWindowsClipboard.cpp index 4e232372..19ea653f 100644 --- a/platform/CXWindowsClipboard.cpp +++ b/platform/CXWindowsClipboard.cpp @@ -2,7 +2,7 @@ #include "CXWindowsUtil.h" #include "CThread.h" #include "CLog.h" -#include "TMethodJob.h" +#include "CStopwatch.h" #include #include @@ -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,7 +384,8 @@ CXWindowsClipboard::clearCache() const void CXWindowsClipboard::doClearCache() { - m_cached = false; + m_checkCache = false; + m_cached = false; for (SInt32 index = 0; index < kNumFormats; ++index) { m_data[index] = ""; m_added[index] = false; @@ -381,6 +396,7 @@ void CXWindowsClipboard::fillCache() const { // get the selection data if not already cached + checkCache(); if (!m_cached) { const_cast(this)->doFillCache(); } @@ -395,8 +411,9 @@ CXWindowsClipboard::doFillCache() else { icccmFillCache(); } - m_cached = true; - m_cacheTime = m_timeOwned; + m_checkCache = false; + m_cached = true; + m_cacheTime = m_timeOwned; } void @@ -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(&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( - 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(this)); + } + else { + CThread::sleep(0.01); + } } - timer.cancel(); // 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(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 diff --git a/platform/CXWindowsClipboard.h b/platform/CXWindowsClipboard.h index 92657adc..82d695e5 100644 --- a/platform/CXWindowsClipboard.h +++ b/platform/CXWindowsClipboard.h @@ -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];