1 /*
2  * Copyright (C) 2000-2015 Paul Davis <paul@linuxaudiosystems.com>
3  * Copyright (C) 2013 John Emmas <john@creativepost.co.uk>
4  * Copyright (C) 2015-2017 Robin Gareus <robin@gareus.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20 
21 #ifndef __pbd_base_ui_h__
22 #define __pbd_base_ui_h__
23 
24 #include <string>
25 #include <stdint.h>
26 
27 #include <sigc++/slot.h>
28 #include <sigc++/trackable.h>
29 
30 #include <glibmm/threads.h>
31 #include <glibmm/main.h>
32 
33 #include "pbd/libpbd_visibility.h"
34 #include "pbd/crossthread.h"
35 #include "pbd/event_loop.h"
36 #include "pbd/pthread_utils.h"
37 
38 /** A BaseUI is an abstraction designed to be used with any "user
39  * interface" (not necessarily graphical) that needs to wait on
40  * events/requests and dispatch/process them as they arrive.
41  *
42  * This implementation starts up a thread that runs a Glib main loop
43  * to wait on events/requests etc.
44  */
45 
46 
47 class LIBPBD_API BaseUI : public sigc::trackable, public PBD::EventLoop
48 {
49   public:
50 	BaseUI (const std::string& name);
51 	virtual ~BaseUI();
52 
base_instance()53 	BaseUI* base_instance() { return base_ui_instance; }
54 
main_loop()55 	Glib::RefPtr<Glib::MainLoop> main_loop() const { return _main_loop; }
event_loop_thread()56         Glib::Threads::Thread* event_loop_thread() const { return run_loop_thread; }
caller_is_self()57         bool caller_is_self () const { return Glib::Threads::Thread::self() == run_loop_thread; }
58 
ok()59 	bool ok() const { return _ok; }
60 
61 	static RequestType new_request_type();
62 	static RequestType CallSlot;
63 	static RequestType Quit;
64 
set_thread_priority(int p)65 	static void set_thread_priority (int p) {
66 		_thread_priority = p;
67 	}
68 
69 	/** start up a thread to run the main loop
70 	 */
71 	void run ();
72 
73 	/** stop the thread running the main loop (and block
74 	 *   until it exits)
75 	 */
76 	void quit ();
77 
78   protected:
79 	bool _ok;
80 
81 	Glib::RefPtr<Glib::MainLoop> _main_loop;
82 	Glib::RefPtr<Glib::MainContext> m_context;
83 	Glib::Threads::Thread*       run_loop_thread;
84 	Glib::Threads::Mutex        _run_lock;
85 	Glib::Threads::Cond         _running;
86 
87 	/* this signals _running from within the event loop,
88 	   from an idle callback
89 	*/
90 
91 	bool signal_running ();
92 
93 	/** Derived UI objects can implement thread_init()
94 	 * which will be called by the event loop thread
95 	 * immediately before it enters the event loop.
96 	 */
97 
thread_init()98 	virtual void thread_init () {};
99 
100 	int set_thread_priority () const;
101 
102 	/** Called when there input ready on the request_channel
103 	 */
104 	bool request_handler (Glib::IOCondition);
105 
106 	void signal_new_request ();
107 	void attach_request_source ();
108 
109 	/** Derived UI objects must implement this method,
110 	 * which will be called whenever there are requests
111 	 * to be dealt with.
112 	 */
113 	virtual void handle_ui_requests () = 0;
114 
115   private:
116 	BaseUI* base_ui_instance;
117 
118 	CrossThreadChannel request_channel;
119 
120 	static uint64_t rt_bit;
121 	static int _thread_priority;
122 
123 	int setup_request_pipe ();
124 	void main_thread ();
125 };
126 
127 #endif /* __pbd_base_ui_h__ */
128