/[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 1898 - (show annotations) (download)
Sun May 10 09:35:56 2009 UTC (12 years, 4 months ago) by persson
File size: 9380 byte(s)
* Windows: look for translations using base directory of libgigedit
  dll
* virtual keyboard fixes: restore to grey when outside keyboard. Don't
  trigger multiple notes for each key when moving mouse.

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

  ViewVC Help
Powered by ViewVC