Merge branch 'develop' into DeprecatedGradleFeatures

This commit is contained in:
Joseph Cloutier
2022-09-03 18:36:04 -04:00
22 changed files with 333 additions and 269 deletions

View File

@@ -1,3 +1,34 @@
8.0.0 (08/30/2022)
------------------
* Updated HashLink to version 1.12
* Updated Android minimum SDK version to 21
* Updated Electron template to version 18
* Updated HTML5 to high DPI by default
* Added `--template` command line option to Lime tools
* Added `--appstore` and `--adhoc` command line options for AIR on iOS to Lime tools (to match iOS native)
* Added `-air-simulator` command line option for AIR to Lime tools (avoids packaging full AIR app)
* Added `<config:air profile="value"/>` to optionally support custom AIR profiles in simulator
* Added `setTextInputRect` to `Window` to specify a rectangle that has focus for text input
* Added `JNISafety` to improve JNI communication on Android
* Added `manageCookies` to `HTTPRequest` to support cookies on native platforms (only session for now)
* Added `pitch` property to `AudioSource`
* Added `-Delectron` flag to Electron builds so that it's possible to use `#if electron`
* Added icon priorities to allow a library to provide a default icon that the user can override
* Improved HashLink _.app_ file generation on macOS
* Improved performance of `HTTPRequest` on native platforms with better buffer management
* Improved support for Android 12 (SDK 31) and newer
* Improved output file size if no assets are defined (sets `disable_preloader_assets` define)
* Improved stage sizing on Electron (defaults to `0` for fluid width/height, same as regular browsers)
* Fixed garbage collector crash issue on iOS 12
* Fixed iOS build that failed because of missing _Metal.framework_ dependency
* Fixed switching between light and dark modes on Android destroying the Lime activity
* Fixed `getCurrentTime` on `AudioSource` for streaming sounds on native platforms
* Fixed wrong types on `NativeMenuItem` Flash externs
* Fixed set clipboard when `null` is passed (now changes to an empty string automatically)
* Fixed warnings for deprecated "devicemotion" events on Firefox
* Fixed incompatibility with "genes" Haxelib to allow generating JS Modules
7.9.0 (03/10/2021)
------------------

View File

