/[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 2332 by persson, Wed Mar 14 05:22:26 2012 UTC revision 2689 by schoenebeck, Sun Jan 4 17:19:19 2015 UTC
# Line 1  Line 1 
1  /*  /*
2   * Copyright (C) 2007-2009 Andreas Persson   * Copyright (C) 2007-2015 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 23  Line 23 
23  #include <glibmm/main.h>  #include <glibmm/main.h>
24  #include <gtkmm/main.h>  #include <gtkmm/main.h>
25    
26    #if defined(__APPLE__)
27    # include <CoreFoundation/CoreFoundation.h>
28    # include "MacHelper.h"
29    #endif
30    
31  #include "mainwindow.h"  #include "mainwindow.h"
32    
33  #include "global.h"  #include "global.h"
34    
35    #ifdef __APPLE__
36    #include <dlfcn.h>
37    #include <glibmm/fileutils.h>
38    #include <glibmm/miscutils.h>
39    #endif
40    
41    //TODO: (hopefully) just a temporary nasty hack for launching gigedit on the main thread on Mac (see comments below in this file for details)
42    #if defined(__APPLE__) // the following global external variables are defined in LinuxSampler's global_private.cpp ...
43    extern bool g_mainThreadCallbackSupported;
44    extern void (*g_mainThreadCallback)(void* info);
45    extern void* g_mainThreadCallbackInfo;
46    extern bool g_fireMainThreadCallback;
47    #endif
48    
49  namespace {  namespace {
50    
51  // State for a gigedit thread.  // State for a gigedit thread.
# Line 39  namespace { Line 58  namespace {
58  //  //
59  class GigEditState : public sigc::trackable {  class GigEditState : public sigc::trackable {
60  public:  public:
61      GigEditState(GigEdit* parent) : parent(parent) { }      GigEditState(GigEdit* parent) : parent(parent), instrument(NULL) { }
62      void run(gig::Instrument* pInstrument);      void run(gig::Instrument* pInstrument);
63    
64      MainWindow* window;      MainWindow* window;
# Line 79  private: Line 98  private:
98      GigEdit* parent;      GigEdit* parent;
99      Cond open;      Cond open;
100      Cond close;      Cond close;
101        Cond initialized;
102      gig::Instrument* instrument;      gig::Instrument* instrument;
103    
104      void open_window();      void open_window();
105      void close_window();      void close_window();
106    #if defined(__APPLE__)
107        static void runInCFMainLoop(void* info);
108    #endif
109  };  };
110    
111  #ifdef WIN32  #ifdef WIN32
112  HINSTANCE gigedit_dll_handle = 0;  HINSTANCE gigedit_dll_handle = 0;
113  #endif  #endif
114    
115    #ifdef __APPLE__
116    std::string gigedit_localedir;
117    #endif
118    
119  void init_app() {  void init_app() {
120      static bool process_initialized = false;      static bool process_initialized = false;
121      if (!process_initialized) {      if (!process_initialized) {
# Line 96  void init_app() { Line 123  void init_app() {
123                    << std::flush;                    << std::flush;
124          setlocale(LC_ALL, "");          setlocale(LC_ALL, "");
125    
126  #if HAVE_GETTEXT  #ifdef __APPLE__
127            // Look for pango.modules, gdk-pixbuf.loaders and locale files
128            // under the same dir as the gigedit dylib is installed in.
129            Dl_info info;
130            if (dladdr((void*)&init_app, &info)) {
131                std::string libdir = Glib::path_get_dirname(info.dli_fname);
132    
133                if (Glib::getenv("PANGO_SYSCONFDIR") == "" &&
134                    Glib::file_test(Glib::build_filename(libdir,
135                                                         "pango/pango.modules"),
136                                    Glib::FILE_TEST_EXISTS)) {
137                    Glib::setenv("PANGO_SYSCONFDIR", libdir, true);
138                }
139                if (Glib::getenv("GDK_PIXBUF_MODULE_FILE") == "") {
140                    std::string module_file =
141                        Glib::build_filename(libdir,
142                                             "gtk-2.0/gdk-pixbuf.loaders");
143                    if (Glib::file_test(module_file, Glib::FILE_TEST_EXISTS)) {
144                        Glib::setenv("GDK_PIXBUF_MODULE_FILE", module_file, true);
145                    }
146                }
147      //FIXME: for some reason AC GETTEXT check fails on the Mac cross compiler?
148      //#if HAVE_GETTEXT
149                std::string localedir = Glib::build_filename(libdir, "locale");
150                if (Glib::file_test(localedir, Glib::FILE_TEST_EXISTS)) {
151                    gigedit_localedir = localedir;
152                    bindtextdomain(GETTEXT_PACKAGE, gigedit_localedir.c_str());
153                } else {
154                    bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
155                }
156      //#endif
157            }
158    
159  #ifdef WIN32          // The gtk file dialog stores its recent files state in
160  #if GLIB_CHECK_VERSION(2, 16, 0)          // ~/.local/share
161            g_mkdir_with_parents(
162                Glib::build_filename(Glib::get_home_dir(),
163                                     ".local/share").c_str(), 0777);
164    #endif // __APPLE__
165    
166    //FIXME: for some reason AC GETTEXT check fails on the Mac cross compiler?
167    #if (HAVE_GETTEXT || defined(__APPLE__))
168    
169      #ifdef WIN32
170        #if GLIB_CHECK_VERSION(2, 16, 0)
171          gchar* root =          gchar* root =
172              g_win32_get_package_installation_directory_of_module(gigedit_dll_handle);              g_win32_get_package_installation_directory_of_module(gigedit_dll_handle);
173  #else      #else
174          gchar* root =          gchar* root =
175              g_win32_get_package_installation_directory(NULL, NULL);              g_win32_get_package_installation_directory(NULL, NULL);
176  #endif      #endif
177          gchar* temp = g_build_filename(root, "/share/locale", NULL);          gchar* temp = g_build_filename(root, "/share/locale", NULL);
178          g_free(root);          g_free(root);
179          gchar* localedir = g_win32_locale_filename_from_utf8(temp);          gchar* localedir = g_win32_locale_filename_from_utf8(temp);
180          g_free(temp);          g_free(temp);
181          bindtextdomain(GETTEXT_PACKAGE, localedir);          bindtextdomain(GETTEXT_PACKAGE, localedir);
182          g_free(localedir);          g_free(localedir);
183  #else    #elif !defined(__APPLE__)
184          bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);          bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
185  #endif    #endif
186          bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");          bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
187          textdomain(GETTEXT_PACKAGE);          textdomain(GETTEXT_PACKAGE);
188  #endif // HAVE_GETTEXT  #endif // HAVE_GETTEXT
# Line 167  void connect_signals(GigEdit* gigedit, M Line 235  void connect_signals(GigEdit* gigedit, M
235      mainwindow->signal_keyboard_key_released().connect(      mainwindow->signal_keyboard_key_released().connect(
236          gigedit->signal_keyboard_key_released().make_slot()          gigedit->signal_keyboard_key_released().make_slot()
237      );      );
238        mainwindow->signal_switch_sampler_instrument().connect(
239            gigedit->signal_switch_sampler_instrument().make_slot()
240        );
241  }  }
242    
243  } // namespace  } // namespace
# Line 179  int GigEdit::run(int argc, char* argv[]) Line 250  int GigEdit::run(int argc, char* argv[])
250      init_app();      init_app();
251    
252      Gtk::Main kit(argc, argv);      Gtk::Main kit(argc, argv);
253    
254    //FIXME: for some reason AC GETTEXT check fails on the Mac cross compiler?
255    #if (/*HAVE_GETTEXT &&*/ defined(__APPLE__))
256        // Gtk::Main binds the gtk locale to a possible non-existent
257        // directory. If we have bundled gtk locale files, we rebind here,
258        // after the Gtk::Main constructor.
259        if (!gigedit_localedir.empty()) {
260            bindtextdomain("gtk20", gigedit_localedir.c_str());
261        }
262    #endif
263    
264      MainWindow window;      MainWindow window;
265      connect_signals(this, &window);      connect_signals(this, &window);
266      if (argc >= 2) window.load_file(argv[1]);      if (argc >= 2) window.load_file(argv[1]);
# Line 256  sigc::signal<void, int/*key*/, int/*velo Line 338  sigc::signal<void, int/*key*/, int/*velo
338      return keyboard_key_released_signal;      return keyboard_key_released_signal;
339  }  }
340    
341    sigc::signal<void, gig::Instrument*>& GigEdit::signal_switch_sampler_instrument() {
342        return switch_sampler_instrument_signal;
343    }
344    
345  #ifdef OLD_THREADS  #ifdef OLD_THREADS
346  Glib::StaticMutex GigEditState::mutex = GLIBMM_STATIC_MUTEX_INIT;  Glib::StaticMutex GigEditState::mutex = GLIBMM_STATIC_MUTEX_INIT;
347  #else  #else
# Line 291  void GigEditState::main_loop_run(Cond* i Line 377  void GigEditState::main_loop_run(Cond* i
377      const char* argv_c[] = { "gigedit" };      const char* argv_c[] = { "gigedit" };
378      char** argv = const_cast<char**>(argv_c);      char** argv = const_cast<char**>(argv_c);
379      Gtk::Main main_loop(argc, argv);      Gtk::Main main_loop(argc, argv);
380    //FIXME: for some reason AC GETTEXT check fails on the Mac cross compiler?
381    #if (/*HAVE_GETTEXT &&*/ defined(__APPLE__))
382        if (!gigedit_localedir.empty()) {
383            bindtextdomain("gtk20", gigedit_localedir.c_str());
384        }
385    #endif
386    
387      dispatcher = new Glib::Dispatcher();      dispatcher = new Glib::Dispatcher();
388      dispatcher->connect(sigc::ptr_fun(&GigEditState::open_window_static));      dispatcher->connect(sigc::ptr_fun(&GigEditState::open_window_static));
# Line 299  void GigEditState::main_loop_run(Cond* i Line 391  void GigEditState::main_loop_run(Cond* i
391      main_loop.run();      main_loop.run();
392  }  }
393    
394    #if defined(__APPLE__)
395    
396    void GigEditState::runInCFMainLoop(void* info) {
397        printf("runInCFMainLoop() entered\n"); fflush(stdout);
398        GigEditState* state = static_cast<GigEditState*>(info);
399        state->main_loop_run(
400            &state->initialized
401        );
402        printf("runInCFMainLoop() left\n"); fflush(stdout);
403    }
404    
405    #endif // __APPLE__
406    
407  void GigEditState::run(gig::Instrument* pInstrument) {  void GigEditState::run(gig::Instrument* pInstrument) {
408      mutex.lock(); // lock access to static variables      mutex.lock(); // lock access to static variables
409    
410      static bool main_loop_started = false;      static bool main_loop_started = false;
411        instrument = pInstrument;
412      if (!main_loop_started) {      if (!main_loop_started) {
413          Cond initialized;  #if defined(__APPLE__)
414  #ifdef OLD_THREADS          // spawn GUI on main thread :
415            //     On OS X the Gtk GUI can only be launched on a process's "main"
416            //     thread. When trying to launch the Gtk GUI on any other thread,
417            //     there will only be a white box, because the GUI would not receive
418            //     any events, since it would listen to the wrong system event loop.
419            //     So far we haven't investigated whether there is any kind of
420            //     circumvention to allow doing that also on other OS X threads.
421            {
422                // In case the sampler was launched as standalone sampler (not as
423                // plugin), use the following global callback variable hack ...
424                if (g_mainThreadCallbackSupported) {
425                    printf("Setting callback ...\n"); fflush(stdout);
426                    g_mainThreadCallback = runInCFMainLoop;
427                    g_mainThreadCallbackInfo = this;
428                    g_fireMainThreadCallback = true;
429                    printf("Callback variables set.\n"); fflush(stdout);
430                } else { // Sampler was launched as (i.e. AU / VST) plugin ...
431                    // When the sampler was launched as plugin, we have no idea
432                    // whether any sampler thread is the process's "main" thread.
433                    // So that's why we are trying to use Apple's API for trying to
434                    // launch our callback function on the process's main thread.
435                    // However this will only work, if the plugin host application
436                    // established a CF event loop, that is if the application is
437                    // using Cocoa for its GUI. For other host applications the
438                    // callback will never be executed and thus gigedit would not
439                    // popup.
440                    
441                    // should be pretty much the same as the Objective-C solution below with macHelperRunCFuncOnMainThread()
442                    /*CFRunLoopSourceContext sourceContext = CFRunLoopSourceContext();
443                    sourceContext.info = this;
444                    sourceContext.perform = runInCFMainLoop;
445                    printf("CFRunLoopSourceCreate\n"); fflush(stdout);
446                    CFRunLoopSourceRef source = CFRunLoopSourceCreate(
447                        kCFAllocatorDefault, // allocator
448                        1, // priority
449                        &sourceContext
450                    );
451                    printf("CFRunLoopAddSource\n"); fflush(stdout);
452                    CFRunLoopAddSource(CFRunLoopGetMain(), source, kCFRunLoopDefaultMode);
453                    CFRelease(source);*/
454                    
455                    // use Apple's Objective-C API to call our callback function
456                    // 'runInCFMainLoop()' on the process's "main" thread
457                    macHelperRunCFuncOnMainThread(runInCFMainLoop, this);
458                }
459            }
460    #else
461      #ifdef OLD_THREADS
462          Glib::Thread::create(          Glib::Thread::create(
463              sigc::bind(sigc::ptr_fun(&GigEditState::main_loop_run),              sigc::bind(sigc::ptr_fun(&GigEditState::main_loop_run),
464                         &initialized),                         &initialized),
465              false);              false);
466  #else    #else
467          Glib::Threads::Thread::create(          Glib::Threads::Thread::create(
468              sigc::bind(sigc::ptr_fun(&GigEditState::main_loop_run),              sigc::bind(sigc::ptr_fun(&GigEditState::main_loop_run),
469                         &initialized));                         &initialized));
470      #endif
471  #endif  #endif
472            printf("Waiting for GUI being initialized (on main thread) ....\n"); fflush(stdout);
473          initialized.wait();          initialized.wait();
474            printf("GUI is now initialized. Everything done.\n"); fflush(stdout);
475          main_loop_started = true;          main_loop_started = true;
476      }      }
     instrument = pInstrument;  
477      current = this;      current = this;
478      dispatcher->emit();      dispatcher->emit();
479      open.wait(); // wait until the GUI thread has read current      open.wait(); // wait until the GUI thread has read current

Legend:
Removed from v.2332  
changed lines
  Added in v.2689

  ViewVC Help
Powered by ViewVC