Skip to content

Commit d2a0a1b

Browse files
committed
osx loader
1 parent 041e30d commit d2a0a1b

File tree

5 files changed

+178
-133
lines changed

5 files changed

+178
-133
lines changed

Makefile

+8
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ all: $(OUTPUT_DIR)/libs $(if $(ANDROID),,$(LUAJIT)) \
3030
$(if $(ANDROID),$(LPEG_DYNLIB) $(LPEG_RE),) \
3131
$(if $(WIN32),,$(ZMQ_LIB) $(CZMQ_LIB) $(FILEMQ_LIB) $(ZYRE_LIB)) \
3232
$(if $(WIN32),,$(OUTPUT_DIR)/sdcv) \
33+
$(if $(MACOS),$(OUTPUT_DIR)/koreader,) \
3334
$(if $(MACOS),$(SDL2_LIB),) \
3435
$(if $(or $(CERVANTES),$(KINDLE),$(KOBO)),$(OUTPUT_DIR)/dropbear,) \
3536
$(if $(or $(CERVANTES),$(KINDLE),$(KOBO)),$(OUTPUT_DIR)/sftp-server,) \
@@ -210,6 +211,13 @@ ffi/lodepng_h.lua: ffi-cdecl/lodepng_decl.c $(LODEPNG_DIR)
210211
# include all third party libs
211212
include Makefile.third
212213

214+
# ===========================================================================
215+
# entry point for the application in OSX
216+
217+
$(OUTPUT_DIR)/koreader: osx_loader.c
218+
$(CC) -pagezero_size 10000 -image_base 100000000 \
219+
-I$(LUAJIT_DIR)/src $(LUAJIT_STATIC) -o $@ $^
220+
213221
# ===========================================================================
214222
# very simple "launcher" for koreader on the remarkable
215223

Makefile.defs

+2-1
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ endif
190190

191191
USE_LUAJIT_LIB=$(or $(DARWIN),$(ANDROID),$(WIN32))
192192

193-
SKIP_LUAJIT_BIN=$(or $(ANDROID),)
193+
SKIP_LUAJIT_BIN=$(or $(ANDROID),$(MACOS))
194194

195195
# handle utility params on different host systems
196196
ifdef DARWINHOST
@@ -695,6 +695,7 @@ LUAJIT_DIR=$(CURDIR)/$(LUAJIT_BUILD_DIR)/luajit-prefix/src/luajit
695695
LUAJIT=$(OUTPUT_DIR)/$(if $(WIN32),luajit.exe,luajit)
696696
LUAJIT_JIT=$(OUTPUT_DIR)/jit
697697
LUAJIT_LIB=$(OUTPUT_DIR)/$(if $(WIN32),lua51.dll,libs/libluajit.so)
698+
LUAJIT_STATIC=$(LUAJIT_DIR)/src/libluajit.a
698699

699700
POPEN_NOSHELL_BUILD_DIR=$(THIRDPARTY_DIR)/popen-noshell/build/$(MACHINE)
700701
POPEN_NOSHELL_DIR=$(CURDIR)/$(POPEN_NOSHELL_BUILD_DIR)/popen-noshell-prefix/src/popen-noshell

