#include "CXWindowsUtil.h" #include "CLog.h" #include "CThread.h" #include 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; // 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) { // FIXME -- must catch Alloc errors (using XSetErrorHandler()) and // report failure to caller. const UInt32 length = 4 * XMaxRequestSize(display); const unsigned char* data = reinterpret_cast(vdata); const UInt32 datumSize = static_cast(format / 8); // 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 (size > 0) { chunkSize = size; if (chunkSize > length) chunkSize = length; XChangeProperty(display, window, property, type, format, PropModeAppend, data, chunkSize / datumSize); data += chunkSize; size -= chunkSize; } return true; } 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; while (XCheckIfEvent(display, &xevent, &CXWindowsUtil::propertyNotifyPredicate, (XPointer)&filter) != True) { // wait a bit CThread::sleep(0.05); } 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; }