|
@@ -100,13 +100,9 @@ static void cocoa_switch(DisplayChangeListener *dcl,
|
|
static int left_command_key_enabled = 1;
|
|
static int left_command_key_enabled = 1;
|
|
static bool swap_opt_cmd;
|
|
static bool swap_opt_cmd;
|
|
|
|
|
|
-static int gArgc;
|
|
|
|
-static char **gArgv;
|
|
|
|
static bool stretch_video;
|
|
static bool stretch_video;
|
|
static NSTextField *pauseLabel;
|
|
static NSTextField *pauseLabel;
|
|
|
|
|
|
-static QemuSemaphore display_init_sem;
|
|
|
|
-static QemuSemaphore app_started_sem;
|
|
|
|
static bool allow_events;
|
|
static bool allow_events;
|
|
|
|
|
|
static NSInteger cbchangecount = -1;
|
|
static NSInteger cbchangecount = -1;
|
|
@@ -597,7 +593,7 @@ - (void) updateUIInfo
|
|
/*
|
|
/*
|
|
* Don't try to tell QEMU about UI information in the application
|
|
* Don't try to tell QEMU about UI information in the application
|
|
* startup phase -- we haven't yet registered dcl with the QEMU UI
|
|
* startup phase -- we haven't yet registered dcl with the QEMU UI
|
|
- * layer, and also trying to take the iothread lock would deadlock.
|
|
|
|
|
|
+ * layer.
|
|
* When cocoa_display_init() does register the dcl, the UI layer
|
|
* When cocoa_display_init() does register the dcl, the UI layer
|
|
* will call cocoa_switch(), which will call updateUIInfo, so
|
|
* will call cocoa_switch(), which will call updateUIInfo, so
|
|
* we don't lose any information here.
|
|
* we don't lose any information here.
|
|
@@ -790,16 +786,6 @@ - (void) handleMonitorInput:(NSEvent *)event
|
|
|
|
|
|
- (bool) handleEvent:(NSEvent *)event
|
|
- (bool) handleEvent:(NSEvent *)event
|
|
{
|
|
{
|
|
- if(!allow_events) {
|
|
|
|
- /*
|
|
|
|
- * 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.)
|
|
|
|
- */
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
return bool_with_iothread_lock(^{
|
|
return bool_with_iothread_lock(^{
|
|
return [self handleEventLocked:event];
|
|
return [self handleEventLocked:event];
|
|
});
|
|
});
|
|
@@ -1287,8 +1273,6 @@ - (void)applicationDidFinishLaunching: (NSNotification *) note
|
|
{
|
|
{
|
|
COCOA_DEBUG("QemuCocoaAppController: applicationDidFinishLaunching\n");
|
|
COCOA_DEBUG("QemuCocoaAppController: applicationDidFinishLaunching\n");
|
|
allow_events = true;
|
|
allow_events = true;
|
|
- /* Tell cocoa_display_init to proceed */
|
|
|
|
- qemu_sem_post(&app_started_sem);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- (void)applicationWillTerminate:(NSNotification *)aNotification
|
|
- (void)applicationWillTerminate:(NSNotification *)aNotification
|
|
@@ -1919,92 +1903,45 @@ static void cocoa_clipboard_request(QemuClipboardInfo *info,
|
|
/*
|
|
/*
|
|
* The startup process for the OSX/Cocoa UI is complicated, because
|
|
* 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
|
|
* 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():
|
|
|
|
- *
|
|
|
|
- * Initial thread: 2nd thread:
|
|
|
|
|
|
+ * need to start a second thread which runs the qemu_default_main():
|
|
* in main():
|
|
* 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
|
|
|
|
- * 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.
|
|
|
|
|
|
+ * in cocoa_display_init():
|
|
|
|
+ * assign cocoa_main to qemu_main
|
|
|
|
+ * create application, menus, etc
|
|
|
|
+ * in cocoa_main():
|
|
|
|
+ * create qemu-main thread
|
|
|
|
+ * enter OSX run loop
|
|
*/
|
|
*/
|
|
|
|
|
|
static void *call_qemu_main(void *opaque)
|
|
static void *call_qemu_main(void *opaque)
|
|
{
|
|
{
|
|
int status;
|
|
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_default_main()\n");
|
|
|
|
+ qemu_mutex_lock_iothread();
|
|
|
|
+ status = qemu_default_main();
|
|
|
|
+ qemu_mutex_unlock_iothread();
|
|
|
|
+ COCOA_DEBUG("Second thread: qemu_default_main() returned, exiting\n");
|
|
[cbowner release];
|
|
[cbowner release];
|
|
exit(status);
|
|
exit(status);
|
|
}
|
|
}
|
|
|
|
|
|
-int main (int argc, char **argv) {
|
|
|
|
|
|
+static int cocoa_main()
|
|
|
|
+{
|
|
QemuThread thread;
|
|
QemuThread thread;
|
|
|
|
|
|
- COCOA_DEBUG("Entered main()\n");
|
|
|
|
- gArgc = argc;
|
|
|
|
- gArgv = argv;
|
|
|
|
-
|
|
|
|
- qemu_sem_init(&display_init_sem, 0);
|
|
|
|
- qemu_sem_init(&app_started_sem, 0);
|
|
|
|
|
|
+ COCOA_DEBUG("Entered %s()\n", __func__);
|
|
|
|
|
|
|
|
+ qemu_mutex_unlock_iothread();
|
|
qemu_thread_create(&thread, "qemu_main", call_qemu_main,
|
|
qemu_thread_create(&thread, "qemu_main", call_qemu_main,
|
|
NULL, QEMU_THREAD_DETACHED);
|
|
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");
|
|
|
|
-
|
|
|
|
- NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
|
|
|
|
-
|
|
|
|
- // Pull this console process up to being a fully-fledged graphical
|
|
|
|
- // app with a menubar and Dock icon
|
|
|
|
- ProcessSerialNumber psn = { 0, kCurrentProcess };
|
|
|
|
- TransformProcessType(&psn, kProcessTransformToForegroundApplication);
|
|
|
|
-
|
|
|
|
- [QemuApplication sharedApplication];
|
|
|
|
-
|
|
|
|
- create_initial_menus();
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * Create the menu entries which depend on QEMU state (for consoles
|
|
|
|
- * and removeable devices). These make calls back into QEMU functions,
|
|
|
|
- * which is OK because at this point we know that the second thread
|
|
|
|
- * holds the iothread lock and is synchronously waiting for us to
|
|
|
|
- * finish.
|
|
|
|
- */
|
|
|
|
- add_console_menu_entries();
|
|
|
|
- addRemovableDevicesMenuItems();
|
|
|
|
-
|
|
|
|
- // Create an Application controller
|
|
|
|
- QemuCocoaAppController *appController = [[QemuCocoaAppController alloc] init];
|
|
|
|
- [NSApp setDelegate:appController];
|
|
|
|
-
|
|
|
|
// Start the main event loop
|
|
// Start the main event loop
|
|
COCOA_DEBUG("Main thread: entering OSX run loop\n");
|
|
COCOA_DEBUG("Main thread: entering OSX run loop\n");
|
|
[NSApp run];
|
|
[NSApp run];
|
|
- COCOA_DEBUG("Main thread: left OSX run loop, exiting\n");
|
|
|
|
|
|
+ COCOA_DEBUG("Main thread: left OSX run loop, which should never happen\n");
|
|
|
|
|
|
- [appController release];
|
|
|
|
- [pool release];
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
|
|
+ abort();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -2083,25 +2020,42 @@ static void cocoa_refresh(DisplayChangeListener *dcl)
|
|
|
|
|
|
static void cocoa_display_init(DisplayState *ds, DisplayOptions *opts)
|
|
static void cocoa_display_init(DisplayState *ds, DisplayOptions *opts)
|
|
{
|
|
{
|
|
|
|
+ NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
|
|
|
|
+
|
|
COCOA_DEBUG("qemu_cocoa: cocoa_display_init\n");
|
|
COCOA_DEBUG("qemu_cocoa: cocoa_display_init\n");
|
|
|
|
|
|
- /* 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");
|
|
|
|
|
|
+ qemu_main = cocoa_main;
|
|
|
|
+
|
|
|
|
+ // Pull this console process up to being a fully-fledged graphical
|
|
|
|
+ // app with a menubar and Dock icon
|
|
|
|
+ ProcessSerialNumber psn = { 0, kCurrentProcess };
|
|
|
|
+ TransformProcessType(&psn, kProcessTransformToForegroundApplication);
|
|
|
|
+
|
|
|
|
+ [QemuApplication sharedApplication];
|
|
|
|
+
|
|
|
|
+ create_initial_menus();
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Create the menu entries which depend on QEMU state (for consoles
|
|
|
|
+ * and removeable devices). These make calls back into QEMU functions,
|
|
|
|
+ * which is OK because at this point we know that the second thread
|
|
|
|
+ * holds the iothread lock and is synchronously waiting for us to
|
|
|
|
+ * finish.
|
|
|
|
+ */
|
|
|
|
+ add_console_menu_entries();
|
|
|
|
+ addRemovableDevicesMenuItems();
|
|
|
|
+
|
|
|
|
+ // Create an Application controller
|
|
|
|
+ QemuCocoaAppController *controller = [[QemuCocoaAppController alloc] init];
|
|
|
|
+ [NSApp setDelegate:controller];
|
|
|
|
|
|
- QemuCocoaAppController *controller = (QemuCocoaAppController *)[[NSApplication sharedApplication] delegate];
|
|
|
|
/* if fullscreen mode is to be used */
|
|
/* if fullscreen mode is to be used */
|
|
if (opts->has_full_screen && opts->full_screen) {
|
|
if (opts->has_full_screen && opts->full_screen) {
|
|
- dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
|
- [NSApp activateIgnoringOtherApps: YES];
|
|
|
|
- [controller toggleFullScreen: nil];
|
|
|
|
- });
|
|
|
|
|
|
+ [NSApp activateIgnoringOtherApps: YES];
|
|
|
|
+ [controller toggleFullScreen: nil];
|
|
}
|
|
}
|
|
if (opts->u.cocoa.has_full_grab && opts->u.cocoa.full_grab) {
|
|
if (opts->u.cocoa.has_full_grab && opts->u.cocoa.full_grab) {
|
|
- dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
|
- [controller setFullGrab: nil];
|
|
|
|
- });
|
|
|
|
|
|
+ [controller setFullGrab: nil];
|
|
}
|
|
}
|
|
|
|
|
|
if (opts->has_show_cursor && opts->show_cursor) {
|
|
if (opts->has_show_cursor && opts->show_cursor) {
|
|
@@ -2121,6 +2075,8 @@ static void cocoa_display_init(DisplayState *ds, DisplayOptions *opts)
|
|
qemu_event_init(&cbevent, false);
|
|
qemu_event_init(&cbevent, false);
|
|
cbowner = [[QemuCocoaPasteboardTypeOwner alloc] init];
|
|
cbowner = [[QemuCocoaPasteboardTypeOwner alloc] init];
|
|
qemu_clipboard_peer_register(&cbpeer);
|
|
qemu_clipboard_peer_register(&cbpeer);
|
|
|
|
+
|
|
|
|
+ [pool release];
|
|
}
|
|
}
|
|
|
|
|
|
static QemuDisplay qemu_display_cocoa = {
|
|
static QemuDisplay qemu_display_cocoa = {
|