mirror of
https://github.com/debauchee/barrier.git
synced 2024-12-25 03:53:18 +03:00
c6ecc79c0d
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.
256 lines
6.0 KiB
C++
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;
|
|
}
|