mirror of
https://github.com/debauchee/barrier.git
synced 2024-12-19 00:41:49 +03:00
synergy.cpp and server.cpp into cmd/synergyd as synergyd.cpp. Moved and renamed related files. Moved remaining source files into lib/.... Modified and added makefiles as appropriate. Result is that library files are under lib with each library in its own directory and program files are under cmd with each command in its own directory.
263 lines
6.2 KiB
C++
263 lines
6.2 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,
|
|
SInt32* format, bool deleteProperty)
|
|
{
|
|
assert(display != NULL);
|
|
|
|
Atom actualType;
|
|
int actualDatumSize;
|
|
|
|
// ignore errors. XGetWindowProperty() will report failure.
|
|
CXWindowsUtil::CErrorLock lock(display);
|
|
|
|
// read the property
|
|
int result = Success;
|
|
const long length = XMaxRequestSize(display);
|
|
long offset = 0;
|
|
unsigned long bytesLeft = 1;
|
|
while (bytesLeft != 0) {
|
|
// get more data
|
|
unsigned long numItems;
|
|
unsigned char* rawData;
|
|
result = XGetWindowProperty(display, window, property,
|
|
offset, length, False, AnyPropertyType,
|
|
&actualType, &actualDatumSize,
|
|
&numItems, &bytesLeft, &rawData);
|
|
if (result != Success || actualType == None || actualDatumSize == 0) {
|
|
// failed
|
|
break;
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
|
|
if (result == Success) {
|
|
log((CLOG_DEBUG1 "read property %d on window 0x%08x: bytes=%d", property, window, (data == NULL) ? 0 : data->size()));
|
|
return true;
|
|
}
|
|
else {
|
|
log((CLOG_DEBUG1 "can't read property %d on window 0x%08x", property, window));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|