From 484989e925e8fa02c76ccf81969b6304f3ab7298 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Sat, 20 Apr 2019 21:38:26 -0400 Subject: [PATCH] Implemented uiInit() on macOS. The tests work so far! --- common/init.c | 38 ++++++++++++++++++++++++++++++++------ common/uipriv.h | 2 +- darwin/main.m | 34 ++++++++++++++++++++++++++++++++++ darwin/meson.build | 16 ++++++++++++++++ darwin/uipriv_darwin.h | 18 ++++++++++++++++++ meson.build | 2 +- test/initmain.c | 15 +++++++++------ ui.h | 2 +- 8 files changed, 112 insertions(+), 15 deletions(-) create mode 100644 darwin/main.m create mode 100644 darwin/meson.build create mode 100644 darwin/uipriv_darwin.h diff --git a/common/init.c b/common/init.c index 6e10937b..67e8c97b 100644 --- a/common/init.c +++ b/common/init.c @@ -5,28 +5,54 @@ static int initialized = 0; -int uiprivInitCheckParams(void *options, uiInitError *err) +#define errAlreadyInitialized "libui already initialized" +#define errOptionsMustBeNULL "options parameter to uiInit() must be NULL" + +static const char *commonInitErrors[] = { + errAlreadyInitialized, + errOptionsMustBeNULL, + NULL, +}; + +static int checkInitErrorLengths(uiInitError *err, const char *initErrors[]) +{ + const char **p; + + for (p = initErrors; *p != NULL; p++) + if (strlen(*p) > 255) { + strcpy(err->Message, "[INTERNAL] uiInit() error too long: "); + strncat(err->Message, *p, 32); + strcat(err->Message, "..."); + return 0; + } + return 1; +} + +int uiprivInitCheckParams(void *options, uiInitError *err, const char *initErrors[]) { if (err == NULL) return 0; if (err->Size != sizeof (uiInitError)) return 0; + if (!checkInitErrorLengths(err, commonInitErrors)) + return 0; + if (!checkInitErrorLengths(err, initErrors)) + return 0; + if (initialized) - return uiprivInitReturnError(err, "xxxxxxxxx"); + return uiprivInitReturnError(err, errAlreadyInitialized); if (options != NULL) - return uiprivInitReturnError(err, "xxxxxxxx"); + return uiprivInitReturnError(err, errOptionsMustBeNULL); return 1; } int uiprivInitReturnError(uiInitError *err, const char *msg) { + // checkInitErrorLengths() above ensures that err->Message[255] will always be '\0' strncpy(err->Message, msg, 256); - if (err->Message[255] != '\0') - // TODO there should be some check to make sure this doesn't happen - err->Message[255] = '\0'; return 0; } diff --git a/common/uipriv.h b/common/uipriv.h index 5a3aef03..6f085ace 100644 --- a/common/uipriv.h +++ b/common/uipriv.h @@ -1,6 +1,6 @@ // 19 april 2019 // init.c -extern int uiprivInitCheckParams(void *options, uiInitError *err); +extern int uiprivInitCheckParams(void *options, uiInitError *err, const char *initErrors[]); extern int uiprivInitReturnError(uiInitError *err, const char *msg); extern void uiprivMarkInitialized(void); diff --git a/darwin/main.m b/darwin/main.m new file mode 100644 index 00000000..b12ffe9f --- /dev/null +++ b/darwin/main.m @@ -0,0 +1,34 @@ +// 20 april 2019 +#import "uipriv_darwin.h" + +@interface uiprivApplication : NSApplication +@end + +@implementation uiprivApplication +@end + +static NSApplication *uiprivApp; + +#define errNSAppAlreadyInitialized "NSApp is not of type uiprivApplication; was likely already initialized beforehand" + +static const char *initErrors[] = { + errNSAppAlreadyInitialized, + NULL, +}; + +int uiInit(void *options, uiInitError *err) +{ + if (!uiprivInitCheckParams(options, err, initErrors)) + return 0; + + uiprivApp = [uiprivApplication sharedApplication]; + if (![NSApp isKindOfClass:[uiprivApplication class]]) + return uiprivInitReturnError(err, errNSAppAlreadyInitialized); + + uiprivMarkInitialized(); + return 1; +} + +void uiUninit(void) +{ +} diff --git a/darwin/meson.build b/darwin/meson.build new file mode 100644 index 00000000..dfe3edc7 --- /dev/null +++ b/darwin/meson.build @@ -0,0 +1,16 @@ +# 23 march 2019 + +libui_sources += [ + 'darwin/main.m', +] + +libui_deps += [ + meson.get_compiler('objc').find_library('objc', + required: true), + dependency('appleframeworks', + modules: ['Foundation', 'AppKit'], + required: true), +] +libui_soversion = 'A' +# the / is required by some older versions of OS X +libui_rpath = '@executable_path/' diff --git a/darwin/uipriv_darwin.h b/darwin/uipriv_darwin.h new file mode 100644 index 00000000..4a089dde --- /dev/null +++ b/darwin/uipriv_darwin.h @@ -0,0 +1,18 @@ +// 6 january 2015 +// note: as of OS X Sierra, the -mmacosx-version-min compiler options governs deprecation warnings; keep these around anyway just in case +#define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_8 +#define MAC_OS_X_VERSION_MAX_ALLOWED MAC_OS_X_VERSION_10_8 +#import +#import // see future.m +#import "../ui.h" +#import "../ui_darwin.h" +#import "../common/uipriv.h" + +#if __has_feature(objc_arc) +#error Sorry, libui cannot be compiled with ARC. +#endif + +// TODO find a better place for this +#ifndef NSAppKitVersionNumber10_9 +#define NSAppKitVersionNumber10_9 1265 +#endif diff --git a/meson.build b/meson.build index ec9b057a..369f2a50 100644 --- a/meson.build +++ b/meson.build @@ -145,7 +145,7 @@ if libui_OS == 'windows' # subdir('windows') install_headers('ui_windows.h') elif libui_OS == 'darwin' -# subdir('darwin') + subdir('darwin') install_headers('ui_darwin.h') else # subdir('unix') diff --git a/test/initmain.c b/test/initmain.c index 8629c4f1..43b40586 100644 --- a/test/initmain.c +++ b/test/initmain.c @@ -3,11 +3,14 @@ #include "../ui.h" #include "testing.h" -#define invalidOptionsError "TODOTODOTODO" -#define alreadyInitializedError "TODOTODOTODO" +// TODO fix up the formatting of testing.c so we can use newlines on the got/want stuff + +#define errInvalidOptions "options parameter to uiInit() must be NULL" +#define errAlreadyInitialized "libui already initialized" testingTestBefore(Init) { + uiInitError err; int ret; ret = uiInit(NULL, NULL); @@ -26,8 +29,8 @@ testingTestBefore(Init) ret = uiInit(&err, &err); if (ret != 0) testingTErrorf(t, "uiInit() with non-NULL options succeeded with return value %d; expected failure", err); - if (strcmp(err.Message, invalidOptionsError) != 0) - testingTErrorf(t, "uiInit() with non-NULL options returned bad error message: got %s, want %s", err.Message, invalidOptionsError); + if (strcmp(err.Message, errInvalidOptions) != 0) + testingTErrorf(t, "uiInit() with non-NULL options returned bad error message: got %s, want %s", err.Message, errInvalidOptions); memset(&err, 0, sizeof (uiInitError)); err.Size = sizeof (uiInitError); @@ -40,8 +43,8 @@ testingTestBefore(Init) ret = uiInit(NULL, &err); if (ret != 0) testingTErrorf(t, "uiInit() after a previous successful call succeeded with return value %d; expected failure", ret); - if (strcmp(err.Message, alreadyInitializedError) != 0) - testingTErrorf(t, "uiInit() after a previous successful call returned bad error message: got %s, want %s", err.Message, alreadyInitializedError); + if (strcmp(err.Message, errAlreadyInitialized) != 0) + testingTErrorf(t, "uiInit() after a previous successful call returned bad error message: got %s, want %s", err.Message, errAlreadyInitialized); } testingTestAfter(Uninit) diff --git a/ui.h b/ui.h index c80eb04e..1310f421 100644 --- a/ui.h +++ b/ui.h @@ -13,7 +13,7 @@ extern "C" { #ifdef uiprivBuildingLibui #if defined(_WIN32) && !defined(uiStatic) #define uiprivExtern __declspec(dllexport) extern -#elif deffined(_WIN32) +#elif defined(_WIN32) #define uiprivExtern extern #else #define uiprivExtern __attribute__((visibility("default"))) extern