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:
parent
4d113aa235
commit
a5391a0a1d
|
@ -7,10 +7,61 @@
|
||||||
#include "CLock.h"
|
#include "CLock.h"
|
||||||
#include "CThread.h"
|
#include "CThread.h"
|
||||||
#include "CLog.h"
|
#include "CLog.h"
|
||||||
|
#include "IJob.h"
|
||||||
#include "CString.h"
|
#include "CString.h"
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
//
|
||||||
|
// CXWindowsScreen::CTimer
|
||||||
|
//
|
||||||
|
|
||||||
|
CXWindowsScreen::CTimer::CTimer(IJob* job, double timeout) :
|
||||||
|
m_job(job),
|
||||||
|
m_timeout(timeout)
|
||||||
|
{
|
||||||
|
assert(m_job != NULL);
|
||||||
|
assert(m_timeout > 0.0);
|
||||||
|
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
CXWindowsScreen::CTimer::~CTimer()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CXWindowsScreen::CTimer::run()
|
||||||
|
{
|
||||||
|
m_job->run();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CXWindowsScreen::CTimer::reset()
|
||||||
|
{
|
||||||
|
m_time = m_timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
CXWindowsScreen::CTimer::CTimer&
|
||||||
|
CXWindowsScreen::CTimer::operator-=(double dt)
|
||||||
|
{
|
||||||
|
m_time -= dt;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
CXWindowsScreen::CTimer::operator double() const
|
||||||
|
{
|
||||||
|
return m_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CXWindowsScreen::CTimer::operator<(const CTimer& t) const
|
||||||
|
{
|
||||||
|
return m_time < t.m_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// CXWindowsScreen
|
// CXWindowsScreen
|
||||||
//
|
//
|
||||||
|
@ -37,6 +88,38 @@ CXWindowsScreen::~CXWindowsScreen()
|
||||||
s_screen = NULL;
|
s_screen = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CXWindowsScreen::addTimer(IJob* job, double timeout)
|
||||||
|
{
|
||||||
|
CLock lock(&m_timersMutex);
|
||||||
|
removeTimerNoLock(job);
|
||||||
|
m_timers.push(CTimer(job, timeout));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CXWindowsScreen::removeTimer(IJob* job)
|
||||||
|
{
|
||||||
|
CLock lock(&m_timersMutex);
|
||||||
|
removeTimerNoLock(job);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CXWindowsScreen::removeTimerNoLock(IJob* job)
|
||||||
|
{
|
||||||
|
// do it the hard way. first collect all jobs that are not
|
||||||
|
// the removed job.
|
||||||
|
CTimerPriorityQueue::container_type tmp;
|
||||||
|
for (CTimerPriorityQueue::iterator index = m_timers.begin();
|
||||||
|
index != m_timers.end(); ++index) {
|
||||||
|
if (index->getJob() != job) {
|
||||||
|
tmp.push_back(*index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// now swap in the new list
|
||||||
|
m_timers.swap(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CXWindowsScreen::openDisplay()
|
CXWindowsScreen::openDisplay()
|
||||||
{
|
{
|
||||||
|
@ -81,7 +164,7 @@ CXWindowsScreen::openDisplay()
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize the screen saver
|
// initialize the screen saver
|
||||||
m_screenSaver = new CXWindowsScreenSaver(m_display);
|
m_screenSaver = new CXWindowsScreenSaver(this, m_display);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -181,6 +264,12 @@ CXWindowsScreen::getEvent(XEvent* xevent) const
|
||||||
m_mutex.lock();
|
m_mutex.lock();
|
||||||
for (;;) {
|
for (;;) {
|
||||||
while (!m_stop && XPending(m_display) == 0) {
|
while (!m_stop && XPending(m_display) == 0) {
|
||||||
|
// check timers
|
||||||
|
if (const_cast<CXWindowsScreen*>(this)->processTimers()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait
|
||||||
m_mutex.unlock();
|
m_mutex.unlock();
|
||||||
CThread::sleep(0.01);
|
CThread::sleep(0.01);
|
||||||
m_mutex.lock();
|
m_mutex.lock();
|
||||||
|
@ -298,13 +387,56 @@ CXWindowsScreen::processEvent(XEvent* xevent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// let screen saver have a go
|
// let screen saver have a go
|
||||||
if (m_screenSaver->processEvent(xevent)) {
|
m_screenSaver->processEvent(xevent);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CXWindowsScreen::processTimers()
|
||||||
|
{
|
||||||
|
std::vector<IJob*> jobs;
|
||||||
|
{
|
||||||
|
CLock lock(&m_timersMutex);
|
||||||
|
|
||||||
|
// get current time
|
||||||
|
const double time = m_time.getTime();
|
||||||
|
|
||||||
|
// done if no timers have expired
|
||||||
|
if (m_timers.empty() || m_timers.top() > time) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// subtract current time from all timers. note that this won't
|
||||||
|
// change the order of elements in the priority queue (except
|
||||||
|
// for floating point round off which we'll ignore).
|
||||||
|
for (CTimerPriorityQueue::iterator index = m_timers.begin();
|
||||||
|
index != m_timers.end(); ++index) {
|
||||||
|
(*index) -= time;
|
||||||
|
}
|
||||||
|
|
||||||
|
// process all timers at or below zero, saving the jobs
|
||||||
|
while (m_timers.top() <= 0.0) {
|
||||||
|
CTimer timer = m_timers.top();
|
||||||
|
jobs.push_back(timer.getJob());
|
||||||
|
timer.reset();
|
||||||
|
m_timers.pop();
|
||||||
|
m_timers.push(timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset the clock
|
||||||
|
m_time.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
// now run the jobs. note that if one of these jobs removes
|
||||||
|
// a timer later in the jobs list and deletes that job pointer
|
||||||
|
// then this will crash when it tries to run that job.
|
||||||
|
for (std::vector<IJob*>::iterator index = jobs.begin();
|
||||||
|
index != jobs.end(); ++index) {
|
||||||
|
(*index)->run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CXWindowsScreenSaver*
|
CXWindowsScreenSaver*
|
||||||
CXWindowsScreen::getScreenSaver() const
|
CXWindowsScreen::getScreenSaver() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,13 +3,18 @@
|
||||||
|
|
||||||
#include "ClipboardTypes.h"
|
#include "ClipboardTypes.h"
|
||||||
#include "CMutex.h"
|
#include "CMutex.h"
|
||||||
|
#include "CStopwatch.h"
|
||||||
|
#include "stdvector.h"
|
||||||
#if defined(X_DISPLAY_MISSING)
|
#if defined(X_DISPLAY_MISSING)
|
||||||
# error X11 is required to build synergy
|
# error X11 is required to build synergy
|
||||||
#else
|
#else
|
||||||
# include <X11/Xlib.h>
|
# include <X11/Xlib.h>
|
||||||
#endif
|
#endif
|
||||||
|
#include <algorithm>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
class IClipboard;
|
class IClipboard;
|
||||||
|
class IJob;
|
||||||
class IScreenSaver;
|
class IScreenSaver;
|
||||||
class CXWindowsClipboard;
|
class CXWindowsClipboard;
|
||||||
class CXWindowsScreenSaver;
|
class CXWindowsScreenSaver;
|
||||||
|
@ -19,6 +24,15 @@ public:
|
||||||
CXWindowsScreen();
|
CXWindowsScreen();
|
||||||
virtual ~CXWindowsScreen();
|
virtual ~CXWindowsScreen();
|
||||||
|
|
||||||
|
// manipulators
|
||||||
|
|
||||||
|
// add/remove a job to invoke every timeout seconds. the job is
|
||||||
|
// called with the display locked. if a job timeout expires twice
|
||||||
|
// or more before the job can be called then the job is called
|
||||||
|
// just once. the caller retains ownership of the job.
|
||||||
|
void addTimer(IJob*, double timeout);
|
||||||
|
void removeTimer(IJob*);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
class CDisplayLock {
|
class CDisplayLock {
|
||||||
public:
|
public:
|
||||||
|
@ -94,9 +108,15 @@ protected:
|
||||||
virtual void onLostClipboard(ClipboardID) = 0;
|
virtual void onLostClipboard(ClipboardID) = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// remove a timer without locking
|
||||||
|
void removeTimerNoLock(IJob*);
|
||||||
|
|
||||||
// internal event processing
|
// internal event processing
|
||||||
bool processEvent(XEvent*);
|
bool processEvent(XEvent*);
|
||||||
|
|
||||||
|
// process timers
|
||||||
|
bool processTimers();
|
||||||
|
|
||||||
// determine the clipboard from the X selection. returns
|
// determine the clipboard from the X selection. returns
|
||||||
// kClipboardEnd if no such clipboard.
|
// kClipboardEnd if no such clipboard.
|
||||||
ClipboardID getClipboardID(Atom selection) const;
|
ClipboardID getClipboardID(Atom selection) const;
|
||||||
|
@ -112,6 +132,112 @@ private:
|
||||||
static int ioErrorHandler(Display*);
|
static int ioErrorHandler(Display*);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// a priority queue will direct access to the elements
|
||||||
|
template <class T, class Container = std::vector<T>,
|
||||||
|
class Compare = std::greater<typename Container::value_type> >
|
||||||
|
class CPriorityQueue {
|
||||||
|
public:
|
||||||
|
typedef typename Container::value_type value_type;
|
||||||
|
typedef typename Container::size_type size_type;
|
||||||
|
typedef typename Container::iterator iterator;
|
||||||
|
typedef Container container_type;
|
||||||
|
|
||||||
|
CPriorityQueue() { }
|
||||||
|
CPriorityQueue(Container& swappedIn);
|
||||||
|
~CPriorityQueue() { }
|
||||||
|
|
||||||
|
// manipulators
|
||||||
|
|
||||||
|
void push(const value_type& v)
|
||||||
|
{
|
||||||
|
c.push_back(v);
|
||||||
|
std::push_heap(c.begin(), c.end(), comp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop()
|
||||||
|
{
|
||||||
|
std::pop_heap(c.begin(), c.end(), comp);
|
||||||
|
c.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator begin()
|
||||||
|
{
|
||||||
|
return c.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator end()
|
||||||
|
{
|
||||||
|
return c.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void swap(CPriorityQueue<T, Container, Compare>& q)
|
||||||
|
{
|
||||||
|
c.swap(q.c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void swap(Container& c2)
|
||||||
|
{
|
||||||
|
c.swap(c2);
|
||||||
|
std::make_heap(c.begin(), c.end(), comp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// accessors
|
||||||
|
|
||||||
|
bool empty() const
|
||||||
|
{
|
||||||
|
return c.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_type size() const
|
||||||
|
{
|
||||||
|
return c.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
const value_type&
|
||||||
|
top() const
|
||||||
|
{
|
||||||
|
return c.front();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Container c;
|
||||||
|
Compare comp;
|
||||||
|
};
|
||||||
|
|
||||||
|
// a timer priority queue element
|
||||||
|
class CTimer {
|
||||||
|
public:
|
||||||
|
CTimer(IJob* job, double timeout);
|
||||||
|
~CTimer();
|
||||||
|
|
||||||
|
// manipulators
|
||||||
|
|
||||||
|
void run();
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
CTimer& operator-=(double);
|
||||||
|
|
||||||
|
// accessors
|
||||||
|
|
||||||
|
IJob* getJob() const
|
||||||
|
{
|
||||||
|
return m_job;
|
||||||
|
}
|
||||||
|
|
||||||
|
operator double() const;
|
||||||
|
|
||||||
|
bool operator<(const CTimer&) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
IJob* m_job;
|
||||||
|
double m_timeout;
|
||||||
|
double m_time;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef CPriorityQueue<CTimer> CTimerPriorityQueue;
|
||||||
|
|
||||||
Display* m_display;
|
Display* m_display;
|
||||||
int m_screen;
|
int m_screen;
|
||||||
Window m_root;
|
Window m_root;
|
||||||
|
@ -125,6 +251,11 @@ private:
|
||||||
// screen saver
|
// screen saver
|
||||||
CXWindowsScreenSaver* m_screenSaver;
|
CXWindowsScreenSaver* m_screenSaver;
|
||||||
|
|
||||||
|
// timers, the stopwatch used to time, and a mutex for the timers
|
||||||
|
CTimerPriorityQueue m_timers;
|
||||||
|
CStopwatch m_time;
|
||||||
|
CMutex m_timersMutex;
|
||||||
|
|
||||||
// X is not thread safe
|
// X is not thread safe
|
||||||
CMutex m_mutex;
|
CMutex m_mutex;
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,31 @@
|
||||||
#include "CXWindowsScreenSaver.h"
|
#include "CXWindowsScreenSaver.h"
|
||||||
|
#include "CXWindowsScreen.h"
|
||||||
#include "CXWindowsUtil.h"
|
#include "CXWindowsUtil.h"
|
||||||
#include "CLog.h"
|
#include "CLog.h"
|
||||||
|
#include "TMethodJob.h"
|
||||||
#include <X11/Xatom.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::CXWindowsScreenSaver(Display* display) :
|
CXWindowsScreenSaver::CXWindowsScreenSaver(
|
||||||
|
CXWindowsScreen* screen, Display* display) :
|
||||||
|
m_screen(screen),
|
||||||
m_display(display),
|
m_display(display),
|
||||||
m_notify(None),
|
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
|
// get atoms
|
||||||
m_atomScreenSaver = XInternAtom(m_display,
|
m_atomScreenSaver = XInternAtom(m_display,
|
||||||
"SCREENSAVER", False);
|
"SCREENSAVER", False);
|
||||||
|
@ -22,8 +36,9 @@ CXWindowsScreenSaver::CXWindowsScreenSaver(Display* display) :
|
||||||
m_atomScreenSaverDeactivate = XInternAtom(m_display,
|
m_atomScreenSaverDeactivate = XInternAtom(m_display,
|
||||||
"DEACTIVATE", False);
|
"DEACTIVATE", False);
|
||||||
|
|
||||||
// create dummy window to receive xscreensaver responses. earlier
|
// create dummy window to receive xscreensaver responses. this
|
||||||
// versions of xscreensaver will die if we pass None as the window.
|
// shouldn't be necessary (we should be able to send responses
|
||||||
|
// to None) but it doesn't hurt.
|
||||||
XSetWindowAttributes attr;
|
XSetWindowAttributes attr;
|
||||||
attr.event_mask = 0;//PropertyChangeMask;
|
attr.event_mask = 0;//PropertyChangeMask;
|
||||||
attr.do_not_propagate_mask = 0;
|
attr.do_not_propagate_mask = 0;
|
||||||
|
@ -53,7 +68,9 @@ CXWindowsScreenSaver::CXWindowsScreenSaver(Display* display) :
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the xscreensaver window, if any
|
// get the xscreensaver window, if any
|
||||||
updateXScreenSaver();
|
if (!findXScreenSaver()) {
|
||||||
|
setXScreenSaver(None);
|
||||||
|
}
|
||||||
|
|
||||||
// get the built-in settings
|
// get the built-in settings
|
||||||
XGetScreenSaver(m_display, &m_timeout, &m_interval,
|
XGetScreenSaver(m_display, &m_timeout, &m_interval,
|
||||||
|
@ -62,30 +79,67 @@ CXWindowsScreenSaver::CXWindowsScreenSaver(Display* display) :
|
||||||
|
|
||||||
CXWindowsScreenSaver::~CXWindowsScreenSaver()
|
CXWindowsScreenSaver::~CXWindowsScreenSaver()
|
||||||
{
|
{
|
||||||
|
// clear watch list
|
||||||
|
clearWatchForXScreenSaver();
|
||||||
|
|
||||||
// stop watching root for events
|
// stop watching root for events
|
||||||
CXWindowsUtil::CErrorLock lock(m_display);
|
CXWindowsUtil::CErrorLock lock(m_display);
|
||||||
Window root = DefaultRootWindow(m_display);
|
Window root = DefaultRootWindow(m_display);
|
||||||
XSelectInput(m_display, root, m_rootEventMask);
|
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
|
bool
|
||||||
CXWindowsScreenSaver::processEvent(XEvent* xevent)
|
CXWindowsScreenSaver::processEvent(XEvent* xevent)
|
||||||
{
|
{
|
||||||
switch (xevent->type) {
|
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:
|
case DestroyNotify:
|
||||||
if (xevent->xdestroywindow.window == m_xscreensaver) {
|
if (xevent->xdestroywindow.window == m_xscreensaver) {
|
||||||
// xscreensaver is gone
|
// xscreensaver is gone
|
||||||
setXScreenSaver(false);
|
|
||||||
log((CLOG_DEBUG "xscreensaver died"));
|
log((CLOG_DEBUG "xscreensaver died"));
|
||||||
m_xscreensaver = None;
|
setXScreenSaver(None);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PropertyNotify:
|
||||||
|
if (xevent->xproperty.state == PropertyNewValue) {
|
||||||
|
if (isXScreenSaver(xevent->xproperty.window)) {
|
||||||
|
// found the xscreensaver
|
||||||
|
setXScreenSaver(xevent->xcreatewindow.window);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case MapNotify:
|
case MapNotify:
|
||||||
if (xevent->xmap.window == m_xscreensaver) {
|
if (xevent->xmap.window == m_xscreensaver) {
|
||||||
// xscreensaver has activated
|
// xscreensaver has activated
|
||||||
setXScreenSaver(true);
|
setXScreenSaverActive(true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -93,7 +147,7 @@ CXWindowsScreenSaver::processEvent(XEvent* xevent)
|
||||||
case UnmapNotify:
|
case UnmapNotify:
|
||||||
if (xevent->xunmap.window == m_xscreensaver) {
|
if (xevent->xunmap.window == m_xscreensaver) {
|
||||||
// xscreensaver has deactivated
|
// xscreensaver has deactivated
|
||||||
setXScreenSaver(false);
|
setXScreenSaverActive(false);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -111,14 +165,11 @@ CXWindowsScreenSaver::setNotify(Window notify)
|
||||||
void
|
void
|
||||||
CXWindowsScreenSaver::enable()
|
CXWindowsScreenSaver::enable()
|
||||||
{
|
{
|
||||||
// try xscreensaver
|
log((CLOG_INFO "enable screensaver"));
|
||||||
updateXScreenSaver();
|
// for xscreensaver
|
||||||
if (m_xscreensaver) {
|
m_screen->removeTimer(m_disableJob);
|
||||||
// FIXME
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// use built-in X screen saver
|
// for built-in X screen saver
|
||||||
XSetScreenSaver(m_display, m_timeout, m_interval,
|
XSetScreenSaver(m_display, m_timeout, m_interval,
|
||||||
m_preferBlanking, m_allowExposures);
|
m_preferBlanking, m_allowExposures);
|
||||||
}
|
}
|
||||||
|
@ -126,12 +177,10 @@ CXWindowsScreenSaver::enable()
|
||||||
void
|
void
|
||||||
CXWindowsScreenSaver::disable()
|
CXWindowsScreenSaver::disable()
|
||||||
{
|
{
|
||||||
// try xscreensaver
|
log((CLOG_INFO "disable screensaver"));
|
||||||
updateXScreenSaver();
|
// for xscreensaver. 5 seconds should be plenty often to
|
||||||
if (m_xscreensaver) {
|
// suppress the screen saver.
|
||||||
// FIXME
|
m_screen->addTimer(m_disableJob, 5.0);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// use built-in X screen saver
|
// use built-in X screen saver
|
||||||
XGetScreenSaver(m_display, &m_timeout, &m_interval,
|
XGetScreenSaver(m_display, &m_timeout, &m_interval,
|
||||||
|
@ -145,8 +194,8 @@ void
|
||||||
CXWindowsScreenSaver::activate()
|
CXWindowsScreenSaver::activate()
|
||||||
{
|
{
|
||||||
// try xscreensaver
|
// try xscreensaver
|
||||||
updateXScreenSaver();
|
findXScreenSaver();
|
||||||
if (m_xscreensaver) {
|
if (m_xscreensaver != None) {
|
||||||
sendXScreenSaverCommand(m_atomScreenSaverActivate);
|
sendXScreenSaverCommand(m_atomScreenSaverActivate);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -159,8 +208,8 @@ void
|
||||||
CXWindowsScreenSaver::deactivate()
|
CXWindowsScreenSaver::deactivate()
|
||||||
{
|
{
|
||||||
// try xscreensaver
|
// try xscreensaver
|
||||||
updateXScreenSaver();
|
findXScreenSaver();
|
||||||
if (m_xscreensaver) {
|
if (m_xscreensaver != None) {
|
||||||
sendXScreenSaverCommand(m_atomScreenSaverDeactivate);
|
sendXScreenSaverCommand(m_atomScreenSaverDeactivate);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -202,55 +251,75 @@ CXWindowsScreenSaver::sendNotify(bool activated)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
bool
|
||||||
CXWindowsScreenSaver::setXScreenSaver(bool activated)
|
CXWindowsScreenSaver::findXScreenSaver()
|
||||||
{
|
|
||||||
if (m_xscreensaverActive != activated) {
|
|
||||||
log((CLOG_DEBUG "xscreensaver %s", activated ? "activated" : "deactivated"));
|
|
||||||
m_xscreensaverActive = activated;
|
|
||||||
sendNotify(activated);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CXWindowsScreenSaver::updateXScreenSaver()
|
|
||||||
{
|
{
|
||||||
// do nothing if we've already got the xscreensaver window
|
// do nothing if we've already got the xscreensaver window
|
||||||
if (m_xscreensaver != None) {
|
if (m_xscreensaver == None) {
|
||||||
return;
|
// find top-level window xscreensaver window
|
||||||
}
|
|
||||||
|
|
||||||
// find top-level window with m_atomScreenSaverVersion string property
|
|
||||||
CXWindowsUtil::CErrorLock lock(m_display);
|
|
||||||
Window root = DefaultRootWindow(m_display);
|
Window root = DefaultRootWindow(m_display);
|
||||||
Window rw, pw, *cw;
|
Window rw, pw, *cw;
|
||||||
unsigned int nc;
|
unsigned int nc;
|
||||||
if (XQueryTree(m_display, root, &rw, &pw, &cw, &nc)) {
|
if (XQueryTree(m_display, root, &rw, &pw, &cw, &nc)) {
|
||||||
CString data;
|
|
||||||
Atom type;
|
|
||||||
for (unsigned int i = 0; i < nc; ++i) {
|
for (unsigned int i = 0; i < nc; ++i) {
|
||||||
if (CXWindowsUtil::getWindowProperty(m_display, cw[i],
|
if (isXScreenSaver(cw[i])) {
|
||||||
m_atomScreenSaverVersion,
|
setXScreenSaver(cw[i]);
|
||||||
&data, &type, NULL, False) &&
|
|
||||||
type == XA_STRING) {
|
|
||||||
m_xscreensaver = cw[i];
|
|
||||||
log((CLOG_DEBUG "found xscreensaver: 0x%08x", m_xscreensaver));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
XFree(cw);
|
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
|
// see if xscreensaver is active
|
||||||
if (m_xscreensaver != None) {
|
|
||||||
bool error = false;
|
bool error = false;
|
||||||
CXWindowsUtil::CErrorLock lock(m_display, &error);
|
CXWindowsUtil::CErrorLock lock(m_display, &error);
|
||||||
XWindowAttributes attr;
|
XWindowAttributes attr;
|
||||||
XGetWindowAttributes(m_display, m_xscreensaver, &attr);
|
XGetWindowAttributes(m_display, m_xscreensaver, &attr);
|
||||||
setXScreenSaver(!error && attr.map_state != IsUnmapped);
|
setXScreenSaverActive(!error && attr.map_state != IsUnmapped);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
setXScreenSaver(false);
|
// 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,6 +343,93 @@ CXWindowsScreenSaver::sendXScreenSaverCommand(Atom cmd, long arg1, long arg2)
|
||||||
CXWindowsUtil::CErrorLock lock(m_display, &error);
|
CXWindowsUtil::CErrorLock lock(m_display, &error);
|
||||||
XSendEvent(m_display, m_xscreensaver, False, 0, &event);
|
XSendEvent(m_display, m_xscreensaver, False, 0, &event);
|
||||||
if (error) {
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -2,18 +2,22 @@
|
||||||
#define CXWINDOWSSCREENSAVER_H
|
#define CXWINDOWSSCREENSAVER_H
|
||||||
|
|
||||||
#include "IScreenSaver.h"
|
#include "IScreenSaver.h"
|
||||||
|
#include "stdmap.h"
|
||||||
#if defined(X_DISPLAY_MISSING)
|
#if defined(X_DISPLAY_MISSING)
|
||||||
# error X11 is required to build synergy
|
# error X11 is required to build synergy
|
||||||
#else
|
#else
|
||||||
# include <X11/Xlib.h>
|
# include <X11/Xlib.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
class IJob;
|
||||||
|
class CXWindowsScreen;
|
||||||
|
|
||||||
class CXWindowsScreenSaver : public IScreenSaver {
|
class CXWindowsScreenSaver : public IScreenSaver {
|
||||||
public:
|
public:
|
||||||
// note -- the caller must ensure that Display* passed to c'tor isn't
|
// note -- the caller must ensure that Display* passed to c'tor isn't
|
||||||
// being used in another call to Xlib when calling any method on this
|
// being used in another call to Xlib when calling any method on this
|
||||||
// object (including during the c'tor and d'tor) except processEvent().
|
// object (including during the c'tor and d'tor) except processEvent().
|
||||||
CXWindowsScreenSaver(Display*);
|
CXWindowsScreenSaver(CXWindowsScreen*, Display*);
|
||||||
virtual ~CXWindowsScreenSaver();
|
virtual ~CXWindowsScreenSaver();
|
||||||
|
|
||||||
// process X event. returns true if the event was handled.
|
// process X event. returns true if the event was handled.
|
||||||
|
@ -38,17 +42,42 @@ private:
|
||||||
// send a notification
|
// send a notification
|
||||||
void sendNotify(bool activated);
|
void sendNotify(bool activated);
|
||||||
|
|
||||||
|
// find and set the running xscreensaver's window. returns true iff
|
||||||
|
// found.
|
||||||
|
bool findXScreenSaver();
|
||||||
|
|
||||||
|
// set the xscreensaver's window, updating the activation state flag
|
||||||
|
void setXScreenSaver(Window);
|
||||||
|
|
||||||
|
// returns true if the window appears to be the xscreensaver window
|
||||||
|
bool isXScreenSaver(Window) const;
|
||||||
|
|
||||||
// set xscreensaver's activation state flag. sends notification
|
// set xscreensaver's activation state flag. sends notification
|
||||||
// if the state has changed.
|
// if the state has changed.
|
||||||
void setXScreenSaver(bool activated);
|
void setXScreenSaverActive(bool activated);
|
||||||
|
|
||||||
// find the running xscreensaver's window
|
|
||||||
void updateXScreenSaver();
|
|
||||||
|
|
||||||
// send a command to xscreensaver
|
// send a command to xscreensaver
|
||||||
void sendXScreenSaverCommand(Atom, long = 0, long = 0);
|
void sendXScreenSaverCommand(Atom, long = 0, long = 0);
|
||||||
|
|
||||||
|
// watch all windows that could potentially be the xscreensaver for
|
||||||
|
// the events that will confirm it.
|
||||||
|
void watchForXScreenSaver();
|
||||||
|
|
||||||
|
// stop watching all watched windows
|
||||||
|
void clearWatchForXScreenSaver();
|
||||||
|
|
||||||
|
// add window to the watch list
|
||||||
|
void addWatchXScreenSaver(Window window);
|
||||||
|
|
||||||
|
// called periodically to prevent the screen saver from starting
|
||||||
|
void disableCallback(void*);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
typedef std::map<Window, long> CWatchList;
|
||||||
|
|
||||||
|
// the event loop object
|
||||||
|
CXWindowsScreen* m_screen;
|
||||||
|
|
||||||
// the X display
|
// the X display
|
||||||
Display* m_display;
|
Display* m_display;
|
||||||
|
|
||||||
|
@ -67,6 +96,9 @@ private:
|
||||||
// dummy window to receive xscreensaver repsonses
|
// dummy window to receive xscreensaver repsonses
|
||||||
Window m_xscreensaverSink;
|
Window m_xscreensaverSink;
|
||||||
|
|
||||||
|
// potential xscreensaver windows being watched
|
||||||
|
CWatchList m_watchWindows;
|
||||||
|
|
||||||
// atoms used to communicate with xscreensaver's window
|
// atoms used to communicate with xscreensaver's window
|
||||||
Atom m_atomScreenSaver;
|
Atom m_atomScreenSaver;
|
||||||
Atom m_atomScreenSaverVersion;
|
Atom m_atomScreenSaverVersion;
|
||||||
|
@ -78,6 +110,9 @@ private:
|
||||||
int m_interval;
|
int m_interval;
|
||||||
int m_preferBlanking;
|
int m_preferBlanking;
|
||||||
int m_allowExposures;
|
int m_allowExposures;
|
||||||
|
|
||||||
|
// the job used to invoke disableCallback
|
||||||
|
IJob* m_disableJob;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -13,7 +13,6 @@ CXWindowsUtil::getWindowProperty(Display* display, Window window,
|
||||||
int* format, bool deleteProperty)
|
int* format, bool deleteProperty)
|
||||||
{
|
{
|
||||||
assert(display != NULL);
|
assert(display != NULL);
|
||||||
assert(data != NULL);
|
|
||||||
|
|
||||||
Atom actualType;
|
Atom actualType;
|
||||||
int actualDatumSize;
|
int actualDatumSize;
|
||||||
|
@ -59,7 +58,13 @@ CXWindowsUtil::getWindowProperty(Display* display, Window window,
|
||||||
}
|
}
|
||||||
|
|
||||||
// append data
|
// append data
|
||||||
|
if (data != NULL) {
|
||||||
data->append((char*)rawData, numBytes);
|
data->append((char*)rawData, numBytes);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// data is not required so don't try to get any more
|
||||||
|
bytesLeft = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// done with returned data
|
// done with returned data
|
||||||
XFree(rawData);
|
XFree(rawData);
|
||||||
|
@ -78,7 +83,7 @@ CXWindowsUtil::getWindowProperty(Display* display, Window window,
|
||||||
*format = static_cast<SInt32>(actualDatumSize);
|
*format = static_cast<SInt32>(actualDatumSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
log((CLOG_DEBUG1 "read property %d on window 0x%08x: bytes=%d", property, window, data->size()));
|
log((CLOG_DEBUG1 "read property %d on window 0x%08x: bytes=%d", property, window, (data == NULL) ? 0 : data->size()));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1284,6 +1284,12 @@ CServer::handshakeClient(void* vsocket)
|
||||||
// now connected; client no longer subject to timeout.
|
// now connected; client no longer subject to timeout.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// activate screen saver on new client if active on the
|
||||||
|
// primary screen
|
||||||
|
if (m_primary->isScreenSaverActive()) {
|
||||||
|
protocol->sendScreenSaver(true);
|
||||||
|
}
|
||||||
|
|
||||||
// handle messages from client. returns when the client
|
// handle messages from client. returns when the client
|
||||||
// disconnects.
|
// disconnects.
|
||||||
log((CLOG_NOTE "client \"%s\" has connected", name.c_str()));
|
log((CLOG_NOTE "client \"%s\" has connected", name.c_str()));
|
||||||
|
|
|
@ -545,6 +545,13 @@ CXWindowsPrimaryScreen::isLockedToScreen() const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CXWindowsPrimaryScreen::isScreenSaverActive() const
|
||||||
|
{
|
||||||
|
CDisplayLock display(this);
|
||||||
|
return getScreenSaver()->isActive();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CXWindowsPrimaryScreen::onOpenDisplay(Display* display)
|
CXWindowsPrimaryScreen::onOpenDisplay(Display* display)
|
||||||
{
|
{
|
||||||
|
|
|
@ -26,6 +26,7 @@ public:
|
||||||
virtual void getClipboard(ClipboardID, IClipboard*) const;
|
virtual void getClipboard(ClipboardID, IClipboard*) const;
|
||||||
virtual KeyModifierMask getToggleMask() const;
|
virtual KeyModifierMask getToggleMask() const;
|
||||||
virtual bool isLockedToScreen() const;
|
virtual bool isLockedToScreen() const;
|
||||||
|
virtual bool isScreenSaverActive() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// CXWindowsScreen overrides
|
// CXWindowsScreen overrides
|
||||||
|
|
|
@ -29,6 +29,8 @@ synergyd_LDADD = \
|
||||||
$(DEPTH)/base/libbase.a \
|
$(DEPTH)/base/libbase.a \
|
||||||
$(X_LIBS) \
|
$(X_LIBS) \
|
||||||
$(X_PRE_LIBS) \
|
$(X_PRE_LIBS) \
|
||||||
|
-lXtst \
|
||||||
|
-lXext \
|
||||||
-lX11 \
|
-lX11 \
|
||||||
$(X_EXTRA_LIBS) \
|
$(X_EXTRA_LIBS) \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
|
@ -88,6 +88,9 @@ public:
|
||||||
// any other reason that the user should not be allowed to switch
|
// any other reason that the user should not be allowed to switch
|
||||||
// screens.
|
// screens.
|
||||||
virtual bool isLockedToScreen() const = 0;
|
virtual bool isLockedToScreen() const = 0;
|
||||||
|
|
||||||
|
// return true if the screen saver is activated
|
||||||
|
virtual bool isScreenSaverActive() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue