diff --git a/client/CXWindowsSecondaryScreen.cpp b/client/CXWindowsSecondaryScreen.cpp index 5e10f84c..553564e1 100644 --- a/client/CXWindowsSecondaryScreen.cpp +++ b/client/CXWindowsSecondaryScreen.cpp @@ -86,6 +86,12 @@ void CXWindowsSecondaryScreen::run() xevent.xproperty.time); } break; + + case DestroyNotify: + // looks like one of the windows that requested a clipboard + // transfer has gone bye-bye. + destroyClipboardRequest(xevent.xdestroywindow.window); + break; } } } diff --git a/server/CXWindowsPrimaryScreen.cpp b/server/CXWindowsPrimaryScreen.cpp index 45f80328..2401e9f4 100644 --- a/server/CXWindowsPrimaryScreen.cpp +++ b/server/CXWindowsPrimaryScreen.cpp @@ -160,6 +160,12 @@ void CXWindowsPrimaryScreen::run() xevent.xproperty.time); } break; + + case DestroyNotify: + // looks like one of the windows that requested a clipboard + // transfer has gone bye-bye. + destroyClipboardRequest(xevent.xdestroywindow.window); + break; } } } diff --git a/synergy/CXWindowsScreen.cpp b/synergy/CXWindowsScreen.cpp index ebc933f4..e3cfee8f 100644 --- a/synergy/CXWindowsScreen.cpp +++ b/synergy/CXWindowsScreen.cpp @@ -578,6 +578,7 @@ void CXWindowsScreen::processClipboardRequest( return; } CRequestList* list = index->second; + assert(list != NULL); // find the property in the list CRequestList::iterator index2; @@ -591,6 +592,7 @@ void CXWindowsScreen::processClipboardRequest( return; } CClipboardRequest* request = *index2; + assert(request != NULL); // compute amount of data to send assert(request->m_sent <= request->m_data.size()); @@ -617,15 +619,45 @@ void CXWindowsScreen::processClipboardRequest( // if we sent zero bytes then we're done sending this data. remove // it from the list and, if the list is empty, the list from the - // map. - list->erase(index2); - delete request; - if (list->empty()) { - m_requests.erase(index); - delete list; + // map. also stop watching the requestor for events. + if (count == 0) { + list->erase(index2); + delete request; + if (list->empty()) { + m_requests.erase(index); + delete list; + } + XSelectInput(m_display, requestor, NoEventMask); } } +void CXWindowsScreen::destroyClipboardRequest( + Window requestor) +{ + CLock lock(&m_mutex); + + // find the request list + CRequestMap::iterator index = m_requests.find(requestor); + if (index == m_requests.end()) { + return; + } + CRequestList* list = index->second; + assert(list != NULL); + + // destroy every request in the list + for (CRequestList::iterator index2 = list->begin(); + index2 != list->end(); ++index2) { + delete *index2; + } + + // remove and destroy the list + m_requests.erase(index); + delete list; + + // note -- we don't stop watching the window for events because + // we're called in response to the window being destroyed. +} + bool CXWindowsScreen::sendClipboardData( Window requestor, Atom target, Atom property, Time time) @@ -658,15 +690,6 @@ bool CXWindowsScreen::sendClipboardData( if (data.size() > kMaxRequestSize) { log((CLOG_DEBUG "handling clipboard request for %d as INCR", target)); - // FIXME -- handle Alloc errors (by returning false) - // set property to INCR - const UInt32 zero = 0; - XChangeProperty(m_display, requestor, property, - m_atomINCR, 8 * sizeof(zero), - PropModeReplace, - reinterpret_cast(&zero), - 1); - // get the appropriate list, creating it if necessary CRequestList* list = m_requests[requestor]; if (list == NULL) { @@ -685,6 +708,20 @@ bool CXWindowsScreen::sendClipboardData( // add request to request list list->push_back(request); + + // start watching requestor for property changes and + // destruction + XSelectInput(m_display, requestor, StructureNotifyMask | + PropertyChangeMask); + + // FIXME -- handle Alloc errors (by returning false) + // set property to INCR + const UInt32 zero = 0; + XChangeProperty(m_display, requestor, property, + m_atomINCR, 8 * sizeof(zero), + PropModeReplace, + reinterpret_cast(&zero), + 1); } else { log((CLOG_DEBUG "handling clipboard request for %d", target)); diff --git a/synergy/CXWindowsScreen.h b/synergy/CXWindowsScreen.h index 4de7f27c..0166a473 100644 --- a/synergy/CXWindowsScreen.h +++ b/synergy/CXWindowsScreen.h @@ -81,6 +81,9 @@ class CXWindowsScreen { void processClipboardRequest(Window window, Atom property, Time time); + // terminate a selection request + void destroyClipboardRequest(Window window); + // called by openDisplay() to allow subclasses to prepare the display virtual void onOpenDisplay() = 0;