#include "CXWindowsUtil.h" #include "CThread.h" #include "CLog.h" #include // // CXWindowsUtil // bool CXWindowsUtil::getWindowProperty(Display* display, Window window, Atom property, CString* data, Atom* type, int* format, bool deleteProperty) { assert(display != NULL); assert(data != 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 data->append((char*)rawData, numBytes); // 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(actualDatumSize); } log((CLOG_DEBUG1 "read property %d on window 0x%08x: bytes=%d", property, window, 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(vdata); const UInt32 datumSize = static_cast(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(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 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 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(flag) = true; }