removed getEventMask() from primary screen. added a class to

CXWindowsUtil that installs/uninstalls an X error hander.
using that in primary screen, clipboard, and util to ensure
that certain errors don't kill the app.
This commit is contained in:
crs 2002-05-27 18:30:13 +00:00
parent 7cf20d9ad0
commit 189537b8b9
6 changed files with 133 additions and 20 deletions

View File

@ -440,6 +440,7 @@ void CXWindowsPrimaryScreen::onOpenDisplay()
CWDontPropagate | CWEventMask | CWDontPropagate | CWEventMask |
CWOverrideRedirect | CWCursor, CWOverrideRedirect | CWCursor,
&attr); &attr);
log((CLOG_DEBUG "window is 0x%08x", m_window));
// start watching for events on other windows // start watching for events on other windows
selectEvents(display, getRoot()); selectEvents(display, getRoot());
@ -469,18 +470,17 @@ void CXWindowsPrimaryScreen::onLostClipboard(
m_server->grabClipboard(id); m_server->grabClipboard(id);
} }
long CXWindowsPrimaryScreen::getEventMask(Window w) const void CXWindowsPrimaryScreen::selectEvents(
Display* display, Window w) const
{ {
if (w == m_window) // ignore errors while we adjust event masks
return PointerMotionMask |// PointerMotionHintMask | CXWindowsUtil::CErrorLock lock;
ButtonPressMask | ButtonReleaseMask |
KeyPressMask | KeyReleaseMask | // adjust event masks
KeymapStateMask; doSelectEvents(display, w);
else
return PointerMotionMask | SubstructureNotifyMask;
} }
void CXWindowsPrimaryScreen::selectEvents( void CXWindowsPrimaryScreen::doSelectEvents(
Display* display, Window w) const Display* display, Window w) const
{ {
// we want to track the mouse everywhere on the display. to achieve // we want to track the mouse everywhere on the display. to achieve
@ -500,7 +500,7 @@ void CXWindowsPrimaryScreen::selectEvents(
unsigned int nc; unsigned int nc;
if (XQueryTree(display, w, &rw, &pw, &cw, &nc)) { if (XQueryTree(display, w, &rw, &pw, &cw, &nc)) {
for (unsigned int i = 0; i < nc; ++i) for (unsigned int i = 0; i < nc; ++i)
selectEvents(display, cw[i]); doSelectEvents(display, cw[i]);
XFree(cw); XFree(cw);
} }
} }

View File

@ -34,10 +34,10 @@ protected:
createClipboard(ClipboardID); createClipboard(ClipboardID);
virtual void onCloseDisplay(); virtual void onCloseDisplay();
virtual void onLostClipboard(ClipboardID); virtual void onLostClipboard(ClipboardID);
virtual long getEventMask(Window) const;
private: private:
void selectEvents(Display*, Window) const; void selectEvents(Display*, Window) const;
void doSelectEvents(Display*, Window) const;
void warpCursorNoLock(Display*, void warpCursorNoLock(Display*,
SInt32 xAbsolute, SInt32 yAbsolute); SInt32 xAbsolute, SInt32 yAbsolute);

View File

@ -190,6 +190,7 @@ bool CXWindowsClipboard::destroyRequest(
// destroy all replies for this window // destroy all replies for this window
clearReplies(index->second); clearReplies(index->second);
m_replies.erase(index);
// note -- we don't stop watching the window for events because // note -- we don't stop watching the window for events because
// we're called in response to the window being destroyed. // we're called in response to the window being destroyed.
@ -758,11 +759,24 @@ void CXWindowsClipboard::insertReply(CReply* reply)
// want events in case the window is destroyed or any of its // want events in case the window is destroyed or any of its
// properties change. // properties change.
if (newWindow) { if (newWindow) {
// note errors while we adjust event masks
bool error = false;
CXWindowsUtil::CErrorLock lock(&error);
// get and save the current event mask
XWindowAttributes attr; XWindowAttributes attr;
XGetWindowAttributes(m_display, reply->m_requestor, &attr); XGetWindowAttributes(m_display, reply->m_requestor, &attr);
m_eventMasks[reply->m_requestor] = attr.your_event_mask;
// add the events we want
XSelectInput(m_display, reply->m_requestor, attr.your_event_mask | XSelectInput(m_display, reply->m_requestor, attr.your_event_mask |
StructureNotifyMask | PropertyChangeMask); StructureNotifyMask | PropertyChangeMask);
m_eventMasks[reply->m_requestor] = attr.your_event_mask;
// if we failed then the window has already been destroyed
if (error) {
m_replies.erase(reply->m_requestor);
delete reply;
}
} }
} }
@ -799,6 +813,7 @@ void CXWindowsClipboard::pushReplies(
// if there are no more replies in the list then remove the list // if there are no more replies in the list then remove the list
// and stop watching the requestor for events. // and stop watching the requestor for events.
if (replies.empty()) { if (replies.empty()) {
CXWindowsUtil::CErrorLock lock;
Window requestor = mapIndex->first; Window requestor = mapIndex->first;
XSelectInput(m_display, requestor, m_eventMasks[requestor]); XSelectInput(m_display, requestor, m_eventMasks[requestor]);
m_replies.erase(mapIndex); m_replies.erase(mapIndex);
@ -871,6 +886,7 @@ bool CXWindowsClipboard::sendReply(CReply* reply)
log((CLOG_DEBUG1 "clipboard: sending failure to 0x%08x,%d,%d", reply->m_requestor, reply->m_target, reply->m_property)); log((CLOG_DEBUG1 "clipboard: sending failure to 0x%08x,%d,%d", reply->m_requestor, reply->m_target, reply->m_property));
reply->m_done = true; reply->m_done = true;
if (reply->m_property != None) { if (reply->m_property != None) {
CXWindowsUtil::CErrorLock lock;
XDeleteProperty(m_display, reply->m_requestor, reply->m_property); XDeleteProperty(m_display, reply->m_requestor, reply->m_property);
} }
@ -958,6 +974,7 @@ void CXWindowsClipboard::sendNotify(
event.xselection.target = target; event.xselection.target = target;
event.xselection.property = property; event.xselection.property = property;
event.xselection.time = time; event.xselection.time = time;
CXWindowsUtil::CErrorLock lock;
XSendEvent(m_display, requestor, False, 0, &event); XSendEvent(m_display, requestor, False, 0, &event);
} }

View File

@ -76,9 +76,6 @@ protected:
// called when a clipboard is lost // called when a clipboard is lost
virtual void onLostClipboard(ClipboardID) = 0; virtual void onLostClipboard(ClipboardID) = 0;
// get the X event mask required by the subclass for the given window
virtual long getEventMask(Window) const = 0;
private: private:
// internal event processing // internal event processing
bool processEvent(XEvent*); bool processEvent(XEvent*);

View File

@ -1,8 +1,13 @@
#include "CXWindowsUtil.h" #include "CXWindowsUtil.h"
#include "CLog.h" #include "CLog.h"
#include "CThread.h" #include "CThread.h"
#include <assert.h>
#include <X11/Xatom.h> #include <X11/Xatom.h>
//
// CXWindowsUtil
//
bool CXWindowsUtil::getWindowProperty( bool CXWindowsUtil::getWindowProperty(
Display* display, Display* display,
Window window, Atom property, Window window, Atom property,
@ -15,6 +20,9 @@ bool CXWindowsUtil::getWindowProperty(
Atom actualType; Atom actualType;
int actualDatumSize; int actualDatumSize;
// ignore errors. XGetWindowProperty() will report failure.
CXWindowsUtil::CErrorLock lock;
// read the property // read the property
const long length = XMaxRequestSize(display); const long length = XMaxRequestSize(display);
long offset = 0; long offset = 0;
@ -82,13 +90,14 @@ bool CXWindowsUtil::setWindowProperty(
const void* vdata, UInt32 size, const void* vdata, UInt32 size,
Atom type, SInt32 format) Atom type, SInt32 format)
{ {
// FIXME -- must catch Alloc errors (using XSetErrorHandler()) and
// report failure to caller.
const UInt32 length = 4 * XMaxRequestSize(display); const UInt32 length = 4 * XMaxRequestSize(display);
const unsigned char* data = reinterpret_cast<const unsigned char*>(vdata); const unsigned char* data = reinterpret_cast<const unsigned char*>(vdata);
const UInt32 datumSize = static_cast<UInt32>(format / 8); const UInt32 datumSize = static_cast<UInt32>(format / 8);
// save errors
bool error = false;
CXWindowsUtil::CErrorLock lock(&error);
// how much data to send in first chunk? // how much data to send in first chunk?
UInt32 chunkSize = size; UInt32 chunkSize = size;
if (chunkSize > length) if (chunkSize > length)
@ -102,7 +111,7 @@ bool CXWindowsUtil::setWindowProperty(
// append remaining chunks // append remaining chunks
data += chunkSize; data += chunkSize;
size -= chunkSize; size -= chunkSize;
while (size > 0) { while (!error && size > 0) {
chunkSize = size; chunkSize = size;
if (chunkSize > length) if (chunkSize > length)
chunkSize = length; chunkSize = length;
@ -113,7 +122,7 @@ bool CXWindowsUtil::setWindowProperty(
size -= chunkSize; size -= chunkSize;
} }
return true; return !error;
} }
Time CXWindowsUtil::getCurrentTime( Time CXWindowsUtil::getCurrentTime(
@ -167,3 +176,63 @@ Bool CXWindowsUtil::propertyNotifyPredicate(
xevent->xproperty.atom == filter->m_property && xevent->xproperty.atom == filter->m_property &&
xevent->xproperty.state == PropertyNewValue) ? True : False; xevent->xproperty.state == PropertyNewValue) ? True : False;
} }
//
// CXWindowsUtil::CErrorLock
//
CXWindowsUtil::CErrorLock* CXWindowsUtil::CErrorLock::s_top = NULL;
CXWindowsUtil::CErrorLock::CErrorLock()
{
install(&CXWindowsUtil::CErrorLock::ignoreHandler, NULL);
}
CXWindowsUtil::CErrorLock::CErrorLock(bool* flag)
{
install(&CXWindowsUtil::CErrorLock::saveHandler, flag);
}
CXWindowsUtil::CErrorLock::CErrorLock(ErrorHandler handler, void* data)
{
install(handler, data);
}
CXWindowsUtil::CErrorLock::~CErrorLock()
{
XSetErrorHandler(m_oldXHandler);
s_top = m_next;
}
void CXWindowsUtil::CErrorLock::install(
ErrorHandler handler, void* data)
{
m_handler = handler;
m_userData = data;
m_oldXHandler = XSetErrorHandler(
&CXWindowsUtil::CErrorLock::internalHandler);
m_next = s_top;
s_top = this;
}
int CXWindowsUtil::CErrorLock::internalHandler(
Display* display, XErrorEvent* event)
{
if (s_top != NULL && s_top->m_handler != NULL) {
s_top->m_handler(display, event, s_top->m_userData);
}
return 0;
}
void CXWindowsUtil::CErrorLock::ignoreHandler(
Display*, XErrorEvent*, void*)
{
// do nothing
}
void CXWindowsUtil::CErrorLock::saveHandler(
Display*, XErrorEvent*, void* flag)
{
*reinterpret_cast<bool*>(flag) = true;
}

View File

@ -17,6 +17,36 @@ public:
Atom type, SInt32 format); Atom type, SInt32 format);
static Time getCurrentTime(Display*, Window); static Time getCurrentTime(Display*, Window);
// class to set an X error handler in the c'tor and restore the
// previous error handler in the d'tor. a lock should only
// be installed while the display is locked by the thread.
//
// CErrorLock() ignores errors
// CErrorLock(bool* flag) sets *flag to true if any error occurs
class CErrorLock {
public:
typedef void (*ErrorHandler)(Display*, XErrorEvent*, void* userData);
CErrorLock();
CErrorLock(bool* errorFlag);
CErrorLock(ErrorHandler, void* userData);
~CErrorLock();
private:
void install(ErrorHandler, void*);
static int internalHandler(Display*, XErrorEvent*);
static void ignoreHandler(Display*, XErrorEvent*, void*);
static void saveHandler(Display*, XErrorEvent*, void*);
private:
typedef int (*XErrorHandler)(Display*, XErrorEvent*);
ErrorHandler m_handler;
void* m_userData;
XErrorHandler m_oldXHandler;
CErrorLock* m_next;
static CErrorLock* s_top;
};
private: private:
class CPropertyNotifyPredicateInfo { class CPropertyNotifyPredicateInfo {
public: public: