From 63b1758537f3623dc83f33569e4b10b760d5478f Mon Sep 17 00:00:00 2001 From: defnax Date: Fri, 9 Jan 2009 01:51:49 +0000 Subject: [PATCH] added idle sources git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@923 b45a01b8-16f6-495d-af2f-9b41ad6348cc --- retroshare-gui/src/idle/idle.cpp | 130 ++++++++++++++++++++++ retroshare-gui/src/idle/idle.h | 83 ++++++++++++++ retroshare-gui/src/idle/idle_mac.cpp | 160 +++++++++++++++++++++++++++ retroshare-gui/src/idle/idle_win.cpp | 102 +++++++++++++++++ retroshare-gui/src/idle/idle_x11.cpp | 98 ++++++++++++++++ 5 files changed, 573 insertions(+) create mode 100644 retroshare-gui/src/idle/idle.cpp create mode 100644 retroshare-gui/src/idle/idle.h create mode 100644 retroshare-gui/src/idle/idle_mac.cpp create mode 100644 retroshare-gui/src/idle/idle_win.cpp create mode 100644 retroshare-gui/src/idle/idle_x11.cpp diff --git a/retroshare-gui/src/idle/idle.cpp b/retroshare-gui/src/idle/idle.cpp new file mode 100644 index 000000000..8b39996b7 --- /dev/null +++ b/retroshare-gui/src/idle/idle.cpp @@ -0,0 +1,130 @@ +/* + * idle.cpp - detect desktop idle time + * Copyright (C) 2003 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "idle.h" + +#include +#include +#include + +static IdlePlatform *platform = 0; +static int platform_ref = 0; + +Idle::Idle() +{ + d = new Private; + d->active = false; + d->idleTime = 0; + + // try to use platform idle + if(!platform) { + IdlePlatform *p = new IdlePlatform; + if(p->init()) + platform = p; + else + delete p; + } + if(platform) + ++platform_ref; + + connect(&d->checkTimer, SIGNAL(timeout()), SLOT(doCheck())); +} + +Idle::~Idle() +{ + if(platform) { + --platform_ref; + if(platform_ref == 0) { + delete platform; + platform = 0; + } + } + delete d; +} + +bool Idle::isActive() const +{ + return d->active; +} + +bool Idle::usingPlatform() const +{ + return (platform ? true: false); +} + +void Idle::start() +{ + d->startTime = QDateTime::currentDateTime(); + + if(!platform) { + // generic idle + d->lastMousePos = QCursor::pos(); + d->idleSince = QDateTime::currentDateTime(); + } + + // poll every second (use a lower value if you need more accuracy) + d->checkTimer.start(1000); +} + +void Idle::stop() +{ + d->checkTimer.stop(); +} + +int Idle::secondsIdle() +{ + int i; + if (platform) + i = platform->secondsIdle(); + else { + QPoint curMousePos = QCursor::pos(); + QDateTime curDateTime = QDateTime::currentDateTime(); + if(d->lastMousePos != curMousePos) { + d->lastMousePos = curMousePos; + d->idleSince = curDateTime; + } + i = d->idleSince.secsTo(curDateTime); + } + + // set 'beginIdle' to the beginning of the idle time (by backtracking 'i' seconds from now) + QDateTime beginIdle = QDateTime::currentDateTime().addSecs(-i); + + // set 't' to hold the number of seconds between 'beginIdle' and 'startTime' + int t = beginIdle.secsTo(d->startTime); + + // beginIdle later than (or equal to) startTime? + if(t <= 0) { + // scoot ourselves up to the new idle start + d->startTime = beginIdle; + } + // beginIdle earlier than startTime? + else if(t > 0) { + // do nothing + } + + // how long have we been idle? + int idleTime = d->startTime.secsTo(QDateTime::currentDateTime()); + return idleTime; +} + +void Idle::doCheck() +{ + secondsIdle(secondsIdle()); +} diff --git a/retroshare-gui/src/idle/idle.h b/retroshare-gui/src/idle/idle.h new file mode 100644 index 000000000..5e6a9d694 --- /dev/null +++ b/retroshare-gui/src/idle/idle.h @@ -0,0 +1,83 @@ +/* + * idle.h - detect desktop idle time + * Copyright (C) 2003 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef IDLE_H +#define IDLE_H + +#include +#include +#include +#include + +class IdlePlatform; + +class Idle : public QObject +{ + Q_OBJECT +public: + Idle(); + ~Idle(); + + bool isActive() const; + bool usingPlatform() const; + void start(); + void stop(); + int secondsIdle(); + +signals: + void secondsIdle(int); + +private slots: + void doCheck(); + +private: + class Private; + Private *d; +}; + +class IdlePlatform +{ +public: + IdlePlatform(); + ~IdlePlatform(); + + bool init(); + int secondsIdle(); + +private: + class Private; + Private *d; +}; + +class Idle::Private +{ +public: + Private() {} + + QPoint lastMousePos; + QDateTime idleSince; + + bool active; + int idleTime; + QDateTime startTime; + QTimer checkTimer; +}; + +#endif diff --git a/retroshare-gui/src/idle/idle_mac.cpp b/retroshare-gui/src/idle/idle_mac.cpp new file mode 100644 index 000000000..e54ccbb5d --- /dev/null +++ b/retroshare-gui/src/idle/idle_mac.cpp @@ -0,0 +1,160 @@ +/* + * idle_mac.cpp - detect desktop idle time + * Copyright (C) 2003 Tarkvara Design Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "idle.h" +#include + + +// Why does Apple have to make this so complicated? +static OSStatus LoadFrameworkBundle(CFStringRef framework, CFBundleRef *bundlePtr) { + OSStatus err; + FSRef frameworksFolderRef; + CFURLRef baseURL; + CFURLRef bundleURL; + + if ( bundlePtr == nil ) return( -1 ); + + *bundlePtr = nil; + + baseURL = nil; + bundleURL = nil; + + err = FSFindFolder(kOnAppropriateDisk, kFrameworksFolderType, true, &frameworksFolderRef); + if (err == noErr) { + baseURL = CFURLCreateFromFSRef(kCFAllocatorSystemDefault, &frameworksFolderRef); + if (baseURL == nil) { + err = coreFoundationUnknownErr; + } + } + if (err == noErr) { + bundleURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault, baseURL, framework, false); + if (bundleURL == nil) { + err = coreFoundationUnknownErr; + } + } + if (err == noErr) { + *bundlePtr = CFBundleCreate(kCFAllocatorSystemDefault, bundleURL); + if (*bundlePtr == nil) { + err = coreFoundationUnknownErr; + } + } + if (err == noErr) { + if ( ! CFBundleLoadExecutable( *bundlePtr ) ) { + err = coreFoundationUnknownErr; + } + } + + // Clean up. + if (err != noErr && *bundlePtr != nil) { + CFRelease(*bundlePtr); + *bundlePtr = nil; + } + if (bundleURL != nil) { + CFRelease(bundleURL); + } + if (baseURL != nil) { + CFRelease(baseURL); + } + + return err; +} + + +class IdlePlatform::Private { +public: + EventLoopTimerRef mTimerRef; + int mSecondsIdle; + + Private() : mTimerRef(0), mSecondsIdle(0) {} + + static pascal void IdleTimerAction(EventLoopTimerRef, EventLoopIdleTimerMessage inState, void* inUserData); + +}; + + +pascal void IdlePlatform::Private::IdleTimerAction(EventLoopTimerRef, EventLoopIdleTimerMessage inState, void* inUserData) { + switch (inState) { + case kEventLoopIdleTimerStarted: + case kEventLoopIdleTimerStopped: + // Get invoked with this constant at the start of the idle period, + // or whenever user activity cancels the idle. + ((IdlePlatform::Private*)inUserData)->mSecondsIdle = 0; + break; + case kEventLoopIdleTimerIdling: + // Called every time the timer fires (i.e. every second). + ((IdlePlatform::Private*)inUserData)->mSecondsIdle++; + break; + } +} + + +IdlePlatform::IdlePlatform() { + d = new Private(); +} + +IdlePlatform::~IdlePlatform() { + RemoveEventLoopTimer(d->mTimerRef); + delete d; +} + + +// Typedef for the function we're getting back from CFBundleGetFunctionPointerForName. +typedef OSStatus (*InstallEventLoopIdleTimerPtr)(EventLoopRef inEventLoop, + EventTimerInterval inFireDelay, + EventTimerInterval inInterval, + EventLoopIdleTimerUPP inTimerProc, + void * inTimerData, + EventLoopTimerRef * outTimer); + + +bool IdlePlatform::init() { + // May already be init'ed. + if (d->mTimerRef) { + return true; + } + + // According to the docs, InstallEventLoopIdleTimer is new in 10.2. + // According to the headers, it has been around since 10.0. + // One of them is lying. We'll play it safe and weak-link the function. + + // Load the "Carbon.framework" bundle. + CFBundleRef carbonBundle; + if (LoadFrameworkBundle( CFSTR("Carbon.framework"), &carbonBundle ) != noErr) { + return false; + } + + // Load the Mach-O function pointers for the routine we will be using. + InstallEventLoopIdleTimerPtr myInstallEventLoopIdleTimer = (InstallEventLoopIdleTimerPtr)CFBundleGetFunctionPointerForName(carbonBundle, CFSTR("InstallEventLoopIdleTimer")); + if (myInstallEventLoopIdleTimer == 0) { + return false; + } + + EventLoopIdleTimerUPP timerUPP = NewEventLoopIdleTimerUPP(Private::IdleTimerAction); + if ((*myInstallEventLoopIdleTimer)(GetMainEventLoop(), kEventDurationSecond, kEventDurationSecond, timerUPP, 0, &d->mTimerRef)) { + return true; + } + + return false; +} + + +int IdlePlatform::secondsIdle() { + return d->mSecondsIdle; +} diff --git a/retroshare-gui/src/idle/idle_win.cpp b/retroshare-gui/src/idle/idle_win.cpp new file mode 100644 index 000000000..e31cb8bd9 --- /dev/null +++ b/retroshare-gui/src/idle/idle_win.cpp @@ -0,0 +1,102 @@ +/* + * idle_win.cpp - detect desktop idle time + * Copyright (C) 2003 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include "idle.h" + +#include +#include + +#ifndef tagLASTINPUTINFO +typedef struct __tagLASTINPUTINFO { + UINT cbSize; + DWORD dwTime; + } __LASTINPUTINFO, *__PLASTINPUTINFO; +#endif + +class IdlePlatform::Private +{ +public: + Private() + { + GetLastInputInfo = NULL; + lib = 0; + } + + BOOL (__stdcall * GetLastInputInfo)(__PLASTINPUTINFO); + DWORD (__stdcall * IdleUIGetLastInputTime)(void); + QLibrary *lib; +}; + +IdlePlatform::IdlePlatform() +{ + d = new Private; +} + +IdlePlatform::~IdlePlatform() +{ + delete d->lib; + delete d; +} + +bool IdlePlatform::init() +{ + if(d->lib) + return true; + void *p; + + // try to find the built-in Windows 2000 function + d->lib = new QLibrary("user32"); + if(d->lib->load() && (p = d->lib->resolve("GetLastInputInfo"))) { + d->GetLastInputInfo = (BOOL (__stdcall *)(__PLASTINPUTINFO))p; + return true; + } else { + delete d->lib; + d->lib = 0; + } + + // fall back on idleui + d->lib = new QLibrary("idleui"); + if(d->lib->load() && (p = d->lib->resolve("IdleUIGetLastInputTime"))) { + d->IdleUIGetLastInputTime = (DWORD (__stdcall *)(void))p; + return true; + } else { + delete d->lib; + d->lib = 0; + } + + return false; +} + +int IdlePlatform::secondsIdle() +{ + int i; + if(d->GetLastInputInfo) { + __LASTINPUTINFO li; + li.cbSize = sizeof(__LASTINPUTINFO); + bool ok = d->GetLastInputInfo(&li); + if(!ok) + return 0; + i = li.dwTime; + } else if (d->IdleUIGetLastInputTime) { + i = d->IdleUIGetLastInputTime(); + } else + return 0; + + return (GetTickCount() - i) / 1000; +} diff --git a/retroshare-gui/src/idle/idle_x11.cpp b/retroshare-gui/src/idle/idle_x11.cpp new file mode 100644 index 000000000..2263ade8e --- /dev/null +++ b/retroshare-gui/src/idle/idle_x11.cpp @@ -0,0 +1,98 @@ +/* + * idle_x11.cpp - detect desktop idle time + * Copyright (C) 2003 Justin Karneges + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "idle.h" + +#ifndef HAVE_XSS + +IdlePlatform::IdlePlatform() {} +IdlePlatform::~IdlePlatform() {} +bool IdlePlatform::init() { return false; } +int IdlePlatform::secondsIdle() { return 0; } + +#else + +#include +#include +#include + +#include +#include +#include + +static XErrorHandler old_handler = 0; +extern "C" int xerrhandler(Display* dpy, XErrorEvent* err) +{ + if(err->error_code == BadDrawable) + return 0; + + return (*old_handler)(dpy, err); +} + +class IdlePlatform::Private +{ +public: + Private() {} + + XScreenSaverInfo *ss_info; +}; + +IdlePlatform::IdlePlatform() +{ + d = new Private; + d->ss_info = 0; +} + +IdlePlatform::~IdlePlatform() +{ + if(d->ss_info) + XFree(d->ss_info); + if(old_handler) { + XSetErrorHandler(old_handler); + old_handler = 0; + } + delete d; +} + +bool IdlePlatform::init() +{ + if(d->ss_info) + return true; + + old_handler = XSetErrorHandler(xerrhandler); + + int event_base, error_base; + if(XScreenSaverQueryExtension(QApplication::desktop()->screen()->x11Display(), &event_base, &error_base)) { + d->ss_info = XScreenSaverAllocInfo(); + return true; + } + return false; +} + +int IdlePlatform::secondsIdle() +{ + if(!d->ss_info) + return 0; + if(!XScreenSaverQueryInfo(QApplication::desktop()->screen()->x11Display(), QX11Info::appRootWindow(), d->ss_info)) + return 0; + return d->ss_info->idle / 1000; +} + +#endif