File: osdobjectsbase.h

package info (click to toggle)
vdr-plugin-osdserver 0.1.3-23
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 392 kB
  • sloc: ansic: 3,165; perl: 923; sh: 180; makefile: 46
file content (354 lines) | stat: -rw-r--r-- 9,997 bytes parent folder | download | duplicates (9)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
#ifndef __OSDSERVER_OSDOBJECTSBASE_H
#define __OSDSERVER_OSDOBJECTSBASE_H

#include <map>
#include <set>
#include <queue>

#include <vdr/tools.h>
#include <vdr/thread.h>
#include <vdr/osdbase.h>
#include <vdr/menuitems.h>

#include "tools.h"

class cServerContext;


class cOsdServerObject {
    // Generic base class for named and unnamed objects of the network interface.
    // These objects live in the network thread
    // These objects may 'own' a VDR main thread object.
    // The OsdServerObject holds a copy of the state of the VDR object, and
    // can push its state to the VDR object, or create it if it doesnt exist yet.
    // The VDR object can detach if its lifetime ends.
    // Before deleting this object, always call Detach().

private:
    int id;
    // Unique ID identifying any object
    
    static int nextId;
    // Common ID counter
    
    cServerContext *context;
    // The 'owning' context. Deleting this context deletes the object.
    // The object can be present in more contexts.

public:
    cOsdServerObject();
    virtual ~cOsdServerObject();

    // IDs to identify certain object instances from base class
    enum enumClassId {
        clsidMenu,
        clsidOsdItem,
        clsidMenuEditStrItem,
        clsidMenuEditIntItem,
        clsidMenuEditListItem
    };
    virtual enumClassId ClassId()=0;

    virtual bool IsMenuItem() { return false; }

    // Generic cast function that checks the id.
    // Use as baseobject->Cast<type>()
    template<class T> T* Cast() {
        if (ClassId() != T::classid) return NULL;
        return dynamic_cast<T*>(this);
    }

    // Context object name or NULL if not named
    inline cString Name();


    class cEvent {
    public:
        enum eventType { NullEvent, KeyEvent, CloseEvent, FocusEvent, BlurEvent, EditEvent } type;
        eKeys key;

        cEvent() { type = NullEvent; key = kNone; }
        cEvent(eventType t) { type = t; key = kNone; }
        cEvent(eKeys k) { type = KeyEvent; key = k; }
        
        bool operator<(const cEvent &ev) const {
            if (type == KeyEvent && ev.type == KeyEvent)
                return key < ev.key;
            return type < ev.type;
        }
    };
    class cTriggeredEvent : public cEvent {
    public:
        cOsdServerObject *source;
        
        cTriggeredEvent(cOsdServerObject *src, cEvent ev) : cEvent(ev) { source=src; }
        cTriggeredEvent(cOsdServerObject *src, eKeys k) : cEvent(k) { source=src; }
        cTriggeredEvent(cOsdServerObject *src, eventType t) : cEvent(t) { source=src; }
        cTriggeredEvent() { source=NULL; }
    };

protected:
    std::set<cEvent> enabledEvents;
    std::queue<cTriggeredEvent> eventQueue;
        
    // These are protected by LockShared mutex,
    // unless both threads are synchronized anyway.

    bool IsEventEnabled(cEvent event) {
        std::set<cEvent>::iterator i = enabledEvents.find(event);
        return i != enabledEvents.end();
    }
    
public:    
    void TriggerEvent(cOsdServerObject *src, cEvent ev) { 
        if (src->IsEventEnabled(ev)) eventQueue.push(cTriggeredEvent(src,ev)); 
    }
    void TriggerEvent(cEvent ev) { 
        TriggerEvent(this,ev); 
    }

    virtual bool EnableEvent(cEvent event) {
        enabledEvents.insert(event);
        return true;
    }
        
    virtual bool PollEvent(cTriggeredEvent &Event) { return false; }
    // Primitive event handling


    inline void SetFocusObject();
    // Set object as focused

    inline void UnsetFocusObject();
    // Set object as focused

    inline bool IsFocusObject();
    // Check whether object is focused

    friend class cServerContext;
};


struct ltcstrcase {
  bool operator()(const cString &s1, const cString &s2) const {
    return strcasecmp(s1, s2) < 0;
  }
};


class cServerContext {
    // Manage a collection of named OsdServerObjects.
    
    typedef std::map<cString, cOsdServerObject*, ltcstrcase> ObjectList;
    ObjectList objects; // Maps name to object
    
    typedef std::map<int, cString> IdList;
    IdList idList; // Maps id to name

    cServerContext *localContext;
    cServerContext *parentContext;
    
    cOsdServerObject *focusObject;
    
public:
    cOsdServerObject* GetName(const char *Name);
    // Get object by name
    
    cString GetNameById(int id) {
        // Get object name by id
        IdList::iterator i = idList.find(id);
        return (i != idList.end()) ? i->second : cString::sprintf("_%i", id);
    }

    void Add(cOsdServerObject *Object, cString Name);
    // Also sets the name of the object
    
    void Remove(cOsdServerObject *Object);
    // Removes an object from the context
    
    cServerContext* MakeLocalContext();
    // Create local context as alias of this one

