Make Cocoa_ShowMessageBox work in background threads.
authorJørgen P. Tjernø <jorgen@valvesoftware.com>
Mon, 22 Apr 2013 18:14:32 -0700
changeset 7088 664d8532219b
parent 7087 5639ac726076
child 7089 257fc4e541e1
Make Cocoa_ShowMessageBox work in background threads.
src/video/cocoa/SDL_cocoamessagebox.m
test/testmessage.c
--- a/src/video/cocoa/SDL_cocoamessagebox.m	Mon Apr 22 18:14:26 2013 -0700
+++ b/src/video/cocoa/SDL_cocoamessagebox.m	Mon Apr 22 18:14:32 2013 -0700
@@ -32,6 +32,29 @@
 #include "SDL_messagebox.h"
 #include "SDL_cocoavideo.h"
 
+@interface SDLMessageBoxPresenter : NSObject {
+@public
+    NSInteger clicked;
+}
+@end
+
+@implementation SDLMessageBoxPresenter
+- (id)init
+{
+    self = [super init];
+    if (self) {
+        clicked = -1;
+    }
+
+    return self;
+}
+
+- (void)showAlert:(NSAlert*)alert
+{
+    clicked = [alert runModal];
+}
+@end
+
 
 /* Display a Cocoa message box */
 int
@@ -41,7 +64,7 @@
 
     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 
-    NSAlert* alert = [[NSAlert alloc] init];
+    NSAlert* alert = [[[NSAlert alloc] init] autorelease];
 
     if (messageboxdata->flags & SDL_MESSAGEBOX_ERROR) {
         [alert setAlertStyle:NSCriticalAlertStyle];
@@ -67,14 +90,27 @@
         }
     }
 
-    NSInteger clicked = [alert runModal];
-    clicked -= NSAlertFirstButtonReturn;
-    *buttonid = buttons[clicked].buttonid;
-    [alert release];
+    SDLMessageBoxPresenter* presenter = [[[SDLMessageBoxPresenter alloc] init] autorelease];
+
+    [presenter performSelectorOnMainThread:@selector(showAlert:)
+                                withObject:alert
+                             waitUntilDone:YES];
+
+    int returnValue = 0;
+    NSInteger clicked = presenter->clicked;
+    if (clicked >= NSAlertFirstButtonReturn)
+    {
+        clicked -= NSAlertFirstButtonReturn;
+        *buttonid = buttons[clicked].buttonid;
+    }
+    else
+    {
+        returnValue = SDL_SetError("Did not get a valid `clicked button' id: %d", clicked);
+    }
 
     [pool release];
 
-    return 0;
+    return returnValue;
 }
 
 #endif /* SDL_VIDEO_DRIVER_COCOA */
--- a/test/testmessage.c	Mon Apr 22 18:14:26 2013 -0700
+++ b/test/testmessage.c	Mon Apr 22 18:14:32 2013 -0700
@@ -29,13 +29,67 @@
     exit(rc);
 }
 
+static int
+button_messagebox(void *eventNumber)
+{
+    const SDL_MessageBoxButtonData buttons[] = {
+        {
+            SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT,
+            0,
+            "OK"
+        },{
+            SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT,
+            1,
+            "Cancel"
+        },
+    };
+
+    SDL_MessageBoxData data = {
+        SDL_MESSAGEBOX_INFORMATION,
+        NULL, // no parent window
+        "Custom MessageBox",
+        "This is a custom messagebox",
+        2,
+        buttons,
+        NULL // Default color scheme
+    };
+
+    int button = -1;
+    int success = 0;
+    if (eventNumber) {
+        data.message = "This is a custom messagebox from a background thread.";
+    }
+
+    success =SDL_ShowMessageBox(&data, &button);
+    if (success == -1) {
+        printf("Error Presenting MessageBox: %s\n", SDL_GetError());
+        if (eventNumber) {
+            SDL_UserEvent event;
+            event.type = (intptr_t)eventNumber;
+            SDL_PushEvent((SDL_Event*)&event);
+            return 1;
+        } else {
+            quit(2);
+        }
+    }
+    printf("Pressed button: %d, %s\n", button, button == 1 ? "Cancel" : "OK");
+
+    if (eventNumber) {
+        SDL_UserEvent event;
+        event.type = (intptr_t)eventNumber;
+        SDL_PushEvent((SDL_Event*)&event);
+    }
+
+    return 0;
+}
+
 int
 main(int argc, char *argv[])
 {
     int success;
 
     /* Load the SDL library */
-    if (SDL_Init(0) < 0) {
+    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
         fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError());
         return (1);
     }
@@ -78,36 +132,27 @@
         quit(1);
     }
 
+    button_messagebox(NULL);
+
+    /* Technically this isn't a supported operation for the API, but it doesn't
+     * hurt for it to work.
+     */
     {
-        const SDL_MessageBoxButtonData buttons[] = {
-            {
-                SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT,
-                0,
-                "OK"
-            },{
-                SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT,
-                1,
-                "Cancel"
-            },
-        };
+        int status = 0;
+        SDL_Event event;
+        intptr_t eventNumber = SDL_RegisterEvents(1);
+        SDL_Thread* thread = SDL_CreateThread(&button_messagebox, "MessageBox", (void*)eventNumber);
 
-        SDL_MessageBoxData data = {
-            SDL_MESSAGEBOX_INFORMATION,
-            NULL, // no parent window
-            "Custom MessageBox",
-            "This is a custom messagebox",
-            2,
-            buttons,
-            NULL // Default color scheme
-        };
+        while (SDL_WaitEvent(&event))
+        {
+            if (event.type == eventNumber) {
+                break;
+            }
+        }
 
-        int button = -1;
-        success = SDL_ShowMessageBox(&data, &button);
-        if (success == -1) {
-            printf("Error Presenting MessageBox: %s\n", SDL_GetError());
-            quit(2);
-        }
-        printf("Pressed button: %d, %s\n", button, button == 1 ? "Cancel" : "OK");
+        SDL_WaitThread(thread, &status);
+
+        printf("Message box thread return %i\n", status);
     }
 
     SDL_Quit();