@@ -39,16 +39,18 @@ int main(int argc, char **argv)
#endif
#endif /* CONFIG_SDL */
-#ifdef CONFIG_COCOA
-#undef main
-#define main qemu_main
-#endif /* CONFIG_COCOA */
-
+#ifndef CONFIG_COCOA
int main(int argc, char **argv, char **envp)
{
+ /*
+ * ui/cocoa.m relies on this being the exact content of main(),
+ * because it has to run everything after qemu_init in a secondary
+ * thread.
+ */
qemu_init(argc, argv, envp);
qemu_main_loop();
qemu_cleanup();
return 0;
}
+#endif /* CONFIG_COCOA */
@@ -100,14 +100,13 @@ static int last_buttons;
static int cursor_hide = 1;
static int left_command_key_enabled = 1;
static bool swap_opt_cmd;
+static bool full_screen;
+static bool full_grab;
+static bool have_cocoa_ui;
-static int gArgc;
-static char **gArgv;
static bool stretch_video;
static NSTextField *pauseLabel;
-static QemuSemaphore display_init_sem;
-static QemuSemaphore app_started_sem;
static bool allow_events;
static NSInteger cbchangecount = -1;
@@ -150,39 +149,28 @@ static bool bool_with_iothread_lock(BoolCodeBlock block)
/*
* The startup process for the OSX/Cocoa UI is complicated, because
* OSX insists that the UI runs on the initial main thread, and so we
- * need to start a second thread which runs the vl.c qemu_main():
+ * need to start a second thread which runs qemu_main_loop():
*
* Initial thread: 2nd thread:
* in main():
- * create qemu-main thread
- * wait on display_init semaphore
- * call qemu_main()
- * ...
- * in cocoa_display_init():
- * post the display_init semaphore
- * wait on app_started semaphore
+ * qemu_init()
* create application, menus, etc
* enter OSX run loop
* in applicationDidFinishLaunching:
- * post app_started semaphore
- * tell main thread to fullscreen if needed
- * [...]
- * run qemu main-loop
- *
- * We do this in two stages so that we don't do the creation of the
- * GUI application menus and so on for command line options like --help
- * where we want to just print text to stdout and exit immediately.
+ * fullscreen if needed
+ * create main loop thread
+ * call qemu_main_loop()
*/
-static void *call_qemu_main(void *opaque)
+static void *call_qemu_main_loop(void *opaque)
{
- int status;
-
- COCOA_DEBUG("Second thread: calling qemu_main()\n");
- status = qemu_main(gArgc, gArgv, *_NSGetEnviron());
- COCOA_DEBUG("Second thread: qemu_main() returned, exiting\n");
+ COCOA_DEBUG("Second thread: calling qemu_main_loop()\n");
+ qemu_mutex_lock_iothread();
+ qemu_main_loop();
+ COCOA_DEBUG("Second thread: qemu_main_loop() returned, exiting\n");
+ qemu_cleanup();
[cbowner release];
- exit(status);
+ exit(0);
}
// Mac to QKeyCode conversion
@@ -627,9 +615,9 @@ static CGEventRef handleTapEvent(CGEventTapProxy proxy, CGEventType type, CGEven
* Don't try to tell QEMU about UI information in the application
* startup phase -- we haven't yet registered dcl with the QEMU UI
* layer, and also trying to take the iothread lock would deadlock.
- * When cocoa_display_init() does register the dcl, the UI layer
- * will call cocoa_switch(), which will call updateUIInfo, so
- * we don't lose any information here.
+ * When applicationDidFinishLaunching() does register the dcl, the
+ * UI layer will call cocoa_switch(), which will call updateUIInfo,
+ * so we don't lose any information here.
*/
return;
}
@@ -823,9 +811,7 @@ static CGEventRef handleTapEvent(CGEventTapProxy proxy, CGEventType type, CGEven
/*
* Just let OSX have all events that arrive before
* applicationDidFinishLaunching.
- * This avoids a deadlock on the iothread lock, which cocoa_display_init()
- * will not drop until after the app_started_sem is posted. (In theory
- * there should not be any such events, but OSX Catalina now emits some.)
+ * This may not be needed anymore?
*/
return false;
}
@@ -1321,10 +1307,27 @@ static CGEventRef handleTapEvent(CGEventTapProxy proxy, CGEventType type, CGEven
- (void)applicationDidFinishLaunching: (NSNotification *) note
{
+ QemuThread main_thread;
+
COCOA_DEBUG("QemuCocoaAppController: applicationDidFinishLaunching\n");
allow_events = true;
- /* Tell cocoa_display_init to proceed */
- qemu_sem_post(&app_started_sem);
+
+ // register vga output callbacks
+ register_displaychangelistener(&dcl);
+
+ qemu_clipboard_peer_register(&cbpeer);
+
+ qemu_mutex_unlock_iothread();
+ qemu_thread_create(&main_thread, "qemu_main_loop", call_qemu_main_loop,
+ NULL, QEMU_THREAD_DETACHED);
+
+ if (full_screen) {
+ [NSApp activateIgnoringOtherApps: YES];
+ [self toggleFullScreen: nil];
+ }
+ if (full_grab) {
+ [self setFullGrab: nil];
+ }
}
- (void)applicationWillTerminate:(NSNotification *)aNotification
@@ -1941,22 +1944,17 @@ static void cocoa_clipboard_request(QemuClipboardInfo *info,
}
}
-int main (int argc, char **argv) {
- QemuThread thread;
-
+int main(int argc, char **argv, char **envp)
+{
COCOA_DEBUG("Entered main()\n");
- gArgc = argc;
- gArgv = argv;
- qemu_sem_init(&display_init_sem, 0);
- qemu_sem_init(&app_started_sem, 0);
-
- qemu_thread_create(&thread, "qemu_main", call_qemu_main,
- NULL, QEMU_THREAD_DETACHED);
-
- COCOA_DEBUG("Main thread: waiting for display_init_sem\n");
- qemu_sem_wait(&display_init_sem);
- COCOA_DEBUG("Main thread: initializing app\n");
+ /* Takes iothread lock, released in applicationDidFinishLaunching:. */
+ qemu_init(argc, argv, envp);
+ if (!have_cocoa_ui) {
+ qemu_main_loop();
+ qemu_cleanup();
+ return 0;
+ }
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
@@ -1979,6 +1977,9 @@ int main (int argc, char **argv) {
add_console_menu_entries();
addRemovableDevicesMenuItems();
+ qemu_event_init(&cbevent, false);
+ cbowner = [[QemuCocoaPasteboardTypeOwner alloc] init];
+
// Create an Application controller
QemuCocoaAppController *appController = [[QemuCocoaAppController alloc] init];
[NSApp setDelegate:appController];
@@ -2071,24 +2072,13 @@ static void cocoa_refresh(DisplayChangeListener *dcl)
static void cocoa_display_init(DisplayState *ds, DisplayOptions *opts)
{
COCOA_DEBUG("qemu_cocoa: cocoa_display_init\n");
+ have_cocoa_ui = 1;
- /* Tell main thread to go ahead and create the app and enter the run loop */
- qemu_sem_post(&display_init_sem);
- qemu_sem_wait(&app_started_sem);
- COCOA_DEBUG("cocoa_display_init: app start completed\n");
-
- QemuCocoaAppController *controller = (QemuCocoaAppController *)[[NSApplication sharedApplication] delegate];
- /* if fullscreen mode is to be used */
if (opts->has_full_screen && opts->full_screen) {
- dispatch_async(dispatch_get_main_queue(), ^{
- [NSApp activateIgnoringOtherApps: YES];
- [controller toggleFullScreen: nil];
- });
+ full_screen = 1;
}
if (opts->u.cocoa.has_full_grab && opts->u.cocoa.full_grab) {
- dispatch_async(dispatch_get_main_queue(), ^{
- [controller setFullGrab: nil];
- });
+ full_grab = 1;
}
if (opts->has_show_cursor && opts->show_cursor) {
@@ -2101,13 +2091,6 @@ static void cocoa_display_init(DisplayState *ds, DisplayOptions *opts)
if (opts->u.cocoa.has_left_command_key && !opts->u.cocoa.left_command_key) {
left_command_key_enabled = 0;
}
-
- // register vga output callbacks
- register_displaychangelistener(&dcl);
-
- qemu_event_init(&cbevent, false);
- cbowner = [[QemuCocoaPasteboardTypeOwner alloc] init];
- qemu_clipboard_peer_register(&cbpeer);
}
static QemuDisplay qemu_display_cocoa = {