vdr 2.8.2
skins.c
Go to the documentation of this file.
1/*
2 * skins.c: The optical appearance of the OSD
3 *
4 * See the main source file 'vdr.c' for copyright information and
5 * how to reach the author.
6 *
7 * $Id: skins.c 5.7 2026/05/20 09:43:03 kls Exp $
8 */
9
10#include "skins.h"
11#include "interface.h"
12#include "status.h"
13
14// --- cSkinQueuedMessage ----------------------------------------------------
15
17 friend class cSkins;
18private:
20 char *message;
25 int state;
28public:
29 cSkinQueuedMessage(eMessageType Type, const char *s, int Seconds, int Timeout);
30 virtual ~cSkinQueuedMessage() override;
31 };
32
33cSkinQueuedMessage::cSkinQueuedMessage(eMessageType Type, const char *s, int Seconds, int Timeout)
34{
35 type = Type;
36 message = s ? strdup(s) : NULL;
37 seconds = Seconds;
38 timeout = Timeout;
40 key = kNone;
41 state = 0; // waiting
42}
43
48
50
51// --- cSkinDisplay ----------------------------------------------------------
52
54
56{
57 current = this;
58 editableWidth = 100; //XXX
59}
60
65
66// --- cSkinDisplayChannel ---------------------------------------------------
67
72
74{
75 if (positioner && Positioner != positioner)
76 SetMessage(mtInfo, NULL);
77 positioner = Positioner;
78 if (positioner)
79 SetMessage(mtInfo, cString::sprintf(tr("Moving dish to %.1f..."), double(positioner->TargetLongitude()) / 10));
80}
81
82// --- cSkinDisplayMenu ------------------------------------------------------
83
89
94
95void cSkinDisplayMenu::SetTabs(int Tab1, int Tab2, int Tab3, int Tab4, int Tab5)
96{
97 tabs[0] = 0;
98 tabs[1] = Tab1;
99 tabs[2] = Tab2;
100 tabs[3] = Tab3;
101 tabs[4] = Tab4;
102 tabs[5] = Tab5;
103 for (int i = 1; i < MaxTabs; i++) {
104 if (tabs[i]) {
105 tabs[i] *= (tabs[i] < 0) ? -1 : AvgCharWidth();
106 tabs[i] += tabs[i - 1];
107 }
108 }
109}
110
111void cSkinDisplayMenu::Scroll(bool Up, bool Page)
112{
113 textScroller.Scroll(Up, Page);
114}
115
116const char *cSkinDisplayMenu::GetTabbedText(const char *s, int Tab)
117{
118 if (!s)
119 return NULL;
120 static char buffer[1000];
121 const char *a = s;
122 const char *b = strchrnul(a, '\t');
123 while (*b && Tab-- > 0) {
124 a = b + 1;
125 b = strchrnul(a, '\t');
126 }
127 if (!*b)
128 return (Tab <= 0) ? a : NULL;
129 unsigned int n = b - a;
130 if (n >= sizeof(buffer))
131 n = sizeof(buffer) - 1;
132 strncpy(buffer, a, n);
133 buffer[n] = 0;
134 return buffer;
135}
136
137void cSkinDisplayMenu::SetScrollbar(int Total, int Offset)
138{
139}
140
142{
143 return 0;
144}
145
146const cFont *cSkinDisplayMenu::GetTextAreaFont(bool FixedFont) const
147{
148 return cFont::GetFont(FixedFont ? fontFix : fontOsd);
149}
150
151// --- cSkinDisplayReplay::cProgressBar --------------------------------------
152
153cSkinDisplayReplay::cProgressBar::cProgressBar(int Width, int Height, int Current, int Total, const cMarks *Marks, tColor ColorSeen, tColor ColorRest, tColor ColorSelected, tColor ColorMark, tColor ColorCurrent)
154:cSkinDisplayReplay::cProgressBar::cProgressBar(Width, Height, Current, Total, Marks, NULL, ColorSeen, ColorRest, ColorSelected, ColorMark, ColorCurrent, clrBlack)
155{
156}
157
158cSkinDisplayReplay::cProgressBar::cProgressBar(int Width, int Height, int Current, int Total, const cMarks *Marks, const cErrors *Errors, tColor ColorSeen, tColor ColorRest, tColor ColorSelected, tColor ColorMark, tColor ColorCurrent, tColor ColorError)
159:cBitmap(Width, Height, 4)
160{
161 total = Total;
162 if (total > 0) {
163 int p = Pos(Current);
164 DrawRectangle(0, 0, p, Height - 1, ColorSeen);
165 DrawRectangle(p + 1, 0, Width - 1, Height - 1, ColorRest);
166 if (Marks) {
167 bool Start = true;
168 for (const cMark *m = Marks->First(); m; m = Marks->Next(m)) {
169 int p1 = Pos(m->Position());
170 if (Start) {
171 const cMark *m2 = Marks->Next(m);
172 int p2 = Pos(m2 ? m2->Position() : total);
173 int h = Height / 3;
174 DrawRectangle(p1, h, p2, Height - h - 1, ColorSelected);
175 }
176 Mark(p1, Start, m->Position() == Current, ColorMark, ColorCurrent);
177 Start = !Start;
178 }
179 }
180 if (Errors) {
181 int LastPos = -1;
182 for (int i = 0; i < Errors->Size(); i++) {
183 int p1 = Errors->At(i);
184 if (p1 != LastPos) {
185 Error(Pos(Errors->At(i)), ColorError);
186 LastPos = p1;
187 }
188 }
189 }
190 }
191}
192
193void cSkinDisplayReplay::cProgressBar::Mark(int x, bool Start, bool Current, tColor ColorMark, tColor ColorCurrent)
194{
195 DrawRectangle(x, 0, x, Height() - 1, ColorMark);
196 const int d = Height() / (Current ? 3 : 9);
197 for (int i = 0; i < d; i++) {
198 int h = Start ? i : Height() - 1 - i;
199 DrawRectangle(x - d + i, h, x + d - i, h, Current ? ColorCurrent : ColorMark);
200 }
201}
202
204{
205 const int d = (Height() / 9) & ~0x01; // must be even
206 const int h = Height() / 2;
207 const int e = Height() / 4;
208 DrawRectangle(x, e, x, Height() -e - 1, ColorError);
209 DrawRectangle(x - d, h, x + d, h, ColorError);
210 for (int i = 1; i <= d; i++) {
211 DrawRectangle(x - d + i, h - i, x + d - i, h - i, ColorError);
212 DrawRectangle(x - d + i, h + i, x + d - i, h + i, ColorError);
213 }
214}
215
216// --- cSkinDisplayReplay ----------------------------------------------------
217
219{
220 marks = NULL;
221 errors = NULL;
222}
223
225{
226 SetTitle(Recording->Title());
227}
228
230{
231 marks = Marks;
232}
233
235{
236 errors = Errors;
237}
238
239// --- cSkin -----------------------------------------------------------------
240
242{
243 name = strdup(Name);
244 theme = Theme;
245 if (theme)
247 Skins.Add(this);
248}
249
251{
252 free(name);
253}
254
255// --- cSkins ----------------------------------------------------------------
256
258
260{
261 displayMessage = NULL;
262}
263
265{
266 delete displayMessage;
267}
268
269bool cSkins::SetCurrent(const char *Name)
270{
271 if (Name) {
272 for (cSkin *Skin = First(); Skin; Skin = Next(Skin)) {
273 if (strcmp(Skin->Name(), Name) == 0) {
274 isyslog("setting current skin to \"%s\"", Name);
275 current = Skin;
276 return true;
277 }
278 }
279 }
280 current = First();
281 if (current)
282 isyslog("skin \"%s\" not available - using \"%s\" instead", Name, current->Name());
283 else
284 esyslog("ERROR: no skin available");
285 return current != NULL;
286}
287
288eKeys cSkins::Message(eMessageType Type, const char *s, int Seconds)
289{
290 if (!cThread::IsMainThread()) {
291 if (Type != mtStatus)
292 QueueMessage(Type, s, Seconds);
293 else
294 dsyslog("cSkins::Message(%d, \"%s\", %d) called from background thread - ignored! (Use cSkins::QueueMessage() instead)", Type, s, Seconds);
295 return kNone;
296 }
297 switch (Type) {
298 case mtInfo: isyslog("info: %s", s); break;
299 case mtWarning: isyslog("warning: %s", s); break;
300 case mtError: esyslog("ERROR: %s", s); break;
301 default: ;
302 }
303 if (!Current())
304 return kNone;
305 if (!cSkinDisplay::Current()) {
306 if (displayMessage)
307 delete displayMessage;
308 displayMessage = Current()->DisplayMessage();
309 }
313 eKeys k = kNone;
314 if (Type != mtStatus) {
315 k = Interface->Wait(Seconds);
316 if (displayMessage) {
317 delete displayMessage;
318 displayMessage = NULL;
320 }
321 else {
322 cSkinDisplay::Current()->SetMessage(Type, NULL);
324 }
325 }
326 else if (!s && displayMessage) {
327 delete displayMessage;
328 displayMessage = NULL;
330 }
331 return k;
332}
333
334int cSkins::QueueMessage(eMessageType Type, const char *s, int Seconds, int Timeout)
335{
336 if (Type == mtStatus) {
337 dsyslog("cSkins::QueueMessage() called with mtStatus - ignored!");
338 return kNone;
339 }
340 if (isempty(s)) {
341 if (!cThread::IsMainThread()) {
342 queueMessageMutex.Lock();
343 for (cSkinQueuedMessage *m = SkinQueuedMessages.Last(); m; m = SkinQueuedMessages.Prev(m)) {
344 if (m->threadId == cThread::ThreadId() && m->state == 0)
345 m->state = 2; // done
346 }
347 queueMessageMutex.Unlock();
348 }
349 else
350 dsyslog("cSkins::QueueMessage() called with empty message from main thread - ignored!");
351 return kNone;
352 }
353 int k = kNone;
354 if (Timeout > 0) {
355 if (cThread::IsMainThread()) {
356 dsyslog("cSkins::QueueMessage() called from main thread with Timeout = %d - ignored!", Timeout);
357 return k;
358 }
359 cSkinQueuedMessage *m = new cSkinQueuedMessage(Type, s, Seconds, Timeout);
360 queueMessageMutex.Lock();
361 SkinQueuedMessages.Add(m);
362 m->mutex.Lock();
363 queueMessageMutex.Unlock();
364 if (m->condVar.TimedWait(m->mutex, Timeout * 1000))
365 k = m->key;
366 else
367 k = -1; // timeout, nothing has been displayed
368 m->state = 2; // done
369 m->mutex.Unlock();
370 }
371 else {
372 queueMessageMutex.Lock();
373 // Check if there is a waiting message w/o timeout for this thread:
374 if (Timeout == -1) {
375 for (cSkinQueuedMessage *m = SkinQueuedMessages.Last(); m; m = SkinQueuedMessages.Prev(m)) {
376 if (m->threadId == cThread::ThreadId()) {
377 if (m->state == 0 && m->timeout == -1)
378 m->state = 2; // done
379 break;
380 }
381 }
382 }
383 // Add the new message:
384 SkinQueuedMessages.Add(new cSkinQueuedMessage(Type, s, Seconds, Timeout));
385 queueMessageMutex.Unlock();
386 }
387 return k;
388}
389
391{
392 if (!cThread::IsMainThread()) {
393 dsyslog("cSkins::ProcessQueuedMessages() called from background thread - ignored!");
394 return;
395 }
396 // Check whether there is a cSkinDisplay object (if any) that implements SetMessage():
398 if (!(dynamic_cast<cSkinDisplayChannel *>(sd) ||
399 dynamic_cast<cSkinDisplayMenu *>(sd) ||
400 dynamic_cast<cSkinDisplayReplay *>(sd) ||
401 dynamic_cast<cSkinDisplayMessage *>(sd)))
402 return;
403 }
404 cSkinQueuedMessage *msg = NULL;
405 // Get the first waiting message:
406 queueMessageMutex.Lock();
407 for (cSkinQueuedMessage *m = SkinQueuedMessages.First(); m; m = SkinQueuedMessages.Next(m)) {
408 if (m->state == 0) { // waiting
409 m->state = 1; // active
410 msg = m;
411 break;
412 }
413 }
414 queueMessageMutex.Unlock();
415 // Display the message:
416 if (msg) {
417 msg->mutex.Lock();
418 if (msg->state == 1) { // might have changed since we got it
419 msg->key = Skins.Message(msg->type, msg->message, msg->seconds);
420 if (msg->timeout == 0)
421 msg->state = 2; // done
422 else
423 msg->condVar.Broadcast();
424 }
425 msg->mutex.Unlock();
426 }
427 // Remove done messages from the queue:
428 queueMessageMutex.Lock();
429 for (;;) {
431 if (m && m->state == 2) { // done
432 SkinQueuedMessages.Del(m);
433 }
434 else
435 break;
436 }
437 queueMessageMutex.Unlock();
438}
439
441{
444}
445
447{
448 if (displayMessage) {
449 delete displayMessage;
450 displayMessage = NULL;
451 }
453}
int Height(void) const
Definition osd.h:190
void DrawRectangle(int x1, int y1, int x2, int y2, tColor Color)
Draws a filled rectangle defined by the upper left (x1, y1) and lower right (x2, y2) corners with the...
Definition osd.c:611
cBitmap(int Width, int Height, int Bpp, int X0=0, int Y0=0)
Creates a bitmap with the given Width, Height and color depth (Bpp).
Definition osd.c:261
int Width(void) const
Definition osd.h:189
bool TimedWait(cMutex &Mutex, int TimeoutMs)
Definition thread.c:135
void Broadcast(void)
Definition thread.c:155
Definition font.h:37
static const cFont * GetFont(eDvbFont Font)
Gets the given Font, which was previously set by a call to SetFont().
Definition font.c:412
virtual void Clear(void)
Definition tools.c:2275
cListObject(const cListObject &ListObject)
Definition tools.h:547
Definition tools.h:644
const T * First(void) const
Returns the first element in this list, or NULL if the list is empty.
Definition tools.h:656
const T * Next(const T *Object) const
< Returns the element immediately before Object in this list, or NULL if Object is the first element ...
Definition tools.h:663
int Position(void) const
Definition recording.h:412
void Lock(void)
Definition thread.c:228
void Unlock(void)
Definition thread.c:242
A steerable satellite dish generally points to the south on the northern hemisphere,...
Definition positioner.h:31
const char * Title(char Delimiter=' ', bool NewIndicator=false, int Level=-1) const
Definition recording.c:1257
virtual void SetPositioner(const cPositioner *Positioner)
Sets the Positioner used to move the satellite dish.
Definition skins.c:73
cSkinDisplayChannel(void)
Definition skins.c:68
virtual void SetMessage(eMessageType Type, const char *Text) override=0
Sets a one line message Text, with the given Type.
const cPositioner * positioner
< This class is used to display the current channel, together with the present and following EPG even...
Definition skins.h:70
eMenuCategory menuCategory
Definition skins.h:171
virtual void Scroll(bool Up, bool Page)
If this menu contains a text area that can be scrolled, this function will be called to actually scro...
Definition skins.c:111
virtual void SetTabs(int Tab1, int Tab2=0, int Tab3=0, int Tab4=0, int Tab5=0)
Sets the tab columns to the given values, which are the number of characters in each column.
Definition skins.c:95
virtual int GetTextAreaWidth(void) const
Returns the width in pixel of the area which is used to display text with SetText().
Definition skins.c:141
cTextScroller textScroller
Definition skins.h:174
int Tab(int n)
Returns the offset of the given tab from the left border of the item display area.
Definition skins.h:175
eMenuCategory MenuCategory(void) const
Returns the menu category, set by a previous call to SetMenuCategory().
Definition skins.h:184
virtual void SetScrollbar(int Total, int Offset)
Sets the Total number of items in the currently displayed list, and the Offset of the first item that...
Definition skins.c:137
virtual const cFont * GetTextAreaFont(bool FixedFont) const
Returns a pointer to the font which is used to display text with SetText().
Definition skins.c:146
cSkinDisplayMenu(void)
Definition skins.c:84
const char * GetTabbedText(const char *s, int Tab)
Returns the part of the given string that follows the given Tab (where 0 indicates the beginning of t...
Definition skins.c:116
virtual void SetMenuCategory(eMenuCategory MenuCategory)
Sets the current menu category.
Definition skins.c:90
int tabs[MaxTabs]
Definition skins.h:172
void Mark(int x, bool Start, bool Current, tColor ColorMark, tColor ColorCurrent)
Definition skins.c:193
cProgressBar(int Width, int Height, int Current, int Total, const cMarks *Marks, tColor ColorSeen, tColor ColorRest, tColor ColorSelected, tColor ColorMark, tColor ColorCurrent)
Definition skins.c:153
void Error(int x, tColor ColorError)
Definition skins.c:203
virtual void SetErrors(const cErrors *Errors)
Sets the errors found in the recording to Errors, which shall be used to display the progress bar thr...
Definition skins.c:234
virtual void SetMarks(const cMarks *Marks)
Sets the editing marks to Marks, which shall be used to display the progress bar through a cProgressB...
Definition skins.c:229
virtual void SetTitle(const char *Title)=0
Sets the title of the recording.
virtual void SetRecording(const cRecording *Recording)
Sets the recording that is currently being played.
Definition skins.c:224
const cErrors * errors
Definition skins.h:321
cSkinDisplayReplay(void)
Definition skins.c:218
const cMarks * marks
< This class implements the progress display used during replay of a recording.
Definition skins.h:320
static cSkinDisplay * Current(void)
Returns the currently active cSkinDisplay.
Definition skins.h:61
static cSkinDisplay * current
Definition skins.h:41
virtual void Flush(void)
Actually draws the OSD display to the output device.
Definition skins.h:59
cSkinDisplay(void)
Definition skins.c:55
int editableWidth
Definition skins.h:42
virtual ~cSkinDisplay()
Definition skins.c:61
virtual void SetMessage(eMessageType Type, const char *Text)
Sets a one line message Text, with the given Type.
Definition skins.h:56
static int AvgCharWidth(void)
Returns the average width of a character in pixel (just a raw estimate).
Definition skins.h:46
cSkinQueuedMessage(eMessageType Type, const char *s, int Seconds, int Timeout)
Definition skins.c:33
tThreadId threadId
Definition skins.c:23
eMessageType type
Definition skins.c:19
char * message
Definition skins.c:20
friend class cSkins
Definition skins.c:17
virtual ~cSkinQueuedMessage() override
Definition skins.c:44
cCondVar condVar
Definition skins.c:27
Definition skins.h:405
cTheme * Theme(void)
Definition skins.h:425
const char * Name(void)
Definition skins.h:424
cTheme * theme
Definition skins.h:408
virtual ~cSkin() override
Definition skins.c:250
char * name
Definition skins.h:407
cSkin(const char *Name, cTheme *Theme=NULL)
Creates a new skin class, with the given Name and Theme.
Definition skins.c:241
bool SetCurrent(const char *Name=NULL)
Sets the current skin to the one indicated by name.
Definition skins.c:269
eKeys Message(eMessageType Type, const char *s, int Seconds=0)
Displays the given message, either through a currently visible display object that is capable of doin...
Definition skins.c:288
void Flush(void)
Flushes the currently active cSkinDisplay, if any.
Definition skins.c:440
~cSkins()
Definition skins.c:264
cSkin * current
Definition skins.h:462
cMutex queueMessageMutex
Definition skins.h:464
cSkinDisplayMessage * displayMessage
Definition skins.h:463
void ProcessQueuedMessages(void)
Processes the first queued message, if any.
Definition skins.c:390
cSkins(void)
Definition skins.c:259
virtual void Clear(void) override
Free up all registered skins.
Definition skins.c:446
int QueueMessage(eMessageType Type, const char *s, int Seconds=0, int Timeout=0)
Like Message(), but this function may be called from a background thread.
Definition skins.c:334
static void MsgOsdStatusMessage(const char *Message)
Definition status.h:125
static void MsgOsdClear(void)
Definition status.c:93
static cString sprintf(const char *fmt,...) __attribute__((format(printf
Definition tools.c:1216
static void Save(const char *SkinName, cTheme *Theme)
Definition themes.c:270
static tThreadId IsMainThread(void)
Definition thread.h:132
static tThreadId ThreadId(void)
Definition thread.c:389
int Size(void) const
Definition tools.h:767
T & At(int Index) const
Definition tools.h:744
@ fontOsd
Definition font.h:22
@ fontFix
Definition font.h:23
uint32_t tColor
Definition font.h:30
#define tr(s)
Definition i18n.h:85
cInterface * Interface
Definition interface.c:20
eKeys
Definition keys.h:16
@ kNone
Definition keys.h:55
#define clrBlack
Definition skincurses.c:37
cList< cSkinQueuedMessage > SkinQueuedMessages
Definition skins.c:49
cSkins Skins
Definition skins.c:257
cSkins Skins
Definition skins.c:257
eMenuCategory
Definition skins.h:104
@ mcUndefined
Definition skins.h:105
eMessageType
Definition skins.h:37
@ mtWarning
Definition skins.h:37
@ mtInfo
Definition skins.h:37
@ mtError
Definition skins.h:37
@ mtStatus
Definition skins.h:37
pid_t tThreadId
Definition thread.h:17
bool isempty(const char *s)
Definition tools.c:361
#define dsyslog(a...)
Definition tools.h:37
#define esyslog(a...)
Definition tools.h:35
#define isyslog(a...)
Definition tools.h:36