/[svn]/gigedit/trunk/src/gigedit/gigedit.cpp
ViewVC logotype

Contents of /gigedit/trunk/src/gigedit/gigedit.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2332 - (show annotations) (download)
Wed Mar 14 05:22:26 2012 UTC (12 years ago) by persson
File size: 9796 byte(s)
* compilation fix: glibmm threads API was changed (#178)

1 /*
2 * Copyright (C) 2007-2009 Andreas Persson
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2, or (at
7 * your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with program; see the file COPYING. If not, write to the Free
16 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
17 * 02110-1301 USA.
18 */
19
20 #include "gigedit.h"
21
22 #include <glibmm/dispatcher.h>
23 #include <glibmm/main.h>
24 #include <gtkmm/main.h>
25
26 #include "mainwindow.h"
27
28 #include "global.h"
29
30 namespace {
31
32 // State for a gigedit thread.
33 //
34 // This class is only used when gigedit is run as a plugin and makes
35 // sure that there's only one Gtk::Main event loop. The event loop is
36 // started in a separate thread. The plugin thread just dispatches an
37 // event to the main loop to open a window and then goes to sleep
38 // until the window is closed.
39 //
40 class GigEditState : public sigc::trackable {
41 public:
42 GigEditState(GigEdit* parent) : parent(parent) { }
43 void run(gig::Instrument* pInstrument);
44
45 MainWindow* window;
46
47 private:
48
49 // simple condition variable abstraction
50 class Cond {
51 private:
52 bool pred;
53 Glib::Threads::Mutex mutex;
54 Glib::Threads::Cond cond;
55 public:
56 Cond() : pred(false) { }
57 void signal() {
58 Glib::Threads::Mutex::Lock lock(mutex);
59 pred = true;
60 cond.signal();
61 }
62 void wait() {
63 Glib::Threads::Mutex::Lock lock(mutex);
64 while (!pred) cond.wait(mutex);
65 }
66 };
67
68 #ifdef OLD_THREADS
69 static Glib::StaticMutex mutex;
70 #else
71 static Glib::Threads::Mutex mutex;
72 #endif
73 static Glib::Dispatcher* dispatcher;
74 static GigEditState* current;
75
76 static void main_loop_run(Cond* intialized);
77 static void open_window_static();
78
79 GigEdit* parent;
80 Cond open;
81 Cond close;
82 gig::Instrument* instrument;
83
84 void open_window();
85 void close_window();
86 };
87
88 #ifdef WIN32
89 HINSTANCE gigedit_dll_handle = 0;
90 #endif
91
92 void init_app() {
93 static bool process_initialized = false;
94 if (!process_initialized) {
95 std::cout << "Initializing 3rd party services needed by gigedit.\n"
96 << std::flush;
97 setlocale(LC_ALL, "");
98
99 #if HAVE_GETTEXT
100
101 #ifdef WIN32
102 #if GLIB_CHECK_VERSION(2, 16, 0)
103 gchar* root =
104 g_win32_get_package_installation_directory_of_module(gigedit_dll_handle);
105 #else
106 gchar* root =
107 g_win32_get_package_installation_directory(NULL, NULL);
108 #endif
109 gchar* temp = g_build_filename(root, "/share/locale", NULL);
110 g_free(root);
111 gchar* localedir = g_win32_locale_filename_from_utf8(temp);
112 g_free(temp);
113 bindtextdomain(GETTEXT_PACKAGE, localedir);
114 g_free(localedir);
115 #else
116 bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
117 #endif
118 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
119 textdomain(GETTEXT_PACKAGE);
120 #endif // HAVE_GETTEXT
121
122 #ifdef OLD_THREADS
123 // make sure thread_init() is called once and ONLY once per process
124 if (!Glib::thread_supported()) Glib::thread_init();
125 #endif
126 process_initialized = true;
127 }
128 }
129
130 void connect_signals(GigEdit* gigedit, MainWindow* mainwindow) {
131 // the signals of the "GigEdit" class are actually just proxies, that
132 // is they simply forward the signals of the internal classes to the
133 // outer world
134 mainwindow->signal_file_structure_to_be_changed().connect(
135 gigedit->signal_file_structure_to_be_changed().make_slot()
136 );
137 mainwindow->signal_file_structure_changed().connect(
138 gigedit->signal_file_structure_changed().make_slot()
139 );
140 mainwindow->signal_samples_to_be_removed().connect(
141 gigedit->signal_samples_to_be_removed().make_slot()
142 );
143 mainwindow->signal_samples_removed().connect(
144 gigedit->signal_samples_removed().make_slot()
145 );
146 mainwindow->signal_region_to_be_changed().connect(
147 gigedit->signal_region_to_be_changed().make_slot()
148 );
149 mainwindow->signal_region_changed().connect(
150 gigedit->signal_region_changed().make_slot()
151 );
152 mainwindow->signal_dimreg_to_be_changed().connect(
153 gigedit->signal_dimreg_to_be_changed().make_slot()
154 );
155 mainwindow->signal_dimreg_changed().connect(
156 gigedit->signal_dimreg_changed().make_slot()
157 );
158 mainwindow->signal_sample_changed().connect(
159 gigedit->signal_sample_changed().make_slot()
160 );
161 mainwindow->signal_sample_ref_changed().connect(
162 gigedit->signal_sample_ref_changed().make_slot()
163 );
164 mainwindow->signal_keyboard_key_hit().connect(
165 gigedit->signal_keyboard_key_hit().make_slot()
166 );
167 mainwindow->signal_keyboard_key_released().connect(
168 gigedit->signal_keyboard_key_released().make_slot()
169 );
170 }
171
172 } // namespace
173
174 GigEdit::GigEdit() {
175 state = NULL;
176 }
177
178 int GigEdit::run(int argc, char* argv[]) {
179 init_app();
180
181 Gtk::Main kit(argc, argv);
182 MainWindow window;
183 connect_signals(this, &window);
184 if (argc >= 2) window.load_file(argv[1]);
185 kit.run(window);
186 return 0;
187 }
188
189 int GigEdit::run(gig::Instrument* pInstrument) {
190 init_app();
191
192 GigEditState state(this);
193 this->state = &state;
194 state.run(pInstrument);
195 this->state = NULL;
196 return 0;
197 }
198
199 void GigEdit::on_note_on_event(int key, int velocity) {
200 if (!this->state) return;
201 GigEditState* state = (GigEditState*) this->state;
202 state->window->signal_note_on().emit(key, velocity);
203 }
204
205 void GigEdit::on_note_off_event(int key, int velocity) {
206 if (!this->state) return;
207 GigEditState* state = (GigEditState*) this->state;
208 state->window->signal_note_off().emit(key, velocity);
209 }
210
211 sigc::signal<void, gig::File*>& GigEdit::signal_file_structure_to_be_changed() {
212 return file_structure_to_be_changed_signal;
213 }
214
215 sigc::signal<void, gig::File*>& GigEdit::signal_file_structure_changed() {
216 return file_structure_changed_signal;
217 }
218
219 sigc::signal<void, std::list<gig::Sample*> >& GigEdit::signal_samples_to_be_removed() {
220 return samples_to_be_removed_signal;
221 }
222
223 sigc::signal<void>& GigEdit::signal_samples_removed() {
224 return samples_removed_signal;
225 }
226
227 sigc::signal<void, gig::Region*>& GigEdit::signal_region_to_be_changed() {
228 return region_to_be_changed_signal;
229 }
230
231 sigc::signal<void, gig::Region*>& GigEdit::signal_region_changed() {
232 return region_changed_signal;
233 }
234
235 sigc::signal<void, gig::DimensionRegion*>& GigEdit::signal_dimreg_to_be_changed() {
236 return dimreg_to_be_changed_signal;
237 }
238
239 sigc::signal<void, gig::DimensionRegion*>& GigEdit::signal_dimreg_changed() {
240 return dimreg_changed_signal;
241 }
242
243 sigc::signal<void, gig::Sample*>& GigEdit::signal_sample_changed() {
244 return sample_changed_signal;
245 }
246
247 sigc::signal<void, gig::Sample*/*old*/, gig::Sample*/*new*/>& GigEdit::signal_sample_ref_changed() {
248 return sample_ref_changed_signal;
249 }
250
251 sigc::signal<void, int/*key*/, int/*velocity*/>& GigEdit::signal_keyboard_key_hit() {
252 return keyboard_key_hit_signal;
253 }
254
255 sigc::signal<void, int/*key*/, int/*velocity*/>& GigEdit::signal_keyboard_key_released() {
256 return keyboard_key_released_signal;
257 }
258
259 #ifdef OLD_THREADS
260 Glib::StaticMutex GigEditState::mutex = GLIBMM_STATIC_MUTEX_INIT;
261 #else
262 Glib::Threads::Mutex GigEditState::mutex;
263 #endif
264 Glib::Dispatcher* GigEditState::dispatcher = 0;
265 GigEditState* GigEditState::current = 0;
266
267 void GigEditState::open_window_static() {
268 GigEditState* c = GigEditState::current;
269 c->open.signal();
270 c->open_window();
271 }
272
273 void GigEditState::open_window() {
274 window = new MainWindow();
275
276 connect_signals(parent, window);
277 if (instrument) window->load_instrument(instrument);
278
279 window->signal_hide().connect(sigc::mem_fun(this,
280 &GigEditState::close_window));
281 window->present();
282 }
283
284 void GigEditState::close_window() {
285 delete window;
286 close.signal();
287 }
288
289 void GigEditState::main_loop_run(Cond* initialized) {
290 int argc = 1;
291 const char* argv_c[] = { "gigedit" };
292 char** argv = const_cast<char**>(argv_c);
293 Gtk::Main main_loop(argc, argv);
294
295 dispatcher = new Glib::Dispatcher();
296 dispatcher->connect(sigc::ptr_fun(&GigEditState::open_window_static));
297 initialized->signal();
298
299 main_loop.run();
300 }
301
302 void GigEditState::run(gig::Instrument* pInstrument) {
303 mutex.lock(); // lock access to static variables
304
305 static bool main_loop_started = false;
306 if (!main_loop_started) {
307 Cond initialized;
308 #ifdef OLD_THREADS
309 Glib::Thread::create(
310 sigc::bind(sigc::ptr_fun(&GigEditState::main_loop_run),
311 &initialized),
312 false);
313 #else
314 Glib::Threads::Thread::create(
315 sigc::bind(sigc::ptr_fun(&GigEditState::main_loop_run),
316 &initialized));
317 #endif
318 initialized.wait();
319 main_loop_started = true;
320 }
321 instrument = pInstrument;
322 current = this;
323 dispatcher->emit();
324 open.wait(); // wait until the GUI thread has read current
325 mutex.unlock();
326 close.wait(); // sleep until window is closed
327 }
328
329 #if defined(WIN32)
330 extern "C" {
331 BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved)
332 {
333 switch (reason) {
334 case DLL_PROCESS_ATTACH:
335 gigedit_dll_handle = instance;
336 break;
337 }
338 return TRUE;
339 }
340 }
341 #endif

  ViewVC Help
Powered by ViewVC