Logging improvements to allow prettier displays in the server GUI.
[dcpomatic.git] / src / lib / signaller.h
1 /*
2     Copyright (C) 2015 Carl Hetherington <cth@carlh.net>
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #ifndef DCPOMATIC_SIGNALLER_H
21 #define DCPOMATIC_SIGNALLER_H
22
23 #include "signal_manager.h"
24 #include <boost/thread/mutex.hpp>
25
26 class WrapperBase
27 {
28 public:
29         WrapperBase ()
30                 : _valid (true)
31                 , _finished (false)
32         {}
33
34         virtual ~WrapperBase () {}
35
36         /* Can be called from any thread */
37         void invalidate ()
38         {
39                 boost::mutex::scoped_lock lm (_mutex);
40                 _valid = false;
41         }
42
43         bool finished () const {
44                 boost::mutex::scoped_lock lm (_mutex);
45                 return _finished;
46         }
47
48 protected:
49         /* Protect _valid and _finished */
50         mutable boost::mutex _mutex;
51         bool _valid;
52         bool _finished;
53 };
54
55 /** Helper class to manage lifetime of signals, specifically to address
56  *  the problem where an object containing a signal is deleted before
57  *  its signal is emitted.
58  */
59 template <class T>
60 class Wrapper : public WrapperBase
61 {
62 public:
63         Wrapper (T signal)
64                 : _signal (signal)
65         {
66
67         }
68
69         /* Called by the UI thread only */
70         void signal ()
71         {
72                 boost::mutex::scoped_lock lm (_mutex);
73                 if (_valid) {
74                         _signal ();
75                 }
76                 _finished = true;
77         }
78
79 private:
80         T _signal;
81 };
82
83 /** Parent for any class which needs to raise cross-thread signals (from non-UI
84  *  to UI).  Subclasses should call, e.g. emit (boost::bind (boost::ref (MySignal), foo, bar));
85  */
86 class Signaller
87 {
88 public:
89         /* Can be called from any thread */
90         virtual ~Signaller () {
91                 boost::mutex::scoped_lock lm (_signaller_mutex);
92                 for (std::list<WrapperBase*>::iterator i = _wrappers.begin(); i != _wrappers.end(); ++i) {
93                         (*i)->invalidate ();
94                 }
95         }
96
97         /* Can be called from any thread */
98         template <class T>
99         void emit (T signal)
100         {
101                 Wrapper<T>* w = new Wrapper<T> (signal);
102                 if (signal_manager) {
103                         signal_manager->emit (boost::bind (&Wrapper<T>::signal, w));
104                 }
105
106                 boost::mutex::scoped_lock lm (_signaller_mutex);
107
108                 /* Clean up finished Wrappers */
109                 std::list<WrapperBase*>::iterator i = _wrappers.begin ();
110                 while (i != _wrappers.end ()) {
111                         std::list<WrapperBase*>::iterator tmp = i;
112                         ++tmp;
113                         if ((*i)->finished ()) {
114                                 delete *i;
115                                 _wrappers.erase (i);
116                         }
117                         i = tmp;
118                 }
119
120                 /* Add the new one */
121                 _wrappers.push_back (w);
122         }
123
124 private:
125         /* Protect _wrappers */
126         boost::mutex _signaller_mutex;
127         std::list<WrapperBase*> _wrappers;
128 };
129
130 #endif