    cServerContext* GetParentContext() { return parentContext; }
    // Get parent of this context, or NULL for topmost context

    void DestroyLocalContext();
    // Delete local contexts of this one
    
    cOsdServerObject* GetFocusObject();
    // Get the currently focused object (not menu items, just menus)

    cServerContext();
    virtual ~cServerContext();

    friend class cOsdServerObject;
};



// Forwarded inlines of cOsdServerObject

inline cString cOsdServerObject::Name() {
    return context ? context->GetNameById(id) : cString(); 
}

inline void cOsdServerObject::SetFocusObject() {
    if (context) context->focusObject = this; 
}

inline void cOsdServerObject::UnsetFocusObject() {
    if (context && context->focusObject == this) 
        context->focusObject = NULL;
}

inline bool cOsdServerObject::IsFocusObject() {
    return context ? (this == context->focusObject) : false;
}



class cOsdServerMenu;

class cOsdServerMenuItem : public cListObject, public cOsdServerObject {
    // Base class for menu items
    cOsdServerMenu *menu;
protected:
    virtual cOsdItem* GetItem()=0;

    cOsdServerMenuItem() { menu=NULL; }

public:
    cOsdServerMenu* GetMenu() { return menu; }

    virtual bool IsMenuItem() { return true; }

    virtual void ItemUpdate()=0;
    // Forwarder to cShadowBase if of that class
    
    virtual void ItemDetach()=0;
    // Forwarder to cShadowBase if of that class
    
    friend class cOsdServerMenu; // to set menu
};




class cShadowBase {
    // Abstract base class for shadowed objects. Acts as base class for cShadowTemplate

protected:
    bool Dirty;
    // =true means that this object has changes that are not yet Update()d to
    // the VDR object. Also means that the VDR object will not upload
    // local changes, they will be discarded on Update().
    // Protected by LockShared.

    static cMutex LockShared;
    // Common lock to access certain members from the VDR main thread

    class cPrivateBase {
    public:
        cShadowBase *Parent;
        // Parent is a pointer to the shadow object, or NULL if detached.
        // This member is protected by LockShared mutex.

        cPrivateBase(cShadowBase *parent);
        // Constructors are always called with synced threads

        virtual ~cPrivateBase();
        // Warning: Higher level destructors need to call Parent->Detach().
        // Foreground thread always calls destructor on its own
    };

public:
    virtual void Update()=0;
    // Push object status to VDR object or create VDR object.
    // Both threads MUST be synchronized before calling this

    virtual void Detach()=0;
    // Detach VDR object from this object. Can be called
    // from any context.

    virtual bool IsDetached()=0;
    // Check if object is 'live'

    cShadowBase();
    virtual ~cShadowBase() {};
};

template<class T> class cShadowTemplate : public cShadowBase {
    // VDR object shadow class
    // This template encapsulates a VDR object as cOsdServerShadow<T>::cPrivate
    // and provides the shadow cOsdServerObject for it.
    // cPrivate lives in the VDR main thread, while cOsdServerShadow lives in the network thread.
    // T needs to have a parameter-less constructor. Make one if you need one.

protected:

    class cPrivate : public T, public cShadowBase::cPrivateBase {
        public:
        inline cPrivate(cShadowTemplate<T> *parent) : cShadowBase::cPrivateBase(parent) { };

        friend class cShadowTemplate<T>;
    };
    
    cPrivate *Private;
    // Pointer to the shadowed VDR object, or NULL if none attached (yet).
    // Call Upade() to attach one.

public:
    // Constructor and destructor are called from network thread.
    // Warning: Higher level destructors need to call Detach().
    cShadowTemplate<T>() {
        Private=NULL;
    }

    virtual ~cShadowTemplate<T>() {
        cMutexLock Lock(&LockShared);
        if (Private) {
            esyslog("osdserver: hard detaching of OSD shadow object");
            Detach();
        }
    }

    virtual void Detach() {
        // This Detach() removes the cross-links between cOsdServerShadow and cPrivate.

        // Detach private VDR object, make it independent
        cMutexLock Lock(&LockShared);
    
        if (!Private) return; // already detached
    
        Private->Parent=NULL;
        Private=NULL;        
    }

    virtual bool IsDetached() { return Private==NULL; }
};

template<class T> class cShadowObjectTemplate : public cOsdServerObject, public cShadowTemplate<T> {
    virtual bool EnableEvent(cEvent event) {
        cMutexLock Lock(&cShadowBase::LockShared);
        return cOsdServerObject::EnableEvent(event);
    }
};

template<class T> class cShadowMenuItemTemplate : public cOsdServerMenuItem, public cShadowTemplate<T> {
public:
    using cShadowTemplate<T>::Update;
    using cShadowTemplate<T>::Detach;
    using cShadowTemplate<T>::Private;
    virtual void ItemUpdate() { Update(); }
    virtual void ItemDetach() { Detach(); }
    virtual cOsdItem* GetItem() { return Private; }
    
    virtual bool EnableEvent(cEvent event) {
        cMutexLock Lock(&cShadowBase::LockShared);
        return cOsdServerObject::EnableEvent(event);
    }
};



#endif