From 6f3e04785d9fe8dd68d7d6c2b6d1494aa67046c9 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sun, 27 Dec 2015 11:10:00 +0200 Subject: [PATCH 01/11] Added preprocessor macros for AppKit framework versions These macros are needed to build with earlier OS X SDKs --- src/posix/cocoa/i_common.h | 14 ++++++++++---- src/posix/cocoa/i_video.mm | 5 +---- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/posix/cocoa/i_common.h b/src/posix/cocoa/i_common.h index 545540b2f..dc1e12121 100644 --- a/src/posix/cocoa/i_common.h +++ b/src/posix/cocoa/i_common.h @@ -50,12 +50,18 @@ struct RenderBufferOptions extern RenderBufferOptions rbOpts; +// Version of AppKit framework we are interested in +// The following values are needed to build with earlier SDKs + +#define AppKit10_4 824 +#define AppKit10_5 949 +#define AppKit10_6 1038 +#define AppKit10_7 1138 + + inline bool I_IsHiDPISupported() { - // The following value shoud be equal to NSAppKitVersionNumber10_7 - // and it's hard-coded in order to build on earlier SDKs - - return NSAppKitVersionNumber >= 1138; + return NSAppKitVersionNumber >= AppKit10_7; } void I_ProcessEvent(NSEvent* event); diff --git a/src/posix/cocoa/i_video.mm b/src/posix/cocoa/i_video.mm index 3fc2b2aed..a47a1f1a8 100644 --- a/src/posix/cocoa/i_video.mm +++ b/src/posix/cocoa/i_video.mm @@ -561,10 +561,7 @@ void CocoaVideo::SetWindowVisible(bool visible) static bool HasModernFullscreenAPI() { - // The following value shoud be equal to NSAppKitVersionNumber10_6 - // and it's hard-coded in order to build on earlier SDKs - - return NSAppKitVersionNumber >= 1038; + return NSAppKitVersionNumber >= AppKit10_6; } void CocoaVideo::SetStyleMask(const NSUInteger styleMask) From 0efdccd942c29b235825cb09cbc566dc18d89444 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Sun, 27 Dec 2015 12:05:04 +0200 Subject: [PATCH 02/11] Separated POSIX's i_system.cpp from native OS X implementation --- src/CMakeLists.txt | 3 +- src/posix/cocoa/i_system.mm | 381 ++++++++++++++++++++++++++++++ src/posix/osx/iwadpicker_cocoa.mm | 6 - src/posix/sdl/i_gui.cpp | 5 - src/posix/{ => sdl}/i_system.cpp | 0 5 files changed, 383 insertions(+), 12 deletions(-) create mode 100644 src/posix/cocoa/i_system.mm rename src/posix/{ => sdl}/i_system.cpp (100%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 18fdb992c..25eb25ea4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -592,7 +592,6 @@ set( PLAT_POSIX_SOURCES posix/i_cd.cpp posix/i_movie.cpp posix/i_steam.cpp - posix/i_system.cpp posix/st_start.cpp ) set( PLAT_SDL_SOURCES posix/sdl/crashcatcher.c @@ -601,6 +600,7 @@ set( PLAT_SDL_SOURCES posix/sdl/i_input.cpp posix/sdl/i_joystick.cpp posix/sdl/i_main.cpp + posix/sdl/i_system.cpp posix/sdl/i_timer.cpp posix/sdl/sdlvideo.cpp ) set( PLAT_OSX_SOURCES @@ -611,6 +611,7 @@ set( PLAT_COCOA_SOURCES posix/cocoa/i_input.mm posix/cocoa/i_joystick.cpp posix/cocoa/i_main.mm + posix/cocoa/i_system.mm posix/cocoa/i_timer.cpp posix/cocoa/i_video.mm ) diff --git a/src/posix/cocoa/i_system.mm b/src/posix/cocoa/i_system.mm new file mode 100644 index 000000000..c9471f8e6 --- /dev/null +++ b/src/posix/cocoa/i_system.mm @@ -0,0 +1,381 @@ +/* + ** i_system.mm + ** + **--------------------------------------------------------------------------- + ** Copyright 2012-2015 Alexey Lysiuk + ** All rights reserved. + ** + ** Redistribution and use in source and binary forms, with or without + ** modification, are permitted provided that the following conditions + ** are met: + ** + ** 1. Redistributions of source code must retain the above copyright + ** notice, this list of conditions and the following disclaimer. + ** 2. Redistributions in binary form must reproduce the above copyright + ** notice, this list of conditions and the following disclaimer in the + ** documentation and/or other materials provided with the distribution. + ** 3. The name of the author may not be used to endorse or promote products + ** derived from this software without specific prior written permission. + ** + ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **--------------------------------------------------------------------------- + ** + */ + +#include "i_common.h" + +#include +#include +#include + +#include "d_ticcmd.h" +#include "doomdef.h" +#include "doomerrors.h" +#include "doomstat.h" +#include "g_game.h" +#include "gameconfigfile.h" +#include "i_sound.h" +#include "i_system.h" +#include "v_text.h" +#include "x86.h" + + +EXTERN_CVAR(String, language) + +DWORD LanguageIDs[4]; + + +int (*I_GetTime)(bool saveMS); +int (*I_WaitForTic)(int); +void (*I_FreezeTime)(bool frozen); + + +void I_Tactile(int /*on*/, int /*off*/, int /*total*/) +{ +} + + +ticcmd_t* I_BaseTiccmd() +{ + static ticcmd_t emptycmd; + return &emptycmd; +} + + +void I_WaitVBL(const int count) +{ + // I_WaitVBL is never used to actually synchronize to the + // vertical blank. Instead, it's used for delay purposes. + usleep(1000000 * count / 70); +} + + +// +// SetLanguageIDs +// +void SetLanguageIDs() +{ + size_t langlen = strlen(language); + + DWORD lang = (langlen < 2 || langlen > 3) + ? MAKE_ID('e', 'n', 'u', '\0') + : MAKE_ID(language[0], language[1], language[2], '\0'); + + LanguageIDs[3] = LanguageIDs[2] = LanguageIDs[1] = LanguageIDs[0] = lang; +} + + +void I_InitTimer(); +void I_ShutdownTimer(); + +void I_Init(void) +{ + CheckCPUID(&CPU); + DumpCPUInfo(&CPU); + + atterm(I_ShutdownSound); + I_InitSound(); + I_InitTimer(); +} + +static int has_exited; + +void I_Quit() +{ + has_exited = 1; // Prevent infinitely recursive exits -- killough + + if (demorecording) + { + G_CheckDemoStatus(); + } + + C_DeinitConsole(); + + I_ShutdownTimer(); +} + + +extern FILE* Logfile; +bool gameisdead; + +void STACK_ARGS I_FatalError(const char* const error, ...) +{ + static bool alreadyThrown = false; + gameisdead = true; + + if (!alreadyThrown) // ignore all but the first message -- killough + { + alreadyThrown = true; + + char errortext[MAX_ERRORTEXT]; + int index; + va_list argptr; + va_start(argptr, error); + index = vsnprintf(errortext, MAX_ERRORTEXT, error, argptr); + va_end(argptr); + + extern void Mac_I_FatalError(const char*); + Mac_I_FatalError(errortext); + + // Record error to log (if logging) + if (Logfile) + { + fprintf(Logfile, "\n**** DIED WITH FATAL ERROR:\n%s\n", errortext); + fflush(Logfile); + } + + fprintf(stderr, "%s\n", errortext); + exit(-1); + } + + if (!has_exited) // If it hasn't exited yet, exit now -- killough + { + has_exited = 1; // Prevent infinitely recursive exits -- killough + exit(-1); + } +} + +void STACK_ARGS I_Error(const char* const error, ...) +{ + va_list argptr; + char errortext[MAX_ERRORTEXT]; + + va_start(argptr, error); + vsnprintf(errortext, MAX_ERRORTEXT, error, argptr); + va_end(argptr); + + throw CRecoverableError(errortext); +} + + +void I_SetIWADInfo() +{ +} + + +void I_PrintStr(const char* const message) +{ + // Strip out any color escape sequences before writing to output + char* const copy = new char[strlen(message) + 1]; + const char* srcp = message; + char* dstp = copy; + + while ('\0' != *srcp) + { + if (TEXTCOLOR_ESCAPE == *srcp) + { + if ('\0' != srcp[1]) + { + srcp += 2; + } + else + { + break; + } + } + else if (0x1d == *srcp || 0x1f == *srcp) // Opening and closing bar character + { + *dstp++ = '-'; + *srcp++; + } + else if (0x1e == *srcp) // Middle bar character + { + *dstp++ = '='; + *srcp++; + } + else + { + *dstp++ = *srcp++; + } + } + + *dstp = '\0'; + + fputs(copy, stdout); + delete[] copy; + fflush(stdout); +} + + +int I_PickIWad(WadStuff* const wads, const int numwads, const bool showwin, const int defaultiwad) +{ + if (!showwin) + { + return defaultiwad; + } + + I_SetMainWindowVisible(false); + + extern int I_PickIWad_Cocoa(WadStuff*, int, bool, int); + const int result = I_PickIWad_Cocoa(wads, numwads, showwin, defaultiwad); + + I_SetMainWindowVisible(true); + + return result; +} + + +bool I_WriteIniFailed() +{ + printf("The config file %s could not be saved:\n%s\n", GameConfig->GetPathName(), strerror(errno)); + return false; // return true to retry +} + + +static const char *pattern; + +#if MAC_OS_X_VERSION_MAX_ALLOWED < 1080 +static int matchfile(struct dirent *ent) +#else +static int matchfile(const struct dirent *ent) +#endif +{ + return fnmatch(pattern, ent->d_name, FNM_NOESCAPE) == 0; +} + +void* I_FindFirst(const char* const filespec, findstate_t* const fileinfo) +{ + FString dir; + + const char* const slash = strrchr(filespec, '/'); + + if (slash) + { + pattern = slash+1; + dir = FString(filespec, slash - filespec + 1); + } + else + { + pattern = filespec; + dir = "."; + } + + fileinfo->current = 0; + fileinfo->count = scandir(dir.GetChars(), &fileinfo->namelist, matchfile, alphasort); + + if (fileinfo->count > 0) + { + return fileinfo; + } + + return (void*)-1; +} + +int I_FindNext(void* const handle, findstate_t* const fileinfo) +{ + findstate_t* const state = static_cast(handle); + + if (state->current < fileinfo->count) + { + return ++state->current < fileinfo->count ? 0 : -1; + } + + return -1; +} + +int I_FindClose(void* const handle) +{ + findstate_t* const state = static_cast(handle); + + if (handle != (void*)-1 && state->count > 0) + { + for (int i = 0; i < state->count; ++i) + { + free(state->namelist[i]); + } + + free(state->namelist); + state->namelist = NULL; + state->count = 0; + } + + return 0; +} + +int I_FindAttr(findstate_t* const fileinfo) +{ + dirent* const ent = fileinfo->namelist[fileinfo->current]; + struct stat buf; + + if (stat(ent->d_name, &buf) == 0) + { + return S_ISDIR(buf.st_mode) ? FA_DIREC : 0; + } + + return 0; +} + + +static NSString* GetPasteboardStringType() +{ +#if MAC_OS_X_VERSION_MAX_ALLOWED < 1060 + return NSStringPboardType; +#else // 10.6 or higher + return NSAppKitVersionNumber < AppKit10_6 + ? NSStringPboardType + : NSPasteboardTypeString; +#endif // before 10.6 +} + +void I_PutInClipboard(const char* const string) +{ + NSPasteboard* const pasteBoard = [NSPasteboard generalPasteboard]; + [pasteBoard clearContents]; + [pasteBoard setString:[NSString stringWithUTF8String:string] + forType:GetPasteboardStringType()]; +} + +FString I_GetFromClipboard(bool returnNothing) +{ + if (returnNothing) + { + return FString(); + } + + NSPasteboard* const pasteBoard = [NSPasteboard generalPasteboard]; + NSString* const value = [pasteBoard stringForType:GetPasteboardStringType()]; + + return FString([value UTF8String]); +} + + +unsigned int I_MakeRNGSeed() +{ + return static_cast(arc4random()); +} + + +TArray I_GetGogPaths() +{ + // GOG's Doom games are Windows only at the moment + return TArray(); +} diff --git a/src/posix/osx/iwadpicker_cocoa.mm b/src/posix/osx/iwadpicker_cocoa.mm index d2bc1ff0c..5f2ff2ae2 100644 --- a/src/posix/osx/iwadpicker_cocoa.mm +++ b/src/posix/osx/iwadpicker_cocoa.mm @@ -462,20 +462,14 @@ static void RestartWithParameters(const char* iwadPath, NSString* parameters) [pool release]; } -void I_SetMainWindowVisible(bool visible); - // Simple wrapper so we can call this from outside. int I_PickIWad_Cocoa (WadStuff *wads, int numwads, bool showwin, int defaultiwad) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - I_SetMainWindowVisible(false); - IWADPicker *picker = [IWADPicker alloc]; int ret = [picker pickIWad:wads num:numwads showWindow:showwin defaultWad:defaultiwad]; - I_SetMainWindowVisible(true); - NSString* parametersToAppend = [picker commandLineParameters]; osx_additional_parameters = [parametersToAppend UTF8String]; diff --git a/src/posix/sdl/i_gui.cpp b/src/posix/sdl/i_gui.cpp index f9e6714b4..37a3b1062 100644 --- a/src/posix/sdl/i_gui.cpp +++ b/src/posix/sdl/i_gui.cpp @@ -54,8 +54,3 @@ bool I_SetCursor(FTexture *cursorpic) } return true; } - -void I_SetMainWindowVisible(bool visible) -{ - -} diff --git a/src/posix/i_system.cpp b/src/posix/sdl/i_system.cpp similarity index 100% rename from src/posix/i_system.cpp rename to src/posix/sdl/i_system.cpp From 3676a425126e326adb3b4761bcda648778c31341 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Mon, 28 Dec 2015 12:54:23 +0200 Subject: [PATCH 03/11] Added missing include guard in i_common.h --- src/posix/cocoa/i_common.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/posix/cocoa/i_common.h b/src/posix/cocoa/i_common.h index dc1e12121..63377bb36 100644 --- a/src/posix/cocoa/i_common.h +++ b/src/posix/cocoa/i_common.h @@ -31,6 +31,9 @@ ** */ +#ifndef COCOA_I_COMMON_INCLUDED +#define COCOA_I_COMMON_INCLUDED + #import @@ -174,3 +177,5 @@ typedef NSInteger NSApplicationActivationPolicy; @end #endif // prior to 10.7 + +#endif // COCOA_I_COMMON_INCLUDED From 15a269db9df6c2454c4b11bb474eef750a492900 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Mon, 28 Dec 2015 13:05:07 +0200 Subject: [PATCH 04/11] Extended NSWindow with ability to exit application upon closing by user --- src/posix/cocoa/i_common.h | 5 +++++ src/posix/cocoa/i_video.mm | 17 +++++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/posix/cocoa/i_common.h b/src/posix/cocoa/i_common.h index 63377bb36..cf2fffbdc 100644 --- a/src/posix/cocoa/i_common.h +++ b/src/posix/cocoa/i_common.h @@ -62,6 +62,11 @@ extern RenderBufferOptions rbOpts; #define AppKit10_7 1138 +@interface NSWindow(ExitAppOnClose) +- (void)exitAppOnClose; +@end + + inline bool I_IsHiDPISupported() { return NSAppKitVersionNumber >= AppKit10_7; diff --git a/src/posix/cocoa/i_video.mm b/src/posix/cocoa/i_video.mm index a47a1f1a8..768d147a9 100644 --- a/src/posix/cocoa/i_video.mm +++ b/src/posix/cocoa/i_video.mm @@ -58,6 +58,18 @@ #undef Class +@implementation NSWindow(ExitAppOnClose) + +- (void)exitAppOnClose +{ + NSButton* closeButton = [self standardWindowButton:NSWindowCloseButton]; + [closeButton setAction:@selector(terminate:)]; + [closeButton setTarget:NSApp]; +} + +@end + + EXTERN_CVAR(Bool, ticker ) EXTERN_CVAR(Bool, vid_vsync) EXTERN_CVAR(Bool, vid_hidpi) @@ -659,10 +671,7 @@ void CocoaVideo::SetWindowedMode(const int width, const int height) [m_window setContentSize:windowSize]; [m_window center]; - - NSButton* closeButton = [m_window standardWindowButton:NSWindowCloseButton]; - [closeButton setAction:@selector(terminate:)]; - [closeButton setTarget:NSApp]; + [m_window exitAppOnClose]; } void CocoaVideo::SetMode(const int width, const int height, const bool fullscreen, const bool hiDPI) From 2c3d9e3ab8771b24deff0d72452f8d2f8769b764 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Mon, 28 Dec 2015 16:19:08 +0200 Subject: [PATCH 05/11] Fixed mouse capturing when video isn't initialized yet --- src/posix/cocoa/i_video.mm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/posix/cocoa/i_video.mm b/src/posix/cocoa/i_video.mm index 768d147a9..9fbeb6ffa 100644 --- a/src/posix/cocoa/i_video.mm +++ b/src/posix/cocoa/i_video.mm @@ -567,6 +567,8 @@ void CocoaVideo::SetWindowVisible(bool visible) { [video->m_window orderOut:nil]; } + + I_SetNativeMouse(!visible); } } @@ -1248,5 +1250,4 @@ NSSize I_GetContentViewSize(const NSWindow* const window) void I_SetMainWindowVisible(bool visible) { CocoaVideo::SetWindowVisible(visible); - I_SetNativeMouse(!visible); } From 673e1b4faf6c9c3c05ae5943daee8206191c0638 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Tue, 29 Dec 2015 15:14:41 +0200 Subject: [PATCH 06/11] Fixed compilation warning when building with OS X 10.11 SDK The warning was 'null passed to a callee that requires a non-null argument' --- src/posix/cocoa/i_video.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/posix/cocoa/i_video.mm b/src/posix/cocoa/i_video.mm index 9fbeb6ffa..3734d938c 100644 --- a/src/posix/cocoa/i_video.mm +++ b/src/posix/cocoa/i_video.mm @@ -1219,7 +1219,7 @@ bool I_SetCursor(FTexture* cursorpic) // Create image from representation and set it as cursor NSData* imageData = [bitmapImageRep representationUsingType:NSPNGFileType - properties:nil]; + properties:[NSDictionary dictionary]]; NSImage* cursorImage = [[NSImage alloc] initWithData:imageData]; cursor = [[NSCursor alloc] initWithImage:cursorImage From 3af95e0aeade57165c54c1a0af27894ab0023b0f Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Tue, 29 Dec 2015 15:19:42 +0200 Subject: [PATCH 07/11] Added native startup window for OS X --- src/CMakeLists.txt | 10 +- src/posix/cocoa/i_main.mm | 17 +- src/posix/cocoa/i_system.mm | 3 + src/posix/cocoa/i_video.mm | 3 + src/posix/cocoa/st_console.h | 95 ++++++ src/posix/cocoa/st_console.mm | 506 +++++++++++++++++++++++++++++++ src/posix/cocoa/st_start.mm | 190 ++++++++++++ src/posix/{ => sdl}/st_start.cpp | 0 8 files changed, 808 insertions(+), 16 deletions(-) create mode 100644 src/posix/cocoa/st_console.h create mode 100644 src/posix/cocoa/st_console.mm create mode 100644 src/posix/cocoa/st_start.mm rename src/posix/{ => sdl}/st_start.cpp (100%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 25eb25ea4..469fe5527 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -591,8 +591,7 @@ set( PLAT_WIN32_SOURCES set( PLAT_POSIX_SOURCES posix/i_cd.cpp posix/i_movie.cpp - posix/i_steam.cpp - posix/st_start.cpp ) + posix/i_steam.cpp ) set( PLAT_SDL_SOURCES posix/sdl/crashcatcher.c posix/sdl/hardware.cpp @@ -602,7 +601,8 @@ set( PLAT_SDL_SOURCES posix/sdl/i_main.cpp posix/sdl/i_system.cpp posix/sdl/i_timer.cpp - posix/sdl/sdlvideo.cpp ) + posix/sdl/sdlvideo.cpp + posix/sdl/st_start.cpp ) set( PLAT_OSX_SOURCES posix/osx/iwadpicker_cocoa.mm posix/osx/zdoom.icns ) @@ -613,7 +613,9 @@ set( PLAT_COCOA_SOURCES posix/cocoa/i_main.mm posix/cocoa/i_system.mm posix/cocoa/i_timer.cpp - posix/cocoa/i_video.mm ) + posix/cocoa/i_video.mm + posix/cocoa/st_console.mm + posix/cocoa/st_start.mm ) if( WIN32 ) set( SYSTEM_SOURCES_DIR win32 ) diff --git a/src/posix/cocoa/i_main.mm b/src/posix/cocoa/i_main.mm index 05a8081f6..2f65254a9 100644 --- a/src/posix/cocoa/i_main.mm +++ b/src/posix/cocoa/i_main.mm @@ -47,6 +47,7 @@ #include "i_system.h" #include "m_argv.h" #include "s_sound.h" +#include "st_console.h" #include "version.h" #undef Class @@ -125,18 +126,7 @@ void Mac_I_FatalError(const char* const message) { I_SetMainWindowVisible(false); - const CFStringRef errorString = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, - message, kCFStringEncodingASCII, kCFAllocatorNull); - - if (NULL != errorString) - { - CFOptionFlags dummy; - - CFUserNotificationDisplayAlert( 0, kCFUserNotificationStopAlertLevel, NULL, NULL, NULL, - CFSTR("Fatal Error"), errorString, CFSTR("Exit"), NULL, NULL, &dummy); - - CFRelease(errorString); - } + FConsoleWindow::GetInstance().ShowFatalError(message); } @@ -315,6 +305,9 @@ ApplicationController* appCtrl; [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; + FConsoleWindow::CreateInstance(); + atterm(FConsoleWindow::DeleteInstance); + exit(OriginalMain(s_argc, s_argv)); } diff --git a/src/posix/cocoa/i_system.mm b/src/posix/cocoa/i_system.mm index c9471f8e6..f12ef18eb 100644 --- a/src/posix/cocoa/i_system.mm +++ b/src/posix/cocoa/i_system.mm @@ -45,6 +45,7 @@ #include "gameconfigfile.h" #include "i_sound.h" #include "i_system.h" +#include "st_console.h" #include "v_text.h" #include "x86.h" @@ -184,6 +185,8 @@ void I_SetIWADInfo() void I_PrintStr(const char* const message) { + FConsoleWindow::GetInstance().AddText(message); + // Strip out any color escape sequences before writing to output char* const copy = new char[strlen(message) + 1]; const char* srcp = message; diff --git a/src/posix/cocoa/i_video.mm b/src/posix/cocoa/i_video.mm index 3734d938c..799dd5ffd 100644 --- a/src/posix/cocoa/i_video.mm +++ b/src/posix/cocoa/i_video.mm @@ -47,6 +47,7 @@ #include "m_argv.h" #include "r_renderer.h" #include "r_swrenderer.h" +#include "st_console.h" #include "stats.h" #include "textures.h" #include "v_palette.h" @@ -445,6 +446,8 @@ CocoaVideo::CocoaVideo(const int multisample) [[glView openGLContext] makeCurrentContext]; [m_window setContentView:glView]; + + FConsoleWindow::GetInstance().Show(false); } void CocoaVideo::StartModeIterator(const int bits, const bool fullscreen) diff --git a/src/posix/cocoa/st_console.h b/src/posix/cocoa/st_console.h new file mode 100644 index 000000000..49b6e0547 --- /dev/null +++ b/src/posix/cocoa/st_console.h @@ -0,0 +1,95 @@ +/* + ** st_console.h + ** + **--------------------------------------------------------------------------- + ** Copyright 2015 Alexey Lysiuk + ** All rights reserved. + ** + ** Redistribution and use in source and binary forms, with or without + ** modification, are permitted provided that the following conditions + ** are met: + ** + ** 1. Redistributions of source code must retain the above copyright + ** notice, this list of conditions and the following disclaimer. + ** 2. Redistributions in binary form must reproduce the above copyright + ** notice, this list of conditions and the following disclaimer in the + ** documentation and/or other materials provided with the distribution. + ** 3. The name of the author may not be used to endorse or promote products + ** derived from this software without specific prior written permission. + ** + ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **--------------------------------------------------------------------------- + ** + */ + +#ifndef COCOA_ST_CONSOLE_INCLUDED +#define COCOA_ST_CONSOLE_INCLUDED + +@class NSButton; +@class NSProgressIndicator; +@class NSScrollView; +@class NSTextField; +@class NSTextView; +@class NSView; +@class NSWindow; + +struct PalEntry; + + +class FConsoleWindow +{ +public: + static FConsoleWindow& GetInstance(); + + static void CreateInstance(); + static void DeleteInstance(); + + void Show(bool visible); + void ShowFatalError(const char* message); + + void AddText(const char* message); + + void SetTitleText(); + void SetProgressBar(bool visible); + + // FStartupScreen functionality + void Progress(int current, int maximum); + void NetInit(const char* message, int playerCount); + void NetProgress(int count); + void NetDone(); + +private: + NSWindow* m_window; + NSTextView* m_textView; + NSScrollView* m_scrollView; + NSProgressIndicator* m_progressBar; + + NSView* m_netView; + NSTextField* m_netMessageText; + NSTextField* m_netCountText; + NSProgressIndicator* m_netProgressBar; + NSButton* m_netAbortButton; + + unsigned int m_characterCount; + + int m_netCurPos; + int m_netMaxPos; + + FConsoleWindow(); + ~FConsoleWindow(); + + void ExpandTextView(float height); + + void AddText(const PalEntry& color, const char* message); +}; + +#endif // COCOA_ST_CONSOLE_INCLUDED diff --git a/src/posix/cocoa/st_console.mm b/src/posix/cocoa/st_console.mm new file mode 100644 index 000000000..e0eba7527 --- /dev/null +++ b/src/posix/cocoa/st_console.mm @@ -0,0 +1,506 @@ +/* + ** st_console.mm + ** + **--------------------------------------------------------------------------- + ** Copyright 2015 Alexey Lysiuk + ** All rights reserved. + ** + ** Redistribution and use in source and binary forms, with or without + ** modification, are permitted provided that the following conditions + ** are met: + ** + ** 1. Redistributions of source code must retain the above copyright + ** notice, this list of conditions and the following disclaimer. + ** 2. Redistributions in binary form must reproduce the above copyright + ** notice, this list of conditions and the following disclaimer in the + ** documentation and/or other materials provided with the distribution. + ** 3. The name of the author may not be used to endorse or promote products + ** derived from this software without specific prior written permission. + ** + ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **--------------------------------------------------------------------------- + ** + */ + +#include "i_common.h" + +#include "d_main.h" +#include "i_system.h" +#include "st_console.h" +#include "v_text.h" +#include "version.h" + + +static NSColor* RGB(const BYTE red, const BYTE green, const BYTE blue) +{ + return [NSColor colorWithCalibratedRed:red / 255.0f + green:green / 255.0f + blue:blue / 255.0f + alpha:1.0f]; +} + +static NSColor* RGB(const PalEntry& color) +{ + return RGB(color.r, color.g, color.b); +} + +static NSColor* RGB(const DWORD color) +{ + return RGB(PalEntry(color)); +} + + +static const CGFloat PROGRESS_BAR_HEIGHT = 18.0f; +static const CGFloat NET_VIEW_HEIGHT = 88.0f; + + +FConsoleWindow::FConsoleWindow() +: m_window([NSWindow alloc]) +, m_textView([NSTextView alloc]) +, m_scrollView([NSScrollView alloc]) +, m_progressBar(nil) +, m_netView(nil) +, m_netMessageText(nil) +, m_netCountText(nil) +, m_netProgressBar(nil) +, m_netAbortButton(nil) +, m_characterCount(0) +, m_netCurPos(0) +, m_netMaxPos(0) +{ + const CGFloat initialWidth = 512.0f; + const CGFloat initialHeight = 384.0f; + const NSRect initialRect = NSMakeRect(0.0f, 0.0f, initialWidth, initialHeight); + + [m_textView initWithFrame:initialRect]; + [m_textView setEditable:NO]; + [m_textView setBackgroundColor:RGB(70, 70, 70)]; + [m_textView setMinSize:NSMakeSize(0.0f, initialHeight)]; + [m_textView setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)]; + [m_textView setVerticallyResizable:YES]; + [m_textView setHorizontallyResizable:NO]; + [m_textView setAutoresizingMask:NSViewWidthSizable]; + + NSTextContainer* const textContainer = [m_textView textContainer]; + [textContainer setContainerSize:NSMakeSize(initialWidth, FLT_MAX)]; + [textContainer setWidthTracksTextView:YES]; + + [m_scrollView initWithFrame:NSMakeRect(0.0f, 0.0f, initialWidth, initialHeight)]; + [m_scrollView setBorderType:NSNoBorder]; + [m_scrollView setHasVerticalScroller:YES]; + [m_scrollView setHasHorizontalScroller:NO]; + [m_scrollView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; + [m_scrollView setDocumentView:m_textView]; + + NSString* const title = [NSString stringWithFormat:@"%s %s - Console", GAMESIG, GetVersionString()]; + + [m_window initWithContentRect:initialRect + styleMask:NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask + backing:NSBackingStoreBuffered + defer:NO]; + [m_window setMinSize:[m_window frame].size]; + [m_window setTitle:title]; + [m_window center]; + [m_window exitAppOnClose]; + + [[m_window contentView] addSubview:m_scrollView]; + + [m_window makeKeyAndOrderFront:nil]; +} + +FConsoleWindow::~FConsoleWindow() +{ + [m_window close]; +} + + +static FConsoleWindow* s_instance; + + +void FConsoleWindow::CreateInstance() +{ + assert(NULL == s_instance); + s_instance = new FConsoleWindow; +} + +void FConsoleWindow::DeleteInstance() +{ + assert(NULL != s_instance); + delete s_instance; + s_instance = NULL; +} + +FConsoleWindow& FConsoleWindow::GetInstance() +{ + assert(NULL != s_instance); + return *s_instance; +} + + +void FConsoleWindow::Show(const bool visible) +{ + if (visible) + { + [m_window orderFront:nil]; + } + else + { + [m_window orderOut:nil]; + } +} + +void FConsoleWindow::ShowFatalError(const char* const message) +{ + SetProgressBar(false); + NetDone(); + + const CGFloat textViewWidth = [m_scrollView frame].size.width; + + ExpandTextView(-32.0f); + + NSButton* quitButton = [[NSButton alloc] initWithFrame:NSMakeRect(textViewWidth - 76.0f, 0.0f, 72.0f, 30.0f)]; + [quitButton setAutoresizingMask:NSViewMinXMargin]; + [quitButton setBezelStyle:NSRoundedBezelStyle]; + [quitButton setTitle:@"Quit"]; + [quitButton setKeyEquivalent:@"\r"]; + [quitButton setTarget:NSApp]; + [quitButton setAction:@selector(terminate:)]; + + NSView* quitPanel = [[NSView alloc] initWithFrame:NSMakeRect(0.0f, 0.0f, textViewWidth, 32.0f)]; + [quitPanel setAutoresizingMask:NSViewWidthSizable]; + [quitPanel addSubview:quitButton]; + + [[m_window contentView] addSubview:quitPanel]; + [m_window orderFront:nil]; + + AddText(PalEntry(255, 0, 0), "\nExecution could not continue.\n"); + AddText(PalEntry(255, 255, 170), message); + AddText("\n"); + + // It's impossible to restore minimized window in modal loop + [m_window setStyleMask:[m_window styleMask] & ~NSMiniaturizableWindowMask]; + + [NSApp runModalForWindow:m_window]; +} + + +void FConsoleWindow::AddText(const char* message) +{ + PalEntry color(223, 223, 223); + + char buffer[1024] = {}; + size_t pos = 0; + bool reset = false; + + while (*message != '\0') + { + if ((TEXTCOLOR_ESCAPE == *message && 0 != pos) + || (pos == sizeof buffer - 1) + || reset) + { + buffer[pos] = '\0'; + pos = 0; + reset = false; + + AddText(color, buffer); + } + +#define CHECK_BUFFER_SPACE \ + if (pos >= sizeof buffer - 3) { reset = true; continue; } + + if (TEXTCOLOR_ESCAPE == *message) + { + const BYTE* colorID = reinterpret_cast(message) + 1; + if ('\0' == colorID) + { + break; + } + + const EColorRange range = V_ParseFontColor(colorID, CR_UNTRANSLATED, CR_YELLOW); + + if (range != CR_UNDEFINED) + { + color = V_LogColorFromColorRange(range); + } + + message += 2; + } + else if (0x1d == *message) // Opening bar character + { + CHECK_BUFFER_SPACE; + + // Insert BOX DRAWINGS LIGHT LEFT AND HEAVY RIGHT + buffer[pos++] = '\xe2'; + buffer[pos++] = '\x95'; + buffer[pos++] = '\xbc'; + ++message; + } + else if (0x1e == *message) // Middle bar character + { + CHECK_BUFFER_SPACE; + + // Insert BOX DRAWINGS HEAVY HORIZONTAL + buffer[pos++] = '\xe2'; + buffer[pos++] = '\x94'; + buffer[pos++] = '\x81'; + ++message; + } + else if (0x1f == *message) // Closing bar character + { + CHECK_BUFFER_SPACE; + + // Insert BOX DRAWINGS HEAVY LEFT AND LIGHT RIGHT + buffer[pos++] = '\xe2'; + buffer[pos++] = '\x95'; + buffer[pos++] = '\xbe'; + ++message; + } + else + { + buffer[pos++] = *message++; + } + +#undef CHECK_BUFFER_SPACE + } + + if (0 != pos) + { + buffer[pos] = '\0'; + + AddText(color, buffer); + } + + if ([m_window isVisible]) + { + [m_textView scrollRangeToVisible:NSMakeRange(m_characterCount, 0)]; + + [[NSRunLoop currentRunLoop] limitDateForMode:NSDefaultRunLoopMode]; + } +} + +void FConsoleWindow::AddText(const PalEntry& color, const char* const message) +{ + NSString* const text = [NSString stringWithUTF8String:message]; + + NSDictionary* const attributes = [NSDictionary dictionaryWithObjectsAndKeys: + [NSFont systemFontOfSize:14.0f], NSFontAttributeName, + RGB(color), NSForegroundColorAttributeName, + nil]; + + NSAttributedString* const formattedText = + [[NSAttributedString alloc] initWithString:text + attributes:attributes]; + [[m_textView textStorage] appendAttributedString:formattedText]; + + m_characterCount += [text length]; +} + + +void FConsoleWindow::SetTitleText() +{ + static const CGFloat TITLE_TEXT_HEIGHT = 32.0f; + + NSRect textViewFrame = [m_scrollView frame]; + textViewFrame.size.height -= TITLE_TEXT_HEIGHT; + [m_scrollView setFrame:textViewFrame]; + + const NSRect titleTextRect = NSMakeRect( + 0.0f, + textViewFrame.origin.y + textViewFrame.size.height, + textViewFrame.size.width, + TITLE_TEXT_HEIGHT); + + NSTextField* titleText = [[NSTextField alloc] initWithFrame:titleTextRect]; + [titleText setStringValue:[NSString stringWithUTF8String:DoomStartupInfo.Name]]; + [titleText setAlignment:NSCenterTextAlignment]; + [titleText setTextColor:RGB(DoomStartupInfo.FgColor)]; + [titleText setBackgroundColor:RGB(DoomStartupInfo.BkColor)]; + [titleText setFont:[NSFont fontWithName:@"Trebuchet MS Bold" size:18.0f]]; + [titleText setAutoresizingMask:NSViewWidthSizable | NSViewMinYMargin]; + [titleText setSelectable:NO]; + [titleText setBordered:NO]; + + [[m_window contentView] addSubview:titleText]; +} + +void FConsoleWindow::SetProgressBar(const bool visible) +{ + if ( (!visible && nil == m_progressBar) + || (visible && nil != m_progressBar)) + { + return; + } + + if (visible) + { + ExpandTextView(-PROGRESS_BAR_HEIGHT); + + m_progressBar = [[NSProgressIndicator alloc] initWithFrame:NSMakeRect(2.0f, 0.0f, 508.0f, 16.0f)]; + [m_progressBar setIndeterminate:NO]; + [m_progressBar setAutoresizingMask:NSViewWidthSizable]; + + [[m_window contentView] addSubview:m_progressBar]; + } + else + { + ExpandTextView(PROGRESS_BAR_HEIGHT); + + [m_progressBar removeFromSuperview]; + [m_progressBar release]; + m_progressBar = nil; + } +} + + +void FConsoleWindow::ExpandTextView(const float height) +{ + NSRect textFrame = [m_scrollView frame]; + textFrame.origin.y -= height; + textFrame.size.height += height; + [m_scrollView setFrame:textFrame]; +} + + +void FConsoleWindow::Progress(const int current, const int maximum) +{ + if (nil == m_progressBar) + { + return; + } + + static unsigned int previousTime = I_MSTime(); + unsigned int currentTime = I_MSTime(); + + if (currentTime - previousTime > 33) // approx. 30 FPS + { + previousTime = currentTime; + + [m_progressBar setMaxValue:maximum]; + [m_progressBar setDoubleValue:current]; + + [[NSRunLoop currentRunLoop] limitDateForMode:NSDefaultRunLoopMode]; + } +} + + +void FConsoleWindow::NetInit(const char* const message, const int playerCount) +{ + if (nil == m_netView) + { + SetProgressBar(false); + ExpandTextView(-NET_VIEW_HEIGHT); + + // Message like 'Waiting for players' or 'Contacting host' + m_netMessageText = [[NSTextField alloc] initWithFrame:NSMakeRect(12.0f, 64.0f, 400.0f, 16.0f)]; + [m_netMessageText setAutoresizingMask:NSViewWidthSizable]; + [m_netMessageText setDrawsBackground:NO]; + [m_netMessageText setSelectable:NO]; + [m_netMessageText setBordered:NO]; + + // Text with connected/total players count + m_netCountText = [[NSTextField alloc] initWithFrame:NSMakeRect(428.0f, 64.0f, 72.0f, 16.0f)]; + [m_netCountText setAutoresizingMask:NSViewMinXMargin]; + [m_netCountText setAlignment:NSRightTextAlignment]; + [m_netCountText setDrawsBackground:NO]; + [m_netCountText setSelectable:NO]; + [m_netCountText setBordered:NO]; + + // Connection progress + m_netProgressBar = [[NSProgressIndicator alloc] initWithFrame:NSMakeRect(12.0f, 40.0f, 488.0f, 16.0f)]; + [m_netProgressBar setAutoresizingMask:NSViewWidthSizable]; + [m_netProgressBar setMaxValue:playerCount]; + + if (0 == playerCount) + { + // Joining game + [m_netProgressBar setIndeterminate:YES]; + [m_netProgressBar startAnimation:nil]; + } + else + { + // Hosting game + [m_netProgressBar setIndeterminate:NO]; + } + + // Cancel network game button + m_netAbortButton = [[NSButton alloc] initWithFrame:NSMakeRect(432.0f, 8.0f, 72.0f, 28.0f)]; + [m_netAbortButton setAutoresizingMask:NSViewMinXMargin]; + [m_netAbortButton setBezelStyle:NSRoundedBezelStyle]; + [m_netAbortButton setTitle:@"Cancel"]; + [m_netAbortButton setKeyEquivalent:@"\r"]; + [m_netAbortButton setTarget:NSApp]; + [m_netAbortButton setAction:@selector(terminate:)]; + + // Panel for controls above + m_netView = [[NSView alloc] initWithFrame:NSMakeRect(0.0f, 0.0f, 512.0f, NET_VIEW_HEIGHT)]; + [m_netView setAutoresizingMask:NSViewWidthSizable]; + [m_netView addSubview:m_netMessageText]; + [m_netView addSubview:m_netCountText]; + [m_netView addSubview:m_netProgressBar]; + [m_netView addSubview:m_netAbortButton]; + + NSRect windowRect = [m_window frame]; + windowRect.origin.y -= NET_VIEW_HEIGHT; + windowRect.size.height += NET_VIEW_HEIGHT; + + [m_window setFrame:windowRect display:YES]; + [[m_window contentView] addSubview:m_netView]; + } + + [m_netMessageText setStringValue:[NSString stringWithUTF8String:message]]; + + m_netCurPos = 0; + m_netMaxPos = playerCount; + + NetProgress(1); // You always know about yourself +} + +void FConsoleWindow::NetProgress(const int count) +{ + if (0 == count) + { + ++m_netCurPos; + } + else + { + m_netCurPos = count; + } + + if (nil == m_netView) + { + return; + } + + if (m_netMaxPos > 1) + { + [m_netCountText setStringValue:[NSString stringWithFormat:@"%d / %d", m_netCurPos, m_netMaxPos]]; + [m_netProgressBar setDoubleValue:MIN(m_netCurPos, m_netMaxPos)]; + } +} + +void FConsoleWindow::NetDone() +{ + if (nil != m_netView) + { + ExpandTextView(NET_VIEW_HEIGHT); + + [m_netView removeFromSuperview]; + [m_netView release]; + m_netView = nil; + + // Released by m_netView + m_netMessageText = nil; + m_netCountText = nil; + m_netProgressBar = nil; + m_netAbortButton = nil; + } +} diff --git a/src/posix/cocoa/st_start.mm b/src/posix/cocoa/st_start.mm new file mode 100644 index 000000000..a1db95a0b --- /dev/null +++ b/src/posix/cocoa/st_start.mm @@ -0,0 +1,190 @@ +/* + ** st_start.mm + ** + **--------------------------------------------------------------------------- + ** Copyright 2015 Alexey Lysiuk + ** All rights reserved. + ** + ** Redistribution and use in source and binary forms, with or without + ** modification, are permitted provided that the following conditions + ** are met: + ** + ** 1. Redistributions of source code must retain the above copyright + ** notice, this list of conditions and the following disclaimer. + ** 2. Redistributions in binary form must reproduce the above copyright + ** notice, this list of conditions and the following disclaimer in the + ** documentation and/or other materials provided with the distribution. + ** 3. The name of the author may not be used to endorse or promote products + ** derived from this software without specific prior written permission. + ** + ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + **--------------------------------------------------------------------------- + ** + */ + +#import + +#include "c_cvars.h" +#include "st_console.h" +#include "st_start.h" +#include "v_text.h" + + +FStartupScreen *StartScreen; + + +CUSTOM_CVAR(Int, showendoom, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + if (self < 0) + { + self = 0; + } + else if (self > 2) + { + self = 2; + } +} + + +// --------------------------------------------------------------------------- + + +class FBasicStartupScreen : public FStartupScreen +{ +public: + FBasicStartupScreen(int maxProgress, bool showBar); + ~FBasicStartupScreen(); + + virtual void Progress(); + + virtual void NetInit(const char* message, int playerCount); + virtual void NetProgress(int count); + virtual void NetMessage(const char *format, ...); + virtual void NetDone(); + virtual bool NetLoop(bool (*timerCallback)(void*), void* userData); +}; + + +FBasicStartupScreen::FBasicStartupScreen(int maxProgress, bool showBar) +: FStartupScreen(maxProgress) +{ + FConsoleWindow& consoleWindow = FConsoleWindow::GetInstance(); + consoleWindow.SetProgressBar(true); + consoleWindow.SetTitleText(); + +#if 0 + // Testing code, please do not remove + consoleWindow.AddText("----------------------------------------------------------------\n"); + consoleWindow.AddText("1234567890 !@#$%^&*() ,<.>/?;:'\" [{]}\\| `~-_=+ " + "This is very very very long message needed to trigger word wrapping...\n\n"); + consoleWindow.AddText("Multiline...\n\tmessage...\n\t\twith...\n\t\t\ttabs.\n\n"); + + consoleWindow.AddText(TEXTCOLOR_BRICK "TEXTCOLOR_BRICK\n" TEXTCOLOR_TAN "TEXTCOLOR_TAN\n"); + consoleWindow.AddText(TEXTCOLOR_GRAY "TEXTCOLOR_GRAY & TEXTCOLOR_GREY\n"); + consoleWindow.AddText(TEXTCOLOR_GREEN "TEXTCOLOR_GREEN\n" TEXTCOLOR_BROWN "TEXTCOLOR_BROWN\n"); + consoleWindow.AddText(TEXTCOLOR_GOLD "TEXTCOLOR_GOLD\n" TEXTCOLOR_RED "TEXTCOLOR_RED\n"); + consoleWindow.AddText(TEXTCOLOR_BLUE "TEXTCOLOR_BLUE\n" TEXTCOLOR_ORANGE "TEXTCOLOR_ORANGE\n"); + consoleWindow.AddText(TEXTCOLOR_WHITE "TEXTCOLOR_WHITE\n" TEXTCOLOR_YELLOW "TEXTCOLOR_YELLOW\n"); + consoleWindow.AddText(TEXTCOLOR_UNTRANSLATED "TEXTCOLOR_UNTRANSLATED\n"); + consoleWindow.AddText(TEXTCOLOR_BLACK "TEXTCOLOR_BLACK\n" TEXTCOLOR_LIGHTBLUE "TEXTCOLOR_LIGHTBLUE\n"); + consoleWindow.AddText(TEXTCOLOR_CREAM "TEXTCOLOR_CREAM\n" TEXTCOLOR_OLIVE "TEXTCOLOR_OLIVE\n"); + consoleWindow.AddText(TEXTCOLOR_DARKGREEN "TEXTCOLOR_DARKGREEN\n" TEXTCOLOR_DARKRED "TEXTCOLOR_DARKRED\n"); + consoleWindow.AddText(TEXTCOLOR_DARKBROWN "TEXTCOLOR_DARKBROWN\n" TEXTCOLOR_PURPLE "TEXTCOLOR_PURPLE\n"); + consoleWindow.AddText(TEXTCOLOR_DARKGRAY "TEXTCOLOR_DARKGRAY\n" TEXTCOLOR_CYAN "TEXTCOLOR_CYAN\n"); + consoleWindow.AddText(TEXTCOLOR_NORMAL "TEXTCOLOR_NORMAL\n" TEXTCOLOR_BOLD "TEXTCOLOR_BOLD\n"); + consoleWindow.AddText(TEXTCOLOR_CHAT "TEXTCOLOR_CHAT\n" TEXTCOLOR_TEAMCHAT "TEXTCOLOR_TEAMCHAT\n"); + consoleWindow.AddText("----------------------------------------------------------------\n"); +#endif // _DEBUG +} + +FBasicStartupScreen::~FBasicStartupScreen() +{ + FConsoleWindow::GetInstance().SetProgressBar(false); +} + + +void FBasicStartupScreen::Progress() +{ + if (CurPos < MaxPos) + { + ++CurPos; + } + + FConsoleWindow::GetInstance().Progress(CurPos, MaxPos); +} + + +void FBasicStartupScreen::NetInit(const char* const message, const int playerCount) +{ + FConsoleWindow::GetInstance().NetInit(message, playerCount); +} + +void FBasicStartupScreen::NetProgress(const int count) +{ + FConsoleWindow::GetInstance().NetProgress(count); +} + +void FBasicStartupScreen::NetMessage(const char* const format, ...) +{ + va_list args; + va_start(args, format); + + FString message; + message.VFormat(format, args); + va_end(args); + + Printf("%s\n", message.GetChars()); +} + +void FBasicStartupScreen::NetDone() +{ + FConsoleWindow::GetInstance().NetDone(); +} + +bool FBasicStartupScreen::NetLoop(bool (*timerCallback)(void*), void* const userData) +{ + while (true) + { + if (timerCallback(userData)) + { + break; + } + + [[NSRunLoop currentRunLoop] limitDateForMode:NSDefaultRunLoopMode]; + + // Do not poll to often + usleep(50000); + } + + return true; +} + + +// --------------------------------------------------------------------------- + + +FStartupScreen *FStartupScreen::CreateInstance(const int maxProgress) +{ + return new FBasicStartupScreen(maxProgress, true); +} + + +// --------------------------------------------------------------------------- + + +void ST_Endoom() +{ + extern void I_ShutdownJoysticks(); + I_ShutdownJoysticks(); + + exit(0); +} diff --git a/src/posix/st_start.cpp b/src/posix/sdl/st_start.cpp similarity index 100% rename from src/posix/st_start.cpp rename to src/posix/sdl/st_start.cpp From db207feed1a167866ae134c2ed72db12ce1db1c0 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Wed, 30 Dec 2015 12:17:38 +0200 Subject: [PATCH 08/11] Added missing header #include for old OS X SDKs --- src/posix/cocoa/st_start.mm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/posix/cocoa/st_start.mm b/src/posix/cocoa/st_start.mm index a1db95a0b..36582c64b 100644 --- a/src/posix/cocoa/st_start.mm +++ b/src/posix/cocoa/st_start.mm @@ -31,6 +31,8 @@ ** */ +#include + #import #include "c_cvars.h" From 3466a8c7a90b30156b653704fe81df6d4e496032 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Wed, 30 Dec 2015 12:19:50 +0200 Subject: [PATCH 09/11] Disabled miniaturization for OS X startup window Old versions of OS X don't support changing of window style mask --- src/posix/cocoa/st_console.mm | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/posix/cocoa/st_console.mm b/src/posix/cocoa/st_console.mm index e0eba7527..d9c6ba810 100644 --- a/src/posix/cocoa/st_console.mm +++ b/src/posix/cocoa/st_console.mm @@ -104,7 +104,7 @@ FConsoleWindow::FConsoleWindow() NSString* const title = [NSString stringWithFormat:@"%s %s - Console", GAMESIG, GetVersionString()]; [m_window initWithContentRect:initialRect - styleMask:NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask + styleMask:NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask backing:NSBackingStoreBuffered defer:NO]; [m_window setMinSize:[m_window frame].size]; @@ -186,9 +186,6 @@ void FConsoleWindow::ShowFatalError(const char* const message) AddText(PalEntry(255, 255, 170), message); AddText("\n"); - // It's impossible to restore minimized window in modal loop - [m_window setStyleMask:[m_window styleMask] & ~NSMiniaturizableWindowMask]; - [NSApp runModalForWindow:m_window]; } From 63993dee968f214ed2d1f7f6f5d5c2cda3b629b2 Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Wed, 30 Dec 2015 16:05:16 +0200 Subject: [PATCH 10/11] Hid resize indicator on OS X startup window The resize indicator overlapped with progress bar and Quit/Cancel button on 10.6 and older versions OS X 10.7 and newer don't have this indicator at all --- src/posix/cocoa/st_console.mm | 1 + 1 file changed, 1 insertion(+) diff --git a/src/posix/cocoa/st_console.mm b/src/posix/cocoa/st_console.mm index d9c6ba810..342e251a3 100644 --- a/src/posix/cocoa/st_console.mm +++ b/src/posix/cocoa/st_console.mm @@ -108,6 +108,7 @@ FConsoleWindow::FConsoleWindow() backing:NSBackingStoreBuffered defer:NO]; [m_window setMinSize:[m_window frame].size]; + [m_window setShowsResizeIndicator:NO]; [m_window setTitle:title]; [m_window center]; [m_window exitAppOnClose]; From 94fec26cb67c61fedefcaaf21c7556e3a782046c Mon Sep 17 00:00:00 2001 From: "alexey.lysiuk" Date: Thu, 31 Dec 2015 11:00:05 +0200 Subject: [PATCH 11/11] Fixed runtime warning on OS X 10.4 Tiger The 'invalid pixel format attribute' warning was introduced with automated graphics switching control --- src/posix/cocoa/i_video.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/posix/cocoa/i_video.mm b/src/posix/cocoa/i_video.mm index 799dd5ffd..07c2464f4 100644 --- a/src/posix/cocoa/i_video.mm +++ b/src/posix/cocoa/i_video.mm @@ -420,7 +420,7 @@ CocoaVideo::CocoaVideo(const int multisample) attributes[i++] = NSOpenGLPFAStencilSize; attributes[i++] = NSOpenGLPixelFormatAttribute(8); - if (!vid_autoswitch) + if (NSAppKitVersionNumber >= AppKit10_5 && !vid_autoswitch) { attributes[i++] = NSOpenGLPFAAllowOfflineRenderers; }