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:
parent
7cf20d9ad0
commit
189537b8b9
|
@ -440,6 +440,7 @@ void CXWindowsPrimaryScreen::onOpenDisplay()
|
|||
CWDontPropagate | CWEventMask |
|
||||
CWOverrideRedirect | CWCursor,
|
||||
&attr);
|
||||
log((CLOG_DEBUG "window is 0x%08x", m_window));
|
||||
|
||||
// start watching for events on other windows
|
||||
selectEvents(display, getRoot());
|
||||
|
@ -469,18 +470,17 @@ void CXWindowsPrimaryScreen::onLostClipboard(
|
|||
m_server->grabClipboard(id);
|
||||
}
|
||||
|
||||
long CXWindowsPrimaryScreen::getEventMask(Window w) const
|
||||
void CXWindowsPrimaryScreen::selectEvents(
|
||||
Display* display, Window w) const
|
||||
{
|
||||
if (w == m_window)
|
||||
return PointerMotionMask |// PointerMotionHintMask |
|
||||
ButtonPressMask | ButtonReleaseMask |
|
||||
KeyPressMask | KeyReleaseMask |
|
||||
KeymapStateMask;
|
||||
else
|
||||
return PointerMotionMask | SubstructureNotifyMask;
|
||||
// ignore errors while we adjust event masks
|
||||
CXWindowsUtil::CErrorLock lock;
|
||||
|
||||
// adjust event masks
|
||||
doSelectEvents(display, w);
|
||||
}
|
||||
|
||||
void CXWindowsPrimaryScreen::selectEvents(
|
||||
void CXWindowsPrimaryScreen::doSelectEvents(
|
||||
Display* display, Window w) const
|
||||
{
|
||||
// we want to track the mouse everywhere on the display. to achieve
|
||||
|
@ -500,7 +500,7 @@ void CXWindowsPrimaryScreen::selectEvents(
|
|||
unsigned int nc;
|
||||
if (XQueryTree(display, w, &rw, &pw, &cw, &nc)) {
|
||||
for (unsigned int i = 0; i < nc; ++i)
|
||||
selectEvents(display, cw[i]);
|
||||
doSelectEvents(display, cw[i]);
|
||||
XFree(cw);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,10 +34,10 @@ protected:
|
|||
createClipboard(ClipboardID);
|
||||
virtual void onCloseDisplay();
|
||||
virtual void onLostClipboard(ClipboardID);
|
||||
virtual long getEventMask(Window) const;
|
||||
|
||||
private:
|
||||
void selectEvents(Display*, Window) const;
|
||||
void doSelectEvents(Display*, Window) const;
|
||||
void warpCursorNoLock(Display*,
|
||||
SInt32 xAbsolute, SInt32 yAbsolute);
|
||||
|
||||
|
|
|
@ -190,6 +190,7 @@ bool CXWindowsClipboard::destroyRequest(
|
|||
|
||||
// destroy all replies for this window
|
||||
clearReplies(index->second);
|
||||
m_replies.erase(index);
|
||||
|
||||
// note -- we don't stop watching the window for events because
|
||||
// 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
|
||||
// properties change.
|
||||
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;
|
||||
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 |
|
||||
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
|
||||
// and stop watching the requestor for events.
|
||||
if (replies.empty()) {
|
||||
CXWindowsUtil::CErrorLock lock;
|
||||
Window requestor = mapIndex->first;
|
||||
XSelectInput(m_display, requestor, m_eventMasks[requestor]);
|
||||
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));
|
||||
reply->m_done = true;
|
||||
if (reply->m_property != None) {
|
||||
CXWindowsUtil::CErrorLock lock;
|
||||
XDeleteProperty(m_display, reply->m_requestor, reply->m_property);
|
||||
}
|
||||
|
||||
|
@ -958,6 +974,7 @@ void CXWindowsClipboard::sendNotify(
|
|||
event.xselection.target = target;
|
||||
event.xselection.property = property;
|
||||
event.xselection.time = time;
|
||||
CXWindowsUtil::CErrorLock lock;
|
||||
XSendEvent(m_display, requestor, False, 0, &event);
|
||||
}
|
||||
|
||||
|
|
|
@ -76,9 +76,6 @@ protected:
|
|||
// called when a clipboard is lost
|
||||
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:
|
||||
// internal event processing
|
||||
bool processEvent(XEvent*);
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
#include "CXWindowsUtil.h"
|
||||
#include "CLog.h"
|
||||
#include "CThread.h"
|
||||
#include <assert.h>
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
//
|
||||
// CXWindowsUtil
|
||||
//
|
||||
|
||||
bool CXWindowsUtil::getWindowProperty(
|
||||
Display* display,
|
||||
Window window, Atom property,
|
||||
|
@ -15,6 +20,9 @@ bool CXWindowsUtil::getWindowProperty(
|
|||
Atom actualType;
|
||||
int actualDatumSize;
|
||||
|
||||
// ignore errors. XGetWindowProperty() will report failure.
|
||||
CXWindowsUtil::CErrorLock lock;
|
||||
|
||||
// read the property
|
||||
const long length = XMaxRequestSize(display);
|
||||
long offset = 0;
|
||||
|
@ -82,13 +90,14 @@ bool CXWindowsUtil::setWindowProperty(
|
|||
const void* vdata, UInt32 size,
|
||||
Atom type, SInt32 format)
|
||||
{
|
||||
// FIXME -- must catch Alloc errors (using XSetErrorHandler()) and
|
||||
// report failure to caller.
|
||||
|
||||
const UInt32 length = 4 * XMaxRequestSize(display);
|
||||
const unsigned char* data = reinterpret_cast<const unsigned char*>(vdata);
|
||||
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?
|
||||
UInt32 chunkSize = size;
|
||||
if (chunkSize > length)
|
||||
|
@ -102,7 +111,7 @@ bool CXWindowsUtil::setWindowProperty(
|
|||
// append remaining chunks
|
||||
data += chunkSize;
|
||||
size -= chunkSize;
|
||||
while (size > 0) {
|
||||
while (!error && size > 0) {
|
||||
chunkSize = size;
|
||||
if (chunkSize > length)
|
||||
chunkSize = length;
|
||||
|
@ -113,7 +122,7 @@ bool CXWindowsUtil::setWindowProperty(
|
|||
size -= chunkSize;
|
||||
}
|
||||
|
||||
return true;
|
||||
return !error;
|
||||
}
|
||||
|
||||
Time CXWindowsUtil::getCurrentTime(
|
||||
|
@ -167,3 +176,63 @@ Bool CXWindowsUtil::propertyNotifyPredicate(
|
|||
xevent->xproperty.atom == filter->m_property &&
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,36 @@ public:
|
|||
Atom type, SInt32 format);
|
||||
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:
|
||||
class CPropertyNotifyPredicateInfo {
|
||||
public:
|
||||
|
|
Loading…
Reference in New Issue