/[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 3364 - (hide annotations) (download)
Tue Nov 14 18:07:25 2017 UTC (6 years, 5 months ago) by schoenebeck
File size: 19673 byte(s)
* Added experimental support for upcoming GTK(MM)4
  (for now up to GTKMM 3.91.2 while still preserving backward compatibility
  down to GTKMM 2).
* Re-merged r2845 to compile now with and without Gtk "Stock ID" API
  (see also r3158).

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

  ViewVC Help
Powered by ViewVC