Implemented 'Schedules' menu

This commit is contained in:
Klaus Schmidinger 2000-10-29 13:17:22 +01:00
parent 92d3e366ba
commit e6999e9b3a
20 changed files with 1948 additions and 558 deletions

2
BUGS
View File

@ -4,3 +4,5 @@ Video Disk Recorder - Known Bugs
* Sometimes the picture "jumps" as if a frame is skipped.
Presumably this is a problem in the card driver or firmware?
* The first picture captured with the GRAB command in SVDRP
is empty. Also, these pictures appear to be too dark.

View File

@ -26,6 +26,7 @@ Guido Fiala <gfiala@s.netic.de>
Robert Schneider <Robert.Schneider@lotus.com>
for implementing EIT support for displaying the current/next info
for extending EIT support to implement a complete EPG
Niels de Carpentier <niels@casema.net>
for adding a workaround for a driver timing problem in cDvbApi::Cmd()

25
HISTORY
View File

@ -241,3 +241,28 @@ Video Disk Recorder Revision History
- The "Blue" button in the "Main" menu can now be used to "Resume" a previously
stopped replay session (suggested by Martin Hammerschmid).
- The low and high LNB frequencies can now be changed in the "Setup" menu.
2000-10-29: Version 0.67
- The EIT information is now gathered in a separate thread.
- While the "current/next" information is being displayed (either after switching
channels or due to pressing the "Ok" button in normal viewing mode), the "Green"
and "Yellow" button display detailed information about the current/next broad-
cast (if such information is available).
- The sytem time can now be synchronized to the time broadcast in the DVB data
stream. This can be enabled in the "Setup" menu by setting "SetSystemTime" to
1. Note that this works only if VDR is running under a user id that has
permisson to set the system time.
- The new item "Schedule" in the "Main" menu opens VDR's EPG (thanks to Robert
Schneider). See the MANUAL file for a detailed description.
- The new setup parameters MarginStart and MarginStop define how long (in
minutes) before the official start time of a broadcast VDR shall begin
recording, and how long after the official end time it shall stop recording.
These are used when a recording is programmed from the "Schedules" menu.
- The delay value in the dvb.c.071.diff patch to the driver has been increased
to '3', because on some systems the OSD was not displayed correctly. If you
are running an already patched version 0.71 driver and encounter problems
with the OSD, please make sure the parameter in the ddelay call is '3', not
'2'.
- Fixed initializing the RCU remote control code (didn't work after switching
on the system).

64
MANUAL
View File

@ -53,20 +53,60 @@ Video Disk Recorder User's Manual
At any point in the menu system, pressing the "Menu" key again will
immediately leave the menu system (discarding any pending changes).
* The "Schedule" Menu
The "Schedule" menu implements VDR's "Electronic Program Guide" (EPG).
Select "Schedule" from the "Main" menu and you get a list of all upcoming
broadcasts on the current channel.
"Up" and "Down" can be used to scroll through this list, and pressing "Ok"
displays detailed information about the selected programme. Pressing "Ok"
again (or pressing "Back") gets you back into the "Schedule" menu.
From the "Schedule" menu, the "Green" button opens the "What's on now?"
menu, which displays all programmes that are currently running on all
channels that broadcast their programme information on the current
transponder, or from channels that have been current lately (VDR stores
all information it gathers in an internal list). The more channels you
have been switching through lately, the longer this list will be.
The "Yellow" button opens the "What's on next?" menu, which lists all
programmes that will start next on all channels.
Inside the "What's on now/next?" menus the "Green" button toggles between
the "Now" and "Next" display, and the "Yellow" button gets you back to the
"Schedule" menu of the current channel.
The "Red" button allows you to instantly program a timer to record the
selected programme. You will get into the "Edit Timer" menu in which
everything has already been filled in, and you can make any modifications
you may want to apply. Note that the Start and Stop time are offset by the
MarginStart and MarginStop parameters (see Setup) in order to make sure the
entire programme is recorded in case it doesn't exactly adhere to its
published start/stop times. Of course, no guarantee can be given that the
default margin values will be sufficient, so in case this recording is
really important you may want to add an extra margin ;-)
The "Blue" button can be pressed to switch to the channel with the selected
programme.
* Selecting a Channel
There are three ways to select a channel:
There are four ways to select a channel:
1. With no On Screen Menu displayed press the "Up" or "Down" key to switch
to the next higher or lower channel.
2. Press the "Menu" button to bring up the On Screen Menu, select "Channels"
and browse through the list with the "Up" and "Down" key; to switch to the
selected channel press "Ok".
2. Directly type in the channel number with the numeric keys ('0'..'9');
3. Directly type in the channel number with the numeric keys ('0'..'9');
if no key is pressed for about half a second, the digits collected so
far will define the channel number.
4. From the "Now", "Next" and "Event" menus (accessible through the "Schedule"
menu) by pressing the "Blue" button.
Pressing the '0' key toggles between the current and the previous channel.
Pressing the '0' key in normal viewing mode toggles between the current and
the previous channel.
After switching to a different channel the channel number and name, as well
as the current time are displayed at the top of the screen. If available, the
@ -75,6 +115,11 @@ Video Disk Recorder User's Manual
To bring up the channel display without switching channels you can press
the "Ok" button.
When the "current/next" information is being displayed, pressing the "Green"
button will display the detailed information about the current broadcast,
if such information is available. The "Yellow" button will do the same thing
for the next broadcast.
* Switching through channel groups
If the 'channels.conf' file contains "group separators" you can switch
@ -178,6 +223,9 @@ Video Disk Recorder User's Manual
If this field is left blank, the channel name will be used to form
the name of the recording.
A timer can also be programmed by pressing the "Red" button on the "Schedule",
"Now", "Next" or "Event" menus.
* Parameters in the "Setup" menu
Select "Setup" from the "Main" menu to enter the setup menu. From there you can
@ -216,3 +264,13 @@ Video Disk Recorder User's Manual
LnbFrequLo = 9750 The low and high LNB frequencies (in MHz)
LnbFrequHi = 10600
SetSystemTime = 0 Defines whether the system time will be set according to
the time received from the DVB data stream.
0 = system time will not be set
1 = system time wil be set
Note that this works only if VDR is running under a user
id that has permisson to set the system time.
MarginStart = 2 Defines how many minutes before the official start time
MarginStop = 10 of a broadcast VDR shall start recording, and how long
after the official end time it shall stop recording.

View File

