barrier/platform/CXWindowsUtil.cpp
crs c6ecc79c0d removed restart function from platform. no longer trying to
restart if the X server connection was lost;  since synergy
is likely to be started by xdm or the user's xsession, it's
better for synergy to simply terminate when the connection
is lost.  synergy will still restart due to other errors.
also fixed numerous other minor bugs and cleaned some stuff
up (like app error codes are now consistent and enumerated
in Version.h, for lack of a better place).  and boosted
version and protocol numbers.
2002-07-24 13:01:18 +00:00

256 lines
6.0 KiB
C++

#include "CXWindowsUtil.h"
#include "CThread.h"
#include "CLog.h"
#include <X11/Xatom.h>
//
// CXWindowsUtil
//
bool
CXWindowsUtil::getWindowProperty(Display* display, Window window,
Atom property, CString* data, Atom* type,
int* format, bool deleteProperty)
{
assert(display != NULL);
Atom actualType;
int actualDatumSize;
// ignore errors. XGetWindowProperty() will report failure.
CXWindowsUtil::CErrorLock lock(display);
// read the property
const long length = XMaxRequestSize(display);
long offset = 0;
unsigned long bytesLeft = 1;
while (bytesLeft != 0) {
// get more data
unsigned long numItems;
unsigned char* rawData;
const int result = XGetWindowProperty(display, window, property,
offset, length, False, AnyPropertyType,
&actualType, &actualDatumSize,
&numItems, &bytesLeft, &rawData);
if (result != Success || actualType == None || actualDatumSize == 0) {
// failed
return false;
}
// compute bytes read and advance offset
unsigned long numBytes;
switch (actualDatumSize) {
case 8:
default:
numBytes = numItems;
offset += numItems / 4;
break;
case 16:
numBytes = 2 * numItems;
offset += numItems / 2;
break;
case 32:
numBytes = 4 * numItems;
offset += numItems;
break;
}
// append data
if (data != NULL) {
data->append((char*)rawData, numBytes);
}
else {
// data is not required so don't try to get any more
bytesLeft = 0;
}
// done with returned data
XFree(rawData);
}
// delete the property if requested
if (deleteProperty) {
XDeleteProperty(display, window, property);
}
// save property info
if (type != NULL) {
*type = actualType;
}
if (format != NULL) {
*format = static_cast<SInt32>(actualDatumSize);
}
log((CLOG_DEBUG1 "read property %d on window 0x%08x: bytes=%d", property, window, (data == NULL) ? 0 : data->size()));
return true;
}
bool
CXWindowsUtil::setWindowProperty(Display* display, Window window,
Atom property, const void* vdata, UInt32 size,
Atom type, SInt32 format)
{
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(display, &error);
// how much data to send in first chunk?
UInt32 chunkSize = size;
if (chunkSize > length) {
chunkSize = length;
}
// send first chunk
XChangeProperty(display, window, property,
type, format, PropModeReplace,
data, chunkSize / datumSize);
// append remaining chunks
data += chunkSize;
size -= chunkSize;
while (!error && size > 0) {
chunkSize = size;
if (chunkSize > length) {
chunkSize = length;
}
XChangeProperty(display, window, property,
type, format, PropModeAppend,
data, chunkSize / datumSize);
data += chunkSize;
size -= chunkSize;
}
return !error;
}
Time
CXWindowsUtil::getCurrentTime(Display* display, Window window)
{
// select property events on window
XWindowAttributes attr;
XGetWindowAttributes(display, window, &attr);
XSelectInput(display, window, attr.your_event_mask | PropertyChangeMask);
// make a property name to receive dummy change
Atom atom = XInternAtom(display, "TIMESTAMP", False);
// do a zero-length append to get the current time
unsigned char dummy;
XChangeProperty(display, window, atom,
XA_INTEGER, 8,
PropModeAppend,
&dummy, 0);
// look for property notify events with the following
CPropertyNotifyPredicateInfo filter;
filter.m_window = window;
filter.m_property = atom;
// wait for reply
XEvent xevent;
XIfEvent(display, &xevent, &CXWindowsUtil::propertyNotifyPredicate,
(XPointer)&filter);
assert(xevent.type == PropertyNotify);
assert(xevent.xproperty.window == window);
assert(xevent.xproperty.atom == atom);
// restore event mask
XSelectInput(display, window, attr.your_event_mask);
return xevent.xproperty.time;
}
Bool
CXWindowsUtil::propertyNotifyPredicate(Display*, XEvent* xevent, XPointer arg)
{
CPropertyNotifyPredicateInfo* filter =
reinterpret_cast<CPropertyNotifyPredicateInfo*>(arg);
return (xevent->type == PropertyNotify &&
xevent->xproperty.window == filter->m_window &&
xevent->xproperty.atom == filter->m_property &&
xevent->xproperty.state == PropertyNewValue) ? True : False;
}
//
// CXWindowsUtil::CErrorLock
//
CXWindowsUtil::CErrorLock* CXWindowsUtil::CErrorLock::s_top = NULL;
CXWindowsUtil::CErrorLock::CErrorLock(Display* display) :
m_display(display)
{
install(&CXWindowsUtil::CErrorLock::ignoreHandler, NULL);
}
CXWindowsUtil::CErrorLock::CErrorLock(Display* display, bool* flag) :
m_display(display)
{
install(&CXWindowsUtil::CErrorLock::saveHandler, flag);
}
CXWindowsUtil::CErrorLock::CErrorLock(Display* display,
ErrorHandler handler, void* data) :
m_display(display)
{
install(handler, data);
}
CXWindowsUtil::CErrorLock::~CErrorLock()
{
// make sure everything finishes before uninstalling handler
if (m_display != NULL) {
XSync(m_display, False);
}
// restore old handler
XSetErrorHandler(m_oldXHandler);
s_top = m_next;
}
void
CXWindowsUtil::CErrorLock::install(ErrorHandler handler, void* data)
{
// make sure everything finishes before installing handler
if (m_display != NULL) {
XSync(m_display, False);
}
// install handler
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* e, void*)
{
log((CLOG_DEBUG "ignoring X error: %d", e->error_code));
}
void
CXWindowsUtil::CErrorLock::saveHandler(Display*, XErrorEvent* e, void* flag)
{
log((CLOG_DEBUG "flagging X error: %d", e->error_code));
*reinterpret_cast<bool*>(flag) = true;
}