src/video/uikit/SDL_uikitview.m
author Alex Szpakowski <slime73@gmail.com>
Thu, 15 Jan 2015 01:06:14 -0400
branchiOS-improvements
changeset 9532 318042c16b76
parent 9529 4bf9830d8153
child 9551 950a1a7b4c3c
permissions -rw-r--r--
Several improvements to the iOS backend:

- Added new custom launch screen code. It uses the launch screen nib when available on iOS 8+, the launch images dictionary if the launch screen nib isn't available, and the old standard image names if the launch image dictionary isn't in the plist.
The launch screen is now hidden during the first call to SDL_PumpEvents rather than SDL_CreateWindow so apps can have the launch screen still visible if they do time-consuming loading after creating their window. It also fades out in roughly the same way as the system launch screen behavior.
It can be disabled by setting the SDL_IPHONE_LAUNCHSCREEN define in SDL_config_iphoneos.h to 0.

- A blank UIView is now created and displayed when the window is first created. The old behavior was to defer creating any view until SDL_GL_CreateContext, which prevented rotation, touch events, and other windowing-related things from working until then. This also makes it easier to use SDL_GetWindowWMInfo after creating a window.

- Moved the keyboard and animation callback code from SDL's UIView subclasses to its UIViewController subclass, which lets them work properly in all cases when a SDL window is valid, even before SDL_GL_CreateContext is called and after SDL_GL_DeleteContext is called.

- SDL_GL_CreateContext, SDL_GL_SwapWindow, SDL_GL_MakeCurrent, and SDL_GL_DeleteContext are more robust.

- Fixed some edge cases where SDL windows weren't rotating properly or their reported sizes were out of sync with their actual sizes.

- Removed all calls to [UIApplication setStatusBarOrientation:]. It doesn't seem to work as expected in all cases in recent iOS versions.

- Some code style cleanup.
slouken@6079
     1
 /*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@8149
     3
  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
slouken@5262
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
slouken@5262
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
slouken@5262
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    14
     claim that you wrote the original software. If you use this software
slouken@5535
    15
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@5262
    20
*/
icculus@8093
    21
#include "../../SDL_internal.h"
slouken@6044
    22
slouken@6044
    23
#if SDL_VIDEO_DRIVER_UIKIT
slouken@2765
    24
slouken@6518
    25
#include "SDL_uikitview.h"
slouken@2765
    26
slouken@4490
    27
#include "../../events/SDL_mouse_c.h"
jimtla@4677
    28
#include "../../events/SDL_touch_c.h"
slime73@9532
    29
#include "../../events/SDL_events_c.h"
slouken@4490
    30
slime73@9532
    31
#import "SDL_uikitappdelegate.h"
slime73@9532
    32
#import "SDL_uikitmodes.h"
slime73@9532
    33
#import "SDL_uikitwindow.h"
slouken@2765
    34
slime73@9501
    35
@implementation SDL_uikitview {
slime73@9532
    36
    SDL_Window *sdlwindow;
slime73@9501
    37
slime73@9501
    38
    SDL_TouchID touchId;
slime73@9532
    39
    UITouch * __weak firstFingerDown;
slime73@9501
    40
}
slouken@2765
    41
slime73@9532
    42
- (instancetype)initWithFrame:(CGRect)frame
kees@6003
    43
{
slime73@9532
    44
    if ((self = [super initWithFrame:frame])) {
slime73@9532
    45
        self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
slime73@9532
    46
        self.autoresizesSubviews = YES;
slouken@2765
    47
slime73@9505
    48
        self.multipleTouchEnabled = YES;
slouken@5445
    49
slime73@9505
    50
        touchId = 1;
slime73@9505
    51
        SDL_AddTouch(touchId, "");
slime73@9505
    52
    }
slouken@4661
    53
slouken@5131
    54
    return self;
slouken@2765
    55
}
slouken@2765
    56
slime73@9532
    57
