/[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 2471 - (hide annotations) (download)
Sun Sep 15 17:06:45 2013 UTC (10 years, 7 months ago) by persson
File size: 12147 byte(s)
* fixed compilation error from previous commit (on OS X without gettext)
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 2470 #ifdef __APPLE__
31     #include <dlfcn.h>
32     #include <glibmm/fileutils.h>
33     #include <glibmm/miscutils.h>
34     #endif
35    
36 persson 1456 namespace {
37 schoenebeck 1225
38 persson 1456 // State for a gigedit thread.
39     //
40     // This class is only used when gigedit is run as a plugin and makes
41     // sure that there's only one Gtk::Main event loop. The event loop is
42     // started in a separate thread. The plugin thread just dispatches an
43     // event to the main loop to open a window and then goes to sleep
44     // until the window is closed.
45     //
46     class GigEditState : public sigc::trackable {
47     public:
48     GigEditState(GigEdit* parent) : parent(parent) { }
49     void run(gig::Instrument* pInstrument);
50    
51 schoenebeck 1654 MainWindow* window;
52    
53 persson 1456 private:
54    
55     // simple condition variable abstraction
56     class Cond {
57     private:
58     bool pred;
59 persson 2325 Glib::Threads::Mutex mutex;
60     Glib::Threads::Cond cond;
61 persson 1456 public:
62     Cond() : pred(false) { }
63     void signal() {
64 persson 2325 Glib::Threads::Mutex::Lock lock(mutex);
65 persson 1456 pred = true;
66     cond.signal();
67     }
68     void wait() {
69 persson 2325 Glib::Threads::Mutex::Lock lock(mutex);
70 persson 1456 while (!pred) cond.wait(mutex);
71     }
72     };
73    
74 persson 2325 #ifdef OLD_THREADS
75 persson 1456 static Glib::StaticMutex mutex;
76 persson 2325 #else
77     static Glib::Threads::Mutex mutex;
78     #endif
79 persson 1456 static Glib::Dispatcher* dispatcher;
80     static GigEditState* current;
81    
82     static void main_loop_run(Cond* intialized);
83     static void open_window_static();
84    
85     GigEdit* parent;
86     Cond open;
87     Cond close;
88     gig::Instrument* instrument;
89    
90     void open_window();
91     void close_window();
92     };
93    
94 persson 1898 #ifdef WIN32
95     HINSTANCE gigedit_dll_handle = 0;
96     #endif
97    
98 persson 2470 #ifdef __APPLE__
99     std::string gigedit_localedir;
100     #endif
101    
102 persson 1456 void init_app() {
103 schoenebeck 1333 static bool process_initialized = false;
104     if (!process_initialized) {
105     std::cout << "Initializing 3rd party services needed by gigedit.\n"
106     << std::flush;
107     setlocale(LC_ALL, "");
108 schoenebeck 1396
109 persson 2470 #ifdef __APPLE__
110     // Look for pango.modules, gdk-pixbuf.loaders and locale files
111     // under the same dir as the gigedit dylib is installed in.
112     Dl_info info;
113     if (dladdr((void*)&init_app, &info)) {
114     std::string libdir = Glib::path_get_dirname(info.dli_fname);
115    
116     if (Glib::getenv("PANGO_SYSCONFDIR") == "" &&
117     Glib::file_test(Glib::build_filename(libdir,
118     "pango/pango.modules"),
119     Glib::FILE_TEST_EXISTS)) {
120     Glib::setenv("PANGO_SYSCONFDIR", libdir, true);
121     }
122     if (Glib::getenv("GDK_PIXBUF_MODULE_FILE") == "") {
123     std::string module_file =
124     Glib::build_filename(libdir,
125     "gtk-2.0/gdk-pixbuf.loaders");
126     if (Glib::file_test(module_file, Glib::FILE_TEST_EXISTS)) {
127     Glib::setenv("GDK_PIXBUF_MODULE_FILE", module_file, true);
128     }
129     }
130 schoenebeck 1396 #if HAVE_GETTEXT
131 persson 2470 std::string localedir = Glib::build_filename(libdir, "locale");
132     if (Glib::file_test(localedir, Glib::FILE_TEST_EXISTS)) {
133     gigedit_localedir = localedir;
134     bindtextdomain(GETTEXT_PACKAGE, gigedit_localedir.c_str());
135     } else {
136     bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
137     }
138     #endif
139     }
140 persson 1823
141 persson 2470 // The gtk file dialog stores its recent files state in
142     // ~/.local/share
143     g_mkdir_with_parents(
144     Glib::build_filename(Glib::get_home_dir(),
145     ".local/share").c_str(), 0777);
146     #endif
147    
148     #if HAVE_GETTEXT
149    
150 persson 1823 #ifdef WIN32
151     #if GLIB_CHECK_VERSION(2, 16, 0)
152     gchar* root =
153 persson 1898 g_win32_get_package_installation_directory_of_module(gigedit_dll_handle);
154 persson 1823 #else
155     gchar* root =
156     g_win32_get_package_installation_directory(NULL, NULL);
157     #endif
158     gchar* temp = g_build_filename(root, "/share/locale", NULL);
159     g_free(root);
160     gchar* localedir = g_win32_locale_filename_from_utf8(temp);
161     g_free(temp);
162     bindtextdomain(GETTEXT_PACKAGE, localedir);
163     g_free(localedir);
164 persson 2470 #elif !defined(__APPLE__)
165 schoenebeck 1333 bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
166 persson 1823 #endif
167 schoenebeck 1333 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
168     textdomain(GETTEXT_PACKAGE);
169 schoenebeck 1396 #endif // HAVE_GETTEXT
170    
171 persson 2325 #ifdef OLD_THREADS
172 schoenebeck 1333 // make sure thread_init() is called once and ONLY once per process
173     if (!Glib::thread_supported()) Glib::thread_init();
174 persson 2325 #endif
175 schoenebeck 1333 process_initialized = true;
176     }
177 schoenebeck 1225 }
178    
179 persson 1456 void connect_signals(GigEdit* gigedit, MainWindow* mainwindow) {
180 schoenebeck 1322 // the signals of the "GigEdit" class are actually just proxies, that
181     // is they simply forward the signals of the internal classes to the
182     // outer world
183     mainwindow->signal_file_structure_to_be_changed().connect(
184     gigedit->signal_file_structure_to_be_changed().make_slot()
185     );
186     mainwindow->signal_file_structure_changed().connect(
187     gigedit->signal_file_structure_changed().make_slot()
188     );
189     mainwindow->signal_samples_to_be_removed().connect(
190     gigedit->signal_samples_to_be_removed().make_slot()
191     );
192     mainwindow->signal_samples_removed().connect(
193     gigedit->signal_samples_removed().make_slot()
194     );
195     mainwindow->signal_region_to_be_changed().connect(
196     gigedit->signal_region_to_be_changed().make_slot()
197     );
198     mainwindow->signal_region_changed().connect(
199     gigedit->signal_region_changed().make_slot()
200     );
201     mainwindow->signal_dimreg_to_be_changed().connect(
202     gigedit->signal_dimreg_to_be_changed().make_slot()
203     );
204     mainwindow->signal_dimreg_changed().connect(
205     gigedit->signal_dimreg_changed().make_slot()
206     );
207 schoenebeck 1853 mainwindow->signal_sample_changed().connect(
208     gigedit->signal_sample_changed().make_slot()
209     );
210 schoenebeck 1322 mainwindow->signal_sample_ref_changed().connect(
211     gigedit->signal_sample_ref_changed().make_slot()
212     );
213 schoenebeck 1660 mainwindow->signal_keyboard_key_hit().connect(
214     gigedit->signal_keyboard_key_hit().make_slot()
215     );
216     mainwindow->signal_keyboard_key_released().connect(
217     gigedit->signal_keyboard_key_released().make_slot()
218     );
219 schoenebeck 1322 }
220    
221 schoenebeck 1654 } // namespace
222    
223     GigEdit::GigEdit() {
224     state = NULL;
225 schoenebeck 1225 }
226    
227 persson 1456 int GigEdit::run(int argc, char* argv[]) {
228     init_app();
229    
230     Gtk::Main kit(argc, argv);
231 persson 2470
232 persson 2471 #if HAVE_GETTEXT && defined(__APPLE__)
233 persson 2470 // Gtk::Main binds the gtk locale to a possible non-existent
234     // directory. If we have bundled gtk locale files, we rebind here,
235     // after the Gtk::Main constructor.
236     if (!gigedit_localedir.empty()) {
237     bindtextdomain("gtk20", gigedit_localedir.c_str());
238     }
239     #endif
240    
241 schoenebeck 1225 MainWindow window;
242 persson 1456 connect_signals(this, &window);
243     if (argc >= 2) window.load_file(argv[1]);
244 schoenebeck 1225 kit.run(window);
245     return 0;
246     }
247    
248     int GigEdit::run(gig::Instrument* pInstrument) {
249 persson 1456 init_app();
250    
251     GigEditState state(this);
252 schoenebeck 1654 this->state = &state;
253 persson 1456 state.run(pInstrument);
254 schoenebeck 1654 this->state = NULL;
255 schoenebeck 1225 return 0;
256     }
257 schoenebeck 1322
258 schoenebeck 1654 void GigEdit::on_note_on_event(int key, int velocity) {
259     if (!this->state) return;
260     GigEditState* state = (GigEditState*) this->state;
261     state->window->signal_note_on().emit(key, velocity);
262     }
263    
264     void GigEdit::on_note_off_event(int key, int velocity) {
265     if (!this->state) return;
266     GigEditState* state = (GigEditState*) this->state;
267     state->window->signal_note_off().emit(key, velocity);
268     }
269    
270 schoenebeck 1339 sigc::signal<void, gig::File*>& GigEdit::signal_file_structure_to_be_changed() {
271 schoenebeck 1322 return file_structure_to_be_changed_signal;
272     }
273    
274 schoenebeck 1339 sigc::signal<void, gig::File*>& GigEdit::signal_file_structure_changed() {
275 schoenebeck 1322 return file_structure_changed_signal;
276     }
277    
278 schoenebeck 1339 sigc::signal<void, std::list<gig::Sample*> >& GigEdit::signal_samples_to_be_removed() {
279 schoenebeck 1322 return samples_to_be_removed_signal;
280     }
281    
282 schoenebeck 1339 sigc::signal<void>& GigEdit::signal_samples_removed() {
283 schoenebeck 1322 return samples_removed_signal;
284     }
285    
286 schoenebeck 1339 sigc::signal<void, gig::Region*>& GigEdit::signal_region_to_be_changed() {
287 schoenebeck 1322 return region_to_be_changed_signal;
288     }
289    
290 schoenebeck 1339 sigc::signal<void, gig::Region*>& GigEdit::signal_region_changed() {
291 schoenebeck 1322 return region_changed_signal;
292     }
293    
294 schoenebeck 1339 sigc::signal<void, gig::DimensionRegion*>& GigEdit::signal_dimreg_to_be_changed() {
295 schoenebeck 1322 return dimreg_to_be_changed_signal;
296     }
297    
298 schoenebeck 1339 sigc::signal<void, gig::DimensionRegion*>& GigEdit::signal_dimreg_changed() {
299 schoenebeck 1322 return dimreg_changed_signal;
300     }
301    
302 schoenebeck 1853 sigc::signal<void, gig::Sample*>& GigEdit::signal_sample_changed() {
303     return sample_changed_signal;
304     }
305    
306 schoenebeck 1339 sigc::signal<void, gig::Sample*/*old*/, gig::Sample*/*new*/>& GigEdit::signal_sample_ref_changed() {
307 schoenebeck 1322 return sample_ref_changed_signal;
308     }
309 persson 1456
310 schoenebeck 1660 sigc::signal<void, int/*key*/, int/*velocity*/>& GigEdit::signal_keyboard_key_hit() {
311     return keyboard_key_hit_signal;
312     }
313 persson 1456
314 schoenebeck 1660 sigc::signal<void, int/*key*/, int/*velocity*/>& GigEdit::signal_keyboard_key_released() {
315     return keyboard_key_released_signal;
316     }
317    
318 persson 2325 #ifdef OLD_THREADS
319 persson 1456 Glib::StaticMutex GigEditState::mutex = GLIBMM_STATIC_MUTEX_INIT;
320 persson 2325 #else
321     Glib::Threads::Mutex GigEditState::mutex;
322     #endif
323 persson 1456 Glib::Dispatcher* GigEditState::dispatcher = 0;
324     GigEditState* GigEditState::current = 0;
325    
326     void GigEditState::open_window_static() {
327     GigEditState* c = GigEditState::current;
328     c->open.signal();
329     c->open_window();
330     }
331    
332     void GigEditState::open_window() {
333     window = new MainWindow();
334    
335     connect_signals(parent, window);
336     if (instrument) window->load_instrument(instrument);
337    
338     window->signal_hide().connect(sigc::mem_fun(this,
339     &GigEditState::close_window));
340     window->present();
341     }
342    
343     void GigEditState::close_window() {
344     delete window;
345     close.signal();
346     }
347    
348     void GigEditState::main_loop_run(Cond* initialized) {
349     int argc = 1;
350     const char* argv_c[] = { "gigedit" };
351     char** argv = const_cast<char**>(argv_c);
352     Gtk::Main main_loop(argc, argv);
353 persson 2471 #if HAVE_GETTEXT && defined(__APPLE__)
354 persson 2470 if (!gigedit_localedir.empty()) {
355     bindtextdomain("gtk20", gigedit_localedir.c_str());
356     }
357     #endif
358 persson 1456
359     dispatcher = new Glib::Dispatcher();
360     dispatcher->connect(sigc::ptr_fun(&GigEditState::open_window_static));
361     initialized->signal();
362    
363     main_loop.run();
364     }
365    
366     void GigEditState::run(gig::Instrument* pInstrument) {
367     mutex.lock(); // lock access to static variables
368    
369     static bool main_loop_started = false;
370     if (!main_loop_started) {
371     Cond initialized;
372 persson 2332 #ifdef OLD_THREADS
373     Glib::Thread::create(
374 persson 1456 sigc::bind(sigc::ptr_fun(&GigEditState::main_loop_run),
375     &initialized),
376     false);
377 persson 2332 #else
378     Glib::Threads::Thread::create(
379     sigc::bind(sigc::ptr_fun(&GigEditState::main_loop_run),
380     &initialized));
381     #endif
382 persson 1456 initialized.wait();
383     main_loop_started = true;
384     }
385     instrument = pInstrument;
386     current = this;
387     dispatcher->emit();
388     open.wait(); // wait until the GUI thread has read current
389     mutex.unlock();
390     close.wait(); // sleep until window is closed
391     }
392 persson 1898
393     #if defined(WIN32)
394     extern "C" {
395     BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved)
396     {
397     switch (reason) {
398     case DLL_PROCESS_ATTACH:
399     gigedit_dll_handle = instance;
400     break;
401     }
402     return TRUE;
403     }
404     }
405     #endif

  ViewVC Help
Powered by ViewVC