src/video/cocoa/SDL_cocoamessagebox.m
author Sam Lantinga
Sun, 14 Jul 2013 11:58:57 -0700
changeset 7457 8e6dfbc8ac6b
parent 7140 e1896b95a8a7
child 8093 b43765095a6f
permissions -rw-r--r--
Fixed bug 1970 - Cocoa message boxes ignore parent window requests

Ryan C. Gordon

Cocoa_ShowMessageBox() ignores the "window" field of SDL_MessageBoxData, which means you can't assign a parent window to a message box. This is particularly egregious on Mac OS X, because it'll actually make the NSAlert visually part of the parent window instead of just concerning itself with window focus.
slouken@6617
     1
/*
slouken@6617
     2
  Simple DirectMedia Layer
slouken@6885
     3
  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
slouken@6617
     4
slouken@6617
     5
  This software is provided 'as-is', without any express or implied
slouken@6617
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@6617
     7
  arising from the use of this software.
slouken@6617
     8
slouken@6617
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@6617
    10
  including commercial applications, and to alter it and redistribute it
slouken@6617
    11
  freely, subject to the following restrictions:
slouken@6617
    12
slouken@6617
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@6617
    14
     claim that you wrote the original software. If you use this software
slouken@6617
    15
     in a product, an acknowledgment in the product documentation would be
slouken@6617
    16
     appreciated but is not required.
slouken@6617
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@6617
    18
     misrepresented as being the original software.
slouken@6617
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@6617
    20
*/
slouken@6617
    21
#include "SDL_config.h"
slouken@6617
    22
slouken@6617
    23
#if SDL_VIDEO_DRIVER_COCOA
slouken@6617
    24
kmshanah@7140
    25
#if defined(__APPLE__) && defined(__POWERPC__) && !defined(__APPLE_ALTIVEC__)
icculus@6624
    26
#include <altivec.h>
icculus@6624
    27
#undef bool
icculus@6624
    28
#undef vector
icculus@6626
    29
#undef pixel
icculus@6624
    30
#endif
icculus@6624
    31
slouken@7457
    32
#include "SDL_events.h"
slouken@7457
    33
#include "SDL_timer.h"
slouken@6623
    34
#include "SDL_messagebox.h"
slouken@6617
    35
#include "SDL_cocoavideo.h"
slouken@6617
    36
jorgen@7088
    37
@interface SDLMessageBoxPresenter : NSObject {
jorgen@7088
    38
@public
jorgen@7088
    39
    NSInteger clicked;
slouken@7457
    40
    NSWindow *nswindow;
jorgen@7088
    41
}
slouken@7457
    42
- (id) initWithParentWindow:(SDL_Window *)window;
slouken@7457
    43
- (void) alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo;
jorgen@7088
    44
@end
jorgen@7088
    45
jorgen@7088
    46
@implementation SDLMessageBoxPresenter
slouken@7457
    47
- (id) initWithParentWindow:(SDL_Window *)window
jorgen@7088
    48
{
jorgen@7088
    49
    self = [super init];
jorgen@7088
    50
    if (self) {
jorgen@7088
    51
        clicked = -1;
slouken@7457
    52
slouken@7457
    53
        /* Retain the NSWindow because we'll show the alert later on the main thread */
slouken@7457
    54
        if (window) {
slouken@7457
    55
            nswindow = [((SDL_WindowData *) window->driverdata)->nswindow retain];
slouken@7457
    56
        } else {
slouken@7457
    57
            nswindow = NULL;
slouken@7457
    58
        }
jorgen@7088
    59
    }
jorgen@7088
    60
jorgen@7088
    61
    return self;
jorgen@7088
    62
}
jorgen@7088
    63
jorgen@7088
    64
- (void)showAlert:(NSAlert*)alert
jorgen@7088
    65
{
slouken@7457
    66
    if (nswindow) {
slouken@7457
    67
        [alert beginSheetModalForWindow:nswindow modalDelegate:self didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:nil];
slouken@7457
    68
        while (clicked < 0) {
slouken@7457
    69
            SDL_PumpEvents();
slouken@7457
    70
            SDL_Delay(100);
slouken@7457
    71
        }
slouken@7457
    72
        [nswindow release];
slouken@7457
    73
    } else {
slouken@7457
    74
        clicked = [alert runModal];
slouken@7457
    75
    }
jorgen@7088
    76
}
slouken@7457
    77