- (void)setSDLWindow:(SDL_Window *)window
slime73@9527
    58
{
slime73@9532
    59
    SDL_WindowData *data = nil;
slime73@9532
    60
slime73@9532
    61
    if (window == sdlwindow) {
slime73@9532
    62
        return;
slime73@9532
    63
    }
slime73@9532
    64
slime73@9532
    65
    if (sdlwindow) {
slime73@9532
    66
        SDL_uikitview *view = nil;
slime73@9532
    67
        data = (__bridge SDL_WindowData *) sdlwindow->driverdata;
slime73@9532
    68
slime73@9532
    69
        [data.views removeObject:self];
slime73@9532
    70
slime73@9532
    71
        [self removeFromSuperview];
slime73@9532
    72
slime73@9532
    73
        /* Restore the next-oldest view in the old window. */
slime73@9532
    74
        if (data.views.count > 0) {
slime73@9532
    75
            view = data.views[data.views.count - 1];
slime73@9532
    76
        }
slime73@9532
    77
slime73@9532
    78
        data.viewcontroller.view = view;
slime73@9532
    79
slime73@9532
    80
        if (data.uiwindow.rootViewController != data.viewcontroller) {
slime73@9532
    81
            data.uiwindow.rootViewController = data.viewcontroller;
slime73@9532
    82
        } else if (view) {
slime73@9532
    83
            [data.uiwindow addSubview:view];
slime73@9532
    84
        }
slime73@9532
    85
slime73@9532
    86
        [data.uiwindow layoutIfNeeded];
slime73@9532
    87
    }
slime73@9532
    88
slime73@9532
    89
    if (window) {
slime73@9532
    90
        data = (__bridge SDL_WindowData *) window->driverdata;
slime73@9532
    91
slime73@9532
    92
        /* Make sure the SDL window has a strong reference to this view. */
slime73@9532
    93
        [data.views addObject:self];
slime73@9532
    94
slime73@9532
    95
        /* Replace the view controller's old view with this one. */
slime73@9532
    96
        [data.viewcontroller.view removeFromSuperview];
slime73@9532
    97
        data.viewcontroller.view = self;
slime73@9532
    98
slime73@9532
    99
        if (data.uiwindow.rootViewController != data.viewcontroller) {
slime73@9532
   100
            /* The root view controller handles rotation and the status bar.
slime73@9532
   101
             * Assigning it also adds the controller's view to the window. */
slime73@9532
   102
            data.uiwindow.rootViewController = data.viewcontroller;
slime73@9532
   103
        } else {
slime73@9532
   104
            [data.uiwindow addSubview:self];
slime73@9532
   105
        }
slime73@9532
   106
slime73@9532
   107
        /* The view's bounds may not be correct until the next event cycle. That
slime73@9532
   108
         * might happen after the current dimensions are queried, so we force a
slime73@9532
   109
         * layout now to immediately update the bounds. */
slime73@9532
   110
        [data.uiwindow layoutIfNeeded];
slime73@9532
   111
    }
slime73@9532
   112
slime73@9532
   113
    sdlwindow = window;
slime73@9527
   114
}
slime73@9527
   115
slouken@6436
   116
- (CGPoint)touchLocation:(UITouch *)touch shouldNormalize:(BOOL)normalize
slouken@6079
   117
{
slime73@9524
   118
    CGPoint point = [touch locationInView:self];
slouken@6436
   119
slouken@6436
   120
    if (normalize) {
slime73@9501
   121
        CGRect bounds = self.bounds;
slouken@6439
   122
        point.x /= bounds.size.width;
slouken@6439
   123
        point.y /= bounds.size.height;
slouken@6436
   124
    }
slime73@9488
   125
slouken@6079
   126
    return point;
slouken@6079
   127
}
slouken@6079
   128
kees@6003
   129
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
kees@6003
   130
{
slime73@9487
   131
    for (UITouch *touch in touches) {
slime73@9532
   132
        if (!firstFingerDown) {
slouken@6597
   133
            CGPoint locationInView = [self touchLocation:touch shouldNormalize:NO];
kees@6001
   134
slime73@9532
   135
            /* send mouse moved event */
slime73@9529
   136
            SDL_SendMouseMotion(sdlwindow, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y);
slouken@4488
   137
slouken@6597
   138
            /* send mouse down event */
slime73@9529
   139
            SDL_SendMouseButton(sdlwindow, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT);
jim@4660
   140
slime73@9532
   141
            firstFingerDown = touch;
slouken@6597
   142
        }
slouken@6597
   143
slouken@6436
   144
        CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];
icculus@7050
   145
        SDL_SendTouch(touchId, (SDL_FingerID)((size_t)touch),
slouken@6951
   146
                      SDL_TRUE, locationInView.x, locationInView.y, 1.0f);
slouken@5131
   147
    }
slouken@2765
   148
}
slouken@2765
   149
kees@6003
   150
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
kees@6003
   151
{
slime73@9487
   152
    for (UITouch *touch in touches) {
slime73@9532
   153
        if (touch == firstFingerDown) {
slouken@6597
   154
            /* send mouse up */
slime73@9529
   155
            SDL_SendMouseButton(sdlwindow, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT);
slime73@9532
   156
            firstFingerDown = nil;
slouken@6597
   157
        }
slouken@4661
   158
slouken@6436
   159
        CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];
slime73@9501
   160
        SDL_SendTouch(touchId, (SDL_FingerID)((size_t)touch),
slouken@6951
   161
                      SDL_FALSE, locationInView.x, locationInView.y, 1.0f);
slouken@5131
   162
    }
slouken@2765
   163
}
slouken@2765
   164
kees@6003
   165
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
kees@6003
   166
{
slime73@9524
   167
    [self touchesEnded:touches withEvent:event];
slouken@2765
   168
}
slouken@2765
   169
kees@6003
   170
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
kees@6003
   171
{
slime73@9487
   172
    for (UITouch *touch in touches) {
slime73@9532
   173
        if (touch == firstFingerDown) {
slouken@6597
   174
            CGPoint locationInView = [self touchLocation:touch shouldNormalize:NO];
slouken@4488
   175
slouken@6597
   176
            /* send moved event */
slime73@9529
   177
            SDL_SendMouseMotion(sdlwindow, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y);
slouken@6597
   178
        }
jim@4660
   179
slouken@6436
   180
        CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];
slime73@9501
   181
        SDL_SendTouchMotion(touchId, (SDL_FingerID)((size_t)touch),
slouken@6951
   182
                            locationInView.x, locationInView.y, 1.0f);
slouken@5131
   183
    }
slouken@2765
   184
}
slouken@2765
   185
slouken@2765
   186
@end
slouken@2765
   187
slouken@6044
   188
#endif /* SDL_VIDEO_DRIVER_UIKIT */
slouken@6044
   189
slouken@5132
   190
/* vi: set ts=4 sw=4 expandtab: */