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

Annotation of /gigedit/trunk/src/gigedit/gigedit.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2332 - (hide 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 schoenebeck 1225 /*
2 persson 1898 * Copyright (C) 2007-2009 Andreas Persson
3 schoenebeck 1225 *
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 persson 2325 #include <glibmm/dispatcher.h>
23     #include <glibmm/main.h>
24 schoenebeck 1225 #include <gtkmm/main.h>
25 persson 2325
26 schoenebeck 1225 #include "mainwindow.h"
27    
28 schoenebeck 1396 #include "global.h"
29 schoenebeck 1225
30 persson 1456 namespace {
31 schoenebeck 1225
32 persson 1456 // 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 schoenebeck 1654 MainWindow* window;
46    
47 persson 1456 private:
48    
49     // simple condition variable abstraction
50     class Cond {
51     private:
52     bool pred;
53 persson 2325 Glib::Threads::Mutex mutex;
54     Glib::Threads::Cond cond;
55 persson 1456 public:
56     Cond() : pred(false) { }
57     void signal() {
58 persson 2325 Glib::Threads::Mutex::Lock lock(mutex);
59 persson 1456 pred = true;
60     cond.signal();
61     }
62     void wait() {
63 persson 2325 Glib::Threads::Mutex::Lock lock(mutex);
64 persson 1456 while (!pred) cond.wait(mutex);
65     }
66     };
67    
68 persson 2325 #ifdef OLD_THREADS
69 persson 1456 static Glib::StaticMutex mutex;
70 persson 2325 #else
71     static Glib::Threads::Mutex mutex;
72     #endif
73 persson 1456 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 persson 1898 #ifdef WIN32
89     HINSTANCE gigedit_dll_handle = 0;
90     #endif
91    
92 persson 1456 void init_app() {
93 schoenebeck 1333 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 schoenebeck 1396
99     #if HAVE_GETTEXT
100 persson 1823
101     #ifdef WIN32
102     #if GLIB_CHECK_VERSION(2, 16, 0)
103     gchar* root =
104 persson 1898 g_win32_get_package_installation_directory_of_module(gigedit_dll_handle);
105 persson 1823 #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 schoenebeck 1333 bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
117 persson 1823 #endif
118 schoenebeck 1333 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
119     textdomain(GETTEXT_PACKAGE);
120 schoenebeck 1396 #endif // HAVE_GETTEXT
121    
122 persson 2325 #ifdef OLD_THREADS
123 schoenebeck 1333 // make sure thread_init() is called once and ONLY once per process
124     if (!Glib::thread_supported()) Glib::thread_init();
125 persson 2325 #endif
126 schoenebeck 1333 process_initialized = true;
127     }
128 schoenebeck 1225 }
129    
130 persson 1456 void connect_signals(GigEdit* gigedit, MainWindow* mainwindow) {
131 schoenebeck 1322 // 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 schoenebeck 1853 mainwindow->signal_sample_changed().connect(
159     gigedit->signal_sample_changed().make_slot()
160     );
161 schoenebeck 1322 mainwindow->signal_sample_ref_changed().connect(
162     gigedit->signal_sample_ref_changed().make_slot()
163     );
164 schoenebeck 1660 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 schoenebeck 1322 }
171    
172 schoenebeck 1654 } // namespace
173    
174     GigEdit::GigEdit() {
175     state = NULL;
176 schoenebeck 1225 }
177    
178 persson 1456 int GigEdit::run(int argc, char* argv[]) {
179     init_app();
180    
181     Gtk::Main kit(argc, argv);
182 schoenebeck 1225 MainWindow window;
183 persson 1456 connect_signals(this, &window);
184     if (argc >= 2) window.load_file(argv[1]);
185 schoenebeck 1225 kit.run(window);
186     return 0;
187     }
188    
189     int GigEdit::run(gig::Instrument* pInstrument) {
190 persson 1456 init_app();
191    
192     GigEditState state(this);
193 schoenebeck 1654 this->state = &state;
194 persson 1456 state.run(pInstrument);
195 schoenebeck 1654 this->state = NULL;
196 schoenebeck 1225 return 0;
197     }
198 schoenebeck 1322
199 schoenebeck 1654 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 schoenebeck 1339 sigc::signal<void, gig::File*>& GigEdit::signal_file_structure_to_be_changed() {
212 schoenebeck 1322 return file_structure_to_be_changed_signal;
213     }
214    
215 schoenebeck 1339 sigc::signal<void, gig::File*>& GigEdit::signal_file_structure_changed() {
216 schoenebeck 1322 return file_structure_changed_signal;
217     }
218    
219 schoenebeck 1339 sigc::signal<void, std::list<gig::Sample*> >& GigEdit::signal_samples_to_be_removed() {
220 schoenebeck 1322 return samples_to_be_removed_signal;
221     }
222    
223 schoenebeck 1339 sigc::signal<void>& GigEdit::signal_samples_removed() {
224 schoenebeck 1322 return samples_removed_signal;
225     }
226    
227 schoenebeck 1339 sigc::signal<void, gig::Region*>& GigEdit::signal_region_to_be_changed() {
228 schoenebeck 1322 return region_to_be_changed_signal;
229     }
230    
231 schoenebeck 1339 sigc::signal<void, gig::Region*>& GigEdit::signal_region_changed() {
232 schoenebeck 1322 return region_changed_signal;
233     }
234    
235 schoenebeck 1339 sigc::signal<void, gig::DimensionRegion*>& GigEdit::signal_dimreg_to_be_changed() {
236 schoenebeck 1322 return dimreg_to_be_changed_signal;
237     }
238    
239 schoenebeck 1339 sigc::signal<void, gig::DimensionRegion*>& GigEdit::signal_dimreg_changed() {
240 schoenebeck 1322 return dimreg_changed_signal;
241     }
242    
243 schoenebeck 1853 sigc::signal<void, gig::Sample*>& GigEdit::signal_sample_changed() {
244     return sample_changed_signal;
245     }
246    
247 schoenebeck 1339 sigc::signal<void, gig::Sample*/*old*/, gig::Sample*/*new*/>& GigEdit::signal_sample_ref_changed() {
248 schoenebeck 1322 return sample_ref_changed_signal;
249     }
250 persson 1456
251 schoenebeck 1660 sigc::signal<void, int/*key*/, int/*velocity*/>& GigEdit::signal_keyboard_key_hit() {
252     return keyboard_key_hit_signal;
253     }
254 persson 1456
255 schoenebeck 1660 sigc::signal<void, int/*key*/, int/*velocity*/>& GigEdit::signal_keyboard_key_released() {
256     return keyboard_key_released_signal;
257     }
258    
259 persson 2325 #ifdef OLD_THREADS
260 persson 1456 Glib::StaticMutex GigEditState::mutex = GLIBMM_STATIC_MUTEX_INIT;
261 persson 2325 #else
262     Glib::Threads::Mutex GigEditState::mutex;
263     #endif
264 persson 1456 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 persson 2332 #ifdef OLD_THREADS
309     Glib::Thread::create(
310 persson 1456 sigc::bind(sigc::ptr_fun(&GigEditState::main_loop_run),
311     &initialized),
312     false);
313 persson 2332 #else
314     Glib::Threads::Thread::create(
315     sigc::bind(sigc::ptr_fun(&GigEditState::main_loop_run),
316     &initialized));
317     #endif
318 persson 1456 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 persson 1898
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