/[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 3489 - (show 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 /*
2 * Copyright (C) 2007-2019 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 "compat.h"
21 #include "gigedit.h"
22
23 #ifdef GLIB_THREADS
24 #ifndef OLD_THREADS
25 #include <glibmm/threads.h>
26 #endif
27 #else
28 #include <thread>
29 #include <mutex>
30 #include <condition_variable>
31 #endif
32 #if GTKMM_MAJOR_VERSION < 3
33 #include <gdkmm/region.h>
34 #endif
35 #include <glibmm/dispatcher.h>
36 #include <glibmm/main.h>
37 #include <glibmm/miscutils.h>
38 #include <gtkmm/main.h>
39
40 #if defined(WIN32) || defined(__APPLE__)
41 #include <gtkmm/icontheme.h>
42 #endif
43
44 #if defined(__APPLE__)
45 # include <CoreFoundation/CoreFoundation.h>
46 # include "MacHelper.h"
47 #endif
48
49 #include "mainwindow.h"
50
51 #include "global.h"
52
53 #ifdef __APPLE__
54 #include <dlfcn.h>
55 #include <glibmm/fileutils.h>
56 #endif
57
58 //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 #if defined(__APPLE__) && HAVE_LINUXSAMPLER // the following global external variables are defined in LinuxSampler's global_private.cpp ...
60 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 namespace {
67
68 // 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 GigEditState(GigEdit* parent) :
79 window(0), parent(parent), instrument(0) { }
80 void run(gig::Instrument* pInstrument);
81
82 MainWindow* window;
83
84 private:
85
86 // simple condition variable abstraction
87 class Cond {
88 private:
89 bool pred;
90 #ifdef GLIB_THREADS
91 Glib::Threads::Mutex mutex;
92 Glib::Threads::Cond cond;
93 #else
94 std::mutex mutex;
95 std::condition_variable cond;
96 #endif
97 public:
98 Cond() : pred(false) { }
99 void signal() {
100 #ifdef GLIB_THREADS
101 Glib::Threads::Mutex::Lock lock(mutex);
102 pred = true;
103 cond.signal();
104 #else
105 std::lock_guard<std::mutex> lock(mutex);
106 pred = true;
107 cond.notify_one();
108 #endif
109 }
110 void wait() {
111 #ifdef GLIB_THREADS
112 Glib::Threads::Mutex::Lock lock(mutex);
113 while (!pred) cond.wait(mutex);
114 #else
115 std::unique_lock<std::mutex> lock(mutex);
116 while (!pred) cond.wait(lock);
117 #endif
118 }
119 };
120
121 #ifdef OLD_THREADS
122 static Glib::StaticMutex mutex;
123 #elif defined(GLIB_THREADS)
124 static Glib::Threads::Mutex mutex;
125 #else
126 static std::mutex mutex;
127 #endif
128 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 Cond initialized;
138 gig::Instrument* instrument;
139
140 void open_window();
141 void close_window();
142 #if defined(__APPLE__)
143 static void runInCFMainLoop(void* info);
144 #endif
145 };
146
147 #ifdef WIN32
148 HINSTANCE gigedit_dll_handle = 0;
149 std::string gigedit_datadir;
150 bool gigedit_installdir_is_parent = false;
151 #endif
152
153 #ifdef __APPLE__
154 std::string gigedit_localedir;
155 std::string gigedit_datadir;
156 #endif
157
158 void init_app() {
159 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
165 #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 #ifdef CONFIG_FORCE_GTK_LIBDIR
171 std::string libdir = CONFIG_FORCE_GTK_LIBDIR;
172 #else
173 std::string libdir = Glib::path_get_dirname(info.dli_fname);
174 #endif
175
176 // newer pango versions don't use modules
177 #if PANGO_VERSION_MAJOR == 1 && PANGO_VERSION_MINOR < 38
178 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 #endif
185 if (Glib::getenv("GDK_PIXBUF_MODULE_FILE") == "") {
186 std::string module_file =
187 Glib::build_filename(libdir,
188 "gdk-pixbuf-2.0/2.10.0/loaders.cache");
189 if (Glib::file_test(module_file, Glib::FILE_TEST_EXISTS)) {
190 Glib::setenv("GDK_PIXBUF_MODULE_FILE", module_file, true);
191 }
192 }
193 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 //FIXME: for some reason AC GETTEXT check fails on the Mac cross compiler?
210 //#if HAVE_GETTEXT
211 if (!gigedit_localedir.empty()) {
212 bindtextdomain(GETTEXT_PACKAGE, gigedit_localedir.c_str());
213 } else {
214 bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
215 }
216 //#endif
217 }
218
219 // 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 #endif // __APPLE__
225
226 #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
232 #if GLIB_CHECK_VERSION(2, 16, 0)
233 gchar* root =
234 g_win32_get_package_installation_directory_of_module(gigedit_dll_handle);
235 #else
236 gchar* root =
237 g_win32_get_package_installation_directory(NULL, NULL);
238 #endif
239 std::string installdir(root);
240 g_free(root);
241 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 bindtextdomain(GETTEXT_PACKAGE, localedir);
262 g_free(localedir);
263 #elif !defined(__APPLE__)
264 bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
265 #endif
266 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
267 textdomain(GETTEXT_PACKAGE);
268 #endif // HAVE_GETTEXT
269
270 #ifdef OLD_THREADS
271 // make sure thread_init() is called once and ONLY once per process
272 if (!Glib::thread_supported()) Glib::thread_init();
273 #endif
274 process_initialized = true;
275 }
276 }
277
278
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 void init_app_after_gtk_init() {
312 #if GTKMM_MAJOR_VERSION >= 3
313 enforceGtk3Settings();
314 #endif
315
316 //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 #if GTKMM_MAJOR_VERSION < 3
323 bindtextdomain("gtk20", gigedit_localedir.c_str());
324 #else
325 bindtextdomain("gtk30", gigedit_localedir.c_str());
326 #endif
327 }
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 #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 }
343
344 void connect_signals(GigEdit* gigedit, MainWindow* mainwindow) {
345 // 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 mainwindow->signal_sample_changed().connect(
373 gigedit->signal_sample_changed().make_slot()
374 );
375 mainwindow->signal_sample_ref_changed().connect(
376 gigedit->signal_sample_ref_changed().make_slot()
377 );
378 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 mainwindow->signal_switch_sampler_instrument().connect(
385 gigedit->signal_switch_sampler_instrument().make_slot()
386 );
387 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 }
394
395 } // namespace
396
397 GigEdit::GigEdit() {
398 state = NULL;
399 }
400
401 int GigEdit::run(int argc, char* argv[]) {
402 init_app();
403
404 #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 Gtk::Main kit(argc, argv);
406 #else
407 Glib::RefPtr<Gtk::Application> app =
408 Gtk::Application::create("org.linuxsampler.gigedit");
409 #endif
410 init_app_after_gtk_init();
411
412 MainWindow window;
413 connect_signals(this, &window);
414 if (argc >= 2) window.load_file(argv[1]);
415 #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 kit.run(window);
417 #else
418 app->run(window, argc, argv);
419 #endif
420
421 return 0;
422 }
423
424 int GigEdit::run(gig::Instrument* pInstrument) {
425 init_app();
426
427 GigEditState state(this);
428 this->state = &state;
429 state.run(pInstrument);
430 this->state = NULL;
431 return 0;
432 }
433
434 void GigEdit::on_note_on_event(int key, int velocity) {
435 if (!this->state) return;
436 GigEditState* state = static_cast<GigEditState*>(this->state);
437 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 GigEditState* state = static_cast<GigEditState*>(this->state);
443 state->window->signal_note_off().emit(key, velocity);
444 }
445
446 sigc::signal<void, gig::File*>& GigEdit::signal_file_structure_to_be_changed() {
447 return file_structure_to_be_changed_signal;
448 }
449
450 sigc::signal<void, gig::File*>& GigEdit::signal_file_structure_changed() {
451 return file_structure_changed_signal;
452 }
453
454 sigc::signal<void, std::list<gig::Sample*> >& GigEdit::signal_samples_to_be_removed() {
455 return samples_to_be_removed_signal;
456 }
457
458 sigc::signal<void>& GigEdit::signal_samples_removed() {
459 return samples_removed_signal;
460 }
461
462 sigc::signal<void, gig::Region*>& GigEdit::signal_region_to_be_changed() {
463 return region_to_be_changed_signal;
464 }
465
466 sigc::signal<void, gig::Region*>& GigEdit::signal_region_changed() {
467 return region_changed_signal;
468 }
469
470 sigc::signal<void, gig::DimensionRegion*>& GigEdit::signal_dimreg_to_be_changed() {
471 return dimreg_to_be_changed_signal;
472 }
473
474 sigc::signal<void, gig::DimensionRegion*>& GigEdit::signal_dimreg_changed() {
475 return dimreg_changed_signal;
476 }
477
478 sigc::signal<void, gig::Sample*>& GigEdit::signal_sample_changed() {
479 return sample_changed_signal;
480 }
481
482 sigc::signal<void, gig::Sample*/*old*/, gig::Sample*/*new*/>& GigEdit::signal_sample_ref_changed() {
483 return sample_ref_changed_signal;
484 }
485
486 sigc::signal<void, int/*key*/, int/*velocity*/>& GigEdit::signal_keyboard_key_hit() {
487 return keyboard_key_hit_signal;
488 }
489
490 sigc::signal<void, int/*key*/, int/*velocity*/>& GigEdit::signal_keyboard_key_released() {
491 return keyboard_key_released_signal;
492 }
493
494 sigc::signal<void, gig::Instrument*>& GigEdit::signal_switch_sampler_instrument() {
495 return switch_sampler_instrument_signal;
496 }
497
498 #ifdef OLD_THREADS
499 Glib::StaticMutex GigEditState::mutex = GLIBMM_STATIC_MUTEX_INIT;
500 #elif defined(GLIB_THREADS)
501 Glib::Threads::Mutex GigEditState::mutex;
502 #else
503 std::mutex GigEditState::mutex;
504 #endif
505 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 window->signal_hide().connect(sigc::mem_fun(*this,
521 &GigEditState::close_window));
522 window->present();
523 }
524
525 void GigEditState::close_window() {
526 delete window;
527 close.signal();
528 }
529
530 #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 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 #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 Gtk::Main main_loop(argc, argv);
540 #endif
541 init_app_after_gtk_init();
542
543 dispatcher = new Glib::Dispatcher();
544 dispatcher->connect(sigc::ptr_fun(&GigEditState::open_window_static));
545 initialized->signal();
546
547 #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 main_loop.run();
549 #else
550 Gtk::Main::run();
551 #endif
552 }
553
554 #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 void GigEditState::run(gig::Instrument* pInstrument) {
568 mutex.lock(); // lock access to static variables
569
570 static bool main_loop_started = false;
571 instrument = pInstrument;
572 if (!main_loop_started) {
573 #if defined(__APPLE__) && HAVE_LINUXSAMPLER
574 // 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 Glib::Thread::create(
623 sigc::bind(sigc::ptr_fun(&GigEditState::main_loop_run),
624 &initialized),
625 false);
626 #elif defined(GLIB_THREADS)
627 Glib::Threads::Thread::create(
628 sigc::bind(sigc::ptr_fun(&GigEditState::main_loop_run),
629 &initialized));
630 #else
631 new std::thread([this]() { main_loop_run(&initialized); });
632 #endif
633 #endif
634 printf("Waiting for GUI being initialized (on main thread) ....\n"); fflush(stdout);
635 initialized.wait();
636 printf("GUI is now initialized. Everything done.\n"); fflush(stdout);
637 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
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