slouken@7457
    78
- (void) alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo
slouken@7457
    79
{
slouken@7457
    80
    clicked = returnCode;
slouken@7457
    81
}
slouken@7457
    82
jorgen@7088
    83
@end
jorgen@7088
    84
slouken@6617
    85
slouken@6617
    86
/* Display a Cocoa message box */
slouken@6617
    87
int
slouken@6617
    88
Cocoa_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
slouken@6617
    89
{
icculus@6639
    90
    Cocoa_RegisterApp();
icculus@6639
    91
slouken@6848
    92
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
slouken@6848
    93
jorgen@7088
    94
    NSAlert* alert = [[[NSAlert alloc] init] autorelease];
slouken@6617
    95
slouken@6848
    96
    if (messageboxdata->flags & SDL_MESSAGEBOX_ERROR) {
slouken@6848
    97
        [alert setAlertStyle:NSCriticalAlertStyle];
slouken@6848
    98
    } else if (messageboxdata->flags & SDL_MESSAGEBOX_WARNING) {
slouken@6848
    99
        [alert setAlertStyle:NSWarningAlertStyle];
slouken@6848
   100
    } else {
slouken@6848
   101
        [alert setAlertStyle:NSInformationalAlertStyle];
slouken@6848
   102
    }
slouken@6617
   103
slouken@6848
   104
    [alert setMessageText:[NSString stringWithUTF8String:messageboxdata->title]];
slouken@6848
   105
    [alert setInformativeText:[NSString stringWithUTF8String:messageboxdata->message]];
slouken@6617
   106
slouken@6848
   107
    const SDL_MessageBoxButtonData *buttons = messageboxdata->buttons;
slouken@6848
   108
    int i;
slouken@6848
   109
    for (i = 0; i < messageboxdata->numbuttons; ++i) {
slouken@6848
   110
        NSButton *button = [alert addButtonWithTitle:[NSString stringWithUTF8String:buttons[i].text]];
slouken@6848
   111
        if (buttons[i].flags & SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT) {
slouken@6848
   112
            [button setKeyEquivalent:@"\r"];
slouken@6848
   113
        } else if (buttons[i].flags & SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT) {
slouken@6848
   114
            [button setKeyEquivalent:@"\033"];
slouken@6848
   115
        } else {
slouken@6848
   116
            [button setKeyEquivalent:@""];
slouken@6617
   117
        }
slouken@6848
   118
    }
alexey@6832
   119
slouken@7457
   120
    SDLMessageBoxPresenter* presenter = [[[SDLMessageBoxPresenter alloc] initWithParentWindow:messageboxdata->window] autorelease];
jorgen@7088
   121
jorgen@7088
   122
    [presenter performSelectorOnMainThread:@selector(showAlert:)
jorgen@7088
   123
                                withObject:alert
jorgen@7088
   124
                             waitUntilDone:YES];
jorgen@7088
   125
jorgen@7088
   126
    int returnValue = 0;
jorgen@7088
   127
    NSInteger clicked = presenter->clicked;
jorgen@7088
   128
    if (clicked >= NSAlertFirstButtonReturn)
jorgen@7088
   129
    {
jorgen@7088
   130
        clicked -= NSAlertFirstButtonReturn;
jorgen@7088
   131
        *buttonid = buttons[clicked].buttonid;
jorgen@7088
   132
    }
jorgen@7088
   133
    else
jorgen@7088
   134
    {
jorgen@7088
   135
        returnValue = SDL_SetError("Did not get a valid `clicked button' id: %d", clicked);
jorgen@7088
   136
    }
slouken@6848
   137
slouken@6848
   138
    [pool release];
slouken@6617
   139
jorgen@7088
   140
    return returnValue;
slouken@6617
   141
}
slouken@6617
   142
slouken@6617
   143
#endif /* SDL_VIDEO_DRIVER_COCOA */
slouken@6617
   144
slouken@6617
   145
/* vi: set ts=4 sw=4 expandtab: */