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

Diff of /gigedit/trunk/src/gigedit/gigedit.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1225 by schoenebeck, Sun Jun 10 10:56:11 2007 UTC revision 2471 by persson, Sun Sep 15 17:06:45 2013 UTC
# Line 1  Line 1 
1  /*  /*
2   * Copyright (C) 2007 Andreas Persson   * Copyright (C) 2007-2009 Andreas Persson
3   *   *
4   * This program is free software; you can redistribute it and/or   * This program is free software; you can redistribute it and/or
5   * modify it under the terms of the GNU General Public License as   * modify it under the terms of the GNU General Public License as
# Line 19  Line 19 
19    
20  #include "gigedit.h"  #include "gigedit.h"
21    
22    #include <glibmm/dispatcher.h>
23    #include <glibmm/main.h>
24  #include <gtkmm/main.h>  #include <gtkmm/main.h>
25    
26  #include "mainwindow.h"  #include "mainwindow.h"
27    
28  #include <libintl.h>  #include "global.h"
29  #include <config.h>  
30    #ifdef __APPLE__
31    #include <dlfcn.h>
32    #include <glibmm/fileutils.h>
33    #include <glibmm/miscutils.h>
34    #endif
35    
36    namespace {
37    
38    // 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        MainWindow* window;
52    
53    private:
54    
55        // simple condition variable abstraction
56        class Cond {
57        private:
58            bool pred;
59            Glib::Threads::Mutex mutex;
60            Glib::Threads::Cond cond;
61        public:
62            Cond() : pred(false) { }
63            void signal() {
64                Glib::Threads::Mutex::Lock lock(mutex);
65                pred = true;
66                cond.signal();
67            }
68            void wait() {
69                Glib::Threads::Mutex::Lock lock(mutex);
70                while (!pred) cond.wait(mutex);
71            }
72        };
73    
74    #ifdef OLD_THREADS
75        static Glib::StaticMutex mutex;
76    #else
77        static Glib::Threads::Mutex mutex;
78    #endif
79        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  // the app has to work from a DLL as well, so we hard code argv      void open_window();
91  int argc = 1;      void close_window();
92  const char* argv_c[] = { "gigedit" };  };
 char** argv = const_cast<char**>(argv_c);  
93    
94  static void __init_app() {  #ifdef WIN32
95      setlocale(LC_ALL, "");  HINSTANCE gigedit_dll_handle = 0;
96      bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);  #endif
     bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");  
     textdomain(GETTEXT_PACKAGE);  
97    
98      Glib::thread_init();  #ifdef __APPLE__
99    std::string gigedit_localedir;
100    #endif
101    
102    void init_app() {
103        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    
109    #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    #if HAVE_GETTEXT
131                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    
141            // 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    #ifdef WIN32
151    #if GLIB_CHECK_VERSION(2, 16, 0)
152            gchar* root =
153                g_win32_get_package_installation_directory_of_module(gigedit_dll_handle);
154    #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    #elif !defined(__APPLE__)
165            bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
166    #endif
167            bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
168            textdomain(GETTEXT_PACKAGE);
169    #endif // HAVE_GETTEXT
170    
171    #ifdef OLD_THREADS
172            // make sure thread_init() is called once and ONLY once per process
173            if (!Glib::thread_supported()) Glib::thread_init();
174    #endif
175            process_initialized = true;
176        }
177  }  }
178    
179  int GigEdit::run() {  void connect_signals(GigEdit* gigedit, MainWindow* mainwindow) {
180      __init_app();      // the signals of the "GigEdit" class are actually just proxies, that
181      Gtk::Main kit(argc, argv);      // is they simply forward the signals of the internal classes to the
182      MainWindow window;      // outer world
183      kit.run(window);      mainwindow->signal_file_structure_to_be_changed().connect(
184      return 0;          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        mainwindow->signal_sample_changed().connect(
208            gigedit->signal_sample_changed().make_slot()
209        );
210        mainwindow->signal_sample_ref_changed().connect(
211            gigedit->signal_sample_ref_changed().make_slot()
212        );
213        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  }  }
220    
221  int GigEdit::run(const char* pFileName) {  } // namespace
222      __init_app();  
223    GigEdit::GigEdit() {
224        state = NULL;
225    }
226    
227    int GigEdit::run(int argc, char* argv[]) {
228        init_app();
229    
230      Gtk::Main kit(argc, argv);      Gtk::Main kit(argc, argv);
231    
232    #if HAVE_GETTEXT && defined(__APPLE__)
233        // 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      MainWindow window;      MainWindow window;
242      if (pFileName) window.load_file(pFileName);      connect_signals(this, &window);
243        if (argc >= 2) window.load_file(argv[1]);
244      kit.run(window);      kit.run(window);
245      return 0;      return 0;
246  }  }
247    
248  int GigEdit::run(gig::Instrument* pInstrument) {  int GigEdit::run(gig::Instrument* pInstrument) {
249      __init_app();      init_app();
250      Gtk::Main kit(argc, argv);  
251      MainWindow window;      GigEditState state(this);
252      if (pInstrument) window.load_instrument(pInstrument);      this->state = &state;
253      kit.run(window);      state.run(pInstrument);
254        this->state = NULL;
255      return 0;      return 0;
256  }  }
257    
258    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    sigc::signal<void, gig::File*>& GigEdit::signal_file_structure_to_be_changed() {
271        return file_structure_to_be_changed_signal;
272    }
273    
274    sigc::signal<void, gig::File*>& GigEdit::signal_file_structure_changed() {
275        return file_structure_changed_signal;
276    }
277    
278    sigc::signal<void, std::list<gig::Sample*> >& GigEdit::signal_samples_to_be_removed() {
279        return samples_to_be_removed_signal;
280    }
281    
282    sigc::signal<void>& GigEdit::signal_samples_removed() {
283        return samples_removed_signal;
284    }
285    
286    sigc::signal<void, gig::Region*>& GigEdit::signal_region_to_be_changed() {
287        return region_to_be_changed_signal;
288    }
289    
290    sigc::signal<void, gig::Region*>& GigEdit::signal_region_changed() {
291        return region_changed_signal;
292    }
293    
294    sigc::signal<void, gig::DimensionRegion*>& GigEdit::signal_dimreg_to_be_changed() {
295        return dimreg_to_be_changed_signal;
296    }
297    
298    sigc::signal<void, gig::DimensionRegion*>& GigEdit::signal_dimreg_changed() {
299        return dimreg_changed_signal;
300    }
301    
302    sigc::signal<void, gig::Sample*>& GigEdit::signal_sample_changed() {
303        return sample_changed_signal;
304    }
305    
306    sigc::signal<void, gig::Sample*/*old*/, gig::Sample*/*new*/>& GigEdit::signal_sample_ref_changed() {
307        return sample_ref_changed_signal;
308    }
309    
310    sigc::signal<void, int/*key*/, int/*velocity*/>& GigEdit::signal_keyboard_key_hit() {
311        return keyboard_key_hit_signal;
312    }
313    
314    sigc::signal<void, int/*key*/, int/*velocity*/>& GigEdit::signal_keyboard_key_released() {
315        return keyboard_key_released_signal;
316    }
317    
318    #ifdef OLD_THREADS
319    Glib::StaticMutex GigEditState::mutex = GLIBMM_STATIC_MUTEX_INIT;
320    #else
321    Glib::Threads::Mutex GigEditState::mutex;
322    #endif
323    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    #if HAVE_GETTEXT && defined(__APPLE__)
354        if (!gigedit_localedir.empty()) {
355            bindtextdomain("gtk20", gigedit_localedir.c_str());
356        }
357    #endif
358    
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    #ifdef OLD_THREADS
373            Glib::Thread::create(
374                sigc::bind(sigc::ptr_fun(&GigEditState::main_loop_run),
375                           &initialized),
376                false);
377    #else
378            Glib::Threads::Thread::create(
379                sigc::bind(sigc::ptr_fun(&GigEditState::main_loop_run),
380                           &initialized));
381    #endif
382            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    
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

Legend:
Removed from v.1225  
changed lines
  Added in v.2471

  ViewVC Help
Powered by ViewVC