/*
* screen_saver.cc
*
* Copyright (C) 1995-2001 Kenichi Kourai
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with qvwm; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef USE_SS
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include "screen_saver.h"
#include "main.h"
#include "misc.h"
#include "timer.h"
#include "qvwm.h"
ScreenSaver::ScreenSaver(char* locker, unsigned long lockSec)
{
m_lockerPid = 0;
m_locker = locker;
m_lockMsec = lockSec * 1000;
if (lockSec == 0) {
m_ssSupport = False;
return;
}
#ifdef USE_SSEXT
int ssEventBase, ssErrorBase;
m_ssSupport = XScreenSaverQueryExtension(display, &ssEventBase,
&ssErrorBase);
if (!m_ssSupport) {
QvwmError("Screen saver extension not supported");
return;
}
m_info = XScreenSaverAllocInfo();
#else // USE_SSEXT
m_ssSupport = True;
Callback<ScreenSaver>* cb =
new Callback<ScreenSaver>(this, &ScreenSaver::QueryPointer);
timer->SetTimeout(1000, cb); // 1sec
SelectEventsForAll();
#endif // USE_SSEXT
timer->SetTimeout(m_lockMsec,
new Callback<ScreenSaver>(this, &ScreenSaver::Start));
}
ScreenSaver::~ScreenSaver()
{
#ifdef USE_SSEXT
if (m_ssSupport)
XFree(m_info);
#endif
}
void ScreenSaver::Start()
{
#ifdef USE_SSEXT
XScreenSaverQueryInfo(display, root, m_info);
if (m_info->idle < m_lockMsec) {
timer->SetTimeout(m_lockMsec - m_info->idle,
new Callback<ScreenSaver>(this, &ScreenSaver::Start));
return;
}
#endif // USE_SSEXT
if (m_lockerPid == 0) {
rootQvwm->InstallWindowColormaps();
m_lockerPid = vfork();
if (m_lockerPid == 0) {
execl("/bin/sh", "/bin/sh", "-c", m_locker, NULL);
QvwmError("cannot start screen saver %s", m_locker);
_exit(1);
}
}
}
Bool ScreenSaver::NotifyDeadPid(pid_t pid)
{
if (pid == m_lockerPid) {
m_lockerPid = 0;
timer->SetTimeout(m_lockMsec,
new Callback<ScreenSaver>(this, &ScreenSaver::Start));
return True;
}
return False;
}
#ifndef USE_SSEXT
void ScreenSaver::SelectEventsForAll()
{
SelectEvents(root);
Callback<ScreenSaver>* cb =
new Callback<ScreenSaver>(this, &ScreenSaver::SelectEventsForAll);
timer->SetTimeout(10000, cb); // 10sec
}
void ScreenSaver::SelectEvents(Window win)
{
XWindowAttributes attr;
int keyMask, newMask;
Window junkRoot, junkParent;
Window *children;
unsigned int nChildren;
if (!m_ssSupport)
return;
if (win != root) {
if (XGetWindowAttributes(display, win, &attr) == 0)
return;
// if a foreign window
if (attr.your_event_mask == 0 ||
attr.your_event_mask & SubstructureNotifyMask) {
keyMask = (attr.all_event_masks | attr.do_not_propagate_mask)
& KeyPressMask;
newMask = attr.your_event_mask | SubstructureNotifyMask | keyMask;
XSelectInput(display, win, newMask);
}
}
if (!XQueryTree(display, win, &junkRoot, &junkParent, &children, &nChildren))
return;
for (int i = 0; i < nChildren; i++)
SelectEvents(children[i]);
if (nChildren)
XFree(children);
}
void ScreenSaver::ResetTimer()
{
if (!m_ssSupport)
return;
timer->ResetTimeout(new Callback<ScreenSaver>(this, &ScreenSaver::Start));
timer->SetTimeout(m_lockMsec,
new Callback<ScreenSaver>(this, &ScreenSaver::Start));
}
// approximation instead of setting *MotionMask to all windows
void ScreenSaver::QueryPointer()
{
Window junkRoot, junkChild;
Point ptRoot, ptJunk;
unsigned int mask;
XQueryPointer (display, root, &junkRoot, &junkChild, &ptRoot.x, &ptRoot.y,
&ptJunk.x, &ptJunk.y, &mask);
if (m_ptPrevRoot.x != ptRoot.x || m_ptPrevRoot.y != ptRoot.y ||
m_prevMask != mask) {
ResetTimer();
m_ptPrevRoot = ptRoot;
m_prevMask = mask;
}
Callback<ScreenSaver>* cb =
new Callback<ScreenSaver>(this, &ScreenSaver::QueryPointer);
timer->SetTimeout(1000, cb);
}
#endif // !USE_SSEXT
#endif // USE_SS
syntax highlighted by Code2HTML, v. 0.9.1