@@ -43,11 +43,11 @@ First install the latest version of [Haxe](http://www.haxe.org/download).
Development Builds
==================
When there are changes, Lime is built nightly. Builds are available for download [here](https://github.com/openfl/lime/actions?query=branch%3Adevelop).
When there are changes, Lime is built nightly. Builds are available for download [here](https://github.com/openfl/lime/actions?query=branch%3Adevelop+is%3Asuccess).
To install a development build, use the "haxelib local" command:
haxelib local filename.zip
haxelib local lime-haxelib.zip
Building from Source

View File

@@ -0,0 +1,6 @@
body .navbar .brand:first-of-type {
background: url(./images/logo.png) center left no-repeat;
background-size: 32px 32px;
padding-left: 40px;
margin: 0.5em 0;
}

View File

@@ -6,6 +6,22 @@ function readCookie(name) {
return localStorage.getItem(name);
}
function isDarkTheme() {
return document.querySelector("html").classList.contains("dark-theme");
}
function toggleTheme() {
const htmlTag = document.querySelector("html");
let isDark = isDarkTheme();
if (isDark) {
htmlTag.classList.remove("dark-theme");
} else {
htmlTag.classList.add("dark-theme");
}
isDark = isDarkTheme();
localStorage.theme = isDark ? "dark" : "light";
}
function toggleInherited(el) {
var toggle = $(el).closest(".toggle");
toggle.toggleClass("toggle-on");

View File

@@ -1,6 +1,11 @@
<style>
::raw "
a, code .type {
a,
code a,
code .type,
.dark-theme a,
.dark-theme code a,
.dark-theme code .type {
color: #6fac17;
}
.navbar .brand {
@@ -11,7 +16,12 @@ a, code .type {
.navbar .brand img {
max-width: 75px;
}
.nav-list>.active>a.treeLink, .nav-list>.active>a.treeLink:hover, .nav-list>.active>a.treeLink:focus {
.nav-list>.active>a.treeLink,
.nav-list>.active>a.treeLink:hover,
.nav-list>.active>a.treeLink:focus,
.dark-theme .nav-list>.active>a.treeLink,
.dark-theme .nav-list>.active>a.treeLink:hover,
.dark-theme .nav-list>.active>a.treeLink:focus {
background: #6fac17;
color: #ffffff;
text-shadow: 0 0 0 transparent;
@@ -45,6 +55,7 @@ a, code .type {
<div class="container">
<a ::cond api.isDefined("logo"):: ::attr href if(api.isDefined("website")) api.getValue("website") else api.config.rootPath:: class="brand"><img alt="" ::attr src api.getValue("logo"):: /></a>
<a ::attr href api.config.rootPath:: class="brand" style="color:$$getHexValue(::textColor::)">::if api.config.pageTitle!=null::::api.config.pageTitle::::else::Lime API Documentation::end::</a>
<a href="#" id="theme-toggle" style="color:$$getHexValue(::textColor::)" onclick="toggleTheme()" title="Toggle Dark Mode"><i class="fa fa-moon-o"></i></a>
</div>
</div>
</div>

View File

@@ -11,13 +11,54 @@ import java.lang.Float;
import java.lang.Double;
/**
An object that was originally created by Haxe code. You can call its
functions using `callX("functionName")`, where X is the number of arguments.
A placeholder for an object created in Haxe. You can call the object's
functions using `callN("functionName")`, where N is the number of arguments.
Caution: the Haxe function will run on the thread you called it from. In many
cases, this will be the UI thread, which is _not_ the same as Haxe's main
thread. To avoid unpredictable thread-related errors, consider using a
`lime.system.ForegroundWorker` as your `HaxeObject`.
Caution: the Haxe function will run on whichever thread you call it from.
Java code typically runs on the UI thread, not Haxe's main thread, which can
easily cause thread-related errors. This cannot be easily remedied using Java
code, but is fixable in Haxe using `lime.system.JNI.JNISafety`.
Sample usage:
```haxe
// MyHaxeObject.hx
import lime.system.JNI;
class MyHaxeObject implements JNISafety
{
@:runOnMainThread
public function onActivityResult(requestCode:Int, resultCode:Int):Void
{
// Insert code to process the result. This code will safely run on the
// main Haxe thread.
}
}
```
```java
// MyJavaTool.java
import android.content.Intent;
import org.haxe.extension.Extension;
import org.haxe.lime.HaxeObject;
public class MyJavaTool extends Extension
{
private static var haxeObject:HaxeObject;
public static function registerHaxeObject(object:HaxeObject)
{
haxeObject = object;
}
// onActivityResult() always runs on the Android UI thread.
@Override public boolean onActivityResult(int requestCode, int resultCode, Intent data)
{
haxeObject.call2(requestCode, resultCode);
return true;
}
}
```
**/
public class HaxeObject
{

View File

@@ -70,10 +70,7 @@ class Build extends Script
"https://github.com/openfl/lime/tree/develop/src/",
"-D",
"website",
"http://lime.software",
"-D",
"logo",
"/images/logo.png",
"https://lime.openfl.org",
"-D",
"textColor",
"0x777777",

View File

@@ -13,4 +13,4 @@ hxml/android.hxml
hxml/html5.hxml
--next
-cmd haxelib run dox -i xml -in lime --title "Lime API Reference" -D website "http://lime.software" -D source-path "https://github.com/openfl/lime/tree/develop/src/" -D logo "/images/logo.png" -D textColor 0x777777 -theme ../assets/docs-theme --toplevel-package lime
-cmd haxelib run dox -i xml -in lime --title "Lime API Reference" -D website "https://lime.openfl.org" -D source-path "https://github.com/openfl/lime/tree/develop/src/" -D textColor 0x777777 -theme ../assets/docs-theme --toplevel-package lime

View File

@@ -6,8 +6,8 @@ package flash.display;
var data:Dynamic;
var enabled:Bool;
var isSeparator(default, never):Bool;
var keyEquivalent:flash.ui.Keyboard;
var keyEquivalentModifiers:Array<flash.ui.Keyboard>;
var keyEquivalent:String;
var keyEquivalentModifiers:Array<UInt>;
var label:String;
var menu(default, never):NativeMenu;
var mnemonicIndex:Int;

View File

@@ -5,7 +5,11 @@
"tags": [],
"description": "A foundational Haxe framework for cross-platform development",
"version": "8.0.0",
"releasenote": "",
"contributors": [ "singmajesty" ],
"releasenote": "Update HashLink, iOS and Android build fixes, and ongoing improvements",
"contributors": [
"singmajesty",
"bowlerhat",
"Dimensionscape"
],
"classPath": "src"
}

View File

@@ -81,7 +81,7 @@ namespace lime {
static int VorbisFile_BufferClose (VorbisFile_Buffer* src) {
free (src);
delete src;
return 0;
}
@@ -154,8 +154,8 @@ namespace lime {
if (ov_open_callbacks (buffer, vorbisFile, NULL, 0, VORBIS_FILE_BUFFER_CALLBACKS) != 0) {
free (buffer);
free (vorbisFile);
delete buffer;
delete vorbisFile;
return 0;
}
@@ -178,7 +178,7 @@ namespace lime {
if (ov_open_callbacks (file, vorbisFile, NULL, 0, VORBIS_FILE_FILE_CALLBACKS) != 0) {
free (vorbisFile);
delete vorbisFile;
lime::fclose (file);
return 0;

View File

@@ -349,7 +349,6 @@ class NativeHTTPRequest
future.onComplete(function(bytes)
{
bytes = buildBuffer();
if (bytes == null)
{
promise.complete(null);
@@ -395,7 +394,8 @@ class NativeHTTPRequest
private function curl_onWrite(curl:CURL, output:Bytes):Int
{
buffer.add(output);
buffer.addBytes(output, 0, output.length);
return output.length;
}

View File

@@ -1,210 +0,0 @@
package lime.system;
import haxe.macro.Context;
import haxe.macro.Expr;
import haxe.macro.Type;
#if target.threaded
import sys.thread.Thread;
#elseif cpp
import cpp.vm.Thread;
#elseif neko
import neko.vm.Thread;
#end
/**
An object whose instance functions always run on the main thread. If called
from any other thread, they'll switch to the main thread before proceeding.
This is important for Android apps that use JNI, as most times a Java class
calls a Haxe function, it does so on the UI thread.
Usage:
```haxe
class MyClass extends ForegroundWorker
{
public function foregroundFunction():Void
{
// Code here is guaranteed to run on Haxe's main thread.
}
@:anyThread public function anyThreadFunction():Void
{
// Code here will run on whichever thread calls the function, thanks
// to `@:anyThread`.
}
}
```
@see `ForegroundWorkerBuilder` for details and more options.
**/
#if (target.threaded || cpp || neko)
@:autoBuild(lime.system.ForegroundWorkerBuilder.modifyInstanceFunctions())
#end
// Yes, this could also be an interface, but that opens up edge cases. Better to
// leave those for advanced users who use `ForegroundWorkerBuilder`.
class ForegroundWorker
{
#if (target.threaded || cpp || neko)
private static var mainThread:Thread = Thread.current();
#end
/**
@return Whether the calling function is being run on the main thread.
**/
public static inline function onMainThread():Bool
{
#if (target.threaded || cpp || neko)
return Thread.current() == mainThread;
#else
return true;
#end
}
}
class ForegroundWorkerBuilder
{
/**
A build macro that iterates through a class's instance functions
(excluding those marked `@:anyThread`) and inserts code to ensure these
functions run only on the main thread.
Caution: build macros never directly modify superclasses. To make a
superclass's functions run on the main thread, either annotate that
class with its own `@:build` metadata or override all of its functions.
Usage:
```haxe
@:build(lime.system.ForegroundWorker.ForegroundWorkerBuilder.modifyInstanceFunctions())
class MyClass
{
public var array0:Array<String> = [];
private var array1:Array<String> = [];
public function copyItems():Void
{
//Thread safety code will be inserted automatically. You can
//write thread-unsafe code as normal.
for (i in 0...array0.length)
if (this.array0[i] != null)
this.array1.push(this.array0[i]);
}
}
```
**/
public static macro function modifyInstanceFunctions():Array<Field>
{
var fields:Array<Field> = Context.getBuildFields();
for (field in fields)
{
if (field.access.indexOf(AStatic) >= 0)
continue;
modifyField(field);
}
return fields;
}
/**
A build macro that iterates through a class's static functions
(excluding those marked `@:anyThread`) and inserts code to ensure these
functions run only on the main thread.
Usage:
```haxe
@:build(lime.system.ForegroundWorker.ForegroundWorkerBuilder.modifyStaticFunctions())
class MyClass
{
private static var eventCount:Map<String, Int> = new Map();
public static function countEvent(event:String):Void
{
//Thread safety code will be inserted automatically. You can
//write thread-unsafe code as normal.
if (eventCount.exists(event))
eventCount[event]++;
else
eventCount[event] = 1;
}
}
```
**/
public static macro function modifyStaticFunctions():Array<Field>
{
var fields:Array<Field> = Context.getBuildFields();
for (field in fields)
{
if (field.access.indexOf(AStatic) < 0)
continue;
modifyField(field);
}
return fields;
}
#if macro
private static function modifyField(field:Field):Void
{
if (field.name == "new")
return;
if (field.meta != null)
{
for (meta in field.meta)
{
if (meta.name == ":anyThread")
return;
}
}
switch (field.kind)
{
case FFun(f):
field.access.remove(AInline);
var qualifiedIdent:Array<String>;
if (field.access.indexOf(AStatic) >= 0)
{
if (Context.getLocalClass() == null)
throw "ForegroundWorkerBuilder is only designed to work on classes.";
var localClass:ClassType = Context.getLocalClass().get();
qualifiedIdent = localClass.pack.copy();
if (localClass.module != localClass.name)
qualifiedIdent.push(localClass.module);
qualifiedIdent.push(localClass.name);
}
else
{
qualifiedIdent = [];
}
qualifiedIdent.push(field.name);
var args:Array<Expr> = [for (arg in f.args) macro $i{arg.name}];
var exprs:Array<Expr>;
switch (f.expr.expr)
{
case EBlock(e):
exprs = e;
default:
exprs = [f.expr];
f.expr = { pos: field.pos, expr: EBlock(exprs) };
}
exprs.unshift(macro
if (!lime.system.ForegroundWorker.onMainThread())
{
haxe.MainLoop.runInMainThread($p{qualifiedIdent}.bind($a{args}));
return;
}
);
default:
}
}
#end
}

View File

@@ -1,7 +1,22 @@
package lime.system;
#if (!lime_doc_gen || android)
#if macro
import haxe.macro.Context;
import haxe.macro.Expr;
import haxe.macro.Type;
#else
import lime._internal.backend.native.NativeCFFI;
#end
#if !lime_doc_gen
#if target.threaded
import sys.thread.Thread;
#elseif cpp
import cpp.vm.Thread;
#elseif neko
import neko.vm.Thread;
#end
#end
/**
The Java Native Interface (JNI) allows C++ code to call Java functions, and
@@ -19,7 +34,7 @@ import lime._internal.backend.native.NativeCFFI;
Note that most Java code runs on a different thread than Haxe, meaning that
you can get thread-related errors in both directions. Java functions can
use `Extension.callbackHandler.post()` to switch to the UI thread, while
Haxe code can avoid the problem using `lime.system.ForegroundWorker`.
Haxe code can avoid the problem using `lime.system.JNI.JNISafety`.
**/
#if !lime_debug
@:fileXml('tags="haxe,release"')
@@ -325,4 +340,126 @@ class JNIMethod
}
}
}
/**
Most times a Java class calls a Haxe function, it does so on the UI thread,
which can lead to thread-related errors. These errors can be avoided by
switching back to the main thread before executing any code.
Usage:
```haxe
class MyClass implements JNISafety
{
@:runOnMainThread
public function callbackFunction(data:Dynamic):Void
{
// Code here is guaranteed to run on Haxe's main thread. It's safe
// to call `callbackFunction` via JNI.
}
public function notACallbackFunction():Void
{
// Code here will run on whichever thread calls the function. It may
// not be safe to call `notACallbackFunction` via JNI.
}
}
```
**/
// Haxe 3 can't parse "target.threaded" inside parentheses.
#if !doc_gen
#if target.threaded
@:autoBuild(lime.system.JNI.JNISafetyTools.build())
#elseif (cpp || neko)
@:autoBuild(lime.system.JNI.JNISafetyTools.build())
#end
#end
interface JNISafety {}
#if !doc_gen
class JNISafetyTools
{
#if target.threaded
private static var mainThread:Thread = Thread.current();
#elseif (cpp || neko)
private static var mainThread:Thread = Thread.current();
#end
/**
@return Whether the calling function is being run on the main thread.
**/
public static inline function onMainThread():Bool
{
#if target.threaded
return Thread.current() == mainThread;
#elseif (cpp || neko)
return Thread.current() == mainThread;
#else
return true;
#end
}
public static macro function build():Array<Field>
{
var fields:Array<Field> = Context.getBuildFields();
#if macro
for (field in fields)
{
// Don't modify constructors.
if (field.name == "new")
{
continue;
}
// Don't modify functions lacking `@:runOnMainThread`.
if (field.meta == null || !Lambda.exists(field.meta,
function(meta) return meta.name == ":runOnMainThread"))
{
continue;
}
switch (field.kind)
{
case FFun(f):
// The function needs to call itself and can't be inline.
field.access.remove(AInline);
// Make sure there's no return value.
switch (f.ret)
{
case macro:Void:
// Good to go.
case null:
f.ret = macro:Void;
default:
Context.error("Expected return type Void, got "
+ new haxe.macro.Printer().printComplexType(f.ret) + ".", field.pos);
}
var args:Array<Expr> = [];
for (arg in f.args)
{
args.push(macro $i{arg.name});
// Account for an unlikely edge case.
if (arg.name == field.name)
Context.error('${field.name}() should not take an argument named ${field.name}.', field.pos);
}
// Check the thread before running the function.
f.expr = macro
if (!lime.system.JNI.JNISafetyTools.onMainThread())
haxe.MainLoop.runInMainThread($i{field.name}.bind($a{args}))
else
${f.expr};
default:
}
}
#end
return fields;
}
}
#end
#end

View File

@@ -286,7 +286,12 @@ class AIRHelper
var extDirs:Array<String> = getExtDirs(project);
var profile:String;
if (targetPlatform == ANDROID)
if (project.config.exists("air.profile"))
{
profile = project.config.getString("air.profile");
}
else if (targetPlatform == ANDROID)
{
profile = "mobileDevice";
}

View File

@@ -298,9 +298,11 @@ class IconHelper
for (icon in icons)
{
var iconDifference = icon.width - width + icon.height - height;
if (Path.extension(icon.path) == "svg")
// If size is unspecified, accept it as an almost-perfect match
if (icon.width == 0 && icon.height == 0)
{
iconDifference = 0;
iconDifference = 1;
}
if (iconDifference < 0 && !acceptSmaller)

View File

@@ -112,7 +112,10 @@ class FileDialog
var path = null;
#if hl
var bytes = NativeCFFI.lime_file_dialog_open_file(title, filter, defaultPath);
path = @:privateAccess String.fromUTF8(cast bytes);
if (bytes != null)
{
path = @:privateAccess String.fromUTF8(cast bytes);
}
#else
path = NativeCFFI.lime_file_dialog_open_file(title, filter, defaultPath);
#end
@@ -149,7 +152,10 @@ class FileDialog
var path = null;
#if hl
var bytes = NativeCFFI.lime_file_dialog_open_directory(title, filter, defaultPath);
path = @:privateAccess String.fromUTF8(cast bytes);
if (bytes != null)
{
path = @:privateAccess String.fromUTF8(cast bytes);
}
#else
path = NativeCFFI.lime_file_dialog_open_directory(title, filter, defaultPath);
#end
@@ -164,7 +170,10 @@ class FileDialog
var path = null;
#if hl
var bytes = NativeCFFI.lime_file_dialog_save_file(title, filter, defaultPath);
if (bytes != null) path = @:privateAccess String.fromUTF8(cast bytes);
if (bytes != null)
{
path = @:privateAccess String.fromUTF8(cast bytes);
}
#else
path = NativeCFFI.lime_file_dialog_save_file(title, filter, defaultPath);
#end

View File

@@ -1,5 +1,6 @@
package lime.utils;
import haxe.ds.ObjectMap;
import haxe.io.Bytes;
import haxe.io.Path;
import haxe.macro.Compiler;
@@ -35,18 +36,14 @@ class Preloader #if flash extends Sprite #end
public var onProgress = new Event<Int->Int->Void>();
@:noCompletion private var bytesLoaded:Int;
#if !disable_preloader_assets
@:noCompletion private var bytesLoadedCache = new Map<AssetLibrary, Int>();
#end
@:noCompletion private var bytesLoadedCache = new ObjectMap<#if !disable_preloader_assets AssetLibrary #else Dynamic #end, Int>();
@:noCompletion private var bytesLoadedCache2 = new Map<String, Int>();
@:noCompletion private var bytesTotal:Int;
@:noCompletion private var bytesTotalCache = new Map<String, Int>();
@:noCompletion private var initLibraryNames:Bool;
#if !disable_preloader_assets
@:noCompletion private var libraries:Array<AssetLibrary>;
@:noCompletion private var libraries:Array<#if !disable_preloader_assets AssetLibrary #else Dynamic #end>;
@:noCompletion private var libraryNames:Array<String>;
@:noCompletion private var loadedLibraries:Int;
#end
@:noCompletion private var loadedStage:Bool;
@:noCompletion private var preloadComplete:Bool;
@:noCompletion private var preloadStarted:Bool;
@@ -63,10 +60,8 @@ class Preloader #if flash extends Sprite #end
bytesLoaded = 0;
bytesTotal = 0;
#if !disable_preloader_assets
libraries = new Array<AssetLibrary>();
libraries = new Array<#if !disable_preloader_assets AssetLibrary #else Dynamic #end>();
libraryNames = new Array<String>();
#end
onProgress.add(update);
@@ -111,8 +106,7 @@ class Preloader #if flash extends Sprite #end
#end
}
#if !disable_preloader_assets
public function addLibrary(library:AssetLibrary):Void
public function addLibrary(library:#if !disable_preloader_assets AssetLibrary #else Dynamic #end):Void
{
libraries.push(library);
}
@@ -124,21 +118,17 @@ class Preloader #if flash extends Sprite #end
libraryNames.push(name);
}
}
#end
public function load():Void
{
#if !disable_preloader_assets
for (library in libraries)
{
bytesTotal += library.bytesTotal;
}
loadedLibraries = -1;
#end
preloadStarted = false;
#if !disable_preloader_assets
for (library in libraries)
{
Log.verbose("Preloading asset library");
@@ -170,7 +160,7 @@ class Preloader #if flash extends Sprite #end
}
else
{
bytesLoaded += library.bytesTotal - bytesLoadedCache.get(library);
bytesLoaded += Std.int(library.bytesTotal) - bytesLoadedCache.get(library);
}
loadedAssetLibrary();
@@ -189,12 +179,10 @@ class Preloader #if flash extends Sprite #end
}
loadedLibraries++;
#end
preloadStarted = true;
updateProgress();
}
#if !disable_preloader_assets
@:noCompletion private function loadedAssetLibrary(name:String = null):Void
{
loadedLibraries++;
@@ -215,7 +203,6 @@ class Preloader #if flash extends Sprite #end
updateProgress();
}
#end
@:noCompletion private function start():Void
{
@@ -309,8 +296,8 @@ class Preloader #if flash extends Sprite #end
}
#end
if (!simulateProgress #if flash && loadedStage #end#if !disable_preloader_assets
&& loadedLibraries == (libraries.length + libraryNames.length) #end)
if (!simulateProgress #if flash && loadedStage #end
&& loadedLibraries == (libraries.length + libraryNames.length))
{
if (!preloadComplete)
{

View File

@@ -17,7 +17,7 @@
<meta-data android:name="SDL_ENV.SDL_IOS_ORIENTATIONS" android:value= "LandscapeLeft LandscapeRight" />
::end::
<activity android:name="MainActivity" android:launchMode="singleTask" android:label="::APP_TITLE::" android:configChanges="keyboardHidden|orientation|screenSize|screenLayout"::if (WIN_ORIENTATION=="portrait"):: android:screenOrientation="sensorPortrait"::end::::if (WIN_ORIENTATION=="landscape"):: android:screenOrientation="sensorLandscape"::end:: android:exported="true">
<activity android:name="MainActivity" android:exported="true" android:launchMode="singleTask" android:label="::APP_TITLE::" android:configChanges="keyboardHidden|orientation|screenSize|screenLayout|uiMode"::if (WIN_ORIENTATION=="portrait"):: android:screenOrientation="sensorPortrait"::end::::if (WIN_ORIENTATION=="landscape"):: android:screenOrientation="sensorLandscape"::end::>
<intent-filter>

View File

@@ -1,7 +1,5 @@
#if !disable_preloader_assets
package;
import haxe.io.Bytes;
import lime.utils.AssetBundle;
import lime.utils.AssetLibrary;
@@ -12,6 +10,18 @@ import lime.utils.Assets;
import sys.FileSystem;
#end
#if disable_preloader_assets
@:dox(hide) class ManifestResources {
public static var preloadLibraries:Array<Dynamic>;
public static var preloadLibraryNames:Array<String>;
public static var rootPath:String;
public static function init (config:Dynamic):Void {
preloadLibraries = new Array ();
preloadLibraryNames = new Array ();
}
}
#else
@:access(lime.utils.Assets)

View File

@@ -0,0 +1,4 @@
#!/usr/bin/env sh
# HashLink needs a specific working directory to find hlboot.dat and libraries
cd "$(dirname "$0")"
exec ./hl

View File

@@ -207,6 +207,20 @@ class MacPlatform extends PlatformTarget
if (noOutput) return;
HashlinkHelper.copyHashlink(project, targetDirectory, executableDirectory, executablePath, is64);
// HashLink looks for hlboot.dat and libraries in the current
// working directory, so the .app file won't work properly if it
// tries to run the HashLink executable directly.
// when the .app file is launched, we can tell it to run a shell
// script instead of the HashLink executable. the shell script will
// adjusts the working directory before running the HL executable.
// unlike other platforms, we want to use the original "hl" name
var hlExecutablePath = Path.combine(executableDirectory, "hl");
System.renameFile(executablePath, hlExecutablePath);
System.runCommand("", "chmod", ["755", hlExecutablePath]);
// then we can use the executable name for the shell script
System.copyFileTemplate(project.templatePaths, 'hl/mac-launch.sh', executablePath);
}
else if (targetType == "java")
{