osx_loader.c

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/* Entry point for the SDL OSX application
2+
3+
SDL has some arcane magic that handles standalone apps (ie: apps without a bundle) and "normal" osx app bundles.
4+
We use this binary to make SDL aware that we're running within an application bundle. It also allows us to use XCode Instruments for profiling.
5+
For some reason these things won't happen if the executable in the bundle is a shell/lua script.
6+
7+
NOTE: SDL will fail to detect that we're a bundle if this binary is called using a symbolic link, so we prevent that here too */
8+
9+
#include <stdio.h> // for fprintf, stderr, printf
10+
#include <stdlib.h> // for exit, setenv, EXIT_FAILURE
11+
#include <stdint.h> // for uint32_t
12+
#include <string.h> // for strerror, strncpy
13+
#include <unistd.h> // for chdir, readlink
14+
#include <libgen.h> // for dirname
15+
#include <mach-o/dyld.h> // for _NSGetExecutablePath
16+
#include <sys/errno.h> // for errno, EINVAL
17+
#include <sys/syslimits.h> // for PATH_MAX
18+
19+
#include "lua.h"
20+
#include "lualib.h"
21+
#include "lauxlib.h"
22+
23+
#define LOGNAME "OSX loader"
24+
#define LANGUAGE "en_US.UTF-8"
25+
#define PLATFORM "KO_MULTIUSER"
26+
#define LUA_ERROR "failed to run lua chunk: %s\n"
27+
28+
int main(int argc, const char * argv[]) {
29+
int retval;
30+
lua_State *L;
31+
char path[PATH_MAX];
32+
char buffer[PATH_MAX];
33+
uint32_t size = sizeof(buffer);
34+
35+
if (_NSGetExecutablePath(buffer, &size) != 0) {
36+
printf("[%s]: unable to get executable path", LOGNAME);
37+
exit(EXIT_FAILURE);
38+
}
39+
40+
retval = readlink(buffer, path, sizeof(path));
41+
if (retval == -1) {
42+
if (errno != EINVAL) {
43+
fprintf(stderr, "[%s]: %s\n", LOGNAME, strerror(errno));
44+
exit(EXIT_FAILURE);
45+
} else {
46+
strncpy(path, buffer, sizeof(buffer));
47+
}
48+
} else {
49+
path[retval] = '\0';
50+
fprintf(stderr, "[%s]: symbolic links not allowed\n", LOGNAME);
51+
fprintf(stderr, "[%s]: please append %s to your PATH\n", LOGNAME, dirname(path));
52+
exit(EXIT_FAILURE);
53+
}
54+
55+
if (!(chdir(dirname(path)) == 0 && chdir("../koreader") == 0)) {
56+
fprintf(stderr, "[%s]: chdir to koreader assets failed!\n", LOGNAME);
57+
exit(EXIT_FAILURE);
58+
}
59+
60+
if (!((setenv("LC_ALL", LANGUAGE, 1) == 0) && (setenv(PLATFORM, "1", 1) == 0))) {
61+
fprintf(stderr, "[%s]: set environment variables failed!\n", LOGNAME);
62+
exit(EXIT_FAILURE);
63+
}
64+
65+
L = luaL_newstate();
66+
luaL_openlibs(L);
67+
68+
if (argc == 1) {
69+
retval = luaL_dostring(L, "arg = { os.getenv('HOME') }");
70+
if (retval) {
71+
fprintf(stderr, LUA_ERROR, lua_tostring(L, -1));
72+
goto quit;
73+
}
74+
75+
} else {
76+
retval = luaL_dostring(L, "arg = {}");
77+
if (retval) {
78+
fprintf(stderr, LUA_ERROR, lua_tostring(L, -1));
79+
goto quit;
80+
}
81+
for (int i = 1; i < argc; ++i) {
82+
if (snprintf(buffer, PATH_MAX, "table.insert(arg, '%s')", argv[i]) >= 0) {
83+
retval = luaL_dostring(L, buffer);
84+
if (retval) {
85+
fprintf(stderr, LUA_ERROR, lua_tostring(L, -1));
86+
goto quit;
87+
}
88+
}
89+
}
90+
}
91+
92+
retval = luaL_dofile(L, "reader.lua");
93+
if (retval)
94+
fprintf(stderr, LUA_ERROR, lua_tostring(L, -1));
95+
96+
goto quit;
97+
98+
quit:
99+
lua_close(L);
100+
unsetenv("LC_ALL");
101+
unsetenv("KO_MULTIUSER");
102+
return retval;
103+
}

thirdparty/sdl2/CMakeLists.txt

+3-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ enable_language(C)
1010

1111
ep_get_source_dir(SOURCE_DIR)
1212

13-
# override process name, remove workarounds for standalone applications
13+
# remove workarounds for standalone applications and add a couple of actions
14+
# to be used from the osx main menu.
15+
1416
set(PATCH_CMD "${KO_PATCH_SH} ${CMAKE_CURRENT_SOURCE_DIR}/cocoa.patch")
1517

1618
set(SDL2_VER "2.0.12")

thirdparty/sdl2/cocoa.patch

