mirror of
https://github.com/Ryujinx/SDL.git
synced 2025-01-17 03:57:08 +00:00
334 lines
11 KiB
Objective-C
334 lines
11 KiB
Objective-C
/*
|
|
Simple DirectMedia Layer
|
|
Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
warranty. In no event will the authors be held liable for any damages
|
|
arising from the use of this software.
|
|
|
|
Permission is granted to anyone to use this software for any purpose,
|
|
including commercial applications, and to alter it and redistribute it
|
|
freely, subject to the following restrictions:
|
|
|
|
1. The origin of this software must not be misrepresented; you must not
|
|
claim that you wrote the original software. If you use this software
|
|
in a product, an acknowledgment in the product documentation would be
|
|
appreciated but is not required.
|
|
2. Altered source versions must be plainly marked as such, and must not be
|
|
misrepresented as being the original software.
|
|
3. This notice may not be removed or altered from any source distribution.
|
|
*/
|
|
#include "SDL_config.h"
|
|
|
|
#if SDL_VIDEO_DRIVER_UIKIT
|
|
|
|
#include "SDL_syswm.h"
|
|
#include "SDL_video.h"
|
|
#include "SDL_mouse.h"
|
|
#include "SDL_assert.h"
|
|
#include "SDL_hints.h"
|
|
#include "../SDL_sysvideo.h"
|
|
#include "../SDL_pixels_c.h"
|
|
#include "../../events/SDL_events_c.h"
|
|
|
|
#include "SDL_uikitvideo.h"
|
|
#include "SDL_uikitevents.h"
|
|
#include "SDL_uikitmodes.h"
|
|
#include "SDL_uikitwindow.h"
|
|
#import "SDL_uikitappdelegate.h"
|
|
|
|
#import "SDL_uikitopenglview.h"
|
|
|
|
#include <Foundation/Foundation.h>
|
|
|
|
|
|
|
|
|
|
static int SetupWindowData(_THIS, SDL_Window *window, UIWindow *uiwindow, SDL_bool created)
|
|
{
|
|
SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
|
|
SDL_DisplayModeData *displaymodedata = (SDL_DisplayModeData *) display->current_mode.driverdata;
|
|
SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata;
|
|
SDL_WindowData *data;
|
|
|
|
/* Allocate the window data */
|
|
data = (SDL_WindowData *)SDL_malloc(sizeof(*data));
|
|
if (!data) {
|
|
return SDL_OutOfMemory();
|
|
}
|
|
data->uiwindow = uiwindow;
|
|
data->viewcontroller = nil;
|
|
data->view = nil;
|
|
|
|
/* Fill in the SDL window with the window data */
|
|
{
|
|
window->x = 0;
|
|
window->y = 0;
|
|
|
|
CGRect bounds;
|
|
if (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) {
|
|
bounds = [displaydata->uiscreen bounds];
|
|
} else {
|
|
bounds = [displaydata->uiscreen applicationFrame];
|
|
}
|
|
|
|
/* Get frame dimensions in pixels */
|
|
int width = (int)(bounds.size.width * displaymodedata->scale);
|
|
int height = (int)(bounds.size.height * displaymodedata->scale);
|
|
|
|
/* Make sure the width/height are oriented correctly */
|
|
if (UIKit_IsDisplayLandscape(displaydata->uiscreen) != (width > height)) {
|
|
int temp = width;
|
|
width = height;
|
|
height = temp;
|
|
}
|
|
|
|
window->w = width;
|
|
window->h = height;
|
|
}
|
|
|
|
window->driverdata = data;
|
|
|
|
/* only one window on iOS, always shown */
|
|
window->flags &= ~SDL_WINDOW_HIDDEN;
|
|
|
|
/* SDL_WINDOW_BORDERLESS controls whether status bar is hidden.
|
|
* This is only set if the window is on the main screen. Other screens
|
|
* just force the window to have the borderless flag.
|
|
*/
|
|
if (displaydata->uiscreen == [UIScreen mainScreen]) {
|
|
window->flags |= SDL_WINDOW_INPUT_FOCUS; /* always has input focus */
|
|
|
|
/* This was setup earlier for our window, and in iOS 7 is controlled by the view, not the application
|
|
if ([UIApplication sharedApplication].statusBarHidden) {
|
|
window->flags |= SDL_WINDOW_BORDERLESS;
|
|
} else {
|
|
window->flags &= ~SDL_WINDOW_BORDERLESS;
|
|
}
|
|
*/
|
|
} else {
|
|
window->flags &= ~SDL_WINDOW_RESIZABLE; /* window is NEVER resizeable */
|
|
window->flags &= ~SDL_WINDOW_INPUT_FOCUS; /* never has input focus */
|
|
window->flags |= SDL_WINDOW_BORDERLESS; /* never has a status bar. */
|
|
}
|
|
|
|
/* The View Controller will handle rotating the view when the
|
|
* device orientation changes. This will trigger resize events, if
|
|
* appropriate.
|
|
*/
|
|
SDL_uikitviewcontroller *controller;
|
|
controller = [SDL_uikitviewcontroller alloc];
|
|
data->viewcontroller = [controller initWithSDLWindow:window];
|
|
[data->viewcontroller setTitle:@"SDL App"]; /* !!! FIXME: hook up SDL_SetWindowTitle() */
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
UIKit_CreateWindow(_THIS, SDL_Window *window)
|
|
{
|
|
SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
|
|
SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
|
|
const BOOL external = ([UIScreen mainScreen] != data->uiscreen);
|
|
|
|
/* SDL currently puts this window at the start of display's linked list. We rely on this. */
|
|
SDL_assert(_this->windows == window);
|
|
|
|
/* We currently only handle a single window per display on iOS */
|
|
if (window->next != NULL) {
|
|
return SDL_SetError("Only one window allowed per display.");
|
|
}
|
|
|
|
/* If monitor has a resolution of 0x0 (hasn't been explicitly set by the
|
|
* user, so it's in standby), try to force the display to a resolution
|
|
* that most closely matches the desired window size.
|
|
*/
|
|
if (SDL_UIKit_supports_multiple_displays) {
|
|
const CGSize origsize = [[data->uiscreen currentMode] size];
|
|
if ((origsize.width == 0.0f) && (origsize.height == 0.0f)) {
|
|
if (display->num_display_modes == 0) {
|
|
_this->GetDisplayModes(_this, display);
|
|
}
|
|
|
|
int i;
|
|
const SDL_DisplayMode *bestmode = NULL;
|
|
for (i = display->num_display_modes; i >= 0; i--) {
|
|
const SDL_DisplayMode *mode = &display->display_modes[i];
|
|
if ((mode->w >= window->w) && (mode->h >= window->h))
|
|
bestmode = mode;
|
|
}
|
|
|
|
if (bestmode) {
|
|
SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)bestmode->driverdata;
|
|
[data->uiscreen setCurrentMode:modedata->uiscreenmode];
|
|
|
|
/* desktop_mode doesn't change here (the higher level will
|
|
* use it to set all the screens back to their defaults
|
|
* upon window destruction, SDL_Quit(), etc.
|
|
*/
|
|
display->current_mode = *bestmode;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (data->uiscreen == [UIScreen mainScreen]) {
|
|
if (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) {
|
|
[UIApplication sharedApplication].statusBarHidden = YES;
|
|
} else {
|
|
[UIApplication sharedApplication].statusBarHidden = NO;
|
|
}
|
|
}
|
|
|
|
if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
|
|
if (window->w > window->h) {
|
|
if (!UIKit_IsDisplayLandscape(data->uiscreen)) {
|
|
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight animated:NO];
|
|
}
|
|
} else if (window->w < window->h) {
|
|
if (UIKit_IsDisplayLandscape(data->uiscreen)) {
|
|
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:NO];
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ignore the size user requested, and make a fullscreen window */
|
|
/* !!! FIXME: can we have a smaller view? */
|
|
UIWindow *uiwindow = [UIWindow alloc];
|
|
uiwindow = [uiwindow initWithFrame:[data->uiscreen bounds]];
|
|
|
|
/* put the window on an external display if appropriate. This implicitly
|
|
* does [uiwindow setframe:[uiscreen bounds]], so don't do it on the
|
|
* main display, where we land by default, as that would eat the
|
|
* status bar real estate.
|
|
*/
|
|
if (external) {
|
|
[uiwindow setScreen:data->uiscreen];
|
|
}
|
|
|
|
if (SetupWindowData(_this, window, uiwindow, SDL_TRUE) < 0) {
|
|
[uiwindow release];
|
|
return -1;
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
void
|
|
UIKit_ShowWindow(_THIS, SDL_Window * window)
|
|
{
|
|
UIWindow *uiwindow = ((SDL_WindowData *) window->driverdata)->uiwindow;
|
|
|
|
[uiwindow makeKeyAndVisible];
|
|
}
|
|
|
|
void
|
|
UIKit_HideWindow(_THIS, SDL_Window * window)
|
|
{
|
|
UIWindow *uiwindow = ((SDL_WindowData *) window->driverdata)->uiwindow;
|
|
|
|
uiwindow.hidden = YES;
|
|
}
|
|
|
|
void
|
|
UIKit_RaiseWindow(_THIS, SDL_Window * window)
|
|
{
|
|
/* We don't currently offer a concept of "raising" the SDL window, since
|
|
* we only allow one per display, in the iOS fashion.
|
|
* However, we use this entry point to rebind the context to the view
|
|
* during OnWindowRestored processing.
|
|
*/
|
|
_this->GL_MakeCurrent(_this, _this->current_glwin, _this->current_glctx);
|
|
}
|
|
|
|
void
|
|
UIKit_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
|
|
{
|
|
SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata;
|
|
SDL_DisplayModeData *displaymodedata = (SDL_DisplayModeData *) display->current_mode.driverdata;
|
|
UIWindow *uiwindow = ((SDL_WindowData *) window->driverdata)->uiwindow;
|
|
|
|
if (fullscreen) {
|
|
[UIApplication sharedApplication].statusBarHidden = YES;
|
|
} else {
|
|
[UIApplication sharedApplication].statusBarHidden = NO;
|
|
}
|
|
|
|
CGRect bounds;
|
|
if (fullscreen) {
|
|
bounds = [displaydata->uiscreen bounds];
|
|
} else {
|
|
bounds = [displaydata->uiscreen applicationFrame];
|
|
}
|
|
|
|
/* Get frame dimensions in pixels */
|
|
int width = (int)(bounds.size.width * displaymodedata->scale);
|
|
int height = (int)(bounds.size.height * displaymodedata->scale);
|
|
|
|
/* We can pick either width or height here and we'll rotate the
|
|
screen to match, so we pick the closest to what we wanted.
|
|
*/
|
|
if (window->w >= window->h) {
|
|
if (width > height) {
|
|
window->w = width;
|
|
window->h = height;
|
|
} else {
|
|
window->w = height;
|
|
window->h = width;
|
|
}
|
|
} else {
|
|
if (width > height) {
|
|
window->w = height;
|
|
window->h = width;
|
|
} else {
|
|
window->w = width;
|
|
window->h = height;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
UIKit_DestroyWindow(_THIS, SDL_Window * window)
|
|
{
|
|
SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
|
|
if (data) {
|
|
[data->viewcontroller release];
|
|
[data->uiwindow release];
|
|
SDL_free(data);
|
|
window->driverdata = NULL;
|
|
}
|
|
}
|
|
|
|
SDL_bool
|
|
UIKit_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
|
|
{
|
|
UIWindow *uiwindow = ((SDL_WindowData *) window->driverdata)->uiwindow;
|
|
|
|
if (info->version.major <= SDL_MAJOR_VERSION) {
|
|
info->subsystem = SDL_SYSWM_UIKIT;
|
|
info->info.uikit.window = uiwindow;
|
|
return SDL_TRUE;
|
|
} else {
|
|
SDL_SetError("Application not compiled with SDL %d.%d\n",
|
|
SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
|
|
return SDL_FALSE;
|
|
}
|
|
}
|
|
|
|
int
|
|
SDL_iPhoneSetAnimationCallback(SDL_Window * window, int interval, void (*callback)(void*), void *callbackParam)
|
|
{
|
|
SDL_WindowData *data = window ? (SDL_WindowData *)window->driverdata : NULL;
|
|
|
|
if (!data || !data->view) {
|
|
return SDL_SetError("Invalid window or view not set");
|
|
}
|
|
|
|
[data->view setAnimationCallback:interval callback:callback callbackParam:callbackParam];
|
|
return 0;
|
|
}
|
|
|
|
#endif /* SDL_VIDEO_DRIVER_UIKIT */
|
|
|
|
/* vi: set ts=4 sw=4 expandtab: */
|