Setup parameters
Remember me...
Index: config.c
===================================================================
--- config.c (.../tags/1.5.0) (Revision 846)
+++ config.c (.../branches/shutdown) (Revision 846)
@@ -267,6 +267,7 @@
SplitEditedFiles = 0;
MinEventTimeout = 30;
MinUserInactivity = 300;
+ NextWakeupEvent = 0;
MultiSpeedMode = 0;
ShowReplayMode = 0;
ResumeID = 0;
@@ -428,6 +429,7 @@
else if (!strcasecmp(Name, "SplitEditedFiles")) SplitEditedFiles = atoi(Value);
else if (!strcasecmp(Name, "MinEventTimeout")) MinEventTimeout = atoi(Value);
else if (!strcasecmp(Name, "MinUserInactivity")) MinUserInactivity = atoi(Value);
+ else if (!strcasecmp(Name, "NextWakeupEvent")) NextWakeupEvent = atoi(Value);
else if (!strcasecmp(Name, "MultiSpeedMode")) MultiSpeedMode = atoi(Value);
else if (!strcasecmp(Name, "ShowReplayMode")) ShowReplayMode = atoi(Value);
else if (!strcasecmp(Name, "ResumeID")) ResumeID = atoi(Value);
@@ -496,6 +498,7 @@
Store("SplitEditedFiles", SplitEditedFiles);
Store("MinEventTimeout", MinEventTimeout);
Store("MinUserInactivity", MinUserInactivity);
+ Store("NextWakeupEvent", NextWakeupEvent);
Store("MultiSpeedMode", MultiSpeedMode);
Store("ShowReplayMode", ShowReplayMode);
Store("ResumeID", ResumeID);
Index: config.h
===================================================================
--- config.h (.../tags/1.5.0) (Revision 846)
+++ config.h (.../branches/shutdown) (Revision 846)
@@ -244,6 +244,7 @@
int MaxVideoFileSize;
int SplitEditedFiles;
int MinEventTimeout, MinUserInactivity;
+ time_t NextWakeupEvent;
int MultiSpeedMode;
int ShowReplayMode;
int ResumeID;
Index: vdr.c
===================================================================
--- vdr.c (.../tags/1.5.0) (Revision 846)
+++ vdr.c (.../branches/shutdown) (Revision 846)
@@ -54,6 +54,7 @@
#include "plugin.h"
#include "rcu.h"
#include "recording.h"
+#include "shutdown.h"
#include "skinclassic.h"
#include "skinsttng.h"
#include "sources.h"
@@ -70,7 +71,7 @@
#define CHANNELSAVEDELTA 600 // seconds before saving channels.conf after automatic modifications
#define DEVICEREADYTIMEOUT 30 // seconds to wait until all devices are ready
#define MENUTIMEOUT 120 // seconds of user inactivity after which an OSD display is closed
-#define SHUTDOWNRETRY 300 // seconds before trying again to shut down
+#define SHUTDOWNRETRY 360 // seconds before trying again to shut down
#define TIMERCHECKDELTA 10 // seconds between checks for timers that need to see their channel
#define TIMERDEVICETIMEOUT 8 // seconds before a device used for timer check may be reused
#define TIMERLOOKAHEADTIME 60 // seconds before a non-VPS timer starts and the channel is switched if possible
@@ -184,7 +185,6 @@
bool MuteAudio = false;
int WatchdogTimeout = DEFAULTWATCHDOG;
const char *Terminal = NULL;
- const char *Shutdown = NULL;
bool UseKbd = true;
const char *LircDevice = NULL;
@@ -313,7 +313,7 @@
break;
case 'r': cRecordingUserCommand::SetCommand(optarg);
break;
- case 's': Shutdown = optarg;
+ case 's': Shutdown.SetShutdownCommand(optarg);
break;
case 't': Terminal = optarg;
if (access(Terminal, R_OK | W_OK) < 0) {
@@ -498,10 +498,7 @@
int PreviousChannel[2] = { 1, 1 };
int PreviousChannelIndex = 0;
time_t LastChannelChanged = time(NULL);
- time_t LastActivity = 0;
int MaxLatencyTime = 0;
- bool ForceShutdown = false;
- bool UserShutdown = false;
bool InhibitEpgScan = false;
bool IsInfoMenu = false;
cSkin *CurrentSkin = NULL;
@@ -596,6 +593,11 @@
}
}
+
+ // Check for timers in automatic start time window:
+ Shutdown.CheckManualStart(MANUALSTART);
+
+
// User interface:
Interface = new cInterface(SVDRPport);
@@ -856,9 +858,14 @@
// User Input:
cOsdObject *Interact = Menu ? Menu : cControl::Control();
eKeys key = Interface->GetKey(!Interact || !Interact->NeedsFastResponse());
- if (NORMALKEY(key) != kNone) {
+ if (NORMALKEY(key) != kNone && NORMALKEY(key) != k_Plugin) {
EITScanner.Activity();
- LastActivity = time(NULL);
+
+ // Cancel 5 minute shutdown countdown:
+ if (Shutdown.countdown) Shutdown.countdown.Cancel();
+
+ // Set user active for MinUserInactivity time in the future
+ Shutdown.SetUserInactiveTimeout();
}
// Keys that must work independent of any interactive mode:
switch (key) {
@@ -996,37 +1003,39 @@
}
break;
// Power off:
- case kPower: {
+ case kPower:
isyslog("Power button pressed");
DELETE_MENU;
- if (!Shutdown) {
- Skins.Message(mtError, tr("Can't shutdown - option '-s' not given!"));
+
+ // Check for activity, request power button again if active
+ if (!Shutdown.ConfirmShutdown(false)
+ && Skins.Message(mtWarning, tr("VDR will shut down later. Press power to force."), 5) != kPower) {
+ // Not pressed power. Set VDR to be non-interactive and power down later.
+ Shutdown.SetUserInactive();
break;
}
- LastActivity = 1; // not 0, see below!
- UserShutdown = true;
- if (cRecordControls::Active()) {
- if (!Interface->Confirm(tr("Recording - shut down anyway?")))
- break;
+
+ // No activity or 2x power button pressed. Ask for confirmations.
+ if (!Shutdown.ConfirmShutdown(true)) {
+ // Non-confirmed background activity, set VDR to be non-interactive and power down later.
+ Shutdown.SetUserInactive();
+ break;
}
- if (cPluginManager::Active(tr("shut down anyway?")))
+
+ // Ask the final question
+ if (!Interface->Confirm(tr("Press any key to cancel shutdown"), 5, true))
+ // If final question was canceled, continue to be active
break;
- if (!cRecordControls::Active()) {
- cTimer *timer = Timers.GetNextActiveTimer();
- time_t Next = timer ? timer->StartTime() : 0;
- time_t Delta = timer ? Next - time(NULL) : 0;
- if (Next && Delta <= Setup.MinEventTimeout * 60) {
- char *buf;
- asprintf(&buf, tr("Recording in %ld minutes, shut down anyway?"), Delta / 60);
- bool confirm = Interface->Confirm(buf);
- free(buf);
- if (!confirm)
- break;
- }
- }
- ForceShutdown = true;
+
+ // Ok, now call the shutdown scripts
+ Shutdown.DoShutdown(true);
+ // Set VDR to be non-interactive and power down again later.
+ Shutdown.SetUserInactive();
+ // Do not attempt to automatically shut down for 6 minutes
+ Shutdown.SetRetry(SHUTDOWNRETRY);
+
+ // will retry shutdown in 6 minutes
break;
- }
default: break;
}
Interact = Menu ? Menu : cControl::Control(); // might have been closed in the mean time
@@ -1041,7 +1050,7 @@
continue;
}
}
- else if (time(NULL) - LastActivity > MENUTIMEOUT)
+ else if (cRemote::LastActivity() > MENUTIMEOUT)
state = osEnd;
}
switch (state) {
@@ -1143,74 +1152,82 @@
Skins.Message(mtInfo, tr("Editing process finished"));
}
}
- if (!Interact && ((!cRecordControls::Active() && !cCutter::Active() && (!Interface->HasSVDRPConnection() || UserShutdown)) || ForceShutdown)) {
- time_t Now = time(NULL);
- if (Now - LastActivity > ACTIVITYTIMEOUT) {
- // Shutdown:
- if (Shutdown && (Setup.MinUserInactivity || LastActivity == 1) && Now - LastActivity > Setup.MinUserInactivity * 60) {
- cTimer *timer = Timers.GetNextActiveTimer();
- time_t Next = timer ? timer->StartTime() : 0;
- time_t Delta = timer ? Next - Now : 0;
- if (!LastActivity) {
- if (!timer || Delta > MANUALSTART) {
- // Apparently the user started VDR manually
- dsyslog("assuming manual start of VDR");
- LastActivity = Now;
- continue; // don't run into the actual shutdown procedure below
- }
- else
- LastActivity = 1;
- }
- if (timer && Delta < Setup.MinEventTimeout * 60 && ForceShutdown) {
- Delta = Setup.MinEventTimeout * 60;
- Next = Now + Delta;
- timer = NULL;
- dsyslog("reboot at %s", *TimeToString(Next));
- }
- if (!ForceShutdown && cPluginManager::Active()) {
- LastActivity = Now - Setup.MinUserInactivity * 60 + SHUTDOWNRETRY; // try again later
- continue;
- }
- if (!Next || Delta > Setup.MinEventTimeout * 60 || ForceShutdown) {
- ForceShutdown = false;
- if (timer)
- dsyslog("next timer event at %s", *TimeToString(Next));
- if (WatchdogTimeout > 0)
- signal(SIGALRM, SIG_IGN);
- if (Interface->Confirm(tr("Press any key to cancel shutdown"), UserShutdown ? 5 : SHUTDOWNWAIT, true)) {
- cControl::Shutdown();
- int Channel = timer ? timer->Channel()->Number() : 0;
- const char *File = timer ? timer->File() : "";
- if (timer)
- Delta = Next - time(NULL); // compensates for Confirm() timeout
- char *cmd;
- asprintf(&cmd, "%s %ld %ld %d \"%s\" %d", Shutdown, Next, Delta, Channel, *strescape(File, "\"$"), UserShutdown);
- isyslog("executing '%s'", cmd);
- SystemExec(cmd);
- free(cmd);
- LastActivity = time(NULL) - Setup.MinUserInactivity * 60 + SHUTDOWNRETRY; // try again later
- }
- else {
- LastActivity = Now;
- if (WatchdogTimeout > 0) {
- alarm(WatchdogTimeout);
- if (signal(SIGALRM, Watchdog) == SIG_IGN)
- signal(SIGALRM, SIG_IGN);
- }
- }
- UserShutdown = false;
- continue; // skip the rest of the housekeeping for now
- }
- }
- // Disk housekeeping:
- RemoveDeletedRecordings();
- cSchedules::Cleanup();
- // Plugins housekeeping:
- PluginManager.Housekeeping();
+ // Update the shutdown countdown:
+ if (Shutdown.countdown && Shutdown.countdown.Update()) {
+ // Also on countdown, every 10 seconds:
+
+ // Any action that would cancel shutdown?
+ if (!Shutdown.ConfirmShutdown(false))
+ Shutdown.countdown.Cancel();
+ }
+
+ if (!Interact && !cRecordControls::Active() && !cCutter::Active() && !Interface->HasSVDRPConnection() && cRemote::LastActivity() > ACTIVITYTIMEOUT) {
+ // Handle housekeeping tasks
+
+ // Shutdown:
+ // Check whether VDR will be ready for shutdown in 5 minutes:
+ time_t Soon = time(NULL) + SHUTDOWNWAIT;
+ if (Shutdown.IsUserInactive(Soon) && Shutdown.Retry(Soon) && !Shutdown.countdown) {
+ if (Shutdown.ConfirmShutdown(false))
+ // Time to shut down. Start final 5 minute countdown
+ Shutdown.countdown.Start(tr("VDR will shut down in %s minutes"),SHUTDOWNWAIT);
+
+ // Dont try to shut down again for next 6 minutes
+ Shutdown.SetRetry(SHUTDOWNRETRY);
}
+
+ // Countdown run down to 0?
+ if (Shutdown.countdown.Done()) {
+ // Timed out, now do a final check
+ if (Shutdown.IsUserInactive() && Shutdown.ConfirmShutdown(false))
+ // and call the shutdown command
+ Shutdown.DoShutdown(false);
+
+ // Do this again a bit later
+ Shutdown.SetRetry(SHUTDOWNRETRY);
+ }
+
+ // Disk housekeeping:
+ RemoveDeletedRecordings();
+ cSchedules::Cleanup();
+ // Plugins housekeeping:
+ PluginManager.Housekeeping();
}
+
// Main thread hooks of plugins:
PluginManager.MainThreadHook();
+
+
+#define DebugTimeouts
+#ifdef DebugTimeouts
+
+ static time_t DebugTime = time(NULL);
+ time_t Now = time(NULL);
+ if (Now - DebugTime >= 1) {
+ if (!cRemote::LastActivityTime())
+ fprintf(stderr,"LastActivity: Never ");
+ else
+ fprintf(stderr,"LastActivity: %5i ",cRemote::LastActivity());
+
+ time_t ActiveTimeout = Shutdown.GetUserInactiveTime();
+ if (!ActiveTimeout)
+ fprintf(stderr,"ActiveTimeout: Never ");
+ else
+ fprintf(stderr,"ActiveTimeout: %6i ",(int)(Now - ActiveTimeout));
+
+ time_t Retry = Shutdown.GetRetry();
+ if (!Retry)
+ fprintf(stderr,"Retry: Never ");
+ else
+ fprintf(stderr,"Retry: %6i ",(int)(Now - Retry));
+
+ fprintf(stderr,"Counter: %s\r",Shutdown.countdown ? "Yes" : "No ");
+
+ fflush(stderr);
+ DebugTime = Now;
+ }
+
+#endif
}
if (Interrupted)
isyslog("caught signal %d", Interrupted);
Index: Makefile
===================================================================
--- Makefile (.../tags/1.5.0) (Revision 846)
+++ Makefile (.../branches/shutdown) (Revision 846)
@@ -35,7 +35,7 @@
OBJS = audio.o channels.o ci.o config.o cutter.o device.o diseqc.o dvbdevice.o dvbci.o dvbosd.o\
dvbplayer.o dvbspu.o eit.o eitscan.o epg.o filter.o font.o i18n.o interface.o keys.o\
lirc.o menu.o menuitems.o nit.o osdbase.o osd.o pat.o player.o plugin.o rcu.o\
- receiver.o recorder.o recording.o remote.o remux.o ringbuffer.o sdt.o sections.o\
+ receiver.o recorder.o recording.o remote.o remux.o ringbuffer.o sdt.o sections.o shutdown.o\
skinclassic.o skins.o skinsttng.o sources.o spu.o status.o svdrp.o themes.o thread.o\
timers.o tools.o transfer.o vdr.o videodir.o
Index: shutdown.c
===================================================================
--- shutdown.c (.../tags/1.5.0) (Revision 0)
+++ shutdown.c (.../branches/shutdown) (Revision 846)
@@ -0,0 +1,222 @@
+/*
+ * shutdown.c: Handling for shutdown and inactivity
+ *
+ * See the main source file 'vdr.c' for copyright information and
+ * how to reach the author.
+ *
+ * $Id: $
+ */
+
+#include "shutdown.h"
+
+#include
+#include
+#include
+#include
+
+#include "channels.h"
+#include "config.h"
+#include "cutter.h"
+#include "i18n.h"
+#include "interface.h"
+#include "menu.h"
+#include "plugin.h"
+#include "timers.h"
+#include "tools.h"
+
+cShutdown Shutdown;
+
+cCountdown::cCountdown(void)
+{
+ timeout = 0;
+ counter = 0;
+ timedOut = false;
+ format = NULL;
+}
+
+void cCountdown::Start(const char *Format, int Seconds)
+{
+ timeout = time(NULL) + Seconds;
+ counter = -1;
+ timedOut = false;
+ format = Format;
+ Update();
+}
+
+void cCountdown::Cancel(void)
+{
+ if (timeout) {
+ timeout = 0;
+ timedOut = false;
+ Skins.Message(mtStatus, NULL);
+ }
+}
+
+bool cCountdown::Update(void)
+{
+ if (!timeout) return false;
+
+ int NewCounter = (timeout - time(NULL) + 9) / 10;
+ if (NewCounter <= 0)
+ timedOut=true;
+
+ if (counter != NewCounter) {
+ counter = NewCounter;
+
+ char time[10];
+ char *Message;
+ snprintf(time, sizeof time, "%i:%i0", counter>0 ? counter/6 : 0, counter>0 ? counter%6 : 0);
+ asprintf(&Message,format,time);
+
+ Skins.Message(mtStatus, Message);
+ free(Message);
+ return true;
+ }
+ return false;
+}
+
+cShutdown::cShutdown(void)
+{
+ activeTimeout = 0;
+ retry = 0;
+ shutdownCommand = NULL;
+}
+
+void cShutdown::CheckManualStart(int ManualStart)
+{
+ time_t Delta = Setup.NextWakeupEvent ? Setup.NextWakeupEvent - time(NULL) : 0;
+
+ if (!Setup.NextWakeupEvent || abs(Delta) > ManualStart) {
+ // Apparently the user started VDR manually
+ dsyslog("assuming manual start of VDR");
+ // Set inactive after MinUserInactivity
+ SetUserInactiveTimeout();
+ }
+ else
+ // Set inactive from now on
+ SetUserInactive();
+}
+
+void cShutdown::SetShutdownCommand(const char *ShutdownCommand)
+{
+ shutdownCommand = ShutdownCommand;
+}
+
+void cShutdown::CallShutdownCommand(time_t NextEvent, int Channel, const char *File, bool UserShutdown)
+{
+ time_t Delta = NextEvent ? NextEvent - time(NULL) : 0;
+ char *cmd;
+
+ asprintf(&cmd, "%s %ld %ld %d \"%s\" %d", shutdownCommand, NextEvent, Delta, Channel, *strescape(File, "\"$"), UserShutdown);
+ isyslog("executing '%s'", cmd);
+ if (SystemExec(cmd, true) == 0)
+ // Remember this wakeup time for comparison on reboot
+ Setup.NextWakeupEvent = NextEvent;
+ free(cmd);
+}
+
+void cShutdown::SetUserInactiveTimeout(int Seconds, bool Force)
+{
+ if (!Setup.MinUserInactivity && !Force) {
+ activeTimeout = 0;
+ return;
+ }
+ if (Seconds < 0) Seconds = Setup.MinUserInactivity * 60;
+ activeTimeout = time(NULL) + Seconds;
+}
+
+bool cShutdown::ConfirmShutdown(bool Interactive)
+{
+ if (!shutdownCommand) {
+ if (Interactive) Skins.Message(mtError, tr("Can't shutdown - option '-s' not given!"));
+ return false;
+ }
+ if (cReplayControl::NowReplaying()) {
+ if (!Interactive || !Interface->Confirm(tr("Replaying - shut down anyway?")))
+ return false;
+ }
+ if (cCutter::Active()) {
+ if (!Interactive || !Interface->Confirm(tr("Cutting - shut down anyway?")))
+ return false;
+ }
+
+ cTimer *timer = Timers.GetNextActiveTimer();
+ time_t Next = timer ? timer->StartTime() : 0;
+ time_t Delta = timer ? Next - time(NULL) : 0;
+
+ if (cRecordControls::Active() || (Next && Delta <= 0)) {
+ // VPS recordings in timer end margin may cause Delta <= 0
+
+ if (!Interactive || !Interface->Confirm(tr("Recording - shut down anyway?")))
+ return false;
+ }
+ else if (Next && Delta <= Setup.MinEventTimeout * 60) {
+ // Timer within Min Event Timeout
+ if (!Interactive) return false;
+
+ char *buf;
+ asprintf(&buf, tr("Recording in %ld minutes, shut down anyway?"), Delta / 60);
+ bool confirm = Interface->Confirm(buf);
+ free(buf);
+ if (!confirm)
+ return false;
+ }
+
+ if (cPluginManager::Active(Interactive ? tr("shut down anyway?") : NULL))
+ return false;
+
+ cPlugin *Plugin = cPluginManager::GetNextWakeupEventPlugin();
+ Next = Plugin ? Plugin->NextWakeupEvent() : 0;
+ Delta = Next ? Next - time(NULL) : 0;
+ if (Next && Delta <= Setup.MinEventTimeout * 60) {
+ // Plugin event within Min Event Timeout
+ if (!Interactive) return false;
+
+ char *buf;
+ asprintf(&buf, tr("Plugin activity in %ld minutes, shut down anyway?"), Delta / 60);
+ bool confirm = Interface->Confirm(buf);
+ free(buf);
+ if (!confirm)
+ return false;
+ }
+
+ return true;
+}
+
+bool cShutdown::DoShutdown(bool Force)
+{
+ time_t Now = time(NULL);
+ cTimer *timer = Timers.GetNextActiveTimer();
+ cPlugin *Plugin = cPluginManager::GetNextWakeupEventPlugin();
+
+ time_t Next = timer ? timer->StartTime() : 0;
+ time_t NextPlugin = Plugin ? Plugin->NextWakeupEvent() : 0;
+ if (NextPlugin && (!Next || Next > NextPlugin)) {
+ Next = NextPlugin;
+ timer = NULL;
+ }
+ time_t Delta = Next ? Next - Now : 0;
+
+ if (Next && Delta < Setup.MinEventTimeout * 60) {
+ if (!Force)
+ return false;
+ Delta = Setup.MinEventTimeout * 60;
+ Next = Now + Delta;
+ timer = NULL;
+ dsyslog("reboot at %s", *TimeToString(Next));
+ }
+
+ if (Next && timer) {
+ dsyslog("next timer event at %s", *TimeToString(Next));
+ CallShutdownCommand(Next, timer->Channel()->Number(), timer->File(), Force);
+ }
+ else if (Next && Plugin) {
+ CallShutdownCommand(Next, 0, Plugin->Name(), Force);
+ dsyslog("next plugin event at %s", *TimeToString(Next));
+ }
+ else
+ // Next should always be 0 here. Just for safety, pass it.
+ CallShutdownCommand(Next, 0, "", Force);
+
+ return true;
+}
Index: shutdown.h
===================================================================
--- shutdown.h (.../tags/1.5.0) (Revision 0)
+++ shutdown.h (.../branches/shutdown) (Revision 846)
@@ -0,0 +1,110 @@
+/*
+ * shutdown.h: Handling for shutdown and inactivity
+ *
+ * See the main source file 'vdr.c' for copyright information and
+ * how to reach the author.
+ *
+ * $Id: $
+ */
+
+#ifndef __SHUTDOWN_H
+#define __SHUTDOWN_H
+
+#include
+
+class cCountdown {
+private:
+ time_t timeout; ///< 5-minute countdown timer
+ int counter; ///< last shown time in 10s units
+ bool timedOut; ///< Countdown did run down to 0 and was not cancelled
+ const char *format; ///< Format string for message display, %s is placeholder
+
+public:
+ cCountdown(void);
+
+ void Start(const char *Message, int Seconds);
+ ///< Start the 5 minute shutdown warning countdown
+
+ void Cancel(void);
+ ///< Cancel the 5 minute shutdown warning countdown
+
+ bool Done(void) { if (!timedOut) return false; Cancel(); return true; }
+ ///< Check if countdown timer has run out without cancelling
+
+ operator bool(void) const { return timeout != 0; }
+ ///< Check if countdown is running
+
+ bool Update(void);
+ ///< Update status display of the countdown
+ ///< Returns true on actual update
+};
+
+class cShutdown {
+private:
+ time_t activeTimeout;
+ ///< Time when VDR will become non-interactive. 0 means never.
+ time_t retry;
+ ///< Time for retrying the shutdown.
+
+ const char *shutdownCommand;
+ ///< Command for shutting down VDR, set with -s option
+
+public:
+ cShutdown(void);
+
+ void CheckManualStart(int ManualStart);
+ ///< Check whether next timer is in ManualStart time window.
+ ///< If yes, assume non-interactive use
+
+ void SetShutdownCommand(const char *ShutdownCommand);
+ ///< Set the command string for shutdown command
+
+ void CallShutdownCommand(time_t NextEvent, int Channel, const char *File, bool UserShutdown);
+ ///< Call the shutdown command, giving it these parameters
+
+ bool IsUserInactive(time_t AtTime = 0) { return activeTimeout && activeTimeout <= (AtTime ? AtTime : time(NULL)); }
+ ///< Check whether VDR is in interactive mode or non-interactive mode (waiting for shutdown).
+ ///< AtTime checks whether VDR will probably be inactive at that time.
+
+ time_t GetUserInactiveTime(void) { return activeTimeout; }
+ ///< Time when user will become non-inactive, or 0 if never
+
+ void SetUserInactiveTimeout(int Seconds = -1, bool Force = false);
+ ///< Set the time when VDR will switch into non-interactive mode or power down.
+ ///< -1 means Setup.MinUserInactivity in the future.
+ ///< Otherwise, seconds in the future.
+ ///< If MinUserInactivity = 0 and Force = false, Seconds is ignored and VDR will
+ ///< stay interactive forever.
+
+ void SetUserInactive() { SetUserInactiveTimeout(0, true); }
+ ///< Set VDR manually into non-interactive mode.
+
+ bool Retry(time_t AtTime = 0) { return retry <= (AtTime ? AtTime : time(NULL)); }
+ ///< Check whether its time to re-try the shutdown.
+ ///< AtTime checks whether VDR will probably be inactive at that time.
+
+ time_t GetRetry(void) { return retry; }
+ ///< Time when shutdown retry block ends.
+
+ void SetRetry(int Seconds) { retry = time(NULL) + Seconds; }
+ ///< Set shutdown retry so that VDR will not try to automatically shut down
+ ///< within Seconds.
+
+ bool ConfirmShutdown(bool Ask);
+ ///< Check for background activity that blocks shutdown.
+ ///< Returns immediately and without user interaction if Ask=false
+ ///< Asks for confirmation if ask=true
+ ///< Returns true if ready for shutdown.
+
+ bool DoShutdown(bool Force);
+ ///< Call the shutdown script with data of the next pending timer.
+ ///< Fails if force = false and a timer is running or within MinEventTimeout.
+ ///< Always calls shutdown on force = true.
+ ///< Returns true on success.
+
+ cCountdown countdown;
+};
+
+extern cShutdown Shutdown;
+
+#endif
Index: remote.c
===================================================================
--- remote.c (.../tags/1.5.0) (Revision 846)
+++ remote.c (.../branches/shutdown) (Revision 846)
@@ -31,6 +31,7 @@
cCondVar cRemote::keyPressed;
const char *cRemote::keyMacroPlugin = NULL;
const char *cRemote::callPlugin = NULL;
+time_t cRemote::lastActivity = 0;
cRemote::cRemote(const char *Name)
{
@@ -183,6 +184,7 @@
out = 0;
if ((k & k_Repeat) != 0)
repeatTimeout.Set(REPEATTIMEOUT);
+ lastActivity = time(NULL);
return k;
}
else if (!WaitMs || !keyPressed.TimedWait(mutex, WaitMs) && repeatTimeout.TimedOut())
Index: remote.h
===================================================================
--- remote.h (.../tags/1.5.0) (Revision 846)
+++ remote.h (.../branches/shutdown) (Revision 846)
@@ -28,6 +28,7 @@
static char *unknownCode;
static cMutex mutex;
static cCondVar keyPressed;
+ static time_t lastActivity;
static const char *keyMacroPlugin;
static const char *callPlugin;
char *name;
@@ -61,6 +62,10 @@
///< plugin name will be reset to NULL by this call.
static bool HasKeys(void);
static eKeys Get(int WaitMs = 1000, char **UnknownCode = NULL);
+ static int LastActivity() { return time(NULL) - lastActivity; }
+ ///< Seconds since last key was delivered by Get().
+ static time_t LastActivityTime() { return lastActivity; }
+ ///< Absolute time when last key was delivered by Get().
};
class cRemotes : public cList {};
Eigenschaftsänderungen:
___________________________________________________________________
Name: svnmerge-integrated
+ /vdr/trunk:1-833