+62-131
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,50 @@
1-
diff -uNr a/src/video/cocoa/SDL_cocoaevents.m b/src/video/cocoa/SDL_cocoaevents.m
1+
diff -uNr a/src/video/cocoa/SDL_cocoaevents.m e/src/video/cocoa/SDL_cocoaevents.m
22
--- a/src/video/cocoa/SDL_cocoaevents.m 2020-03-11 02:36:18.000000000 +0100
3-
+++ b/src/video/cocoa/SDL_cocoaevents.m 2020-07-19 14:50:50.000000000 +0200
4-
@@ -233,47 +233,12 @@
3+
+++ e/src/video/cocoa/SDL_cocoaevents.m 2020-07-28 21:40:49.000000000 +0200
4+
@@ -34,6 +34,18 @@
5+
#define kIOPMAssertPreventUserIdleDisplaySleep kIOPMAssertionTypePreventUserIdleDisplaySleep
6+
#endif
7+
8+
+static void _openUrl(NSString *url) {
9+
+ [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:url]];
10+
+}
11+
+
12+
+static void _openFile(NSString *file, NSString *app) {
13+
+ NSString *path = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:file];
14+
+ if (path) {
15+
+ if (!app) app = @"TextEdit";
16+
+ [[NSWorkspace sharedWorkspace] openFile:path withApplication:app];
17+
+ }
18+
+}
19+
+
20+
@interface SDLApplication : NSApplication
21+
22+
- (void)terminate:(id)sender;
23+
@@ -45,6 +57,23 @@
24+
25+
@implementation SDLApplication
26+
27+
+/* KOReader specific actions */
28+
+- (IBAction) openWeb: (NSMenuItem*) sender {
29+
+ _openUrl(@"https://koreader.rocks");
30+
+}
31+
+
32+
+- (IBAction) openWiki: (NSMenuItem*) sender {
33+
+ _openUrl(@"https://github.com/koreader/koreader/wiki");
34+
+}
35+
+
36+
+- (IBAction) openForum: (NSMenuItem*) sender {
37+
+ _openUrl(@"https://www.mobileread.com/forums/forumdisplay.php?f=276");
38+
+}
39+
+
40+
+- (IBAction) openLicense: (NSMenuItem*) sender {
41+
+ _openFile(@"COPYING", nil);
42+
+}
43+
+
44+
// Override terminate to handle Quit and System Shutdown smoothly.
45+
- (void)terminate:(id)sender
46+
{
47+
@@ -233,20 +262,7 @@
548

649
- (void)applicationDidFinishLaunching:(NSNotification *)notification
750
{
@@ -19,132 +62,20 @@ diff -uNr a/src/video/cocoa/SDL_cocoaevents.m b/src/video/cocoa/SDL_cocoaevents.
1962
- SDL_Delay(300); /* !!! FIXME: this isn't right. */
2063
- [NSApp activateIgnoringOtherApps:YES];
2164
- }
22-
-
23-
- /* If we call this before NSApp activation, macOS might print a complaint
24-
- * about ApplePersistenceIgnoreState. */
25-
[SDLApplication registerUserDefaults];
26-
}
27-
@end
28-
29-
static SDLAppDelegate *appDelegate = nil;
65+
+ [NSApp activateIgnoringOtherApps:YES];
3066

