/[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 1654 by schoenebeck, Wed Jan 30 02:20:48 2008 UTC
# Line 1  Line 1 
1  /*  /*
2   * Copyright (C) 2007 Andreas Persson   * Copyright (C) 2007, 2008 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 20  Line 20 
20  #include "gigedit.h"  #include "gigedit.h"
21    
22  #include <gtkmm/main.h>  #include <gtkmm/main.h>
23    #include <glibmm/main.h>
24  #include "mainwindow.h"  #include "mainwindow.h"
25    
26  #include <libintl.h>  #include "global.h"
 #include <config.h>  
27    
28  // the app has to work from a DLL as well, so we hard code argv  GigEditJob::GigEditJob() {
29  int argc = 1;      _msecs = 100; // 100ms by default
30  const char* argv_c[] = { "gigedit" };  }
31  char** argv = const_cast<char**>(argv_c);  
32    int GigEditJob::msecs() {
33        return _msecs;
34    }
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        static std::vector< GigEditJob* > timeoutJobs;
52        MainWindow* window;
53    
54    private:
55    
56        // simple condition variable abstraction
57        class Cond {
58        private:
59            bool pred;
60            Glib::Mutex mutex;
61            Glib::Cond cond;
62        public:
63            Cond() : pred(false) { }
64            void signal() {
65                Glib::Mutex::Lock lock(mutex);
66                pred = true;
67                cond.signal();
68            }
69            void wait() {
70                Glib::Mutex::Lock lock(mutex);
71                while (!pred) cond.wait(mutex);
72            }
73        };
74    
75        static Glib::StaticMutex mutex;
76        static Glib::Dispatcher* dispatcher;
77        static GigEditState* current;
78    
79  static void __init_app() {      static void main_loop_run(Cond* intialized);
80      setlocale(LC_ALL, "");      static void open_window_static();
     bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);  
     bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");  
     textdomain(GETTEXT_PACKAGE);  
81    
82      Glib::thread_init();      GigEdit* parent;
83        Cond open;
84        Cond close;
85        gig::Instrument* instrument;
86    
87        void open_window();
88        void close_window();
89    };
90    
91    void init_app() {
92        static bool process_initialized = false;
93        if (!process_initialized) {
94            std::cout << "Initializing 3rd party services needed by gigedit.\n"
95                      << std::flush;
96            setlocale(LC_ALL, "");
97    
98    #if HAVE_GETTEXT
99            bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
100            bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
101            textdomain(GETTEXT_PACKAGE);
102    #endif // HAVE_GETTEXT
103    
104            // make sure thread_init() is called once and ONLY once per process
105            if (!Glib::thread_supported()) Glib::thread_init();
106    
107            process_initialized = true;
108        }
109  }  }
110    
111  int GigEdit::run() {  void connect_signals(GigEdit* gigedit, MainWindow* mainwindow) {
112      __init_app();      // the signals of the "GigEdit" class are actually just proxies, that
113      Gtk::Main kit(argc, argv);      // is they simply forward the signals of the internal classes to the
114      MainWindow window;      // outer world
115      kit.run(window);      mainwindow->signal_file_structure_to_be_changed().connect(
116      return 0;          gigedit->signal_file_structure_to_be_changed().make_slot()
117        );
118        mainwindow->signal_file_structure_changed().connect(
119            gigedit->signal_file_structure_changed().make_slot()
120        );
121        mainwindow->signal_samples_to_be_removed().connect(
122            gigedit->signal_samples_to_be_removed().make_slot()
123        );
124        mainwindow->signal_samples_removed().connect(
125            gigedit->signal_samples_removed().make_slot()
126        );
127        mainwindow->signal_region_to_be_changed().connect(
128            gigedit->signal_region_to_be_changed().make_slot()
129        );
130        mainwindow->signal_region_changed().connect(
131            gigedit->signal_region_changed().make_slot()
132        );
133        mainwindow->signal_dimreg_to_be_changed().connect(
134            gigedit->signal_dimreg_to_be_changed().make_slot()
135        );
136        mainwindow->signal_dimreg_changed().connect(
137            gigedit->signal_dimreg_changed().make_slot()
138        );
139        mainwindow->signal_sample_ref_changed().connect(
140            gigedit->signal_sample_ref_changed().make_slot()
141        );
142  }  }
143    
144  int GigEdit::run(const char* pFileName) {  } // namespace
145      __init_app();  
146    GigEdit::GigEdit() {
147        state = NULL;
148    }
149    
150    int GigEdit::run(int argc, char* argv[]) {
151        init_app();
152    
153      Gtk::Main kit(argc, argv);      Gtk::Main kit(argc, argv);
154      MainWindow window;      MainWindow window;
155      if (pFileName) window.load_file(pFileName);      connect_signals(this, &window);
156        if (argc >= 2) window.load_file(argv[1]);
157      kit.run(window);      kit.run(window);
158      return 0;      return 0;
159  }  }
160    
161  int GigEdit::run(gig::Instrument* pInstrument) {  int GigEdit::run(gig::Instrument* pInstrument) {
162      __init_app();      init_app();
163      Gtk::Main kit(argc, argv);  
164      MainWindow window;      GigEditState state(this);
165      if (pInstrument) window.load_instrument(pInstrument);      this->state = &state;
166      kit.run(window);      state.run(pInstrument);
167        this->state = NULL;
168      return 0;      return 0;
169  }  }
170    
171    void GigEdit::add_timeout_job(GigEditJob* job) {
172        GigEditState::timeoutJobs.push_back(job);
173    }
174    
175    void GigEdit::on_note_on_event(int key, int velocity) {
176        if (!this->state) return;
177        GigEditState* state = (GigEditState*) this->state;
178        state->window->signal_note_on().emit(key, velocity);
179    }
180    
181    void GigEdit::on_note_off_event(int key, int velocity) {
182        if (!this->state) return;
183        GigEditState* state = (GigEditState*) this->state;
184        state->window->signal_note_off().emit(key, velocity);
185    }
186    
187    sigc::signal<void, gig::File*>& GigEdit::signal_file_structure_to_be_changed() {
188        return file_structure_to_be_changed_signal;
189    }
190    
191    sigc::signal<void, gig::File*>& GigEdit::signal_file_structure_changed() {
192        return file_structure_changed_signal;
193    }
194    
195    sigc::signal<void, std::list<gig::Sample*> >& GigEdit::signal_samples_to_be_removed() {
196        return samples_to_be_removed_signal;
197    }
198    
199    sigc::signal<void>& GigEdit::signal_samples_removed() {
200        return samples_removed_signal;
201    }
202    
203    sigc::signal<void, gig::Region*>& GigEdit::signal_region_to_be_changed() {
204        return region_to_be_changed_signal;
205    }
206    
207    sigc::signal<void, gig::Region*>& GigEdit::signal_region_changed() {
208        return region_changed_signal;
209    }
210    
211    sigc::signal<void, gig::DimensionRegion*>& GigEdit::signal_dimreg_to_be_changed() {
212        return dimreg_to_be_changed_signal;
213    }
214    
215    sigc::signal<void, gig::DimensionRegion*>& GigEdit::signal_dimreg_changed() {
216        return dimreg_changed_signal;
217    }
218    
219    sigc::signal<void, gig::Sample*/*old*/, gig::Sample*/*new*/>& GigEdit::signal_sample_ref_changed() {
220        return sample_ref_changed_signal;
221    }
222    
223    
224    Glib::StaticMutex GigEditState::mutex = GLIBMM_STATIC_MUTEX_INIT;
225    Glib::Dispatcher* GigEditState::dispatcher = 0;
226    GigEditState* GigEditState::current = 0;
227    std::vector<GigEditJob*> GigEditState::timeoutJobs;
228    
229    void GigEditState::open_window_static() {
230        GigEditState* c = GigEditState::current;
231        c->open.signal();
232        c->open_window();
233    }
234    
235    void GigEditState::open_window() {
236        window = new MainWindow();
237    
238        connect_signals(parent, window);
239        if (instrument) window->load_instrument(instrument);
240    
241        window->signal_hide().connect(sigc::mem_fun(this,
242                                                    &GigEditState::close_window));
243        window->present();
244    }
245    
246    void GigEditState::close_window() {
247        delete window;
248        close.signal();
249    }
250    
251    void GigEditState::main_loop_run(Cond* initialized) {
252        int argc = 1;
253        const char* argv_c[] = { "gigedit" };
254        char** argv = const_cast<char**>(argv_c);
255        Gtk::Main main_loop(argc, argv);
256    
257        dispatcher = new Glib::Dispatcher();
258        dispatcher->connect(sigc::ptr_fun(&GigEditState::open_window_static));
259        initialized->signal();
260    
261        for (int i = 0; i < GigEditState::timeoutJobs.size(); i++) {
262            GigEditJob* job = timeoutJobs[i];
263            const Glib::RefPtr<Glib::TimeoutSource> timeout_source =
264                Glib::TimeoutSource::create(job->msecs());
265            timeout_source->connect(
266                sigc::mem_fun(*job, &GigEditJob::runGigEditJob)
267            );
268            timeout_source->attach(Glib::MainContext::get_default());
269        }
270    
271        main_loop.run();
272    }
273    
274    void GigEditState::run(gig::Instrument* pInstrument) {
275        mutex.lock(); // lock access to static variables
276    
277        static bool main_loop_started = false;
278        if (!main_loop_started) {
279            Cond initialized;
280            Glib::Thread::create(
281                sigc::bind(sigc::ptr_fun(&GigEditState::main_loop_run),
282                           &initialized),
283                false);
284            initialized.wait();
285            main_loop_started = true;
286        }
287        instrument = pInstrument;
288        current = this;
289        dispatcher->emit();
290        open.wait(); // wait until the GUI thread has read current
291        mutex.unlock();
292        close.wait(); // sleep until window is closed
293    }

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

  ViewVC Help
Powered by ViewVC