mirror of
https://github.com/debauchee/barrier.git
synced 2026-06-30 08:56:21 +08:00
checkpoint screensaver changes. now handling xscreensaver
dying and restarting or starting after synergy does. also now disabling the screen saver on the client. next step: win32 support.
This commit is contained in:
@@ -1,17 +1,31 @@
|
||||
#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(Display* display) :
|
||||
CXWindowsScreenSaver::CXWindowsScreenSaver(
|
||||
CXWindowsScreen* screen, Display* display) :
|
||||
m_screen(screen),
|
||||
m_display(display),
|
||||
m_notify(None),
|
||||
m_xscreensaver(None)
|
||||
m_xscreensaver(None),
|
||||
m_xscreensaverActive(false)
|
||||
{
|
||||
// screen saver disable callback
|
||||
m_disableJob = new TMethodJob<CXWindowsScreenSaver>(this,
|
||||
&CXWindowsScreenSaver::disableCallback);
|
||||
|
||||
// get atoms
|
||||
m_atomScreenSaver = XInternAtom(m_display,
|
||||
"SCREENSAVER", False);
|
||||
@@ -22,8 +36,9 @@ CXWindowsScreenSaver::CXWindowsScreenSaver(Display* display) :
|
||||
m_atomScreenSaverDeactivate = XInternAtom(m_display,
|
||||
"DEACTIVATE", False);
|
||||
|
||||
// create dummy window to receive xscreensaver responses. earlier
|
||||
// versions of xscreensaver will die if we pass None as the window.
|
||||
// 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;
|
||||
@@ -53,7 +68,9 @@ CXWindowsScreenSaver::CXWindowsScreenSaver(Display* display) :
|
||||
}
|
||||
|
||||
// get the xscreensaver window, if any
|
||||
updateXScreenSaver();
|
||||
if (!findXScreenSaver()) {
|
||||
setXScreenSaver(None);
|
||||
}
|
||||
|
||||
// get the built-in settings
|
||||
XGetScreenSaver(m_display, &m_timeout, &m_interval,
|
||||
@@ -62,30 +79,67 @@ CXWindowsScreenSaver::CXWindowsScreenSaver(Display* display) :
|
||||
|
||||
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::processEvent(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
|
||||
setXScreenSaver(false);
|
||||
log((CLOG_DEBUG "xscreensaver died"));
|
||||
m_xscreensaver = None;
|
||||
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
|
||||
setXScreenSaver(true);
|
||||
setXScreenSaverActive(true);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
@@ -93,7 +147,7 @@ CXWindowsScreenSaver::processEvent(XEvent* xevent)
|
||||
case UnmapNotify:
|
||||
if (xevent->xunmap.window == m_xscreensaver) {
|
||||
// xscreensaver has deactivated
|
||||
setXScreenSaver(false);
|
||||
setXScreenSaverActive(false);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
@@ -111,14 +165,11 @@ CXWindowsScreenSaver::setNotify(Window notify)
|
||||
void
|
||||
CXWindowsScreenSaver::enable()
|
||||
{
|
||||
// try xscreensaver
|
||||
updateXScreenSaver();
|
||||
if (m_xscreensaver) {
|
||||
// FIXME
|
||||
return;
|
||||
}
|
||||
log((CLOG_INFO "enable screensaver"));
|
||||
// for xscreensaver
|
||||
m_screen->removeTimer(m_disableJob);
|
||||
|
||||
// use built-in X screen saver
|
||||
// for built-in X screen saver
|
||||
XSetScreenSaver(m_display, m_timeout, m_interval,
|
||||
m_preferBlanking, m_allowExposures);
|
||||
}
|
||||
@@ -126,12 +177,10 @@ CXWindowsScreenSaver::enable()
|
||||
void
|
||||
CXWindowsScreenSaver::disable()
|
||||
{
|
||||
// try xscreensaver
|
||||
updateXScreenSaver();
|
||||
if (m_xscreensaver) {
|
||||
// FIXME
|
||||
return;
|
||||
}
|
||||
log((CLOG_INFO "disable screensaver"));
|
||||
// for xscreensaver. 5 seconds should be plenty often to
|
||||
// suppress the screen saver.
|
||||
m_screen->addTimer(m_disableJob, 5.0);
|
||||
|
||||
// use built-in X screen saver
|
||||
XGetScreenSaver(m_display, &m_timeout, &m_interval,
|
||||
@@ -145,8 +194,8 @@ void
|
||||
CXWindowsScreenSaver::activate()
|
||||
{
|
||||
// try xscreensaver
|
||||
updateXScreenSaver();
|
||||
if (m_xscreensaver) {
|
||||
findXScreenSaver();
|
||||
if (m_xscreensaver != None) {
|
||||
sendXScreenSaverCommand(m_atomScreenSaverActivate);
|
||||
return;
|
||||
}
|
||||
@@ -159,8 +208,8 @@ void
|
||||
CXWindowsScreenSaver::deactivate()
|
||||
{
|
||||
// try xscreensaver
|
||||
updateXScreenSaver();
|
||||
if (m_xscreensaver) {
|
||||
findXScreenSaver();
|
||||
if (m_xscreensaver != None) {
|
||||
sendXScreenSaverCommand(m_atomScreenSaverDeactivate);
|
||||
return;
|
||||
}
|
||||
@@ -202,8 +251,70 @@ CXWindowsScreenSaver::sendNotify(bool activated)
|
||||
}
|
||||
}
|
||||
|
||||
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(bool activated)
|
||||
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"));
|
||||
@@ -212,48 +323,6 @@ CXWindowsScreenSaver::setXScreenSaver(bool activated)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsScreenSaver::updateXScreenSaver()
|
||||
{
|
||||
// do nothing if we've already got the xscreensaver window
|
||||
if (m_xscreensaver != None) {
|
||||
return;
|
||||
}
|
||||
|
||||
// find top-level window with m_atomScreenSaverVersion string property
|
||||
CXWindowsUtil::CErrorLock lock(m_display);
|
||||
Window root = DefaultRootWindow(m_display);
|
||||
Window rw, pw, *cw;
|
||||
unsigned int nc;
|
||||
if (XQueryTree(m_display, root, &rw, &pw, &cw, &nc)) {
|
||||
CString data;
|
||||
Atom type;
|
||||
for (unsigned int i = 0; i < nc; ++i) {
|
||||
if (CXWindowsUtil::getWindowProperty(m_display, cw[i],
|
||||
m_atomScreenSaverVersion,
|
||||
&data, &type, NULL, False) &&
|
||||
type == XA_STRING) {
|
||||
m_xscreensaver = cw[i];
|
||||
log((CLOG_DEBUG "found xscreensaver: 0x%08x", m_xscreensaver));
|
||||
break;
|
||||
}
|
||||
}
|
||||
XFree(cw);
|
||||
}
|
||||
|
||||
// see if xscreensaver is active
|
||||
if (m_xscreensaver != None) {
|
||||
bool error = false;
|
||||
CXWindowsUtil::CErrorLock lock(m_display, &error);
|
||||
XWindowAttributes attr;
|
||||
XGetWindowAttributes(m_display, m_xscreensaver, &attr);
|
||||
setXScreenSaver(!error && attr.map_state != IsUnmapped);
|
||||
}
|
||||
else {
|
||||
setXScreenSaver(false);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsScreenSaver::sendXScreenSaverCommand(Atom cmd, long arg1, long arg2)
|
||||
{
|
||||
@@ -274,6 +343,93 @@ CXWindowsScreenSaver::sendXScreenSaverCommand(Atom cmd, long arg1, long arg2)
|
||||
CXWindowsUtil::CErrorLock lock(m_display, &error);
|
||||
XSendEvent(m_display, m_xscreensaver, False, 0, &event);
|
||||
if (error) {
|
||||
updateXScreenSaver();
|
||||
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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user