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