mirror of
https://github.com/debauchee/barrier.git
synced 2024-12-21 10:01:42 +03:00
fee4095624
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.
447 lines
11 KiB
C++
447 lines
11 KiB
C++
#include "CXWindowsScreenSaver.h"
|
|
#include "CXWindowsScreen.h"
|
|
#include "CXWindowsUtil.h"
|
|
#include "CLog.h"
|
|
#include "TMethodJob.h"
|
|
#include <X11/Xatom.h>
|
|
#if defined(HAVE_X11_EXTENSIONS_XTEST_H)
|
|
# include <X11/extensions/XTest.h>
|
|
#else
|
|
# error The XTest extension is required to build synergy
|
|
#endif
|
|
|
|
//
|
|
// CXWindowsScreenSaver
|
|
//
|
|
|
|
CXWindowsScreenSaver::CXWindowsScreenSaver(
|
|
CXWindowsScreen* screen, Display* display) :
|
|
m_screen(screen),
|
|
m_display(display),
|
|
m_notify(None),
|
|
m_xscreensaver(None),
|
|
m_xscreensaverActive(false),
|
|
m_disabled(false)
|
|
{
|
|
// screen saver disable callback
|
|
m_disableJob = new TMethodJob<CXWindowsScreenSaver>(this,
|
|
&CXWindowsScreenSaver::disableCallback);
|
|
|
|
// get atoms
|
|
m_atomScreenSaver = XInternAtom(m_display,
|
|
"SCREENSAVER", False);
|
|
m_atomScreenSaverVersion = XInternAtom(m_display,
|
|
"_SCREENSAVER_VERSION", False);
|
|
m_atomScreenSaverActivate = XInternAtom(m_display,
|
|
"ACTIVATE", False);
|
|
m_atomScreenSaverDeactivate = XInternAtom(m_display,
|
|
"DEACTIVATE", False);
|
|
|
|
// create dummy window to receive xscreensaver responses. this
|
|
// shouldn't be necessary (we should be able to send responses
|
|
// to None) but it doesn't hurt.
|
|
XSetWindowAttributes attr;
|
|
attr.event_mask = 0;//PropertyChangeMask;
|
|
attr.do_not_propagate_mask = 0;
|
|
attr.override_redirect = True;
|
|
m_xscreensaverSink = XCreateWindow(m_display,
|
|
DefaultRootWindow(m_display),
|
|
0, 0, 1, 1, 0, 0,
|
|
InputOnly, CopyFromParent,
|
|
CWDontPropagate | CWEventMask |
|
|
CWOverrideRedirect,
|
|
&attr);
|
|
log((CLOG_DEBUG "xscreensaver sink window is 0x%08x", m_xscreensaverSink));
|
|
|
|
// watch top-level windows for changes
|
|
{
|
|
bool error = false;
|
|
CXWindowsUtil::CErrorLock lock(m_display, &error);
|
|
Window root = DefaultRootWindow(m_display);
|
|
XWindowAttributes attr;
|
|
XGetWindowAttributes(m_display, root, &attr);
|
|
m_rootEventMask = attr.your_event_mask;
|
|
XSelectInput(m_display, root, m_rootEventMask | SubstructureNotifyMask);
|
|
if (error) {
|
|
log((CLOG_DEBUG "didn't set root event mask"));
|
|
m_rootEventMask = 0;
|
|
}
|
|
}
|
|
|
|
// get the xscreensaver window, if any
|
|
if (!findXScreenSaver()) {
|
|
setXScreenSaver(None);
|
|
}
|
|
|
|
// get the built-in settings
|
|
XGetScreenSaver(m_display, &m_timeout, &m_interval,
|
|
&m_preferBlanking, &m_allowExposures);
|
|
}
|
|
|
|
CXWindowsScreenSaver::~CXWindowsScreenSaver()
|
|
{
|
|
// clear watch list
|
|
clearWatchForXScreenSaver();
|
|
|
|
// stop watching root for events
|
|
CXWindowsUtil::CErrorLock lock(m_display);
|
|
Window root = DefaultRootWindow(m_display);
|
|
XSelectInput(m_display, root, m_rootEventMask);
|
|
|
|
// destroy dummy sink window
|
|
XDestroyWindow(m_display, m_xscreensaverSink);
|
|
|
|
// done with disable job
|
|
m_screen->removeTimer(m_disableJob);
|
|
delete m_disableJob;
|
|
}
|
|
|
|
bool
|
|
CXWindowsScreenSaver::onPreDispatch(const XEvent* xevent)
|
|
{
|
|
switch (xevent->type) {
|
|
case CreateNotify:
|
|
if (m_xscreensaver == None) {
|
|
if (isXScreenSaver(xevent->xcreatewindow.window)) {
|
|
// found the xscreensaver
|
|
setXScreenSaver(xevent->xcreatewindow.window);
|
|
}
|
|
else {
|
|
// another window to watch. to detect the xscreensaver
|
|
// window we look for a property but that property may
|
|
// not yet exist by the time we get this event so we
|
|
// have to watch the window for property changes.
|
|
// this would be so much easier if xscreensaver did the
|
|
// smart thing and stored its window in a property on
|
|
// the root window.
|
|
addWatchXScreenSaver(xevent->xcreatewindow.window);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case DestroyNotify:
|
|
if (xevent->xdestroywindow.window == m_xscreensaver) {
|
|
// xscreensaver is gone
|
|
log((CLOG_DEBUG "xscreensaver died"));
|
|
setXScreenSaver(None);
|
|
return true;
|
|
}
|
|
break;
|
|
|
|
case PropertyNotify:
|
|
if (xevent->xproperty.state == PropertyNewValue) {
|
|
if (isXScreenSaver(xevent->xproperty.window)) {
|
|
// found the xscreensaver
|
|
setXScreenSaver(xevent->xcreatewindow.window);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MapNotify:
|
|
if (xevent->xmap.window == m_xscreensaver) {
|
|
// xscreensaver has activated
|
|
setXScreenSaverActive(true);
|
|
return true;
|
|
}
|
|
break;
|
|
|
|
case UnmapNotify:
|
|
if (xevent->xunmap.window == m_xscreensaver) {
|
|
// xscreensaver has deactivated
|
|
setXScreenSaverActive(false);
|
|
return true;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void
|
|
CXWindowsScreenSaver::setNotify(Window notify)
|
|
{
|
|
m_notify = notify;
|
|
}
|
|
|
|
void
|
|
CXWindowsScreenSaver::enable()
|
|
{
|
|
// for xscreensaver
|
|
m_disabled = false;
|
|
m_screen->removeTimer(m_disableJob);
|
|
|
|
// for built-in X screen saver
|
|
XSetScreenSaver(m_display, m_timeout, m_interval,
|
|
m_preferBlanking, m_allowExposures);
|
|
}
|
|
|
|
void
|
|
CXWindowsScreenSaver::disable()
|
|
{
|
|
// for xscreensaver. 5 seconds should be plenty often to
|
|
// suppress the screen saver.
|
|
m_disabled = true;
|
|
m_screen->addTimer(m_disableJob, 5.0);
|
|
|
|
// use built-in X screen saver
|
|
XGetScreenSaver(m_display, &m_timeout, &m_interval,
|
|
&m_preferBlanking, &m_allowExposures);
|
|
XSetScreenSaver(m_display, 0, m_interval,
|
|
m_preferBlanking, m_allowExposures);
|
|
// FIXME -- now deactivate?
|
|
}
|
|
|
|
void
|
|
CXWindowsScreenSaver::activate()
|
|
{
|
|
// remove disable job timer
|
|
if (m_disabled) {
|
|
m_screen->removeTimer(m_disableJob);
|
|
}
|
|
|
|
// try xscreensaver
|
|
findXScreenSaver();
|
|
if (m_xscreensaver != None) {
|
|
sendXScreenSaverCommand(m_atomScreenSaverActivate);
|
|
return;
|
|
}
|
|
|
|
// use built-in X screen saver
|
|
XForceScreenSaver(m_display, ScreenSaverActive);
|
|
}
|
|
|
|
void
|
|
CXWindowsScreenSaver::deactivate()
|
|
{
|
|
// reinstall disable job timer
|
|
if (m_disabled) {
|
|
m_screen->addTimer(m_disableJob, 5.0);
|
|
}
|
|
|
|
// try xscreensaver
|
|
findXScreenSaver();
|
|
if (m_xscreensaver != None) {
|
|
sendXScreenSaverCommand(m_atomScreenSaverDeactivate);
|
|
return;
|
|
}
|
|
|
|
// use built-in X screen saver
|
|
XForceScreenSaver(m_display, ScreenSaverReset);
|
|
}
|
|
|
|
bool
|
|
CXWindowsScreenSaver::isActive() const
|
|
{
|
|
// check xscreensaver
|
|
if (m_xscreensaver != None) {
|
|
return m_xscreensaverActive;
|
|
}
|
|
|
|
// can't check built-in X screen saver activity
|
|
return false;
|
|
}
|
|
|
|
void
|
|
CXWindowsScreenSaver::sendNotify(bool activated)
|
|
{
|
|
if (m_notify != None) {
|
|
XEvent event;
|
|
event.xclient.type = ClientMessage;
|
|
event.xclient.display = m_display;
|
|
event.xclient.window = m_notify;
|
|
event.xclient.message_type = m_atomScreenSaver;
|
|
event.xclient.format = 32;
|
|
event.xclient.data.l[0] = activated ? 1 : 0;
|
|
event.xclient.data.l[1] = 0;
|
|
event.xclient.data.l[2] = 0;
|
|
event.xclient.data.l[3] = 0;
|
|
event.xclient.data.l[4] = 0;
|
|
|
|
CXWindowsUtil::CErrorLock lock(m_display);
|
|
XSendEvent(m_display, m_notify, False, 0, &event);
|
|
}
|
|
}
|
|
|
|
bool
|
|
CXWindowsScreenSaver::findXScreenSaver()
|
|
{
|
|
// do nothing if we've already got the xscreensaver window
|
|
if (m_xscreensaver == None) {
|
|
// find top-level window xscreensaver window
|
|
Window root = DefaultRootWindow(m_display);
|
|
Window rw, pw, *cw;
|
|
unsigned int nc;
|
|
if (XQueryTree(m_display, root, &rw, &pw, &cw, &nc)) {
|
|
for (unsigned int i = 0; i < nc; ++i) {
|
|
if (isXScreenSaver(cw[i])) {
|
|
setXScreenSaver(cw[i]);
|
|
break;
|
|
}
|
|
}
|
|
XFree(cw);
|
|
}
|
|
}
|
|
|
|
return (m_xscreensaver != None);
|
|
}
|
|
|
|
void
|
|
CXWindowsScreenSaver::setXScreenSaver(Window window)
|
|
{
|
|
log((CLOG_DEBUG "xscreensaver window: 0x%08x", window));
|
|
|
|
// save window
|
|
m_xscreensaver = window;
|
|
|
|
if (m_xscreensaver != None) {
|
|
// clear old watch list
|
|
clearWatchForXScreenSaver();
|
|
|
|
// see if xscreensaver is active
|
|
bool error = false;
|
|
CXWindowsUtil::CErrorLock lock(m_display, &error);
|
|
XWindowAttributes attr;
|
|
XGetWindowAttributes(m_display, m_xscreensaver, &attr);
|
|
setXScreenSaverActive(!error && attr.map_state != IsUnmapped);
|
|
}
|
|
else {
|
|
// screen saver can't be active if it doesn't exist
|
|
setXScreenSaverActive(false);
|
|
|
|
// start watching for xscreensaver
|
|
watchForXScreenSaver();
|
|
}
|
|
}
|
|
|
|
bool
|
|
CXWindowsScreenSaver::isXScreenSaver(Window w) const
|
|
{
|
|
// check for m_atomScreenSaverVersion string property
|
|
Atom type;
|
|
return (CXWindowsUtil::getWindowProperty(m_display, w,
|
|
m_atomScreenSaverVersion,
|
|
NULL, &type, NULL, False) &&
|
|
type == XA_STRING);
|
|
}
|
|
|
|
void
|
|
CXWindowsScreenSaver::setXScreenSaverActive(bool activated)
|
|
{
|
|
if (m_xscreensaverActive != activated) {
|
|
log((CLOG_DEBUG "xscreensaver %s", activated ? "activated" : "deactivated"));
|
|
m_xscreensaverActive = activated;
|
|
sendNotify(activated);
|
|
}
|
|
}
|
|
|
|
void
|
|
CXWindowsScreenSaver::sendXScreenSaverCommand(Atom cmd, long arg1, long arg2)
|
|
{
|
|
XEvent event;
|
|
event.xclient.type = ClientMessage;
|
|
event.xclient.display = m_display;
|
|
event.xclient.window = m_xscreensaverSink;
|
|
event.xclient.message_type = m_atomScreenSaver;
|
|
event.xclient.format = 32;
|
|
event.xclient.data.l[0] = static_cast<long>(cmd);
|
|
event.xclient.data.l[1] = arg1;
|
|
event.xclient.data.l[2] = arg2;
|
|
event.xclient.data.l[3] = 0;
|
|
event.xclient.data.l[4] = 0;
|
|
|
|
log((CLOG_DEBUG "send xscreensaver command: %d %d %d", (long)cmd, arg1, arg2));
|
|
bool error = false;
|
|
CXWindowsUtil::CErrorLock lock(m_display, &error);
|
|
XSendEvent(m_display, m_xscreensaver, False, 0, &event);
|
|
if (error) {
|
|
findXScreenSaver();
|
|
}
|
|
}
|
|
|
|
void
|
|
CXWindowsScreenSaver::watchForXScreenSaver()
|
|
{
|
|
// clear old watch list
|
|
clearWatchForXScreenSaver();
|
|
|
|
// add every child of the root to the list of windows to watch
|
|
Window root = DefaultRootWindow(m_display);
|
|
Window rw, pw, *cw;
|
|
unsigned int nc;
|
|
if (XQueryTree(m_display, root, &rw, &pw, &cw, &nc)) {
|
|
for (unsigned int i = 0; i < nc; ++i) {
|
|
addWatchXScreenSaver(cw[i]);
|
|
}
|
|
XFree(cw);
|
|
}
|
|
|
|
// now check for xscreensaver window in case it set the property
|
|
// before we could request property change events.
|
|
if (findXScreenSaver()) {
|
|
// found it so clear out our watch list
|
|
clearWatchForXScreenSaver();
|
|
}
|
|
}
|
|
|
|
void
|
|
CXWindowsScreenSaver::clearWatchForXScreenSaver()
|
|
{
|
|
// stop watching all windows
|
|
CXWindowsUtil::CErrorLock lock(m_display);
|
|
for (CWatchList::iterator index = m_watchWindows.begin();
|
|
index != m_watchWindows.end(); ++index) {
|
|
XSelectInput(m_display, index->first, index->second);
|
|
}
|
|
m_watchWindows.clear();
|
|
}
|
|
|
|
void
|
|
CXWindowsScreenSaver::addWatchXScreenSaver(Window window)
|
|
{
|
|
bool error = false;
|
|
CXWindowsUtil::CErrorLock lock(m_display, &error);
|
|
|
|
// get window attributes
|
|
XWindowAttributes attr;
|
|
XGetWindowAttributes(m_display, window, &attr);
|
|
|
|
// if successful and window uses override_redirect (like xscreensaver
|
|
// does) then watch it for property changes.
|
|
if (!error && attr.override_redirect == True) {
|
|
XSelectInput(m_display, window,
|
|
attr.your_event_mask | PropertyChangeMask);
|
|
if (!error) {
|
|
// if successful then add the window to our list
|
|
m_watchWindows.insert(std::make_pair(window, attr.your_event_mask));
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
CXWindowsScreenSaver::disableCallback(void*)
|
|
{
|
|
// send fake mouse motion directly to xscreensaver
|
|
if (m_xscreensaver != None) {
|
|
XEvent event;
|
|
event.xmotion.type = MotionNotify;
|
|
event.xmotion.display = m_display;
|
|
event.xmotion.window = m_xscreensaver;
|
|
event.xmotion.root = DefaultRootWindow(m_display);
|
|
event.xmotion.subwindow = None;
|
|
event.xmotion.time = CurrentTime;
|
|
event.xmotion.x = 0;
|
|
event.xmotion.y = 0;
|
|
event.xmotion.x_root = 0;
|
|
event.xmotion.y_root = 0;
|
|
event.xmotion.state = 0;
|
|
event.xmotion.is_hint = NotifyNormal;
|
|
event.xmotion.same_screen = True;
|
|
|
|
CXWindowsUtil::CErrorLock lock(m_display);
|
|
XSendEvent(m_display, m_xscreensaver, False, 0, &event);
|
|
}
|
|
|
|
// force screen saver off and reset the timer
|
|
XForceScreenSaver(m_display, ScreenSaverReset);
|
|
}
|