summaryrefslogtreecommitdiff
path: root/frontends/cocoa
diff options
context:
space:
mode:
Diffstat (limited to 'frontends/cocoa')
-rw-r--r--frontends/cocoa/BrowserView.h4
-rw-r--r--frontends/cocoa/BrowserView.m33
-rw-r--r--frontends/cocoa/DownloadWindowController.m2
-rw-r--r--frontends/cocoa/Makefile33
-rw-r--r--frontends/cocoa/NetSurf.xcodeproj/project.pbxproj12
-rw-r--r--frontends/cocoa/NetsurfApp.m2
-rw-r--r--frontends/cocoa/ScrollableView.m2
-rw-r--r--frontends/cocoa/apple_image.m4
-rw-r--r--frontends/cocoa/desktop-tree.m2
-rw-r--r--frontends/cocoa/fetch.m133
-rw-r--r--frontends/cocoa/gui.m4
-rw-r--r--frontends/cocoa/plotter.m9
l---------frontends/cocoa/res/de.lproj/welcome.html1
l---------frontends/cocoa/res/en.lproj/licence.html1
l---------frontends/cocoa/res/en.lproj/maps.html1
l---------frontends/cocoa/res/en.lproj/welcome.html1
16 files changed, 126 insertions, 118 deletions
diff --git a/frontends/cocoa/BrowserView.h b/frontends/cocoa/BrowserView.h
index 596100f09..cf1b0dc02 100644
--- a/frontends/cocoa/BrowserView.h
+++ b/frontends/cocoa/BrowserView.h
@@ -25,8 +25,6 @@
@interface BrowserView : ScrollableView <NSTextInput> {
struct browser_window *browser;
- NSPoint caretPoint;
- CGFloat caretHeight;
BOOL caretVisible;
BOOL hasCaret;
NSTimer *caretTimer;
@@ -45,7 +43,7 @@
@property (readwrite, assign, nonatomic, getter=isHistoryVisible) BOOL historyVisible;
- (void)removeCaret;
-- (void)addCaretAt:(NSPoint)point height:(CGFloat)height;
+- (void)addCaretAtX: (int)caretX Y: (int)caretY height: (int)caretHeight;
- (void)updateHistory;
diff --git a/frontends/cocoa/BrowserView.m b/frontends/cocoa/BrowserView.m
index c1cf9beb9..110214d74 100644
--- a/frontends/cocoa/BrowserView.m
+++ b/frontends/cocoa/BrowserView.m
@@ -38,6 +38,8 @@
@property (readwrite, copy, nonatomic) NSString *markedText;
+@property (readwrite, nonatomic) NSRect caretRect;
+
- (void)scrollHorizontal:(CGFloat)amount;
- (void)scrollVertical:(CGFloat)amount;
- (CGFloat)pageScroll;
@@ -92,34 +94,22 @@ static const NSTimeInterval CaretBlinkTime = 0.8;
[history redraw];
}
-static inline NSRect cocoa_get_caret_rect(BrowserView *view)
-{
- float bscale = browser_window_get_scale(view->browser);
-
- NSRect caretRect = {
- .origin = NSMakePoint(view->caretPoint.x * bscale, view->caretPoint.y * bscale),
- .size = NSMakeSize(CaretWidth, view->caretHeight * bscale)
- };
-
- return caretRect;
-}
-
- (void)removeCaret
{
hasCaret = NO;
- [self setNeedsDisplayInRect:cocoa_get_caret_rect(self)];
+ [self setNeedsDisplayInRect: self.caretRect];
[self setCaretTimer:nil];
}
-- (void)addCaretAt:(NSPoint)point height:(CGFloat)height
+- (void)addCaretAtX: (int)caretX Y: (int)caretY height: (int)caretHeight
{
if (hasCaret) {
- [self setNeedsDisplayInRect:cocoa_get_caret_rect(self)];
+ [self setNeedsDisplayInRect:self.caretRect];
}
- caretPoint = point;
- caretHeight = height;
+ self.caretRect = cocoa_rect_wh(caretX, caretY, CaretWidth, caretHeight);
+
hasCaret = YES;
caretVisible = YES;
@@ -129,14 +119,14 @@ static inline NSRect cocoa_get_caret_rect(BrowserView *view)
[caretTimer setFireDate:[NSDate dateWithTimeIntervalSinceNow:CaretBlinkTime]];
}
- [self setNeedsDisplayInRect:cocoa_get_caret_rect(self)];
+ [self setNeedsDisplayInRect:self.caretRect];
}
- (void)caretBlink:(NSTimer *)timer
{
if (hasCaret) {
caretVisible = !caretVisible;
- [self setNeedsDisplayInRect:cocoa_get_caret_rect(self)];
+ [self setNeedsDisplayInRect: self.caretRect];
}
}
@@ -165,10 +155,9 @@ static inline NSRect cocoa_get_caret_rect(BrowserView *view)
browser_window_redraw(browser, 0, 0, &clip, &ctx);
}
- NSRect caretRect = cocoa_get_caret_rect(self);
- if (hasCaret && caretVisible && [self needsToDrawRect:caretRect]) {
+ if (hasCaret && caretVisible && [self needsToDrawRect:self.caretRect]) {
[[NSColor blackColor] set];
- [NSBezierPath fillRect:caretRect];
+ [NSBezierPath fillRect: self.caretRect];
}
}
}
diff --git a/frontends/cocoa/DownloadWindowController.m b/frontends/cocoa/DownloadWindowController.m
index 41373710c..8850327b9 100644
--- a/frontends/cocoa/DownloadWindowController.m
+++ b/frontends/cocoa/DownloadWindowController.m
@@ -106,7 +106,7 @@ static void cocoa_register_download(DownloadWindowController *download);
(NSString *)kLSQuarantineTypeWebDownload, (NSString *)kLSQuarantineTypeKey,
nil];
LSSetItemAttribute(&ref, kLSRolesAll, kLSItemQuarantineProperties, (__bridge CFDictionaryRef)attributes);
- LOG("Set quarantine attributes on file %s", [path UTF8String]);
+ NSLOG(netsurf, INFO, "Set quarantine attributes on file %s", [path UTF8String]);
}
[self setOutputFile:[NSFileHandle fileHandleForWritingAtPath:path]];
diff --git a/frontends/cocoa/Makefile b/frontends/cocoa/Makefile
index 212ed0442..92dec45a8 100644
--- a/frontends/cocoa/Makefile
+++ b/frontends/cocoa/Makefile
@@ -4,20 +4,9 @@
POSTEXES += NetSurf.app
-# shut up zconf.h and zlib.h
-#CFLAGS += -D_LARGEFILE64_SOURCE=1
-
-# add Mac Ports include and library paths for openssl
-ifneq ($(shell test -d /opt/local && echo 'yes'),)
- LDFLAGS += -L/opt/local/lib
- CFLAGS += -I/opt/local/include
-else
- # Check for homebrew installation of openssl
- ifneq ($(shell test -d /usr/local/opt/openssl/lib && echo 'yes'),)
- LDFLAGS += -L/usr/local/opt/openssl/lib
- CFLAGS += -I/usr/local/opt/openssl/include
- endif
-endif
+NETSURF_FEATURE_RSVG_CFLAGS := -DWITH_RSVG
+$(eval $(call pkg_config_find_and_add_enabled,RSVG,librsvg-2.0,SVG))
+
SDK_PARAM := $(shell xcodebuild -showsdks | awk '/^$$/{p=0};p; /(OS X|macOS) SDKs:/{p=1}' | head -1 | cut -f3)
@@ -34,14 +23,8 @@ CXXFLAGS := $(SDK_FLAGS) $(CXXFLAGS)
# for timerisset()
CFLAGS += -D_DARWIN_C_SOURCE
-LDFLAGS += -L/usr/lib
-LDFLAGS += -L/usr/X11/lib
-LDFLAGS += -lm -lcurl
-LDFLAGS += -lssl -lcrypto
-
CFLAGS += -Dnscocoa -D_BSD_SOURCE -D_POSIX_C_SOURCE -std=c99 -fobjc-arc
-CFLAGS += -I/usr/X11/include
CFLAGS += -include cocoa/Prefix.pch
VERSION_FULL := $(shell sed -n '/_version.*=.*"/{s/.*"\(.*\)".*/\1/;p;}' desktop/version.c)
@@ -170,17 +153,23 @@ R_RESOURCES := $(addprefix $(FRONTEND_RESOURCES_DIR)/,$(R_RESOURCES))
R_RESOURCES += $(addprefix $(FRONTEND_SOURCE_DIR)/PSMTabBarControl/Images/,$(TABBAR_RESOURCES))
LANGUAGES := de en fr it nl
-LOCALIZED_RESOURCES := Localizable.strings
+LOCALIZED_RESOURCES := \
+ Localizable.strings \
+ welcome.html \
+ maps.html \
+ licence.html
+
#languiage project macro
# $1 is language name
# $2 is list of resources per language
define make_lproj
R_RESOURCES += $$(OBJROOT)/$(1).lproj
+$(2):
$$(OBJROOT)/$(1).lproj: $(2)
$(VQ)echo Bundling language $(1)
$(Q)$(MKDIR) -p $$@
- $(Q)cp -pLR $(2) $$@
+ $(Q)for file in $(2) ; do if [ -e $$$$file ]; then cp -pLR $$$$file $$@ ; fi; done
$(Q)$(SPLIT_MESSAGES) -l $(1) -p cocoa -f messages resources/FatMessages > $$@/Messages
endef
diff --git a/frontends/cocoa/NetSurf.xcodeproj/project.pbxproj b/frontends/cocoa/NetSurf.xcodeproj/project.pbxproj
index b4475ecda..b64b2563c 100644
--- a/frontends/cocoa/NetSurf.xcodeproj/project.pbxproj
+++ b/frontends/cocoa/NetSurf.xcodeproj/project.pbxproj
@@ -1419,7 +1419,7 @@
/* Begin PBXLegacyTarget section */
2636298F12F698E00048542C /* NetSurf */ = {
isa = PBXLegacyTarget;
- buildArgumentsString = "PREFIX=../build TARGET=cocoa SDKROOT= VARIANT=debug $(ACTION)";
+ buildArgumentsString = "PREFIX=../build TARGET=cocoa SDKROOT= VARIANT=debug Q= $(ACTION)";
buildConfigurationList = 2636299512F699250048542C /* Build configuration list for PBXLegacyTarget "NetSurf" */;
buildPhases = (
);
@@ -1811,8 +1811,10 @@
isa = XCBuildConfiguration;
buildSettings = {
MKDIR = "mkdir -p";
- PKG_CONFIG_PATH = /Users/sven/Projekte/NetSurf/build/lib/pkgconfig;
+ PATH = "$(PATH):$NETSURF_LIB_PREFIX/bin";
+ PKG_CONFIG_PATH = "$(NETSURF_LIB_PREFIX)/lib/pkgconfig:$(CURL_PREFIX)/lib/pkgconfig:$(OPENSSL_PREFIX)/lib/pkgconfig:$(RSVG_PREFIX)/lib/pkgconfig";
PRODUCT_NAME = NetSurf;
+ RSVG_PREFIX = /usr/local/opt/librsvg;
};
name = Debug;
};
@@ -1820,8 +1822,10 @@
isa = XCBuildConfiguration;
buildSettings = {
MKDIR = "mkdir -p";
- PKG_CONFIG_PATH = /Users/sven/Projekte/NetSurf/build/lib/pkgconfig;
+ PATH = "$(PATH):$NETSURF_LIB_PREFIX/bin";
+ PKG_CONFIG_PATH = "$(NETSURF_LIB_PREFIX)/lib/pkgconfig:$(CURL_PREFIX)/lib/pkgconfig:$(OPENSSL_PREFIX)/lib/pkgconfig:$(RSVG_PREFIX)/lib/pkgconfig";
PRODUCT_NAME = NetSurf;
+ RSVG_PREFIX = /usr/local/opt/librsvg;
};
name = Release;
};
@@ -2007,6 +2011,7 @@
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CURL_PREFIX = /usr/local/opt/curl;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_NO_COMMON_BLOCKS = YES;
@@ -2043,6 +2048,7 @@
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CURL_PREFIX = /usr/local/opt/curl;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
diff --git a/frontends/cocoa/NetsurfApp.m b/frontends/cocoa/NetsurfApp.m
index 4c5442a2d..fabf8a795 100644
--- a/frontends/cocoa/NetsurfApp.m
+++ b/frontends/cocoa/NetsurfApp.m
@@ -86,7 +86,7 @@ static void die(const char *const error)
urldb_load_cookies(nsoption_charp(cookie_file));
cocoa_update_scale_factor();
- LOG("done setup");
+ NSLOG(netsurf, INFO, "done setup");
}
- (void)saveOptions
diff --git a/frontends/cocoa/ScrollableView.m b/frontends/cocoa/ScrollableView.m
index c495b1d93..6f20bfe28 100644
--- a/frontends/cocoa/ScrollableView.m
+++ b/frontends/cocoa/ScrollableView.m
@@ -38,7 +38,7 @@
- (void)adjustFrame
{
- NSSize frameSize = [[self superview] frame].size;
+ NSSize frameSize = self.enclosingScrollView.contentSize;
[self setFrameSize:NSMakeSize(MAX(self.minimumSize.width, frameSize.width),
MAX(self.minimumSize.height, frameSize.height))];
}
diff --git a/frontends/cocoa/apple_image.m b/frontends/cocoa/apple_image.m
index cee9c2773..596340965 100644
--- a/frontends/cocoa/apple_image.m
+++ b/frontends/cocoa/apple_image.m
@@ -88,7 +88,7 @@ static void animate_image_cb(void *ptr)
data.redraw.width = data.redraw.object_width = ai->base.width;
data.redraw.height = data.redraw.object_height = ai->base.height;
data.redraw.object = &ai->base;
- content_broadcast(&ai->base, CONTENT_MSG_REDRAW, data);
+ content_broadcast(&ai->base, CONTENT_MSG_REDRAW, &data);
cocoa_schedule(ai->frameTimes[ai->currentFrame], animate_image_cb, ai);
}
@@ -108,7 +108,7 @@ static bool apple_image_convert(struct content *c)
if (image == nil) {
union content_msg_data msg_data;
msg_data.error = "cannot decode image";
- content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
+ content_broadcast(c, CONTENT_MSG_ERROR, &msg_data);
return false;
}
diff --git a/frontends/cocoa/desktop-tree.m b/frontends/cocoa/desktop-tree.m
index 1015f9358..0874eeef7 100644
--- a/frontends/cocoa/desktop-tree.m
+++ b/frontends/cocoa/desktop-tree.m
@@ -278,7 +278,7 @@ struct tree *tree_create(unsigned int flags,
tree = calloc(sizeof(struct tree), 1);
if (tree == NULL) {
- LOG("calloc failed");
+ NSLOG(netsurf, INFO, "calloc failed");
guit->misc->warning(messages_get_errorcode(NSERROR_NOMEM), 0);
return NULL;
}
diff --git a/frontends/cocoa/fetch.m b/frontends/cocoa/fetch.m
index 74ba9afa3..764f25438 100644
--- a/frontends/cocoa/fetch.m
+++ b/frontends/cocoa/fetch.m
@@ -26,87 +26,106 @@
static char cocoafiletype[200];
-static const struct mimemap_s {
- const char *const extension;
- const char *const mimetype;
-} cocoamimemap[] = {
- { "css", "text/css" },
- { "f79", "text/css" },
- { "jpg", "image/jpeg" },
- { "jpeg", "image/jpeg" },
- { "gif", "image/gif" },
- { "png", "image/png" },
- { "b60", "image/png" },
- { "jng", "image/jng" },
- { "svg", "image/svg" },
- { NULL, "text/html" }
-};
-
static const char *fetch_filetype(const char *unix_path)
{
- NSString *uti;
- NSString *mimeType = nil;
- NSError *utiError = nil;
-
- uti = [[NSWorkspace sharedWorkspace] typeOfFile:[NSString stringWithUTF8String:unix_path] error:&utiError];
- if (nil != uti) {
- LOG("Looking for mimetype from uti \"%s\"", [uti UTF8String]);
- mimeType = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)uti, kUTTagClassMIMEType);
- } else {
- NSAlert *utiAlert = [NSAlert alertWithError:utiError];
- [utiAlert runModal]; // Ignore return value.
-
- LOG("uti call failed");
-
- strncpy(cocoafiletype, "text/html", sizeof(cocoafiletype));
- return cocoafiletype;
+ NSString *path = @(unix_path);
+ NSString *uti = [[NSWorkspace sharedWorkspace] typeOfFile:path error:NULL];
+ if (uti == nil) {
+ // If the file was not found look up the UTI from the file extension.
+ uti = (__bridge_transfer NSString *)UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)path.pathExtension, nil);
+ }
+
+ if (uti == nil) {
+ // We can’t determine the UTI, let’s pretend this is HTML.
+ return "text/html";
}
- if (nil != mimeType) {
- strncpy(cocoafiletype, [mimeType UTF8String], sizeof(cocoafiletype));
- } else {
- const char *extension;
+ NSString *mimeType = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)uti, kUTTagClassMIMEType);
- LOG("mimetype from uti failed");
+ strncpy(cocoafiletype, [mimeType cStringUsingEncoding: NSUTF8StringEncoding], sizeof cocoafiletype);
- extension = [(__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)uti, kUTTagClassFilenameExtension) UTF8String];
+ NSLOG(netsurf, INFO, "\tMIME type for '%s' is '%s'", unix_path, cocoafiletype);
- if (extension == NULL) {
- /* give up and go with default */
- LOG("No extension going with default type");
- strncpy(cocoafiletype, "text/html", sizeof(cocoafiletype));
- } else {
- int eidx = 0; /* index of extension entry */
+ return cocoafiletype;
+}
- while ((cocoamimemap[eidx].extension != NULL) && (strcmp(cocoamimemap[eidx].extension, extension) != 0)) {
- eidx++;
- }
+static NSString *findResource(const char *path) {
+ NSString *pathString = @(path);
+ NSString *nspath = [[NSBundle mainBundle] pathForResource:pathString ofType:@""];
- strncpy(cocoafiletype,
- cocoamimemap[eidx].mimetype,
- sizeof(cocoafiletype));
- }
+ if (nspath == nil) {
+ nspath = [[NSBundle mainBundle] pathForResource: pathString ofType:@"" inDirectory:nil forLocalization:@"en"];
}
- LOG("\tMIME type for '%s' is '%s'", unix_path, cocoafiletype);
-
- return cocoafiletype;
+ return nspath;
}
static nsurl *gui_get_resource_url(const char *path)
{
- nsurl *url = NULL;
- NSString *nspath = [[NSBundle mainBundle] pathForResource:[NSString stringWithUTF8String:path] ofType:@""];
- if (nspath == nil)
+ NSString *nspath = findResource(path);
+ if (nspath == nil) {
return NULL;
+ }
+
+ nsurl *url = NULL;
nsurl_create([[[NSURL fileURLWithPath:nspath] absoluteString] UTF8String], &url);
return url;
}
+static nserror cocoa_get_resource_data(const char *path, const uint8_t **data, size_t *data_len)
+{
+ NSString *resourcePath = findResource(path);
+ if (resourcePath == nil) {
+ return NSERROR_NOT_FOUND;
+ }
+
+ int file = open(resourcePath.fileSystemRepresentation, O_RDONLY);
+ if (file < 0) {
+ return NSERROR_NOT_FOUND;
+ }
+
+ int size = lseek(file, 0, SEEK_END);
+ if (size < 0) {
+ close(file);
+ return NSERROR_INVALID;
+ }
+
+ void *buffer = malloc(size);
+ if (buffer == NULL) {
+ close(file);
+ return NSERROR_NOMEM;
+ }
+
+ lseek(file, 0, SEEK_SET);
+ int readAmount = read(file, buffer, size);
+
+ if (size != readAmount) {
+ free(buffer);
+ close(file);
+ return NSERROR_INVALID;
+ }
+
+ *data = buffer;
+ *data_len = size;
+
+ close(file);
+
+ return NSERROR_OK;
+}
+
+static nserror cocoa_release_resource_data(const uint8_t *data)
+{
+ free((void *)data);
+ return NSERROR_OK;
+}
+
static struct gui_fetch_table fetch_table = {
.filetype = fetch_filetype,
.get_resource_url = gui_get_resource_url,
+
+ .get_resource_data = cocoa_get_resource_data,
+ .release_resource_data = cocoa_release_resource_data,
};
struct gui_fetch_table *cocoa_fetch_table = &fetch_table;
diff --git a/frontends/cocoa/gui.m b/frontends/cocoa/gui.m
index f564563f8..599c3b49e 100644
--- a/frontends/cocoa/gui.m
+++ b/frontends/cocoa/gui.m
@@ -253,9 +253,7 @@ static void
gui_window_place_caret(struct gui_window *g, int x, int y, int height,
const struct rect *clip)
{
- [[(__bridge BrowserViewController *)g browserView]
- addCaretAt:cocoa_point(x, y)
- height:cocoa_px_to_pt(height)];
+ [[(__bridge BrowserViewController *)g browserView] addCaretAtX:x Y:y height:height];
}
static void gui_window_remove_caret(struct gui_window *g)
diff --git a/frontends/cocoa/plotter.m b/frontends/cocoa/plotter.m
index f91167701..72577da1a 100644
--- a/frontends/cocoa/plotter.m
+++ b/frontends/cocoa/plotter.m
@@ -133,6 +133,11 @@ static nserror plot_clip(const struct redraw_context *ctx, const struct rect *cl
void cocoa_plot_render_path(NSBezierPath *path, const plot_style_t *pstyle)
{
+ // Quick exit if the clip rect has a zero size. Core Graphics doesn’t like that.
+ if (cocoa_plot_clip_rect.size.width == 0 || cocoa_plot_clip_rect.size.height == 0) {
+ return;
+ }
+
[NSGraphicsContext saveGraphicsState];
[NSBezierPath clipRect:cocoa_plot_clip_rect];
@@ -203,7 +208,7 @@ static nserror plot_path(const struct redraw_context *ctx, const plot_style_t *p
return NSERROR_OK;
if (*p != PLOTTER_PATH_MOVE) {
- LOG("Path does not start with move");
+ NSLOG(netsurf, INFO, "Path does not start with move");
return NSERROR_INVALID;
}
@@ -238,7 +243,7 @@ static nserror plot_path(const struct redraw_context *ctx, const plot_style_t *p
break;
default:
- LOG("Invalid path");
+ NSLOG(netsurf, INFO, "Invalid path");
return NSERROR_INVALID;
}
}
diff --git a/frontends/cocoa/res/de.lproj/welcome.html b/frontends/cocoa/res/de.lproj/welcome.html
new file mode 120000
index 000000000..98a53b215
--- /dev/null
+++ b/frontends/cocoa/res/de.lproj/welcome.html
@@ -0,0 +1 @@
+../../../../!NetSurf/Resources/de/welcome.html,faf \ No newline at end of file
diff --git a/frontends/cocoa/res/en.lproj/licence.html b/frontends/cocoa/res/en.lproj/licence.html
new file mode 120000
index 000000000..79f73669b
--- /dev/null
+++ b/frontends/cocoa/res/en.lproj/licence.html
@@ -0,0 +1 @@
+../../../../!NetSurf/Resources/en/licence.html,faf \ No newline at end of file
diff --git a/frontends/cocoa/res/en.lproj/maps.html b/frontends/cocoa/res/en.lproj/maps.html
new file mode 120000
index 000000000..bb3ffcbe7
--- /dev/null
+++ b/frontends/cocoa/res/en.lproj/maps.html
@@ -0,0 +1 @@
+../../../../!NetSurf/Resources/en/maps.html,faf \ No newline at end of file
diff --git a/frontends/cocoa/res/en.lproj/welcome.html b/frontends/cocoa/res/en.lproj/welcome.html
new file mode 120000
index 000000000..601099223
--- /dev/null
+++ b/frontends/cocoa/res/en.lproj/welcome.html
@@ -0,0 +1 @@
+../../../../!NetSurf/Resources/en/welcome.html,faf \ No newline at end of file