@ -4,7 +4,7 @@
# See the main source file 'vdr.c' for copyright information and
# how to reach the author.
#
# $Id: Makefile 1.13 2000/10/07 16:24:08 kls Exp $
# $Id: Makefile 1.14 2000/10/28 16:24:16 kls Exp $
DVBDIR = ../DVB
@ -35,20 +35,20 @@ font: genfontfile fontosd.c
# Dependencies:
config.o : config.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h svdrp.h tools.h
dvbapi.o : dvbapi.c config.h dvbapi.h dvbosd.h font.h interface.h svdrp.h tools.h videodir.h
config.o : config.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h remote.h svdrp.h thread.h tools.h
dvbapi.o : dvbapi.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h remote.h svdrp.h thread.h tools.h videodir.h
dvbosd.o : dvbosd.c dvbosd.h font.h tools.h
eit.o : eit.c eit.h tools.h
eit.o : eit.c eit.h thread.h tools.h
font.o : font.c font.h fontosd.c tools.h
interface.o: interface.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h remote.h svdrp.h thread.h tools.h
menu.o : menu.c config.h dvbapi.h dvbosd.h font.h interface.h menu.h osd.h recording.h svdrp.h tools.h
osd.o : osd.c config.h dvbapi.h dvbosd.h font.h interface.h osd.h svdrp.h tools.h
recording.o: recording.c config.h dvbapi.h dvbosd.h font.h interface.h recording.h svdrp.h tools.h videodir.h
remote.o : remote.c config.h dvbapi.h dvbosd.h font.h remote.h thread.h tools.h
svdrp.o : svdrp.c config.h dvbapi.h dvbosd.h font.h interface.h svdrp.h tools.h
menu.o : menu.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h menu.h osd.h recording.h remote.h svdrp.h thread.h tools.h
osd.o : osd.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h osd.h remote.h svdrp.h thread.h tools.h
recording.o: recording.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h recording.h remote.h svdrp.h thread.h tools.h videodir.h
remote.o : remote.c config.h dvbapi.h dvbosd.h eit.h font.h remote.h thread.h tools.h
svdrp.o : svdrp.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h remote.h svdrp.h thread.h tools.h
thread.o : thread.c thread.h
tools.o : tools.c tools.h
vdr.o : vdr.c config.h dvbapi.h dvbosd.h font.h interface.h menu.h osd.h recording.h svdrp.h tools.h videodir.h
vdr.o : vdr.c config.h dvbapi.h dvbosd.h eit.h font.h interface.h menu.h osd.h recording.h remote.h svdrp.h thread.h tools.h videodir.h
videodir.o : videodir.c tools.h videodir.h
# The main program:

View File