31-
-static NSString *
32-
-GetApplicationName(void)
33-
-{
34-
- NSString *appName;
35-
-
36-
- /* Determine the application name */
37-
- appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"];
38-
- if (!appName) {
39-
- appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"];
40-
- }
41-
-
42-
- if (![appName length]) {
43-
- appName = [[NSProcessInfo processInfo] processName];
44-
- }
45-
-
46-
- return appName;
47-
-}
48-
-
49-
static bool
50-
LoadMainMenuNibIfAvailable(void)
51-
{
52-
@@ -296,11 +261,9 @@
53-
static void
54-
CreateApplicationMenus(void)
55-
{
56-
- NSString *appName;
57-
+ NSString *appName = @"KOReader";
58-
NSString *title;
59-
NSMenu *appleMenu;
60-
- NSMenu *serviceMenu;
61-
- NSMenu *windowMenu;
62-
NSMenuItem *menuItem;
63-
NSMenu *mainMenu;
64-
65-
@@ -317,27 +280,18 @@
66-
mainMenu = nil;
67-
68-
/* Create the application menu */
69-
- appName = GetApplicationName();
70-
appleMenu = [[NSMenu alloc] initWithTitle:@""];
71-
72-
- /* Add menu items */
73-
- title = [@"About " stringByAppendingString:appName];
74-
- [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
75-
-
76-
- [appleMenu addItem:[NSMenuItem separatorItem]];
77-
-
78-
- [appleMenu addItemWithTitle:@"Preferences…" action:nil keyEquivalent:@","];
79-
-
80-
- [appleMenu addItem:[NSMenuItem separatorItem]];
81-
-
82-
- serviceMenu = [[NSMenu alloc] initWithTitle:@""];
83-
- menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Services" action:nil keyEquivalent:@""];
84-
- [menuItem setSubmenu:serviceMenu];
85-
-
86-
- [NSApp setServicesMenu:serviceMenu];
87-
- [serviceMenu release];
88-
-
89-
- [appleMenu addItem:[NSMenuItem separatorItem]];
90-
+ /* Add the fullscreen toggle menu option, if supported */
91-
+ if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6) {
92-
+ /* Cocoa should update the title to Enter or Exit Full Screen automatically.
93-
+ * But if not, then just fallback to Toggle Full Screen.
94-
+ */
95-
+ menuItem = [[NSMenuItem alloc] initWithTitle:@"Toggle Full Screen" action:@selector(toggleFullScreen:) keyEquivalent:@"f"];
96-
+ [menuItem setKeyEquivalentModifierMask:NSEventModifierFlagControl | NSEventModifierFlagCommand];
97-
+ [appleMenu addItem:menuItem];
98-
+ [menuItem release];
99-
+ }
100-
101-
title = [@"Hide " stringByAppendingString:appName];
102-
[appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
103-
@@ -361,38 +315,6 @@
104-
/* Tell the application object that this is now the application menu */
105-
[NSApp setAppleMenu:appleMenu];
106-
[appleMenu release];
107-
-
108-
-
109-
- /* Create the window menu */
110-
- windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
111-
-
112-
- /* Add menu items */
113-
- [windowMenu addItemWithTitle:@"Close" action:@selector(performClose:) keyEquivalent:@"w"];
114-
-
115-
- [windowMenu addItemWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
116-
-
117-
- [windowMenu addItemWithTitle:@"Zoom" action:@selector(performZoom:) keyEquivalent:@""];
118-
-
119-
- /* Add the fullscreen toggle menu option, if supported */
120-
- if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6) {
121-
- /* Cocoa should update the title to Enter or Exit Full Screen automatically.
122-
- * But if not, then just fallback to Toggle Full Screen.
123-
- */
124-
- menuItem = [[NSMenuItem alloc] initWithTitle:@"Toggle Full Screen" action:@selector(toggleFullScreen:) keyEquivalent:@"f"];
125-
- [menuItem setKeyEquivalentModifierMask:NSEventModifierFlagControl | NSEventModifierFlagCommand];
126-
- [windowMenu addItem:menuItem];
127-
- [menuItem release];
128-
- }
129-
-
130-
- /* Put menu into the menubar */
131-
- menuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
132-
- [menuItem setSubmenu:windowMenu];
133-
- [[NSApp mainMenu] addItem:menuItem];
134-
- [menuItem release];
135-
-
136-
- /* Tell the application object that this is now the window menu */
137-
- [NSApp setWindowsMenu:windowMenu];
138-
- [windowMenu release];
139-
}
140-
141-
void
142-
@@ -498,7 +420,7 @@
143-
* seen by OS X power users. there's an additional optional human-readable
144-
* (localized) reason parameter which we don't set.
145-
*/
146-
- NSString *name = [GetApplicationName() stringByAppendingString:@" using SDL_DisableScreenSaver"];
147-
+ NSString *name = [@"luajit" stringByAppendingString:@" using SDL_DisableScreenSaver"];
148-
IOPMAssertionCreateWithDescription(kIOPMAssertPreventUserIdleDisplaySleep,
149-
(CFStringRef) name,
150-
NULL, NULL, NULL, 0, NULL,
67+
/* If we call this before NSApp activation, macOS might print a complaint
68+
* about ApplePersistenceIgnoreState. */
69+
@@ -424,12 +440,6 @@
70+
}
71+
}
72+
[NSApp finishLaunching];
73+
- if ([NSApp delegate]) {
74+
- /* The SDL app delegate calls this in didFinishLaunching if it's
75+
- * attached to the NSApp, otherwise we need to call it manually.
76+
- */
77+
- [SDLApplication registerUserDefaults];
78+
- }
79+
}
80+
if (NSApp && !appDelegate) {
81+
appDelegate = [[SDLAppDelegate alloc] init];

0 commit comments

Comments
 (0)