diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8b797461c..aab932255 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -117,6 +117,7 @@ jobs: rm /usr/local/bin/idle3* rm /usr/local/bin/pydoc3* rm /usr/local/bin/python3* + rm /usr/local/bin/pip3* brew bundle popd diff --git a/project/lib/curl-files.xml b/project/lib/curl-files.xml index 69220ce05..06fecab8a 100644 --- a/project/lib/curl-files.xml +++ b/project/lib/curl-files.xml @@ -1,5 +1,5 @@ - + @@ -30,7 +30,7 @@
- +
diff --git a/project/src/backend/sdl/SDLSystem.cpp b/project/src/backend/sdl/SDLSystem.cpp index 77031cf8f..876734ab4 100644 --- a/project/src/backend/sdl/SDLSystem.cpp +++ b/project/src/backend/sdl/SDLSystem.cpp @@ -39,10 +39,10 @@ #include #include -#ifdef HX_WINDOWS #include #include -#endif + +using wstring_convert = std::wstring_convert>; namespace lime { @@ -111,13 +111,15 @@ namespace lime { case APPLICATION: { char* path = SDL_GetBasePath (); - #ifdef HX_WINDOWS - std::wstring_convert> converter; - result = new std::wstring (converter.from_bytes(path)); - #else - result = new std::wstring (path, path + strlen (path)); - #endif - SDL_free (path); + + if (path != nullptr) { + + wstring_convert converter; + result = new std::wstring (converter.from_bytes(path)); + SDL_free (path); + + } + break; } @@ -125,13 +127,15 @@ namespace lime { case APPLICATION_STORAGE: { char* path = SDL_GetPrefPath (company, title); - #ifdef HX_WINDOWS - std::wstring_convert> converter; - result = new std::wstring (converter.from_bytes(path)); - #else - result = new std::wstring (path, path + strlen (path)); - #endif - SDL_free (path); + + if (path != nullptr) { + + wstring_convert converter; + result = new std::wstring (converter.from_bytes(path)); + SDL_free (path); + + } + break; } @@ -145,11 +149,9 @@ namespace lime { #elif defined (HX_WINDOWS) - char folderPath[MAX_PATH] = ""; - SHGetFolderPath (NULL, CSIDL_DESKTOPDIRECTORY, NULL, SHGFP_TYPE_CURRENT, folderPath); - //WIN_StringToUTF8 (folderPath); - std::wstring_convert> converter; - result = new std::wstring (converter.from_bytes (folderPath)); + WCHAR folderPath[MAX_PATH] = L""; + SHGetFolderPathW (NULL, CSIDL_DESKTOPDIRECTORY, NULL, SHGFP_TYPE_CURRENT, folderPath); + result = new std::wstring (folderPath); #elif defined (IPHONE) @@ -159,15 +161,14 @@ namespace lime { char const* home = getenv ("HOME"); - if (home == NULL) { + if (home != NULL) { - return 0; + std::string path = std::string (home) + std::string ("/Desktop"); + wstring_convert converter; + result = new std::wstring (converter.from_bytes(path)); } - std::string path = std::string (home) + std::string ("/Desktop"); - result = new std::wstring (path.begin (), path.end ()); - #endif break; @@ -182,11 +183,9 @@ namespace lime { #elif defined (HX_WINDOWS) - char folderPath[MAX_PATH] = ""; - SHGetFolderPath (NULL, CSIDL_MYDOCUMENTS, NULL, SHGFP_TYPE_CURRENT, folderPath); - //WIN_StringToUTF8 (folderPath); - std::wstring_convert> converter; - result = new std::wstring (converter.from_bytes (folderPath)); + WCHAR folderPath[MAX_PATH] = L""; + SHGetFolderPathW (NULL, CSIDL_MYDOCUMENTS, NULL, SHGFP_TYPE_CURRENT, folderPath); + result = new std::wstring (folderPath); #elif defined (IPHONE) @@ -203,7 +202,8 @@ namespace lime { if (home != NULL) { std::string path = std::string (home) + std::string ("/Documents"); - result = new std::wstring (path.begin (), path.end ()); + wstring_convert converter; + result = new std::wstring (converter.from_bytes(path)); } @@ -220,11 +220,9 @@ namespace lime { #elif defined (HX_WINDOWS) - char folderPath[MAX_PATH] = ""; - SHGetFolderPath (NULL, CSIDL_FONTS, NULL, SHGFP_TYPE_CURRENT, folderPath); - //WIN_StringToUTF8 (folderPath); - std::wstring_convert> converter; - result = new std::wstring (converter.from_bytes (folderPath)); + WCHAR folderPath[MAX_PATH] = L""; + SHGetFolderPathW (NULL, CSIDL_FONTS, NULL, SHGFP_TYPE_CURRENT, folderPath); + result = new std::wstring (folderPath); #elif defined (HX_MACOS) @@ -260,11 +258,9 @@ namespace lime { #elif defined (HX_WINDOWS) - char folderPath[MAX_PATH] = ""; - SHGetFolderPath (NULL, CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT, folderPath); - //WIN_StringToUTF8 (folderPath); - std::wstring_convert> converter; - result = new std::wstring (converter.from_bytes (folderPath)); + WCHAR folderPath[MAX_PATH] = L""; + SHGetFolderPathW (NULL, CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT, folderPath); + result = new std::wstring (folderPath); #elif defined (IPHONE) @@ -281,7 +277,8 @@ namespace lime { if (home != NULL) { std::string path = std::string (home); - result = new std::wstring (path.begin (), path.end ()); + wstring_convert converter; + result = new std::wstring (converter.from_bytes(path)); } @@ -909,4 +906,4 @@ namespace lime { } -} \ No newline at end of file +} diff --git a/src/lime/_internal/graphics/ImageCanvasUtil.hx b/src/lime/_internal/graphics/ImageCanvasUtil.hx index 539bce20c..3102bcc2c 100644 --- a/src/lime/_internal/graphics/ImageCanvasUtil.hx +++ b/src/lime/_internal/graphics/ImageCanvasUtil.hx @@ -189,13 +189,10 @@ class ImageCanvasUtil if (!image.transparent) { - if (!image.transparent) buffer.__srcCanvas.setAttribute("moz-opaque", "true"); - buffer.__srcContext = untyped #if haxe4 js.Syntax.code #else __js__ #end ('buffer.__srcCanvas.getContext ("2d", { alpha: false })'); - } - else - { - buffer.__srcContext = buffer.__srcCanvas.getContext("2d"); + buffer.__srcCanvas.setAttribute("moz-opaque", "true"); } + + buffer.__srcContext = buffer.__srcCanvas.getContext("2d", {alpha: image.transparent}); } #end } diff --git a/src/lime/tools/IOSHelper.hx b/src/lime/tools/IOSHelper.hx index 56f2438d4..50fa34341 100644 --- a/src/lime/tools/IOSHelper.hx +++ b/src/lime/tools/IOSHelper.hx @@ -360,39 +360,68 @@ class IOSHelper applicationPath = workingDirectory + "/build/" + configuration + "-iphoneos/" + project.app.file + ".app"; } + var requireIPad = project.config.getString("ios.device", "universal") == "ipad"; + var requireIPhone = project.config.getString("ios.device", "universal") == "iphone"; + var xcodeVersion = Std.parseFloat(getXcodeVersion()); if (!Math.isNaN(xcodeVersion) && xcodeVersion >= 16) { // ios-deploy doesn't work with newer iOS SDKs where it can't // find DeveloperDiskImage.dmg. however, Xcode 16 adds new // commands for installing and launching apps on connected // devices, so we'll prefer those, if available. + var deviceUUID:String = null; - // prefer an iOS device with State == 'connected' - // Note: Platform == 'iOS' includes iPadOS - var listDevicesOutput = System.runProcess("", "xcrun", ["devicectl", "list", "devices", "--hide-default-columns", "--columns", "Identifier", "--filter", "Platform == 'iOS' AND State == 'connected'"]); - var ready = false; - for (line in listDevicesOutput.split("\n")) { - if (!ready) { - ready = StringTools.startsWith(line, "----"); - continue; - } - deviceUUID = line; - break; + + // we'll try various combinations of the following filters to + // select an iOS device. there may be multiple devices to choose + // from, so these filters help us figure out the best one. + + var filterPlatformIOS = "Platform == 'iOS'"; // includes iPadOS + var filterDeveloperModeEnabled = "deviceProperties.developerModeStatus == 'enabled'"; + var filterStateConnected = "State == 'connected'"; + var filterStateAvailable = "State == 'available (paired)'"; + var filterTransportTypeWired = "connectionProperties.transportType == 'wired'"; + var filterTransportTypeLocalNetwork = "connectionProperties.transportType == 'localNetwork'"; + var filterDeviceTypeIPhone = "hardwareProperties.deviceType == 'iPhone'"; + var filterDeviceTypeIPad = "hardwareProperties.deviceType == 'iPad'"; + + // first, some strictly required filters: + // 1. the platform must always be iOS (which includes iPadOS). + // 2. the device must be in developer mode. + // 3. if required by the project config, limit to iPhone or iPad only + var baseFilters = [ + filterPlatformIOS, + filterDeveloperModeEnabled, + ]; + if (requireIPad) + { + baseFilters.push(filterDeviceTypeIPad); } - if (deviceUUID == null || deviceUUID.length == 0) { - // preferred fallback is an iOS device that is both - // available and wired - var listDevicesOutput = System.runProcess("", "xcrun", ["devicectl", "list", "devices", "--hide-default-columns", "--columns", "Identifier", "--filter", "Platform == 'iOS' AND State == 'available (paired)' AND connectionProperties.transportType == 'wired'"]); - ready = false; - for (line in listDevicesOutput.split("\n")) { - if (!ready) { - ready = StringTools.startsWith(line, "----"); - continue; + else if (requireIPhone) + { + baseFilters.push(filterDeviceTypeIPhone); + } + + // after that, we have the following preferences, in order: + // 1. state: "connected" preferred over "available (paired)" + // 2. transportType: "wired" preferred over "localNetwork" + var stateFilters = [filterStateConnected, filterStateAvailable]; + var transportTypeFilters = [filterTransportTypeWired, filterTransportTypeLocalNetwork]; + for (stateFilter in stateFilters) + { + for (transportTypeFilter in transportTypeFilters) + { + deviceUUID = findDeviceUUIDWithFilters(baseFilters.concat([ + stateFilter, + transportTypeFilter + ])); + if (deviceUUID != null && deviceUUID.length > 0) + { + break; } - deviceUUID = line; - break; } } + if (deviceUUID == null || deviceUUID.length == 0) { // devices running iOS 16 and older don't support // xcrun devicectl, so if no device was found, try falling @@ -416,6 +445,27 @@ class IOSHelper } } + private static function findDeviceUUIDWithFilters(filters:Array):String + { + var listDevicesOutput = System.runProcess("", "xcrun", + [ + "devicectl", "list", "devices", + "--hide-default-columns", "--columns", "Identifier", + "--filter", filters.join(" AND ") + ]); + var ready = false; + for (line in listDevicesOutput.split("\n")) + { + if (!ready) + { + ready = StringTools.startsWith(line, "----"); + continue; + } + return line; + } + return null; + } + private static function fallbackLaunch(project:HXProject, applicationPath:String):Void { var templatePaths = [ diff --git a/src/lime/ui/FileDialog.hx b/src/lime/ui/FileDialog.hx index c6eed0803..014c11b8b 100644 --- a/src/lime/ui/FileDialog.hx +++ b/src/lime/ui/FileDialog.hx @@ -14,6 +14,7 @@ import hl.Bytes as HLBytes; import hl.NativeArray; #end #if sys +import sys.FileSystem; import sys.io.File; #end #if (js && html5) @@ -98,6 +99,29 @@ class FileDialog { if (type == null) type = FileDialogType.OPEN; + #if sys + if (defaultPath != null && defaultPath.length > 0 + && FileSystem.exists(defaultPath) + && FileSystem.isDirectory(defaultPath)) + { + // if the default path is a directory, and the default path doesn't + // end with a separator, tiny file dialogs may open its parent + // directory instead. + var lastChar = defaultPath.charAt(defaultPath.length - 1); + #if windows + if (lastChar != "/" && lastChar != "\\") + { + defaultPath = defaultPath + "\\"; + } + #else + if (lastChar != "/") + { + defaultPath = defaultPath + "/"; + } + #end + } + #end + #if desktop var worker = new ThreadPool(#if windows SINGLE_THREADED #end); @@ -148,6 +172,7 @@ class FileDialog var path = null; #if (!macro && lime_cffi) + trace(defaultPath); path = CFFI.stringValue(NativeCFFI.lime_file_dialog_open_file(title, filter, defaultPath)); #end diff --git a/src/lime/utils/Assets.hx b/src/lime/utils/Assets.hx index ec6de0cc0..87808483e 100644 --- a/src/lime/utils/Assets.hx +++ b/src/lime/utils/Assets.hx @@ -181,7 +181,23 @@ class Assets } /** - * Gets an instance of an embedded bitmap + * Gets an instance of an embedded bitmap. + * + * _Note:_ This method may behave differently, depending on the target + * platform. On targets that can quickly create a new image synchronously, + * every call to `Assets.getImage()` with the same ID will return a new + * `Image` instance. However, on other targets where creating images + * synchronously is unacceptably slow, or where images may not be created + * synchronously and must be created asynchronously, every call to + * `Assets.getImage()` with the same ID may return a single, shared `Image` + * instance. + * + * With that in mind, modifying or disposing the contents of the `Image` + * returned by `Assets.getImage()` may affect the results of future calls to + * Assets.getImage()` on some targets. To access an `Image` instance that + * may be modified without affecting future calls to `Assets.getImage()`, + * call the `Image` instance's `clone()` method to manually create a copy. + * * @usage var bitmap = new Bitmap(Assets.getBitmapData("image.jpg")); * @param id The ID or asset path for the bitmap * @param useCache (Optional) Whether to use BitmapData from the cache(Default: true) diff --git a/templates/android/template/app/src/main/java/org/haxe/lime/GameActivity.java b/templates/android/template/app/src/main/java/org/haxe/lime/GameActivity.java index 93128758f..ef081f520 100644 --- a/templates/android/template/app/src/main/java/org/haxe/lime/GameActivity.java +++ b/templates/android/template/app/src/main/java/org/haxe/lime/GameActivity.java @@ -9,6 +9,7 @@ import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Handler; +import android.os.Looper; import android.os.VibrationEffect; import android.os.Vibrator; import android.view.DisplayCutout; @@ -202,7 +203,7 @@ public class GameActivity extends SDLActivity { } - handler = new Handler (); + handler = new Handler (Looper.getMainLooper ()); Extension.assetManager = assetManager; Extension.callbackHandler = handler; diff --git a/tools/CommandLineTools.hx b/tools/CommandLineTools.hx index e3cb7b447..ea960923c 100644 --- a/tools/CommandLineTools.hx +++ b/tools/CommandLineTools.hx @@ -1825,6 +1825,13 @@ class CommandLineTools args.push("-notoolscheck"); + var projectDirectory = Path.directory(projectFile); + var localRepository = Path.combine(projectDirectory, ".haxelib"); + if (FileSystem.exists(localRepository) && FileSystem.isDirectory(localRepository) && StringTools.startsWith(path, localRepository)) + { + args.push("-nolocalrepocheck"); + } + Sys.setCwd(path); var args = [Path.combine(path, "run.n")].concat(args); args.push(workingDirectory);