@ -4,18 +4,15 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: config.c 1.26 2000/10/08 16:10:40 kls Exp $
* $Id: config.c 1.27 2000/10/29 13:04:37 kls Exp $
*/
#include "config.h"
#include <ctype.h>
#include <stdlib.h>
#include "dvbapi.h"
#include "eit.h"
#include "interface.h"
extern cEIT EIT;
// -- cKeys ------------------------------------------------------------------
tKey keyTable[] = { // "Up" and "Down" must be the first two keys!
@ -267,10 +264,8 @@ bool cChannel::Switch(cDvbApi *DvbApi)
isyslog(LOG_INFO, "switching to channel %d", number);
CurrentChannel = number;
for (int i = 3; i--;) {
if (DvbApi->SetChannel(frequency, polarization, diseqc, srate, vpid, apid, ca, pnr)) {
EIT.SetProgramNumber(pnr);
if (DvbApi->SetChannel(frequency, polarization, diseqc, srate, vpid, apid, ca, pnr))
return true;
}
esyslog(LOG_ERR, "retrying");
}
return false;
@ -306,6 +301,47 @@ cTimer::cTimer(bool Instant)
snprintf(file, sizeof(file), "%s%s", Setup.MarkInstantRecord ? "@" : "", ch->name);
}
cTimer::cTimer(const cEventInfo *EventInfo)
{
startTime = stopTime = 0;
recording = false;
active = true;
cChannel *ch = Channels.GetByServiceID(EventInfo->GetServiceID());
channel = ch ? ch->number : 0;
time_t tstart = EventInfo->GetTime();
time_t tstop = tstart + EventInfo->GetDuration() + Setup.MarginStop * 60;
tstart -= Setup.MarginStart * 60;
struct tm *time = localtime(&tstart);
day = time->tm_mday;
start = time->tm_hour * 100 + time->tm_min;
time = localtime(&tstop);
stop = time->tm_hour * 100 + time->tm_min;
if (stop >= 2400)
stop -= 2400;
priority = 99;
lifetime = 99;
*file = 0;
const char *Title = EventInfo->GetTitle();
if (!isempty(Title))
strn0cpy(file, EventInfo->GetTitle(), sizeof(file));
summary = NULL;
const char *Subtitle = EventInfo->GetSubtitle();
if (isempty(Subtitle))
Subtitle = "";
const char *Summary = EventInfo->GetExtendedDescription();
if (isempty(Summary))
Summary = "";
if (*Subtitle || *Summary) {
asprintf(&summary, "%s%s%s", Subtitle, (*Subtitle && *Summary) ? "\n\n" : "", Summary);
char *p = summary;
while (*p) {
if (*p == '\n')
*p = '|';
p++;
}
}
}
cTimer::~cTimer()
{
delete summary;
@ -388,14 +424,33 @@ bool cTimer::Parse(const char *s)
char *buffer2 = NULL;
delete summary;
summary = NULL;
//XXX Apparently sscanf() doesn't work correctly if the last %a argument
//XXX results in an empty string (this firt occured when the EIT gathering
//XXX was put into a separate thread - don't know why this happens...
//XXX As a cure we copy the original string and add a blank.
//XXX If anybody can shed some light on why sscanf() failes here, I'd love
//XXX to hear about that!
char *s2 = NULL;
int l2 = strlen(s);
if (s[l2 - 2] == ':') { // note that 's' has a trailing '\n'
s2 = (char *)malloc(l2 + 2);
strcat(strn0cpy(s2, s, l2), " \n");
s = s2;
}
if (8 <= sscanf(s, "%d:%d:%a[^:]:%d:%d:%d:%d:%a[^:\n]:%a[^\n]", &active, &channel, &buffer1, &start, &stop, &priority, &lifetime, &buffer2, &summary)) {
if (summary && !*skipspace(summary)) {
delete summary;
summary = NULL;
}
//TODO add more plausibility checks
day = ParseDay(buffer1);
strn0cpy(file, buffer2, MaxFileName);
delete buffer1;
delete buffer2;
delete s2;
return day != 0;
}
delete s2;
return false;
}
@ -550,6 +605,17 @@ cChannel *cChannels::GetByNumber(int Number)
return NULL;
}
cChannel *cChannels::GetByServiceID(unsigned short ServiceId)
{
cChannel *channel = (cChannel *)First();
while (channel) {
if (channel->pnr == ServiceId)
return channel;
channel = (cChannel *)channel->Next();
}
return NULL;
}
bool cChannels::SwitchTo(int Number, cDvbApi *DvbApi)
{
cChannel *channel = GetByNumber(Number);
@ -599,6 +665,9 @@ cSetup::cSetup(void)
MarkInstantRecord = 1;
LnbFrequLo = 9750;
LnbFrequHi = 10600;
SetSystemTime = 0;
MarginStart = 2;
MarginStop = 10;
}
bool cSetup::Parse(char *s)
@ -613,6 +682,9 @@ bool cSetup::Parse(char *s)
else if (!strcasecmp(Name, "MarkInstantRecord")) MarkInstantRecord = atoi(Value);
else if (!strcasecmp(Name, "LnbFrequLo")) LnbFrequLo = atoi(Value);
else if (!strcasecmp(Name, "LnbFrequHi")) LnbFrequHi = atoi(Value);
else if (!strcasecmp(Name, "SetSystemTime")) SetSystemTime = atoi(Value);
else if (!strcasecmp(Name, "MarginStart")) MarginStart = atoi(Value);
else if (!strcasecmp(Name, "MarginStop")) MarginStop = atoi(Value);
else
return false;
return true;
@ -660,6 +732,9 @@ bool cSetup::Save(const char *FileName)
fprintf(f, "MarkInstantRecord = %d\n", MarkInstantRecord);
fprintf(f, "LnbFrequLo = %d\n", LnbFrequLo);
fprintf(f, "LnbFrequHi = %d\n", LnbFrequHi);
fprintf(f, "SetSystemTime = %d\n", SetSystemTime);
fprintf(f, "MarginStart = %d\n", MarginStart);
fprintf(f, "MarginStop = %d\n", MarginStop);
fclose(f);
isyslog(LOG_INFO, "saved setup to %s", FileName);
return true;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: config.h 1.27 2000/10/08 16:33:48 kls Exp $
* $Id: config.h 1.28 2000/10/29 09:34:10 kls Exp $
*/
#ifndef __CONFIG_H
@ -15,9 +15,10 @@
#include <string.h>
#include <time.h>
#include "dvbapi.h"
#include "eit.h"
#include "tools.h"
#define VDRVERSION "0.66"
#define VDRVERSION "0.67"
#define MaxBuffer 10000
@ -113,6 +114,7 @@ public:
char file[MaxFileName];
char *summary;
cTimer(bool Instant = false);
cTimer(const cEventInfo *EventInfo);
~cTimer();
cTimer& operator= (const cTimer &Timer);
const char *ToText(void);
@ -204,6 +206,7 @@ public:
int GetNextNormal(int Idx); // Get next normal channel (not group)
void ReNumber(void); // Recalculate 'number' based on channel type
cChannel *GetByNumber(int Number);
cChannel *GetByServiceID(unsigned short ServiceId);
const char *GetChannelNameByNumber(int Number);
bool SwitchTo(int Number, cDvbApi *DvbApi = NULL);
int MaxNumber(void) { return maxNumber; }
@ -234,6 +237,8 @@ public:
int MarkInstantRecord;
int LnbFrequLo;
int LnbFrequHi;
int SetSystemTime;
int MarginStart, MarginStop;
cSetup(void);
bool Load(const char *FileName);
bool Save(const char *FileName = NULL);

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: dvbapi.c 1.32 2000/10/14 08:56:08 kls Exp $
* $Id: dvbapi.c 1.33 2000/10/29 10:39:57 kls Exp $
*/
#include "dvbapi.h"
@ -25,6 +25,7 @@ extern "C" {
#include "videodir.h"
#define VIDEODEVICE "/dev/video"
#define VBIDEVICE "/dev/vbi"
// The size of the array used to buffer video data:
#define VIDEOBUFSIZE (1024*1024)
@ -1084,14 +1085,27 @@ int cDvbApi::NumDvbApis = 0;
cDvbApi *cDvbApi::dvbApi[MAXDVBAPI] = { NULL };
cDvbApi *cDvbApi::PrimaryDvbApi = NULL;
cDvbApi::cDvbApi(const char *FileName)
cDvbApi::cDvbApi(const char *VideoFileName, const char *VbiFileName)
{
siProcessor = NULL;
pidRecord = pidReplay = 0;
fromRecord = toRecord = -1;
fromReplay = toReplay = -1;
videoDev = open(FileName, O_RDWR | O_NONBLOCK);
if (videoDev < 0)
LOG_ERROR;
videoDev = open(VideoFileName, O_RDWR | O_NONBLOCK);
if (videoDev >= 0) {
siProcessor = new cSIProcessor(VbiFileName);
if (!NumDvbApis) // only the first one shall set the system time
siProcessor->SetUseTSTime(Setup.SetSystemTime);
siProcessor->AddFilter(0x14, 0x70); // TDT
siProcessor->AddFilter(0x14, 0x73); // TOT
siProcessor->AddFilter(0x12, 0x4e); // event info, actual TS, present/following
siProcessor->AddFilter(0x12, 0x4f); // event info, other TS, present/following
siProcessor->AddFilter(0x12, 0x50); // event info, actual TS, schedule
siProcessor->AddFilter(0x12, 0x60); // event info, other TS, schedule
siProcessor->Start();
}
else
LOG_ERROR_STR(VideoFileName);
cols = rows = 0;
ovlGeoSet = ovlStat = ovlFbSet = false;
@ -1121,6 +1135,7 @@ cDvbApi::cDvbApi(const char *FileName)
cDvbApi::~cDvbApi()
{
if (videoDev >= 0) {
delete siProcessor;
Close();
Stop();
StopRecord();
@ -1174,11 +1189,9 @@ int cDvbApi::Index(void)
bool cDvbApi::Init(void)
{
char fileName[strlen(VIDEODEVICE) + 10];
int i;
NumDvbApis = 0;
for (i = 0; i < MAXDVBAPI; i++) {
for (int i = 0; i < MAXDVBAPI; i++) {
char fileName[strlen(VIDEODEVICE) + 10];
sprintf(fileName, "%s%d", VIDEODEVICE, i);
if (access(fileName, F_OK | R_OK | W_OK) == 0) {
dsyslog(LOG_INFO, "probing %s", fileName);
@ -1188,7 +1201,9 @@ bool cDvbApi::Init(void)
int r = ioctl(f, VIDIOCGCAP, &cap);
close(f);
if (r == 0 && (cap.type & VID_TYPE_DVB)) {
dvbApi[i] = new cDvbApi(fileName);
char vbiFileName[strlen(VBIDEVICE) + 10];
sprintf(vbiFileName, "%s%d", VBIDEVICE, i);
dvbApi[i] = new cDvbApi(fileName, vbiFileName);
NumDvbApis++;
}
}
@ -1223,6 +1238,13 @@ void cDvbApi::Cleanup(void)
PrimaryDvbApi = NULL;
}
const cSchedules *cDvbApi::Schedules(cThreadLock *ThreadLock) const
{
if (siProcessor && ThreadLock->Lock(siProcessor))
return siProcessor->Schedules();
return NULL;
}
bool cDvbApi::GrabImage(const char *FileName, bool Jpeg, int Quality, int SizeX, int SizeY)
{
int result = 0;
@ -1671,8 +1693,11 @@ bool cDvbApi::SetChannel(int FrequencyMHz, char Polarization, int Diseqc, int Sr
front.fec = 8;
front.AFC = 1;
ioctl(videoDev, VIDIOCSFRONTEND, &front);
if (front.sync & 0x1F == 0x1F)
if (front.sync & 0x1F == 0x1F) {
if (siProcessor)
siProcessor->SetCurrentServiceID(Pnr);
return true;
}
esyslog(LOG_ERR, "ERROR: channel not sync'ed (front.sync=%X)!", front.sync);
}
return false;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: dvbapi.h 1.18 2000/10/03 11:26:10 kls Exp $
* $Id: dvbapi.h 1.19 2000/10/29 12:11:16 kls Exp $
*/
#ifndef __DVBAPI_H
@ -21,6 +21,7 @@ typedef unsigned char __u8;
#include <stdio.h>
#include <dvb.h>
#include "dvbosd.h"
#include "eit.h"
// Overlay facilities
#define MAXCLIPRECTS 100
@ -44,7 +45,8 @@ public:
class cDvbApi {
private:
int videoDev;
cDvbApi(const char *FileName);
cSIProcessor *siProcessor;
cDvbApi(const char *VideoFileName, const char *VbiFileName);
public:
~cDvbApi();
@ -71,6 +73,14 @@ public:
// Closes down all DVB devices.
// Must be called at the end of the program.
// EIT facilities
const cSchedules *Schedules(cThreadLock *ThreadLock) const;
// Caller must provide a cThreadLock which has to survive the entire
// time the returned cSchedules is accessed. Once the cSchedules is no
// longer used, the cThreadLock must be destroyed.
void SetUseTSTime(bool On) { if (siProcessor) siProcessor->SetUseTSTime(On); }
// Image Grab facilities
bool GrabImage(const char *FileName, bool Jpeg = true, int Quality = -1, int SizeX = -1, int SizeY = -1);

1504
eit.c

File diff suppressed because it is too large Load Diff

179
eit.h
View File

@ -13,80 +13,127 @@
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* $Id: eit.h 1.1 2000/09/03 10:23:24 kls Exp $
* $Id: eit.h 1.2 2000/10/29 10:21:56 kls Exp $
***************************************************************************/
#ifndef __EIT_H
#define __EIT_H
#include <dvb_v4l.h>
#include "thread.h"
#include "tools.h"
typedef struct eit_event {
bool bIsValid;
char szTitle[512];
char szSubTitle[512];
char szDate[12];
char szTime[12];
}eit_event;
/**
*@author Robert Schneider
*/
class cEIT {
class cEventInfo : public cListObject {
friend class cSchedule;
friend class cEIT;
private:
unsigned short uServiceID; // Service ID of program for that event
bool bIsFollowing; // true if this is the next event on this channel
bool bIsPresent; // true if this is the present event running
char *pExtendedDescription; // Extended description of this event
char *pSubtitle; // Subtitle of event
char *pTitle; // Title of event
unsigned short uEventID; // Event ID of this event
long lDuration; // duration of event in seconds
time_t tTime; // Start time
u_char cExtendedDescriptorNumber; // current extended descriptor number that has to be inserted
int nChannelNumber; // the actual channel number from VDR's channel list (used in cMenuSchedule for sorting by channel number)
protected:
void SetFollowing(bool foll);
void SetPresent(bool pres);
bool SetTitle(char *string);
void SetServiceID(unsigned short servid);
void SetEventID(unsigned short evid);
void SetDuration(long l);
void SetTime(time_t t);
bool AddExtendedDescription(char *string);
bool SetSubtitle(char *string);
void IncreaseExtendedDescriptorNumber(void);
cEventInfo(unsigned short serviceid, unsigned short eventid);
public:
cEIT();
~cEIT();
/** */
int GetEIT();
/** */
int SetProgramNumber(unsigned short pnr);
/** Retrieves the string representing the time of the current event */
char * GetRunningTime();
/** Retrieves the string representing the date of the current event */
char * GetRunningDate();
/** Retrieves the string for the running subtitle */
char * GetRunningSubtitle();
/** retrieves the string for the running title */
char * GetRunningTitle();
/** Retrieves the string representing the time of the next event */
char * GetNextTime();
/** Retrieves the string representing the date of the next event */
char * GetNextDate();
/** Retrieves the string for the next subtitle */
char * GetNextSubtitle();
/** retrieves the string for the next title */
char * GetNextTitle();
/** */
bool IsValid();
~cEventInfo();
const char *GetTimeString(void) const;
const char *GetEndTimeString(void) const;
const char *GetDate(void) const;
bool IsFollowing(void) const;
bool IsPresent(void) const;
const char *GetExtendedDescription(void) const;
const char *GetSubtitle(void) const;
const char *GetTitle(void) const;
unsigned short GetEventID(void) const;
long GetDuration(void) const;
time_t GetTime(void) const;
u_char GetExtendedDescriptorNumber(void) const;
unsigned short GetServiceID(void) const;
int GetChannelNumber(void) const { return nChannelNumber; }
void SetChannelNumber(int ChannelNumber) const { ((cEventInfo *)this)->nChannelNumber = ChannelNumber; } // doesn't modify the EIT data, so it's ok to make it 'const'
};
protected: // Protected attributes
/** Device name of VBI device */
const char * cszBitFilter;
protected: // Protected attributes
/** handle to VBI device (usually /dev/vbi) */
int fsvbi;
/** Describes the event next on */
eit_event evtNext;
/** Describes the running event */
eit_event evtRunning;
protected: // Protected methods
/** Set the bitfilter in vbi device to return
correct tables */
int SetBitFilter(unsigned short pid, unsigned short section, unsigned short mode);
/** */
int GetSection(unsigned char *buf, ushort PID, unsigned char sec);
/** */
int CloseFilter(unsigned short handle);
/** */
char * mjd2string(unsigned short mjd);
/** */
int strdvbcpy(unsigned char *dst, unsigned char *src, int max);
public: // Public attributes
/** */
unsigned short uProgramNumber;
class cSchedule : public cListObject {
friend class cSchedules;
friend class cEIT;
private:
cEventInfo *pPresent;
cEventInfo *pFollowing;
unsigned short uServiceID;
cList<cEventInfo> Events;
protected:
void SetServiceID(unsigned short servid);
bool SetFollowingEvent(cEventInfo *pEvent);
bool SetPresentEvent(cEventInfo *pEvent);
void Cleanup(time_t tTime);
void Cleanup(void);
cSchedule(unsigned short servid = 0);
public:
~cSchedule();
const cEventInfo *GetPresentEvent(void) const;
const cEventInfo *GetFollowingEvent(void) const;
unsigned short GetServiceID(void) const;
const cEventInfo *GetEvent(unsigned short uEventID) const;
const cEventInfo *GetEvent(time_t tTime) const;
const cEventInfo *GetEventNumber(int n) const { return Events.Get(n); }
int NumEvents(void) const { return Events.Count(); }
};
class cSchedules : public cList<cSchedule> {
friend class cSIProcessor;
private:
const cSchedule *pCurrentSchedule;
unsigned short uCurrentServiceID;
protected:
bool SetCurrentServiceID(unsigned short servid);
void Cleanup();
public:
cSchedules(void);
~cSchedules();
const cSchedule *GetSchedule(unsigned short servid) const;
const cSchedule *GetSchedule(void) const;
};
typedef struct sip_filter {
u_char pid;
u_char tid;
int handle;
bool inuse;
}SIP_FILTER;
class cSIProcessor : public cThread {
private:
cSchedules *schedules;
bool useTStime;
SIP_FILTER *filters;
int fsvbi;
bool RefreshFilters(void);
void Action(void);
public:
cSIProcessor(const char *FileName);
~cSIProcessor();
bool SetUseTSTime(bool use);
bool AddFilter(u_char pid, u_char tid);
bool ShutDownFilters(void);
bool SetCurrentServiceID(unsigned short servid);
const cSchedules *Schedules(void) { return schedules; }
};
#endif

View File

@ -4,14 +4,11 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: interface.c 1.25 2000/10/08 16:34:17 kls Exp $
* $Id: interface.c 1.26 2000/10/29 12:53:55 kls Exp $
*/
#include "interface.h"
#include <unistd.h>
#include "eit.h"
cEIT EIT;
cInterface *Interface = NULL;
@ -355,46 +352,141 @@ eKeys cInterface::DisplayChannel(int Number, const char *Name, bool WithInfo)
Write(-5, 0, buffer);
cDvbApi::PrimaryDvbApi->Flush();
char *RunningTitle = "", *RunningSubtitle = "", *NextTitle = "", *NextSubtitle = "";
int Lines = 0;
if (Number && WithInfo && EIT.IsValid()) {
if (*(RunningTitle = EIT.GetRunningTitle())) Lines++;
if (*(RunningSubtitle = EIT.GetRunningSubtitle())) Lines++;
if (*(NextTitle = EIT.GetNextTitle())) Lines++;
if (*(NextSubtitle = EIT.GetNextSubtitle())) Lines++;
#define INFO_TIMEOUT 5
const cEventInfo *Present = NULL, *Following = NULL;
int Tries = 0;
if (Number && WithInfo) {
for (; Tries < INFO_TIMEOUT; Tries++) {
{
cThreadLock ThreadLock;
const cSchedules *Schedules = cDvbApi::PrimaryDvbApi->Schedules(&ThreadLock);
if (Schedules) {
const cSchedule *Schedule = Schedules->GetSchedule();
if (Schedule) {
const char *PresentTitle = NULL, *PresentSubtitle = NULL, *FollowingTitle = NULL, *FollowingSubtitle = NULL;
int Lines = 0;
if ((Present = Schedule->GetPresentEvent()) != NULL) {
PresentTitle = Present->GetTitle();
if (!isempty(PresentTitle))
Lines++;
PresentSubtitle = Present->GetSubtitle();
if (!isempty(PresentSubtitle))
Lines++;
}
if ((Following = Schedule->GetFollowingEvent()) != NULL) {
FollowingTitle = Following->GetTitle();
if (!isempty(FollowingTitle))
Lines++;
FollowingSubtitle = Following->GetSubtitle();
if (!isempty(FollowingSubtitle))
Lines++;
}
if (Lines > 0) {
const int t = 6;
int l = 1;
cDvbApi::PrimaryDvbApi->Fill(0, 1, MenuColumns, Lines, clrBackground);
if (!isempty(PresentTitle)) {
Write(0, l, Present->GetTimeString(), clrYellow, clrBackground);
Write(t, l, PresentTitle, clrCyan, clrBackground);
l++;
}
if (!isempty(PresentSubtitle)) {
Write(t, l, PresentSubtitle, clrCyan, clrBackground);
l++;
}
if (!isempty(FollowingTitle)) {
Write(0, l, Following->GetTimeString(), clrYellow, clrBackground);
Write(t, l, FollowingTitle, clrCyan, clrBackground);
l++;
}
if (!isempty(FollowingSubtitle)) {
Write(t, l, FollowingSubtitle, clrCyan, clrBackground);
}
cDvbApi::PrimaryDvbApi->Flush();
if (Lines == 4) {
Tries = 0;
break;
}
}
}
}
}
eKeys Key = Wait(1, true);
if (Key != kNone)
break;
}
}
if (Lines > 0) {
const int t = 6;
int l = 1;
cDvbApi::PrimaryDvbApi->Fill(0, 1, MenuColumns, Lines, clrBackground);
if (*RunningTitle) {
Write(0, l, EIT.GetRunningTime(), clrYellow, clrBackground);
Write(t, l, RunningTitle, clrCyan, clrBackground);
l++;
}
if (*RunningSubtitle) {
Write(t, l, RunningSubtitle, clrCyan, clrBackground);
l++;
}
if (*NextTitle) {
Write(0, l, EIT.GetNextTime(), clrYellow, clrBackground);
Write(t, l, NextTitle, clrCyan, clrBackground);
l++;
}
if (*NextSubtitle) {
Write(t, l, NextSubtitle, clrCyan, clrBackground);
}
cDvbApi::PrimaryDvbApi->Flush();
}
eKeys Key = Wait(5, true);
eKeys Key = Wait(INFO_TIMEOUT - Tries, true);
Close();
if (Key == kOk)
GetKey();
Close();
if (Key == kGreen || Key == kYellow) {
GetKey();
do {
Key = DisplayDescription((Key == kGreen) ? Present : Following);
} while (Key == kGreen || Key == kYellow);
Key = kNone;
}
return Key;
}
return kNone;
}
eKeys cInterface::DisplayDescription(const cEventInfo *EventInfo)
{
eKeys Key = kNone;
if (EventInfo) {
int line = 0;
Open();
Clear();
char buffer[MenuColumns + 1];
snprintf(buffer, sizeof(buffer), "%s %s", EventInfo->GetDate() ? EventInfo->GetDate() : "", EventInfo->GetTimeString() ? EventInfo->GetTimeString() : "");
Write(-strlen(buffer), line, buffer, clrYellow);
line = WriteParagraph(line, EventInfo->GetTitle());
line = WriteParagraph(line, EventInfo->GetSubtitle());
line = WriteParagraph(line, EventInfo->GetExtendedDescription());
Key = Wait(300);
Close();
}
return Key;
}
int cInterface::WriteParagraph(int Line, const char *Text)
{
if (Line < MenuLines && Text) {
Line++;
char *s = strdup(Text);
char *pStart = s, *pEnd;
char *pEndText = &s[strlen(s) - 1];
while (pStart < pEndText) {
if (strlen(pStart) > (unsigned)(MenuColumns - 2))
pEnd = &pStart[MenuColumns - 2];
else
pEnd = &pStart[strlen(pStart)];
while (*pEnd != 0 && *pEnd != ' ' && pEnd > pStart)
pEnd--;
//XXX what if there are no blanks???
//XXX need to scroll if text is longer
*pEnd = 0;
Write(1, Line++, pStart, clrCyan);
if (Line >= MenuLines)
return Line;
pStart = pEnd + 1;
}
}
return Line;
}
void cInterface::DisplayRecording(int Index, bool On)
{
rcIo->SetPoints(1 << Index, On);

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: interface.h 1.16 2000/10/08 12:15:49 kls Exp $
* $Id: interface.h 1.17 2000/10/29 12:32:12 kls Exp $
*/
#ifndef __INTERFACE_H
@ -28,6 +28,8 @@ private:
void QueryKeys(void);
void HelpButton(int Index, const char *Text, eDvbColor FgColor, eDvbColor BgColor);
eKeys Wait(int Seconds = 1, bool KeepChar = false);
eKeys DisplayDescription(const cEventInfo *EventInfo);
int WriteParagraph(int Line, const char *Text);
public:
cInterface(int SVDRPport = 0);
~cInterface();

304
menu.c
View File

@ -4,15 +4,17 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: menu.c 1.36 2000/10/08 16:11:22 kls Exp $
* $Id: menu.c 1.37 2000/10/29 11:23:33 kls Exp $
*/
#include "menu.h"
#include <ctype.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "config.h"
#include "eit.h"
#define MENUTIMEOUT 120 // seconds
@ -973,6 +975,300 @@ eOSState cMenuTimers::ProcessKey(eKeys Key)
return state;
}
// --- cMenuEventItem --------------------------------------------------------
class cMenuEventItem : public cOsdItem {
public:
cMenuEventItem(const char *Text);
};
cMenuEventItem::cMenuEventItem(const char *Text)
:cOsdItem(Text, osBack)
{
}
// --- cMenuEvent ------------------------------------------------------------
class cMenuEvent : public cOsdMenu {
private:
void AddParagraph(const char *text);
const cEventInfo *eventInfo;
public:
cMenuEvent(const cEventInfo *EventInfo, bool CanSwitch = false);
};
cMenuEvent::cMenuEvent(const cEventInfo *EventInfo, bool CanSwitch)
:cOsdMenu("Event", 1)
{
const char *p;
char buffer[MenuColumns + 1];
eventInfo = EventInfo;
cChannel *channel = Channels.GetByServiceID(eventInfo->GetServiceID());
snprintf(buffer, sizeof(buffer), "\t%-17.*s %.*s %s - %s", 17, channel->name, 5, eventInfo->GetDate(), eventInfo->GetTimeString(), eventInfo->GetEndTimeString());
Add(new cMenuEventItem(buffer));
if ((p = eventInfo->GetTitle()) != NULL && *p) {
Add(new cMenuEventItem(""));
AddParagraph(p);
}
if ((p = eventInfo->GetSubtitle()) != NULL && *p) {
Add(new cMenuEventItem(""));
AddParagraph(p);
}
if ((p = eventInfo->GetExtendedDescription()) != NULL && *p) {
Add(new cMenuEventItem(""));
AddParagraph(p);
}
SetHelp("Record", NULL, NULL, CanSwitch ? "Switch" : NULL);
}
void cMenuEvent::AddParagraph(const char *text)
{
char *ptextsave = strdup(text);
if (ptextsave) {
int column = 1;
char buffer[MenuColumns + 1];
char *pStart = ptextsave;
char *pEndText = &ptextsave[strlen(text) - 1];
while (pStart < pEndText) {
char *pEnd;
if (strlen(pStart) > (unsigned)(MenuColumns - column - 2))
pEnd = &pStart[MenuColumns - column - 2];
else
pEnd = &pStart[strlen(pStart)];
while (*pEnd && *pEnd != ' ' && pEnd > pStart)
pEnd--;
*pEnd = 0;
sprintf(buffer, "\t%s", pStart);
Add(new cMenuEventItem(buffer));
pStart = pEnd + 1;
}
}
delete ptextsave;
}
// --- cMenuWhatsOnItem ------------------------------------------------------
class cMenuWhatsOnItem : public cOsdItem {
public:
const cEventInfo *eventInfo;
cMenuWhatsOnItem(const cEventInfo *EventInfo);
};
cMenuWhatsOnItem::cMenuWhatsOnItem(const cEventInfo *EventInfo)
{
eventInfo = EventInfo;
char *buffer = NULL;
cChannel *channel = Channels.GetByNumber(eventInfo->GetChannelNumber());
asprintf(&buffer, "%d\t%.*s\t%.*s\t%s", eventInfo->GetChannelNumber(), 6, channel ? channel->name : "???", 5, eventInfo->GetTimeString(), eventInfo->GetTitle());
SetText(buffer, false);
}
// --- cMenuWhatsOn ----------------------------------------------------------
class cMenuWhatsOn : public cOsdMenu {
private:
eOSState Record(void);
eOSState Switch(void);
public:
cMenuWhatsOn(const cSchedules *Schedules, bool Now);
virtual eOSState ProcessKey(eKeys Key);
};
static int CompareEventChannel(const void *p1, const void *p2)
{
return (int)( (*(const cEventInfo **)p1)->GetChannelNumber() - (*(const cEventInfo **)p2)->GetChannelNumber());
}
cMenuWhatsOn::cMenuWhatsOn(const cSchedules *Schedules, bool Now)
:cOsdMenu(Now ? "What's on now?" : "What's on next?", 4, 7, 6)
{
const cSchedule *Schedule = Schedules->First();
const cEventInfo **pArray = NULL;
int num = 0;
while (Schedule) {
pArray = (const cEventInfo **)realloc(pArray, (num + 1) * sizeof(cEventInfo *));
pArray[num] = Now ? Schedule->GetPresentEvent() : Schedule->GetFollowingEvent();
if (pArray[num]) {
cChannel *channel = Channels.GetByServiceID(pArray[num]->GetServiceID());
if (channel) {
pArray[num]->SetChannelNumber(channel->number);
num++;
}
}
Schedule = (const cSchedule *)Schedules->Next(Schedule);
}
qsort(pArray, num, sizeof(cEventInfo *), CompareEventChannel);
for (int a = 0; a < num; a++)
Add(new cMenuWhatsOnItem(pArray[a]));
delete pArray;
SetHelp("Record", Now ? "Next" : "Now", "Schedule", "Switch");
}
eOSState cMenuWhatsOn::Switch(void)
{
cMenuWhatsOnItem *item = (cMenuWhatsOnItem *)Get(Current());
if (item) {
cChannel *channel = Channels.GetByServiceID(item->eventInfo->GetServiceID());
if (channel && channel->Switch())
return osEnd;
}
Interface->Error("Can't switch channel!");
return osContinue;
}
eOSState cMenuWhatsOn::Record(void)
{
cMenuWhatsOnItem *item = (cMenuWhatsOnItem *)Get(Current());
if (item) {
cTimer *timer = new cTimer(item->eventInfo);
Timers.Add(timer);
Timers.Save();
isyslog(LOG_INFO, "timer %d added", timer->Index() + 1);
return AddSubMenu(new cMenuEditTimer(timer->Index(), true));
}
return osContinue;
}
eOSState cMenuWhatsOn::ProcessKey(eKeys Key)
{
eOSState state = cOsdMenu::ProcessKey(Key);
if (state == osUnknown) {
switch (Key) {
case kRed: return Record();
case kYellow: return osBack;
case kBlue: return Switch();
case kOk: return AddSubMenu(new cMenuEvent(((cMenuWhatsOnItem *)Get(Current()))->eventInfo, true));
default: break;
}
}
return state;
}
// --- cMenuScheduleItem -----------------------------------------------------
class cMenuScheduleItem : public cOsdItem {
public:
const cEventInfo *eventInfo;
cMenuScheduleItem(const cEventInfo *EventInfo);
};
cMenuScheduleItem::cMenuScheduleItem(const cEventInfo *EventInfo)
{
eventInfo = EventInfo;
char *buffer = NULL;
asprintf(&buffer, "%.*s\t%.*s\t%s", 5, eventInfo->GetDate(), 5, eventInfo->GetTimeString(), eventInfo->GetTitle());
SetText(buffer, false);
}
// --- cMenuSchedule ---------------------------------------------------------
class cMenuSchedule : public cOsdMenu {
private:
cThreadLock threadLock;
const cSchedules *schedules;
bool now, next;
eOSState Record(void);
void PrepareSchedule(void);
void PrepareWhatsOnNext(bool On);
public:
cMenuSchedule(void);
virtual eOSState ProcessKey(eKeys Key);
};
cMenuSchedule::cMenuSchedule(void)
:cOsdMenu("Schedule", 6, 6)
{
now = next = false;
cChannel *channel = Channels.GetByNumber(CurrentChannel);
if (channel) {
char *buffer = NULL;
asprintf(&buffer, "Schedule - %s", channel->name);
SetTitle(buffer, false);
}
PrepareSchedule();
SetHelp("Record", "Now", "Next");
}
static int CompareEventTime(const void *p1, const void *p2)
{
return (int)((*(cEventInfo **)p1)->GetTime() - (*(cEventInfo **)p2)->GetTime());
}
void cMenuSchedule::PrepareSchedule(void)
{
schedules = cDvbApi::PrimaryDvbApi->Schedules(&threadLock);
if (schedules) {
const cSchedule *Schedule = schedules->GetSchedule();
int num = Schedule->NumEvents();
const cEventInfo **pArray = (const cEventInfo **)malloc(num * sizeof(cEventInfo *));
if (pArray) {
time_t now = time(NULL);
int numreal = 0;
for (int a = 0; a < num; a++) {
const cEventInfo *EventInfo = Schedule->GetEventNumber(a);
if (EventInfo->GetTime() + EventInfo->GetDuration() > now)
pArray[numreal++] = EventInfo;
}
qsort(pArray, numreal, sizeof(cEventInfo *), CompareEventTime);
for (int a = 0; a < numreal; a++)
Add(new cMenuScheduleItem(pArray[a]));
delete pArray;
}
}
}
eOSState cMenuSchedule::Record(void)
{
cMenuScheduleItem *item = (cMenuScheduleItem *)Get(Current());
if (item) {
cTimer *timer = new cTimer(item->eventInfo);
Timers.Add(timer);
Timers.Save();
isyslog(LOG_INFO, "timer %d added", timer->Index() + 1);
return AddSubMenu(new cMenuEditTimer(timer->Index(), true));
}
return osContinue;
}
eOSState cMenuSchedule::ProcessKey(eKeys Key)
{
eOSState state = cOsdMenu::ProcessKey(Key);
if (state == osUnknown) {
switch (Key) {
case kRed: return Record();
case kGreen: if (!now && !next) {
now = true;
return AddSubMenu(new cMenuWhatsOn(schedules, true));
}
now = !now;
next = !next;
return AddSubMenu(new cMenuWhatsOn(schedules, now));
case kYellow: return AddSubMenu(new cMenuWhatsOn(schedules, false));
case kOk: return AddSubMenu(new cMenuEvent(((cMenuScheduleItem *)Get(Current()))->eventInfo));
default: break;
}
}
return state;
}
// --- cMenuRecordingItem ----------------------------------------------------
class cMenuRecordingItem : public cOsdItem {
@ -1089,6 +1385,9 @@ cMenuSetup::cMenuSetup(void)
Add(new cMenuEditBoolItem("MarkInstantRecord", &data.MarkInstantRecord));
Add(new cMenuEditIntItem( "LnbFrequLo", &data.LnbFrequLo));
Add(new cMenuEditIntItem( "LnbFrequHi", &data.LnbFrequHi));
Add(new cMenuEditIntItem( "SetSystemTime", &data.SetSystemTime));
Add(new cMenuEditIntItem( "MarginStart", &data.MarginStart));
Add(new cMenuEditIntItem( "MarginStop", &data.MarginStop));
}
eOSState cMenuSetup::ProcessKey(eKeys Key)
@ -1098,6 +1397,7 @@ eOSState cMenuSetup::ProcessKey(eKeys Key)
if (state == osUnknown) {
switch (Key) {
case kOk: state = (Setup.PrimaryDVB != data.PrimaryDVB) ? osSwitchDvb : osBack;
cDvbApi::PrimaryDvbApi->SetUseTSTime(data.SetSystemTime);
Setup = data;
Setup.Save();
break;
@ -1114,6 +1414,7 @@ eOSState cMenuSetup::ProcessKey(eKeys Key)
cMenuMain::cMenuMain(bool Replaying)
:cOsdMenu("Main")
{
Add(new cOsdItem("Schedule", osSchedule));
Add(new cOsdItem("Channels", osChannels));
Add(new cOsdItem("Timer", osTimer));
Add(new cOsdItem("Recordings", osRecordings));
@ -1137,6 +1438,7 @@ eOSState cMenuMain::ProcessKey(eKeys Key)
eOSState state = cOsdMenu::ProcessKey(Key);
switch (state) {
case osSchedule: return AddSubMenu(new cMenuSchedule);
case osChannels: return AddSubMenu(new cMenuChannels);
case osTimer: return AddSubMenu(new cMenuTimers);
case osRecordings: return AddSubMenu(new cMenuRecordings);

12
osd.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: osd.c 1.9 2000/10/08 12:20:34 kls Exp $
* $Id: osd.c 1.10 2000/10/28 09:33:47 kls Exp $
*/
#include "osd.h"
@ -24,7 +24,7 @@ cOsdItem::cOsdItem(eOSState State)
bgColor = clrBackground;
}
cOsdItem::cOsdItem(char *Text, eOSState State)
cOsdItem::cOsdItem(const char *Text, eOSState State)
{
text = NULL;
offset = -1;
@ -74,7 +74,7 @@ eOSState cOsdItem::ProcessKey(eKeys Key)
// --- cOsdMenu --------------------------------------------------------------
cOsdMenu::cOsdMenu(char *Title, int c0, int c1, int c2, int c3, int c4)
cOsdMenu::cOsdMenu(const char *Title, int c0, int c1, int c2, int c3, int c4)
{
visible = false;
title = strdup(Title);
@ -108,6 +108,12 @@ void cOsdMenu::SetStatus(const char *s)
Interface->Status(status);
}
void cOsdMenu::SetTitle(const char *Title, bool Copy)
{
delete title;
title = Copy ? strdup(Title) : Title;
}
void cOsdMenu::SetHelp(const char *Red, const char *Green, const char *Yellow, const char *Blue)
{
// strings are NOT copied - must be constants!!!

10
osd.h
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: osd.h 1.11 2000/09/10 09:50:38 kls Exp $
* $Id: osd.h 1.12 2000/10/28 09:32:59 kls Exp $
*/
#ifndef __OSD_H
@ -19,6 +19,7 @@
enum eOSState { osUnknown,
osMenu,
osContinue,
osSchedule,
osChannels,
osTimer,
osRecordings,
@ -43,7 +44,7 @@ protected:
eDvbColor fgColor, bgColor;
public:
cOsdItem(eOSState State = osUnknown);
cOsdItem(char *Text, eOSState State = osUnknown);
cOsdItem(const char *Text, eOSState State = osUnknown);
virtual ~cOsdItem();
bool HasUserColor(void) { return userColor; }
void SetText(const char *Text, bool Copy = true);
@ -66,7 +67,7 @@ public:
class cOsdMenu : public cOsdBase, public cList<cOsdItem> {
private:
char *title;
const char *title;
int cols[cInterface::MaxCols];
int first, current, marked;
cOsdMenu *subMenu;
@ -83,10 +84,11 @@ protected:
eOSState AddSubMenu(cOsdMenu *SubMenu);
bool HasSubMenu(void) { return subMenu; }
void SetStatus(const char *s);
void SetTitle(const char *Title, bool Copy = true);
void SetHelp(const char *Red, const char *Green = NULL, const char *Yellow = NULL, const char *Blue = NULL);
virtual void Del(int Index);
public:
cOsdMenu(char *Title, int c0 = 0, int c1 = 0, int c2 = 0, int c3 = 0, int c4 = 0);
cOsdMenu(const char *Title, int c0 = 0, int c1 = 0, int c2 = 0, int c3 = 0, int c4 = 0);
virtual ~cOsdMenu();
int Current(void) { return current; }
void Add(cOsdItem *Item, bool Current = false);

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: thread.c 1.2 2000/10/08 16:45:50 kls Exp $
* $Id: thread.c 1.3 2000/10/28 15:26:02 kls Exp $
*/
#include "thread.h"
@ -88,16 +88,27 @@ void cThread::WakeUp(void)
cThreadLock::cThreadLock(cThread *Thread)
{
thread = Thread;
locked = Thread->Lock();
thread = NULL;
locked = false;
Lock(Thread);
}
cThreadLock::~cThreadLock()
{
if (locked)
if (thread && locked)
thread->Unlock();
}
bool cThreadLock::Lock(cThread *Thread)
{
if (Thread && !thread) {
thread = Thread;
locked = Thread->Lock();
return locked;
}
return false;
}
bool cThreadLock::Locked(void)
{
return locked;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: thread.h 1.1 2000/10/08 08:36:21 kls Exp $
* $Id: thread.h 1.2 2000/10/28 15:08:09 kls Exp $
*/
#ifndef __THREAD_H
@ -47,8 +47,9 @@ private:
cThread *thread;
bool locked;
public:
cThreadLock(cThread *Thread);
cThreadLock(cThread *Thread = NULL);
~cThreadLock();
bool Lock(cThread *Thread);
bool Locked(void);
};

15
tools.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: tools.c 1.21 2000/10/07 18:02:24 kls Exp $
* $Id: tools.c 1.22 2000/10/29 11:21:55 kls Exp $
*/
#define _GNU_SOURCE
@ -85,11 +85,16 @@ char *strreplace(char *s, char c1, char c2)
return s;
}
char *skipspace(char *s)
char *skipspace(const char *s)
{
while (*s && isspace(*s))
s++;
return s;
return (char *)s;
}
bool isempty(const char *s)
{
return !(s && *skipspace(s));
}
int time_ms(void)
@ -520,7 +525,7 @@ void cListBase::Clear(void)
objects = lastObject = NULL;
}
cListObject *cListBase::Get(int Index)
cListObject *cListBase::Get(int Index) const
{
if (Index < 0)
return NULL;
@ -530,7 +535,7 @@ cListObject *cListBase::Get(int Index)
return object;
}
int cListBase::Count(void)
int cListBase::Count(void) const
{
int n = 0;
cListObject *object = objects;

19
tools.h
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: tools.h 1.17 2000/10/07 18:00:21 kls Exp $
* $Id: tools.h 1.18 2000/10/29 11:19:20 kls Exp $
*/
#ifndef __TOOLS_H
@ -40,7 +40,8 @@ void purge(int filedes);
char *readline(FILE *f);
char *strn0cpy(char *dest, const char *src, size_t n);
char *strreplace(char *s, char c1, char c2);
char *skipspace(char *s);
char *skipspace(const char *s);
bool isempty(const char *s);
int time_ms(void);
void delay_ms(int ms);
bool isnumber(const char *s);
@ -80,8 +81,8 @@ public:
void Append(cListObject *Object);
void Unlink(void);
int Index(void);
cListObject *Prev(void) { return prev; }
cListObject *Next(void) { return next; }
cListObject *Prev(void) const { return prev; }
cListObject *Next(void) const { return next; }
};
class cListBase {
@ -95,15 +96,15 @@ public:
virtual void Move(int From, int To);
void Move(cListObject *From, cListObject *To);
void Clear(void);
cListObject *Get(int Index);
int Count(void);
cListObject *Get(int Index) const;
int Count(void) const;
};
template<class T> class cList : public cListBase {
public:
T *Get(int Index) { return (T *)cListBase::Get(Index); }
T *First(void) { return (T *)objects; }
T *Next(T *object) { return (T *)object->Next(); }
T *Get(int Index) const { return (T *)cListBase::Get(Index); }
T *First(void) const { return (T *)objects; }
T *Next(const T *object) const { return (T *)object->Next(); }
};
#endif //__TOOLS_H