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 |
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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*);
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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:
|
||||||
|
|
Loading…
Reference in New Issue