/[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 3489 - (hide annotations) (download)
Sun Mar 3 09:08:20 2019 UTC (5 years, 1 month ago) by persson
File size: 22694 byte(s)
* Set gtk settings a bit later to prevent warnings
* Use standard name for gdk pixbuf module file on Mac
* Look for locale files under directory share on Mac
* Support bundled gtk3 on Mac

1 schoenebeck 1225 /*
2 persson 3461 * Copyright (C) 2007-2019 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 schoenebeck 3364 #include "compat.h"
21 persson 3472 #include "gigedit.h"
22    
23     #ifdef GLIB_THREADS
24     #ifndef OLD_THREADS
25 persson 2841 #include <glibmm/threads.h>
26     #endif
27 persson 3472 #else
28     #include <thread>
29     #include <mutex>
30     #include <condition_variable>
31     #endif
32 persson 2844 #if GTKMM_MAJOR_VERSION < 3
33     #include <gdkmm/region.h>
34     #endif
35 persson 2325 #include <glibmm/dispatcher.h>
36     #include <glibmm/main.h>
37 persson 3033 #include <glibmm/miscutils.h>
38 schoenebeck 1225 #include <gtkmm/main.h>
39 persson 2325
40 persson 3489 #if defined(WIN32) || defined(__APPLE__)
41 persson 3033 #include <gtkmm/icontheme.h>
42     #endif
43    
44 schoenebeck 2474 #if defined(__APPLE__)
45     # include <CoreFoundation/CoreFoundation.h>
46     # include "MacHelper.h"
47     #endif
48    
49 schoenebeck 1225 #include "mainwindow.h"
50    
51 schoenebeck 1396 #include "global.h"
52 schoenebeck 1225
53 persson 2470 #ifdef __APPLE__
54     #include <dlfcn.h>
55     #include <glibmm/fileutils.h>
56     #endif
57    
58 schoenebeck 2474 //TODO: (hopefully) just a temporary nasty hack for launching gigedit on the main thread on Mac (see comments below in this file for details)
59 persson 2841 #if defined(__APPLE__) && HAVE_LINUXSAMPLER // the following global external variables are defined in LinuxSampler's global_private.cpp ...
60 schoenebeck 2474 extern bool g_mainThreadCallbackSupported;
61     extern void (*g_mainThreadCallback)(void* info);
62     extern void* g_mainThreadCallbackInfo;
63     extern bool g_fireMainThreadCallback;
64     #endif
65    
66 persson 1456 namespace {
67 schoenebeck 1225
68 persson 1456 // State for a gigedit thread.
69     //
70     // This class is only used when gigedit is run as a plugin and makes
71     // sure that there's only one Gtk::Main event loop. The event loop is
72     // started in a separate thread. The plugin thread just dispatches an
73     // event to the main loop to open a window and then goes to sleep
74     // until the window is closed.
75     //
76     class GigEditState : public sigc::trackable {
77     public:
78 persson 2841 GigEditState(GigEdit* parent) :
79     window(0), parent(parent), instrument(0) { }
80 persson 1456 void run(gig::Instrument* pInstrument);
81    
82 schoenebeck 1654 MainWindow* window;
83    
84 persson 1456 private:
85    
86     // simple condition variable abstraction
87     class Cond {
88     private:
89     bool pred;
90 persson 3472 #ifdef GLIB_THREADS
91 persson 2325 Glib::Threads::Mutex mutex;
92     Glib::Threads::Cond cond;
93 persson 3472 #else
94     std::mutex mutex;
95     std::condition_variable cond;
96     #endif
97 persson 1456 public:
98     Cond() : pred(false) { }
99     void signal() {
100 persson 3472 #ifdef GLIB_THREADS
101 persson 2325 Glib::Threads::Mutex::Lock lock(mutex);
102 persson 1456 pred = true;
103     cond.signal();
104 persson 3472 #else
105     std::lock_guard<std::mutex> lock(mutex);
106     pred = true;
107     cond.notify_one();
108     #endif
109 persson 1456 }
110     void wait() {
111 persson 3472 #ifdef GLIB_THREADS
112 persson 2325 Glib::Threads::Mutex::Lock lock(mutex);
113 persson 1456 while (!pred) cond.wait(mutex);
114 persson 3472 #else
115     std::unique_lock<std::mutex> lock(mutex);
116     while (!pred) cond.wait(lock);
117     #endif
118 persson 1456 }
119     };
120    
121 persson 2325 #ifdef OLD_THREADS
122 persson 1456 static Glib::StaticMutex mutex;
123 persson 3472 #elif defined(GLIB_THREADS)
124     static Glib::Threads::Mutex mutex;
125 persson 2325 #else
126 persson 3472 static std::mutex mutex;
127 persson 2325 #endif
128 persson 1456 static Glib::Dispatcher* dispatcher;
129     static GigEditState* current;
130    
131     static void main_loop_run(Cond* intialized);
132     static void open_window_static();
133    
134     GigEdit* parent;
135     Cond open;
136     Cond close;
137 schoenebeck 2474 Cond initialized;
138 persson 1456 gig::Instrument* instrument;
139    
140     void open_window();
141     void close_window();
142 schoenebeck 2474 #if defined(__APPLE__)
143     static void runInCFMainLoop(void* info);
144     #endif
145 persson 1456 };
146    
147 persson 1898 #ifdef WIN32
148     HINSTANCE gigedit_dll_handle = 0;
149 persson 3033 std::string gigedit_datadir;
150     bool gigedit_installdir_is_parent = false;
151 persson 1898 #endif
152    
153 persson 2470 #ifdef __APPLE__
154     std::string gigedit_localedir;
155 persson 3489 std::string gigedit_datadir;
156 persson 2470 #endif
157    
158 persson 1456 void init_app() {
159 schoenebeck 1333 static bool process_initialized = false;
160     if (!process_initialized) {
161     std::cout << "Initializing 3rd party services needed by gigedit.\n"
162     << std::flush;
163     setlocale(LC_ALL, "");
164 schoenebeck 1396
165 persson 2470 #ifdef __APPLE__
166     // Look for pango.modules, gdk-pixbuf.loaders and locale files
167     // under the same dir as the gigedit dylib is installed in.
168     Dl_info info;
169     if (dladdr((void*)&init_app, &info)) {
170 schoenebeck 3068 #ifdef CONFIG_FORCE_GTK_LIBDIR
171     std::string libdir = CONFIG_FORCE_GTK_LIBDIR;
172     #else
173 persson 2470 std::string libdir = Glib::path_get_dirname(info.dli_fname);
174 schoenebeck 3068 #endif
175 persson 2470
176 persson 3489 // newer pango versions don't use modules
177     #if PANGO_VERSION_MAJOR == 1 && PANGO_VERSION_MINOR < 38
178 persson 2470 if (Glib::getenv("PANGO_SYSCONFDIR") == "" &&
179     Glib::file_test(Glib::build_filename(libdir,
180     "pango/pango.modules"),
181     Glib::FILE_TEST_EXISTS)) {
182     Glib::setenv("PANGO_SYSCONFDIR", libdir, true);
183     }
184 persson 3489 #endif
185 persson 2470 if (Glib::getenv("GDK_PIXBUF_MODULE_FILE") == "") {
186     std::string module_file =
187     Glib::build_filename(libdir,
188 persson 3489 "gdk-pixbuf-2.0/2.10.0/loaders.cache");
189 persson 2470 if (Glib::file_test(module_file, Glib::FILE_TEST_EXISTS)) {
190     Glib::setenv("GDK_PIXBUF_MODULE_FILE", module_file, true);
191     }
192     }
193 persson 3489 std::string datadir = Glib::build_filename(
194     Glib::path_get_dirname(libdir), "share");
195    
196     if (Glib::file_test(datadir, Glib::FILE_TEST_EXISTS)) {
197     gigedit_datadir = datadir;
198    
199     std::string localedir = Glib::build_filename(datadir, "locale");
200     if (Glib::file_test(localedir, Glib::FILE_TEST_EXISTS)) {
201     gigedit_localedir = localedir;
202     }
203     std::string schemadir =
204     Glib::build_filename(gigedit_datadir, "glib-2.0/schemas");
205     if (Glib::file_test(schemadir, Glib::FILE_TEST_EXISTS)) {
206     Glib::setenv("GSETTINGS_SCHEMA_DIR", schemadir);
207     }
208     }
209 schoenebeck 2474 //FIXME: for some reason AC GETTEXT check fails on the Mac cross compiler?
210     //#if HAVE_GETTEXT
211 persson 3489 if (!gigedit_localedir.empty()) {
212 persson 2470 bindtextdomain(GETTEXT_PACKAGE, gigedit_localedir.c_str());
213     } else {
214     bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
215     }
216 schoenebeck 2474 //#endif
217 persson 2470 }
218 persson 1823
219 persson 2470 // The gtk file dialog stores its recent files state in
220     // ~/.local/share
221     g_mkdir_with_parents(
222     Glib::build_filename(Glib::get_home_dir(),
223     ".local/share").c_str(), 0777);
224 schoenebeck 2474 #endif // __APPLE__
225 persson 2470
226 persson 3033 #ifdef WIN32
227     // Find the data directory: the linuxsampler installer puts
228     // the binaries in sub directories "32" and "64", so the share
229     // directory is located in the parent of the directory of the
230     // binaries.
231 persson 2470
232 persson 3033 #if GLIB_CHECK_VERSION(2, 16, 0)
233 persson 1823 gchar* root =
234 persson 1898 g_win32_get_package_installation_directory_of_module(gigedit_dll_handle);
235 persson 3033 #else
236 persson 1823 gchar* root =
237     g_win32_get_package_installation_directory(NULL, NULL);
238 persson 3033 #endif
239     std::string installdir(root);
240 persson 1823 g_free(root);
241 persson 3033 std::string basename = Glib::path_get_basename(installdir);
242     if (basename == "32" || basename == "64") {
243     installdir = Glib::path_get_dirname(installdir);
244     gigedit_installdir_is_parent = true;
245     }
246     gigedit_datadir = Glib::build_filename(installdir, "share");
247    
248     // the file dialogs need glib-2.0/schemas/gschemas.compiled
249     if (gigedit_installdir_is_parent) {
250     Glib::setenv("GSETTINGS_SCHEMA_DIR",
251     Glib::build_filename(gigedit_datadir,
252     "glib-2.0/schemas"));
253     }
254     #endif
255    
256     //FIXME: for some reason AC GETTEXT check fails on the Mac cross compiler?
257     #if (HAVE_GETTEXT || defined(__APPLE__))
258     #ifdef WIN32
259     std::string temp = Glib::build_filename(gigedit_datadir, "locale");
260     gchar* localedir = g_win32_locale_filename_from_utf8(temp.c_str());
261 persson 1823 bindtextdomain(GETTEXT_PACKAGE, localedir);
262     g_free(localedir);
263 schoenebeck 2474 #elif !defined(__APPLE__)
264 schoenebeck 1333 bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
265 schoenebeck 2474 #endif
266 schoenebeck 1333 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
267     textdomain(GETTEXT_PACKAGE);
268 schoenebeck 1396 #endif // HAVE_GETTEXT
269    
270 persson 2325 #ifdef OLD_THREADS
271 schoenebeck 1333 // make sure thread_init() is called once and ONLY once per process
272     if (!Glib::thread_supported()) Glib::thread_init();
273 persson 2325 #endif
274 schoenebeck 1333 process_initialized = true;
275     }
276 schoenebeck 1225 }
277    
278 persson 3489
279     #if GTKMM_MAJOR_VERSION >= 3
280    
281     /**
282     * This is required since GTK 3, because those GTK super heros came up with
283     * the clever idea to simply disable things like icons and keyboard shortcuts
284     * for menus and for buttons by default for all users, all devices and all
285     * apps. Yey! Seriously, I have no idea what came on their mind to find that
286     * was a good idea!
287     */
288     void enforceGtk3Settings() {
289    
290     // got no behavior change on those 2 settings, so ignoring them for now,
291     // actually I though I could use them to show the mnemonics in the GTK 3
292     // menus again, but it seems that was entirely removed from around GTK 3.10.
293     //g_object_set(gtk_settings_get_default(), "gtk-auto-mnemonics", false, NULL);
294     //g_object_set(gtk_settings_get_default(), "gtk-can-change-accels", true, NULL);
295    
296     // bring back keyboard accelerators with GTK 3
297     g_object_set(gtk_settings_get_default(), "gtk-enable-accels", true, NULL);
298     g_object_set(gtk_settings_get_default(), "gtk-enable-mnemonics", true, NULL);
299    
300     // bring back icons with GTK 3
301     g_object_set(gtk_settings_get_default(), "gtk-menu-images", true, NULL);
302     g_object_set(gtk_settings_get_default(), "gtk-button-images", true, NULL);
303    
304     // who knows ... one day those GTK "masterminds" decide to disable tooltips by default as well
305     g_object_set(gtk_settings_get_default(), "gtk-enable-tooltips", true, NULL);
306     }
307    
308     #endif // GTKM 3
309    
310    
311 persson 3033 void init_app_after_gtk_init() {
312 persson 3489 #if GTKMM_MAJOR_VERSION >= 3
313     enforceGtk3Settings();
314     #endif
315    
316 persson 3033 //FIXME: for some reason AC GETTEXT check fails on the Mac cross compiler?
317     #if (/*HAVE_GETTEXT &&*/ defined(__APPLE__))
318     // Gtk::Main binds the gtk locale to a possible non-existent
319     // directory. If we have bundled gtk locale files, we rebind here,
320     // after the Gtk::Main constructor.
321     if (!gigedit_localedir.empty()) {
322 persson 3489 #if GTKMM_MAJOR_VERSION < 3
323 persson 3033 bindtextdomain("gtk20", gigedit_localedir.c_str());
324 persson 3489 #else
325     bindtextdomain("gtk30", gigedit_localedir.c_str());
326     #endif
327 persson 3033 }
328     #endif
329    
330     #ifdef WIN32
331     if (gigedit_installdir_is_parent) {
332     std::string icon_dir = Glib::build_filename(gigedit_datadir, "icons");
333     Gtk::IconTheme::get_default()->append_search_path(icon_dir);
334     }
335     #endif
336 persson 3489 #ifdef __APPLE__
337     if (!gigedit_datadir.empty()) {
338     std::string icon_dir = Glib::build_filename(gigedit_datadir, "icons");
339     Gtk::IconTheme::get_default()->append_search_path(icon_dir);
340     }
341     #endif
342 persson 3033 }
343    
344 persson 1456 void connect_signals(GigEdit* gigedit, MainWindow* mainwindow) {
345 schoenebeck 1322 // the signals of the "GigEdit" class are actually just proxies, that
346     // is they simply forward the signals of the internal classes to the
347     // outer world
348     mainwindow->signal_file_structure_to_be_changed().connect(
349     gigedit->signal_file_structure_to_be_changed().make_slot()
350     );
351     mainwindow->signal_file_structure_changed().connect(
352     gigedit->signal_file_structure_changed().make_slot()
353     );
354     mainwindow->signal_samples_to_be_removed().connect(
355     gigedit->signal_samples_to_be_removed().make_slot()
356     );
357     mainwindow->signal_samples_removed().connect(
358     gigedit->signal_samples_removed().make_slot()
359     );
360     mainwindow->signal_region_to_be_changed().connect(
361     gigedit->signal_region_to_be_changed().make_slot()
362     );
363     mainwindow->signal_region_changed().connect(
364     gigedit->signal_region_changed().make_slot()
365     );
366     mainwindow->signal_dimreg_to_be_changed().connect(
367     gigedit->signal_dimreg_to_be_changed().make_slot()
368     );
369     mainwindow->signal_dimreg_changed().connect(
370     gigedit->signal_dimreg_changed().make_slot()
371     );
372 schoenebeck 1853 mainwindow->signal_sample_changed().connect(
373     gigedit->signal_sample_changed().make_slot()
374     );
375 schoenebeck 1322 mainwindow->signal_sample_ref_changed().connect(
376     gigedit->signal_sample_ref_changed().make_slot()
377     );
378 schoenebeck 1660 mainwindow->signal_keyboard_key_hit().connect(
379     gigedit->signal_keyboard_key_hit().make_slot()
380     );
381     mainwindow->signal_keyboard_key_released().connect(
382     gigedit->signal_keyboard_key_released().make_slot()
383     );
384 schoenebeck 2689 mainwindow->signal_switch_sampler_instrument().connect(
385     gigedit->signal_switch_sampler_instrument().make_slot()
386     );
387 schoenebeck 2903 mainwindow->signal_script_to_be_changed.connect(
388     gigedit->signal_script_to_be_changed.make_slot()
389     );
390     mainwindow->signal_script_changed.connect(
391     gigedit->signal_script_changed.make_slot()
392     );
393 schoenebeck 1322 }
394    
395 schoenebeck 1654 } // namespace
396    
397     GigEdit::GigEdit() {
398     state = NULL;
399 schoenebeck 1225 }
400    
401 persson 1456 int GigEdit::run(int argc, char* argv[]) {
402     init_app();
403    
404 schoenebeck 3364 #if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && (GTKMM_MINOR_VERSION < 89 || (GTKMM_MINOR_VERSION == 89 && GTKMM_MICRO_VERSION < 4))) // GTKMM < 3.89.4
405 persson 1456 Gtk::Main kit(argc, argv);
406 schoenebeck 3364 #else
407     Glib::RefPtr<Gtk::Application> app =
408     Gtk::Application::create("org.linuxsampler.gigedit");
409     #endif
410 persson 3033 init_app_after_gtk_init();
411 persson 2470
412 schoenebeck 1225 MainWindow window;
413 persson 1456 connect_signals(this, &window);
414     if (argc >= 2) window.load_file(argv[1]);
415 schoenebeck 3364 #if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && (GTKMM_MINOR_VERSION < 89 || (GTKMM_MINOR_VERSION == 89 && GTKMM_MICRO_VERSION < 4))) // GTKMM < 3.89.4
416 schoenebeck 1225 kit.run(window);
417 schoenebeck 3364 #else
418     app->run(window, argc, argv);
419     #endif
420    
421 schoenebeck 1225 return 0;
422     }
423    
424     int GigEdit::run(gig::Instrument* pInstrument) {
425 persson 1456 init_app();
426    
427     GigEditState state(this);
428 schoenebeck 1654 this->state = &state;
429 persson 1456 state.run(pInstrument);
430 schoenebeck 1654 this->state = NULL;
431 schoenebeck 1225 return 0;
432     }
433 schoenebeck 1322
434 schoenebeck 1654 void GigEdit::on_note_on_event(int key, int velocity) {
435     if (!this->state) return;
436 persson 2841 GigEditState* state = static_cast<GigEditState*>(this->state);
437 schoenebeck 1654 state->window->signal_note_on().emit(key, velocity);
438     }
439    
440     void GigEdit::on_note_off_event(int key, int velocity) {
441     if (!this->state) return;
442 persson 2841 GigEditState* state = static_cast<GigEditState*>(this->state);
443 schoenebeck 1654 state->window->signal_note_off().emit(key, velocity);
444     }
445    
446 schoenebeck 1339 sigc::signal<void, gig::File*>& GigEdit::signal_file_structure_to_be_changed() {
447 schoenebeck 1322 return file_structure_to_be_changed_signal;
448     }
449    
450 schoenebeck 1339 sigc::signal<void, gig::File*>& GigEdit::signal_file_structure_changed() {
451 schoenebeck 1322 return file_structure_changed_signal;
452     }
453    
454 schoenebeck 1339 sigc::signal<void, std::list<gig::Sample*> >& GigEdit::signal_samples_to_be_removed() {
455 schoenebeck 1322 return samples_to_be_removed_signal;
456     }
457    
458 schoenebeck 1339 sigc::signal<void>& GigEdit::signal_samples_removed() {
459 schoenebeck 1322 return samples_removed_signal;
460     }
461    
462 schoenebeck 1339 sigc::signal<void, gig::Region*>& GigEdit::signal_region_to_be_changed() {
463 schoenebeck 1322 return region_to_be_changed_signal;
464     }
465    
466 schoenebeck 1339 sigc::signal<void, gig::Region*>& GigEdit::signal_region_changed() {
467 schoenebeck 1322 return region_changed_signal;
468     }
469    
470 schoenebeck 1339 sigc::signal<void, gig::DimensionRegion*>& GigEdit::signal_dimreg_to_be_changed() {
471 schoenebeck 1322 return dimreg_to_be_changed_signal;
472     }
473    
474 schoenebeck 1339 sigc::signal<void, gig::DimensionRegion*>& GigEdit::signal_dimreg_changed() {
475 schoenebeck 1322 return dimreg_changed_signal;
476     }
477    
478 schoenebeck 1853 sigc::signal<void, gig::Sample*>& GigEdit::signal_sample_changed() {
479     return sample_changed_signal;
480     }
481    
482 schoenebeck 1339 sigc::signal<void, gig::Sample*/*old*/, gig::Sample*/*new*/>& GigEdit::signal_sample_ref_changed() {
483 schoenebeck 1322 return sample_ref_changed_signal;
484     }
485 persson 1456
486 schoenebeck 1660 sigc::signal<void, int/*key*/, int/*velocity*/>& GigEdit::signal_keyboard_key_hit() {
487     return keyboard_key_hit_signal;
488     }
489 persson 1456
490 schoenebeck 1660 sigc::signal<void, int/*key*/, int/*velocity*/>& GigEdit::signal_keyboard_key_released() {
491     return keyboard_key_released_signal;
492     }
493    
494 schoenebeck 2689 sigc::signal<void, gig::Instrument*>& GigEdit::signal_switch_sampler_instrument() {
495     return switch_sampler_instrument_signal;
496     }
497    
498 persson 2325 #ifdef OLD_THREADS
499 persson 1456 Glib::StaticMutex GigEditState::mutex = GLIBMM_STATIC_MUTEX_INIT;
500 persson 3472 #elif defined(GLIB_THREADS)
501     Glib::Threads::Mutex GigEditState::mutex;
502 persson 2325 #else
503 persson 3472 std::mutex GigEditState::mutex;
504 persson 2325 #endif
505 persson 1456 Glib::Dispatcher* GigEditState::dispatcher = 0;
506     GigEditState* GigEditState::current = 0;
507    
508     void GigEditState::open_window_static() {
509     GigEditState* c = GigEditState::current;
510     c->open.signal();
511     c->open_window();
512     }
513    
514     void GigEditState::open_window() {
515     window = new MainWindow();
516    
517     connect_signals(parent, window);
518     if (instrument) window->load_instrument(instrument);
519    
520 persson 3461 window->signal_hide().connect(sigc::mem_fun(*this,
521 persson 1456 &GigEditState::close_window));
522     window->present();
523     }
524    
525     void GigEditState::close_window() {
526     delete window;
527     close.signal();
528     }
529    
530 persson 3021 #if defined(WIN32) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))
531     // make sure stack is 16-byte aligned for SSE instructions
532     __attribute__((force_align_arg_pointer))
533     #endif
534 persson 1456 void GigEditState::main_loop_run(Cond* initialized) {
535     int argc = 1;
536     const char* argv_c[] = { "gigedit" };
537     char** argv = const_cast<char**>(argv_c);
538 schoenebeck 3364 #if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && (GTKMM_MINOR_VERSION < 89 || (GTKMM_MINOR_VERSION == 89 && GTKMM_MICRO_VERSION < 4))) // GTKMM < 3.89.4
539 persson 1456 Gtk::Main main_loop(argc, argv);
540 schoenebeck 3364 #endif
541 persson 3033 init_app_after_gtk_init();
542 persson 1456
543     dispatcher = new Glib::Dispatcher();
544     dispatcher->connect(sigc::ptr_fun(&GigEditState::open_window_static));
545     initialized->signal();
546    
547 schoenebeck 3364 #if GTKMM_MAJOR_VERSION < 3 || (GTKMM_MAJOR_VERSION == 3 && (GTKMM_MINOR_VERSION < 89 || (GTKMM_MINOR_VERSION == 89 && GTKMM_MICRO_VERSION < 4))) // GTKMM < 3.89.4
548 persson 1456 main_loop.run();
549 schoenebeck 3364 #else
550     Gtk::Main::run();
551     #endif
552 persson 1456 }
553    
554 schoenebeck 2474 #if defined(__APPLE__)
555    
556     void GigEditState::runInCFMainLoop(void* info) {
557     printf("runInCFMainLoop() entered\n"); fflush(stdout);
558     GigEditState* state = static_cast<GigEditState*>(info);
559     state->main_loop_run(
560     &state->initialized
561     );
562     printf("runInCFMainLoop() left\n"); fflush(stdout);
563     }
564    
565     #endif // __APPLE__
566    
567 persson 1456 void GigEditState::run(gig::Instrument* pInstrument) {
568     mutex.lock(); // lock access to static variables
569    
570     static bool main_loop_started = false;
571 schoenebeck 2664 instrument = pInstrument;
572 persson 1456 if (!main_loop_started) {
573 persson 2841 #if defined(__APPLE__) && HAVE_LINUXSAMPLER
574 schoenebeck 2474 // spawn GUI on main thread :
575     // On OS X the Gtk GUI can only be launched on a process's "main"
576     // thread. When trying to launch the Gtk GUI on any other thread,
577     // there will only be a white box, because the GUI would not receive
578     // any events, since it would listen to the wrong system event loop.
579     // So far we haven't investigated whether there is any kind of
580     // circumvention to allow doing that also on other OS X threads.
581     {
582     // In case the sampler was launched as standalone sampler (not as
583     // plugin), use the following global callback variable hack ...
584     if (g_mainThreadCallbackSupported) {
585     printf("Setting callback ...\n"); fflush(stdout);
586     g_mainThreadCallback = runInCFMainLoop;
587     g_mainThreadCallbackInfo = this;
588     g_fireMainThreadCallback = true;
589     printf("Callback variables set.\n"); fflush(stdout);
590     } else { // Sampler was launched as (i.e. AU / VST) plugin ...
591     // When the sampler was launched as plugin, we have no idea
592     // whether any sampler thread is the process's "main" thread.
593     // So that's why we are trying to use Apple's API for trying to
594     // launch our callback function on the process's main thread.
595     // However this will only work, if the plugin host application
596     // established a CF event loop, that is if the application is
597     // using Cocoa for its GUI. For other host applications the
598     // callback will never be executed and thus gigedit would not
599     // popup.
600    
601     // should be pretty much the same as the Objective-C solution below with macHelperRunCFuncOnMainThread()
602     /*CFRunLoopSourceContext sourceContext = CFRunLoopSourceContext();
603     sourceContext.info = this;
604     sourceContext.perform = runInCFMainLoop;
605     printf("CFRunLoopSourceCreate\n"); fflush(stdout);
606     CFRunLoopSourceRef source = CFRunLoopSourceCreate(
607     kCFAllocatorDefault, // allocator
608     1, // priority
609     &sourceContext
610     );
611     printf("CFRunLoopAddSource\n"); fflush(stdout);
612     CFRunLoopAddSource(CFRunLoopGetMain(), source, kCFRunLoopDefaultMode);
613     CFRelease(source);*/
614    
615     // use Apple's Objective-C API to call our callback function
616     // 'runInCFMainLoop()' on the process's "main" thread
617     macHelperRunCFuncOnMainThread(runInCFMainLoop, this);
618     }
619     }
620     #else
621     #ifdef OLD_THREADS
622 persson 2332 Glib::Thread::create(
623 persson 1456 sigc::bind(sigc::ptr_fun(&GigEditState::main_loop_run),
624     &initialized),
625     false);
626 persson 3472 #elif defined(GLIB_THREADS)
627 persson 2332 Glib::Threads::Thread::create(
628     sigc::bind(sigc::ptr_fun(&GigEditState::main_loop_run),
629     &initialized));
630 persson 3472 #else
631     new std::thread([this]() { main_loop_run(&initialized); });
632 schoenebeck 2474 #endif
633 persson 2332 #endif
634 schoenebeck 2474 printf("Waiting for GUI being initialized (on main thread) ....\n"); fflush(stdout);
635 persson 1456 initialized.wait();
636 schoenebeck 2474 printf("GUI is now initialized. Everything done.\n"); fflush(stdout);
637 persson 1456 main_loop_started = true;
638     }
639     current = this;
640     dispatcher->emit();
641     open.wait(); // wait until the GUI thread has read current
642     mutex.unlock();
643     close.wait(); // sleep until window is closed
644     }
645 persson 1898
646     #if defined(WIN32)
647     extern "C" {
648     BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved)
649     {
650     switch (reason) {
651     case DLL_PROCESS_ATTACH:
652     gigedit_dll_handle = instance;
653     break;
654     }
655     return TRUE;
656     }
657     }
658     #endif

  ViewVC Help
Powered by ViewVC