Video-Frame (not sample)
[ardour.git] / libs / pbd / base_ui.cc
1 /*
2     Copyright (C) 2000-2007 Paul Davis
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 #include <cstring>
21 #include <stdint.h>
22 #ifdef COMPILER_MSVC
23 #include <io.h>      // Microsoft's nearest equivalent to <unistd.h>
24 #else
25 #include <unistd.h>
26 #endif
27 #include <fcntl.h>
28 #include <cerrno>
29 #include <cstring>
30
31 #include <pthread.h>
32 #include <sched.h>
33
34 #include "pbd/base_ui.h"
35 #include "pbd/debug.h"
36 #include "pbd/pthread_utils.h"
37 #include "pbd/error.h"
38 #include "pbd/compose.h"
39 #include "pbd/failed_constructor.h"
40
41 #include "pbd/i18n.h"
42
43 #include "pbd/debug.h"
44
45 using namespace std;
46 using namespace PBD;
47 using namespace Glib;
48
49 uint64_t BaseUI::rt_bit = 1;
50 BaseUI::RequestType BaseUI::CallSlot = BaseUI::new_request_type();
51 BaseUI::RequestType BaseUI::Quit = BaseUI::new_request_type();
52
53 BaseUI::BaseUI (const string& loop_name)
54         : EventLoop (loop_name)
55         , m_context(MainContext::get_default())
56         , run_loop_thread (0)
57         , request_channel (true)
58 {
59         base_ui_instance = this;
60         request_channel.set_receive_handler (sigc::mem_fun (*this, &BaseUI::request_handler));
61
62         /* derived class must set _ok */
63 }
64
65 BaseUI::~BaseUI()
66 {
67 }
68
69 BaseUI::RequestType
70 BaseUI::new_request_type ()
71 {
72         RequestType rt;
73
74         /* XXX catch out-of-range */
75
76         rt = RequestType (rt_bit);
77         rt_bit <<= 1;
78
79         return rt;
80 }
81
82 int
83 BaseUI::set_thread_priority (const int policy, int priority) const
84 {
85         return pbd_set_thread_priority (pthread_self(), policy, priority);
86 }
87
88 void
89 BaseUI::main_thread ()
90 {
91         DEBUG_TRACE (DEBUG::EventLoop, string_compose ("%1: event loop running in thread %2\n", event_loop_name(), pthread_name()));
92         set_event_loop_for_thread (this);
93         thread_init ();
94         _main_loop->get_context()->signal_idle().connect (sigc::mem_fun (*this, &BaseUI::signal_running));
95         _main_loop->run ();
96 }
97
98 bool
99 BaseUI::signal_running ()
100 {
101         Glib::Threads::Mutex::Lock lm (_run_lock);
102         _running.signal ();
103
104         return false; // don't call it again
105 }
106
107 void
108 BaseUI::run ()
109 {
110         /* to be called by UI's that need/want their own distinct, self-created event loop thread.
111         */
112
113         m_context = MainContext::create();
114         _main_loop = MainLoop::create (m_context);
115         attach_request_source ();
116
117         Glib::Threads::Mutex::Lock lm (_run_lock);
118         run_loop_thread = Glib::Threads::Thread::create (mem_fun (*this, &BaseUI::main_thread));
119         _running.wait (_run_lock);
120 }
121
122 void
123 BaseUI::quit ()
124 {
125         if (_main_loop && _main_loop->is_running()) {
126                 _main_loop->quit ();
127                 run_loop_thread->join ();
128         }
129 }
130
131 bool
132 BaseUI::request_handler (Glib::IOCondition ioc)
133 {
134         /* check the request pipe */
135
136         if (ioc & ~IO_IN) {
137                 _main_loop->quit ();
138         }
139
140         if (ioc & IO_IN) {
141                 request_channel.drain ();
142
143                 /* there may been an error. we'd rather handle requests first,
144                    and then get IO_HUP or IO_ERR on the next loop.
145                 */
146
147                 /* handle requests */
148
149                 DEBUG_TRACE (DEBUG::EventLoop, string_compose ("%1: request handler\n", event_loop_name()));
150                 handle_ui_requests ();
151         }
152
153         return true;
154 }
155
156 void
157 BaseUI::signal_new_request ()
158 {
159         DEBUG_TRACE (DEBUG::EventLoop, string_compose ("%1: signal_new_request\n", event_loop_name()));
160         request_channel.wakeup ();
161 }
162
163 /**
164  * This method relies on the caller having already set m_context
165  */
166 void
167 BaseUI::attach_request_source ()
168 {
169         DEBUG_TRACE (DEBUG::EventLoop, string_compose ("%1: attach request source\n", event_loop_name()));
170         request_channel.attach (m_context);
171 }