/[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 2471 by persson, Sun Sep 15 17:06:45 2013 UTC revision 3021 by persson, Sun Oct 23 07:24:40 2016 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 17  Line 17 
17   * 02110-1301 USA.   * 02110-1301 USA.
18   */   */
19    
20    #include <glibmmconfig.h>
21    // threads.h must be included first to be able to build with
22    // G_DISABLE_DEPRECATED
23    #if (GLIBMM_MAJOR_VERSION == 2 && GLIBMM_MINOR_VERSION == 31 && GLIBMM_MICRO_VERSION >= 2) || \
24        (GLIBMM_MAJOR_VERSION == 2 && GLIBMM_MINOR_VERSION > 31) || GLIBMM_MAJOR_VERSION > 2
25    #include <glibmm/threads.h>
26    #endif
27    
28  #include "gigedit.h"  #include "gigedit.h"
29    
30    #include <gtkmmconfig.h>
31    #if GTKMM_MAJOR_VERSION < 3
32    #include <gdkmm/region.h>
33    #endif
34  #include <glibmm/dispatcher.h>  #include <glibmm/dispatcher.h>
35  #include <glibmm/main.h>  #include <glibmm/main.h>
36  #include <gtkmm/main.h>  #include <gtkmm/main.h>
37    
38    #if defined(__APPLE__)
39    # include <CoreFoundation/CoreFoundation.h>
40    # include "MacHelper.h"
41    #endif
42    
43  #include "mainwindow.h"  #include "mainwindow.h"
44    
45  #include "global.h"  #include "global.h"
# Line 33  Line 50 
50  #include <glibmm/miscutils.h>  #include <glibmm/miscutils.h>
51  #endif  #endif
52    
53    //TODO: (hopefully) just a temporary nasty hack for launching gigedit on the main thread on Mac (see comments below in this file for details)
54    #if defined(__APPLE__) && HAVE_LINUXSAMPLER // the following global external variables are defined in LinuxSampler's global_private.cpp ...
55    extern bool g_mainThreadCallbackSupported;
56    extern void (*g_mainThreadCallback)(void* info);
57    extern void* g_mainThreadCallbackInfo;
58    extern bool g_fireMainThreadCallback;
59    #endif
60    
61  namespace {  namespace {
62    
63  // State for a gigedit thread.  // State for a gigedit thread.
# Line 45  namespace { Line 70  namespace {
70  //  //
71  class GigEditState : public sigc::trackable {  class GigEditState : public sigc::trackable {
72  public:  public:
73      GigEditState(GigEdit* parent) : parent(parent) { }      GigEditState(GigEdit* parent) :
74            window(0), parent(parent), instrument(0) { }
75      void run(gig::Instrument* pInstrument);      void run(gig::Instrument* pInstrument);
76    
77      MainWindow* window;      MainWindow* window;
# Line 85  private: Line 111  private:
111      GigEdit* parent;      GigEdit* parent;
112      Cond open;      Cond open;
113      Cond close;      Cond close;
114        Cond initialized;
115      gig::Instrument* instrument;      gig::Instrument* instrument;
116    
117      void open_window();      void open_window();
118      void close_window();      void close_window();
119    #if defined(__APPLE__)
120        static void runInCFMainLoop(void* info);
121    #endif
122  };  };
123    
124  #ifdef WIN32  #ifdef WIN32
# Line 127  void init_app() { Line 157  void init_app() {
157                      Glib::setenv("GDK_PIXBUF_MODULE_FILE", module_file, true);                      Glib::setenv("GDK_PIXBUF_MODULE_FILE", module_file, true);
158                  }                  }
159              }              }
160  #if HAVE_GETTEXT    //FIXME: for some reason AC GETTEXT check fails on the Mac cross compiler?
161      //#if HAVE_GETTEXT
162              std::string localedir = Glib::build_filename(libdir, "locale");              std::string localedir = Glib::build_filename(libdir, "locale");
163              if (Glib::file_test(localedir, Glib::FILE_TEST_EXISTS)) {              if (Glib::file_test(localedir, Glib::FILE_TEST_EXISTS)) {
164                  gigedit_localedir = localedir;                  gigedit_localedir = localedir;
# Line 135  void init_app() { Line 166  void init_app() {
166              } else {              } else {
167                  bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);                  bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
168              }              }
169  #endif    //#endif
170          }          }
171    
172          // The gtk file dialog stores its recent files state in          // The gtk file dialog stores its recent files state in
# Line 143  void init_app() { Line 174  void init_app() {
174          g_mkdir_with_parents(          g_mkdir_with_parents(
175              Glib::build_filename(Glib::get_home_dir(),              Glib::build_filename(Glib::get_home_dir(),
176                                   ".local/share").c_str(), 0777);                                   ".local/share").c_str(), 0777);
177  #endif  #endif // __APPLE__
178    
179  #if HAVE_GETTEXT  //FIXME: for some reason AC GETTEXT check fails on the Mac cross compiler?
180    #if (HAVE_GETTEXT || defined(__APPLE__))
181    
182  #ifdef WIN32    #ifdef WIN32
183  #if GLIB_CHECK_VERSION(2, 16, 0)      #if GLIB_CHECK_VERSION(2, 16, 0)
184          gchar* root =          gchar* root =
185              g_win32_get_package_installation_directory_of_module(gigedit_dll_handle);              g_win32_get_package_installation_directory_of_module(gigedit_dll_handle);
186  #else      #else
187          gchar* root =          gchar* root =
188              g_win32_get_package_installation_directory(NULL, NULL);              g_win32_get_package_installation_directory(NULL, NULL);
189  #endif      #endif
190          gchar* temp = g_build_filename(root, "/share/locale", NULL);          gchar* temp = g_build_filename(root, "/share/locale", NULL);
191          g_free(root);          g_free(root);
192          gchar* localedir = g_win32_locale_filename_from_utf8(temp);          gchar* localedir = g_win32_locale_filename_from_utf8(temp);
193          g_free(temp);          g_free(temp);
194          bindtextdomain(GETTEXT_PACKAGE, localedir);          bindtextdomain(GETTEXT_PACKAGE, localedir);
195          g_free(localedir);          g_free(localedir);
196  #elif !defined(__APPLE__)    #elif !defined(__APPLE__)
197          bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);          bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
198  #endif    #endif
199          bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");          bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
200          textdomain(GETTEXT_PACKAGE);          textdomain(GETTEXT_PACKAGE);
201  #endif // HAVE_GETTEXT  #endif // HAVE_GETTEXT
# Line 216  void connect_signals(GigEdit* gigedit, M Line 248  void connect_signals(GigEdit* gigedit, M
248      mainwindow->signal_keyboard_key_released().connect(      mainwindow->signal_keyboard_key_released().connect(
249          gigedit->signal_keyboard_key_released().make_slot()          gigedit->signal_keyboard_key_released().make_slot()
250      );      );
251        mainwindow->signal_switch_sampler_instrument().connect(
252            gigedit->signal_switch_sampler_instrument().make_slot()
253        );
254        mainwindow->signal_script_to_be_changed.connect(
255            gigedit->signal_script_to_be_changed.make_slot()
256        );
257        mainwindow->signal_script_changed.connect(
258            gigedit->signal_script_changed.make_slot()
259        );
260  }  }
261    
262  } // namespace  } // namespace
# Line 229  int GigEdit::run(int argc, char* argv[]) Line 270  int GigEdit::run(int argc, char* argv[])
270    
271      Gtk::Main kit(argc, argv);      Gtk::Main kit(argc, argv);
272    
273  #if HAVE_GETTEXT && defined(__APPLE__)  //FIXME: for some reason AC GETTEXT check fails on the Mac cross compiler?
274    #if (/*HAVE_GETTEXT &&*/ defined(__APPLE__))
275      // Gtk::Main binds the gtk locale to a possible non-existent      // Gtk::Main binds the gtk locale to a possible non-existent
276      // directory. If we have bundled gtk locale files, we rebind here,      // directory. If we have bundled gtk locale files, we rebind here,
277      // after the Gtk::Main constructor.      // after the Gtk::Main constructor.
# Line 257  int GigEdit::run(gig::Instrument* pInstr Line 299  int GigEdit::run(gig::Instrument* pInstr
299    
300  void GigEdit::on_note_on_event(int key, int velocity) {  void GigEdit::on_note_on_event(int key, int velocity) {
301      if (!this->state) return;      if (!this->state) return;
302      GigEditState* state = (GigEditState*) this->state;      GigEditState* state = static_cast<GigEditState*>(this->state);
303      state->window->signal_note_on().emit(key, velocity);      state->window->signal_note_on().emit(key, velocity);
304  }  }
305    
306  void GigEdit::on_note_off_event(int key, int velocity) {  void GigEdit::on_note_off_event(int key, int velocity) {
307      if (!this->state) return;      if (!this->state) return;
308      GigEditState* state = (GigEditState*) this->state;      GigEditState* state = static_cast<GigEditState*>(this->state);
309      state->window->signal_note_off().emit(key, velocity);      state->window->signal_note_off().emit(key, velocity);
310  }  }
311    
# Line 315  sigc::signal<void, int/*key*/, int/*velo Line 357  sigc::signal<void, int/*key*/, int/*velo
357      return keyboard_key_released_signal;      return keyboard_key_released_signal;
358  }  }
359    
360    sigc::signal<void, gig::Instrument*>& GigEdit::signal_switch_sampler_instrument() {
361        return switch_sampler_instrument_signal;
362    }
363    
364  #ifdef OLD_THREADS  #ifdef OLD_THREADS
365  Glib::StaticMutex GigEditState::mutex = GLIBMM_STATIC_MUTEX_INIT;  Glib::StaticMutex GigEditState::mutex = GLIBMM_STATIC_MUTEX_INIT;
366  #else  #else
# Line 345  void GigEditState::close_window() { Line 391  void GigEditState::close_window() {
391      close.signal();      close.signal();
392  }  }
393    
394    #if defined(WIN32) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))
395    // make sure stack is 16-byte aligned for SSE instructions
396    __attribute__((force_align_arg_pointer))
397    #endif
398  void GigEditState::main_loop_run(Cond* initialized) {  void GigEditState::main_loop_run(Cond* initialized) {
399      int argc = 1;      int argc = 1;
400      const char* argv_c[] = { "gigedit" };      const char* argv_c[] = { "gigedit" };
401      char** argv = const_cast<char**>(argv_c);      char** argv = const_cast<char**>(argv_c);
402      Gtk::Main main_loop(argc, argv);      Gtk::Main main_loop(argc, argv);
403  #if HAVE_GETTEXT && defined(__APPLE__)  //FIXME: for some reason AC GETTEXT check fails on the Mac cross compiler?
404    #if (/*HAVE_GETTEXT &&*/ defined(__APPLE__))
405      if (!gigedit_localedir.empty()) {      if (!gigedit_localedir.empty()) {
406          bindtextdomain("gtk20", gigedit_localedir.c_str());          bindtextdomain("gtk20", gigedit_localedir.c_str());
407      }      }
# Line 363  void GigEditState::main_loop_run(Cond* i Line 414  void GigEditState::main_loop_run(Cond* i
414      main_loop.run();      main_loop.run();
415  }  }
416    
417    #if defined(__APPLE__)
418    
419    void GigEditState::runInCFMainLoop(void* info) {
420        printf("runInCFMainLoop() entered\n"); fflush(stdout);
421        GigEditState* state = static_cast<GigEditState*>(info);
422        state->main_loop_run(
423            &state->initialized
424        );
425        printf("runInCFMainLoop() left\n"); fflush(stdout);
426    }
427    
428    #endif // __APPLE__
429    
430  void GigEditState::run(gig::Instrument* pInstrument) {  void GigEditState::run(gig::Instrument* pInstrument) {
431      mutex.lock(); // lock access to static variables      mutex.lock(); // lock access to static variables
432    
433      static bool main_loop_started = false;      static bool main_loop_started = false;
434        instrument = pInstrument;
435      if (!main_loop_started) {      if (!main_loop_started) {
436          Cond initialized;  #if defined(__APPLE__) && HAVE_LINUXSAMPLER
437  #ifdef OLD_THREADS          // spawn GUI on main thread :
438            //     On OS X the Gtk GUI can only be launched on a process's "main"
439            //     thread. When trying to launch the Gtk GUI on any other thread,
440            //     there will only be a white box, because the GUI would not receive
441            //     any events, since it would listen to the wrong system event loop.
442            //     So far we haven't investigated whether there is any kind of
443            //     circumvention to allow doing that also on other OS X threads.
444            {
445                // In case the sampler was launched as standalone sampler (not as
446                // plugin), use the following global callback variable hack ...
447                if (g_mainThreadCallbackSupported) {
448                    printf("Setting callback ...\n"); fflush(stdout);
449                    g_mainThreadCallback = runInCFMainLoop;
450                    g_mainThreadCallbackInfo = this;
451                    g_fireMainThreadCallback = true;
452                    printf("Callback variables set.\n"); fflush(stdout);
453                } else { // Sampler was launched as (i.e. AU / VST) plugin ...
454                    // When the sampler was launched as plugin, we have no idea
455                    // whether any sampler thread is the process's "main" thread.
456                    // So that's why we are trying to use Apple's API for trying to
457                    // launch our callback function on the process's main thread.
458                    // However this will only work, if the plugin host application
459                    // established a CF event loop, that is if the application is
460                    // using Cocoa for its GUI. For other host applications the
461                    // callback will never be executed and thus gigedit would not
462                    // popup.
463                    
464                    // should be pretty much the same as the Objective-C solution below with macHelperRunCFuncOnMainThread()
465                    /*CFRunLoopSourceContext sourceContext = CFRunLoopSourceContext();
466                    sourceContext.info = this;
467                    sourceContext.perform = runInCFMainLoop;
468                    printf("CFRunLoopSourceCreate\n"); fflush(stdout);
469                    CFRunLoopSourceRef source = CFRunLoopSourceCreate(
470                        kCFAllocatorDefault, // allocator
471                        1, // priority
472                        &sourceContext
473                    );
474                    printf("CFRunLoopAddSource\n"); fflush(stdout);
475                    CFRunLoopAddSource(CFRunLoopGetMain(), source, kCFRunLoopDefaultMode);
476                    CFRelease(source);*/
477                    
478                    // use Apple's Objective-C API to call our callback function
479                    // 'runInCFMainLoop()' on the process's "main" thread
480                    macHelperRunCFuncOnMainThread(runInCFMainLoop, this);
481                }
482            }
483    #else
484      #ifdef OLD_THREADS
485          Glib::Thread::create(          Glib::Thread::create(
486              sigc::bind(sigc::ptr_fun(&GigEditState::main_loop_run),              sigc::bind(sigc::ptr_fun(&GigEditState::main_loop_run),
487                         &initialized),                         &initialized),
488              false);              false);
489  #else    #else
490          Glib::Threads::Thread::create(          Glib::Threads::Thread::create(
491              sigc::bind(sigc::ptr_fun(&GigEditState::main_loop_run),              sigc::bind(sigc::ptr_fun(&GigEditState::main_loop_run),
492                         &initialized));                         &initialized));
493      #endif
494  #endif  #endif
495            printf("Waiting for GUI being initialized (on main thread) ....\n"); fflush(stdout);
496          initialized.wait();          initialized.wait();
497            printf("GUI is now initialized. Everything done.\n"); fflush(stdout);
498          main_loop_started = true;          main_loop_started = true;
499      }      }
     instrument = pInstrument;  
500      current = this;      current = this;
501      dispatcher->emit();      dispatcher->emit();
502      open.wait(); // wait until the GUI thread has read current      open.wait(); // wait until the GUI thread has read current

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

  ViewVC Help
Powered by ViewVC