migrating to the latest JUCE version
This commit is contained in:
@ -2,7 +2,7 @@
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
@ -2,7 +2,7 @@
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
@ -2,7 +2,7 @@
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
@ -2,7 +2,7 @@
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
@ -2,7 +2,7 @@
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
@ -1,318 +1,290 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#undef T
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_MAC || JUCE_IOS
|
||||
|
||||
#if JUCE_IOS
|
||||
#if JUCE_MODULE_AVAILABLE_juce_opengl && defined (__IPHONE_12_0) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_12_0
|
||||
#define GLES_SILENCE_DEPRECATION 1
|
||||
#endif
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <CoreData/CoreData.h>
|
||||
#import <MobileCoreServices/MobileCoreServices.h>
|
||||
#include <sys/fcntl.h>
|
||||
#else
|
||||
#if JUCE_MODULE_AVAILABLE_juce_opengl && defined (MAC_OS_X_VERSION_10_14) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14
|
||||
#define GL_SILENCE_DEPRECATION 1
|
||||
#endif
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#if (! defined MAC_OS_X_VERSION_10_12) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12
|
||||
#define NSEventModifierFlagCommand NSCommandKeyMask
|
||||
#define NSEventModifierFlagControl NSControlKeyMask
|
||||
#define NSEventModifierFlagHelp NSHelpKeyMask
|
||||
#define NSEventModifierFlagNumericPad NSNumericPadKeyMask
|
||||
#define NSEventModifierFlagOption NSAlternateKeyMask
|
||||
#define NSEventModifierFlagShift NSShiftKeyMask
|
||||
#define NSCompositingOperationSourceOver NSCompositeSourceOver
|
||||
#define NSEventMaskApplicationDefined NSApplicationDefinedMask
|
||||
#define NSEventTypeApplicationDefined NSApplicationDefined
|
||||
#define NSEventTypeCursorUpdate NSCursorUpdate
|
||||
#define NSEventTypeMouseMoved NSMouseMoved
|
||||
#define NSEventTypeLeftMouseDown NSLeftMouseDown
|
||||
#define NSEventTypeRightMouseDown NSRightMouseDown
|
||||
#define NSEventTypeOtherMouseDown NSOtherMouseDown
|
||||
#define NSEventTypeLeftMouseUp NSLeftMouseUp
|
||||
#define NSEventTypeRightMouseUp NSRightMouseUp
|
||||
#define NSEventTypeOtherMouseUp NSOtherMouseUp
|
||||
#define NSEventTypeLeftMouseDragged NSLeftMouseDragged
|
||||
#define NSEventTypeRightMouseDragged NSRightMouseDragged
|
||||
#define NSEventTypeOtherMouseDragged NSOtherMouseDragged
|
||||
#define NSEventTypeScrollWheel NSScrollWheel
|
||||
#define NSEventTypeKeyDown NSKeyDown
|
||||
#define NSEventTypeKeyUp NSKeyUp
|
||||
#define NSEventTypeFlagsChanged NSFlagsChanged
|
||||
#define NSEventMaskAny NSAnyEventMask
|
||||
#define NSWindowStyleMaskBorderless NSBorderlessWindowMask
|
||||
#define NSWindowStyleMaskClosable NSClosableWindowMask
|
||||
#define NSWindowStyleMaskFullScreen NSFullScreenWindowMask
|
||||
#define NSWindowStyleMaskMiniaturizable NSMiniaturizableWindowMask
|
||||
#define NSWindowStyleMaskResizable NSResizableWindowMask
|
||||
#define NSWindowStyleMaskTitled NSTitledWindowMask
|
||||
#define NSAlertStyleCritical NSCriticalAlertStyle
|
||||
#define NSControlSizeRegular NSRegularControlSize
|
||||
#define NSEventTypeMouseEntered NSMouseEntered
|
||||
#define NSEventTypeMouseExited NSMouseExited
|
||||
#define NSAlertStyleInformational NSInformationalAlertStyle
|
||||
#define NSEventTypeTabletPoint NSTabletPoint
|
||||
#define NSEventTypeTabletProximity NSTabletProximity
|
||||
#define NSEventTypeFlagsChanged NSFlagsChanged
|
||||
#define NSEventTypeAppKitDefined NSAppKitDefined
|
||||
#define NSEventTypeSystemDefined NSSystemDefined
|
||||
#define NSEventTypeApplicationDefined NSApplicationDefined
|
||||
#define NSEventTypePeriodic NSPeriodic
|
||||
#define NSEventTypeSmartMagnify NSEventTypeSmartMagnify
|
||||
#endif
|
||||
#import <CoreAudio/HostTime.h>
|
||||
#include <sys/dir.h>
|
||||
#endif
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/mman.h>
|
||||
#include <fnmatch.h>
|
||||
#include <utime.h>
|
||||
#include <dlfcn.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <mach/mach_time.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#include <objc/runtime.h>
|
||||
#include <objc/objc.h>
|
||||
#include <objc/message.h>
|
||||
#include <poll.h>
|
||||
|
||||
//==============================================================================
|
||||
#elif JUCE_WINDOWS
|
||||
#if JUCE_MSVC
|
||||
#ifndef _CPPRTTI
|
||||
#error "You're compiling without RTTI enabled! This is needed for a lot of JUCE classes, please update your compiler settings!"
|
||||
#endif
|
||||
|
||||
#ifndef _CPPUNWIND
|
||||
#error "You're compiling without exceptions enabled! This is needed for a lot of JUCE classes, please update your compiler settings!"
|
||||
#endif
|
||||
|
||||
#pragma warning (push, 0) // disable all warnings whilst including system headers
|
||||
#endif
|
||||
|
||||
#define NOMINMAX
|
||||
|
||||
#define _WINSOCK_DEPRECATED_NO_WARNINGS 1
|
||||
#define STRICT 1
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#if JUCE_MINGW
|
||||
#define _WIN32_WINNT 0x0600
|
||||
#else
|
||||
#define _WIN32_WINNT 0x0602
|
||||
#endif
|
||||
#define _UNICODE 1
|
||||
#define UNICODE 1
|
||||
#ifndef _WIN32_IE
|
||||
#define _WIN32_IE 0x0501
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
#include <tchar.h>
|
||||
#include <stddef.h>
|
||||
#include <ctime>
|
||||
#include <wininet.h>
|
||||
#include <nb30.h>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <iphlpapi.h>
|
||||
#include <mapi.h>
|
||||
#include <float.h>
|
||||
#include <process.h>
|
||||
#include <shlobj.h>
|
||||
#include <shlwapi.h>
|
||||
#include <mmsystem.h>
|
||||
#include <winioctl.h>
|
||||
|
||||
#if JUCE_MINGW
|
||||
#include <basetyps.h>
|
||||
#include <sys/time.h>
|
||||
#ifndef alloca
|
||||
#define alloca __builtin_alloca
|
||||
#endif
|
||||
#else
|
||||
#include <crtdbg.h>
|
||||
#include <comutil.h>
|
||||
#endif
|
||||
|
||||
#ifndef S_FALSE
|
||||
#define S_FALSE (1) // (apparently some obscure win32 dev environments don't define this)
|
||||
#endif
|
||||
|
||||
#undef PACKED
|
||||
|
||||
#if JUCE_MSVC
|
||||
#pragma warning (pop)
|
||||
#pragma warning (4: 4511 4512 4100)
|
||||
#endif
|
||||
|
||||
#if ! JUCE_MINGW && ! JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES
|
||||
#pragma comment (lib, "kernel32.lib")
|
||||
#pragma comment (lib, "user32.lib")
|
||||
#pragma comment (lib, "wininet.lib")
|
||||
#pragma comment (lib, "advapi32.lib")
|
||||
#pragma comment (lib, "ws2_32.lib")
|
||||
#pragma comment (lib, "version.lib")
|
||||
#pragma comment (lib, "shlwapi.lib")
|
||||
#pragma comment (lib, "winmm.lib")
|
||||
|
||||
#ifdef _NATIVE_WCHAR_T_DEFINED
|
||||
#ifdef _DEBUG
|
||||
#pragma comment (lib, "comsuppwd.lib")
|
||||
#else
|
||||
#pragma comment (lib, "comsuppw.lib")
|
||||
#endif
|
||||
#else
|
||||
#ifdef _DEBUG
|
||||
#pragma comment (lib, "comsuppd.lib")
|
||||
#else
|
||||
#pragma comment (lib, "comsupp.lib")
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Used with DynamicLibrary to simplify importing functions from a win32 DLL.
|
||||
|
||||
dll: the DynamicLibrary object
|
||||
functionName: function to import
|
||||
localFunctionName: name you want to use to actually call it (must be different)
|
||||
returnType: the return type
|
||||
params: list of params (bracketed)
|
||||
*/
|
||||
#define JUCE_LOAD_WINAPI_FUNCTION(dll, functionName, localFunctionName, returnType, params) \
|
||||
typedef returnType (WINAPI *type##localFunctionName) params; \
|
||||
type##localFunctionName localFunctionName = (type##localFunctionName) dll.getFunction (#functionName);
|
||||
|
||||
//==============================================================================
|
||||
#elif JUCE_LINUX
|
||||
#include <arpa/inet.h>
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <fnmatch.h>
|
||||
#include <net/if.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <pthread.h>
|
||||
#include <pwd.h>
|
||||
#include <sched.h>
|
||||
#include <signal.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/dir.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/sysinfo.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/vfs.h>
|
||||
#include <sys/wait.h>
|
||||
#include <utime.h>
|
||||
#include <poll.h>
|
||||
|
||||
//==============================================================================
|
||||
#elif JUCE_BSD
|
||||
#include <arpa/inet.h>
|
||||
#include <dirent.h>
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <fnmatch.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <langinfo.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <pthread.h>
|
||||
#include <pwd.h>
|
||||
#include <sched.h>
|
||||
#include <signal.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/user.h>
|
||||
#include <sys/wait.h>
|
||||
#include <utime.h>
|
||||
#include <poll.h>
|
||||
|
||||
//==============================================================================
|
||||
#elif JUCE_ANDROID
|
||||
#include <jni.h>
|
||||
#include <pthread.h>
|
||||
#include <sched.h>
|
||||
#include <sys/time.h>
|
||||
#include <utime.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <dlfcn.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statfs.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/sysinfo.h>
|
||||
#include <sys/mman.h>
|
||||
#include <pwd.h>
|
||||
#include <dirent.h>
|
||||
#include <fnmatch.h>
|
||||
#include <sys/wait.h>
|
||||
#include <android/api-level.h>
|
||||
#include <poll.h>
|
||||
|
||||
// If you are getting include errors here, then you to re-build the Projucer
|
||||
// and re-save your .jucer file.
|
||||
#include <cpu-features.h>
|
||||
#endif
|
||||
|
||||
// Need to clear various moronic redefinitions made by system headers..
|
||||
#undef max
|
||||
#undef min
|
||||
#undef direct
|
||||
#undef check
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#undef T
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_MAC || JUCE_IOS
|
||||
|
||||
#if JUCE_IOS
|
||||
#if JUCE_MODULE_AVAILABLE_juce_opengl
|
||||
#define GLES_SILENCE_DEPRECATION 1
|
||||
#endif
|
||||
|
||||
#define Component CarbonDummyCompName
|
||||
#import <Foundation/Foundation.h>
|
||||
#undef Component
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <CoreData/CoreData.h>
|
||||
#import <MobileCoreServices/MobileCoreServices.h>
|
||||
#include <sys/fcntl.h>
|
||||
#else
|
||||
#if JUCE_MODULE_AVAILABLE_juce_opengl
|
||||
#define GL_SILENCE_DEPRECATION 1
|
||||
#endif
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <CoreAudio/HostTime.h>
|
||||
#include <sys/dir.h>
|
||||
#endif
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/mman.h>
|
||||
#include <fnmatch.h>
|
||||
#include <utime.h>
|
||||
#include <dlfcn.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <mach/mach_time.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#include <objc/runtime.h>
|
||||
#include <objc/objc.h>
|
||||
#include <objc/message.h>
|
||||
#include <poll.h>
|
||||
|
||||
//==============================================================================
|
||||
#elif JUCE_WINDOWS
|
||||
#if JUCE_MSVC
|
||||
#ifndef _CPPRTTI
|
||||
#error "You're compiling without RTTI enabled! This is needed for a lot of JUCE classes, please update your compiler settings!"
|
||||
#endif
|
||||
|
||||
#ifndef _CPPUNWIND
|
||||
#error "You're compiling without exceptions enabled! This is needed for a lot of JUCE classes, please update your compiler settings!"
|
||||
#endif
|
||||
|
||||
#pragma warning (push, 0) // disable all warnings whilst including system headers
|
||||
#endif
|
||||
|
||||
#define NOMINMAX
|
||||
|
||||
#define _WINSOCK_DEPRECATED_NO_WARNINGS 1
|
||||
#define STRICT 1
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#if JUCE_MINGW
|
||||
#if ! defined (_WIN32_WINNT)
|
||||
#define _WIN32_WINNT 0x0600
|
||||
#endif
|
||||
#else
|
||||
#define _WIN32_WINNT 0x0602
|
||||
#endif
|
||||
#define _UNICODE 1
|
||||
#define UNICODE 1
|
||||
#ifndef _WIN32_IE
|
||||
#define _WIN32_IE 0x0501
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
#include <tchar.h>
|
||||
#include <stddef.h>
|
||||
#include <ctime>
|
||||
#include <wininet.h>
|
||||
#include <nb30.h>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <iphlpapi.h>
|
||||
#include <accctrl.h>
|
||||
#include <aclapi.h>
|
||||
|
||||
#if ! JUCE_CXX17_IS_AVAILABLE
|
||||
#pragma push_macro ("WIN_NOEXCEPT")
|
||||
#define WIN_NOEXCEPT
|
||||
#endif
|
||||
|
||||
#include <mapi.h>
|
||||
|
||||
#if ! JUCE_CXX17_IS_AVAILABLE
|
||||
#pragma pop_macro ("WIN_NOEXCEPT")
|
||||
#endif
|
||||
|
||||
#include <float.h>
|
||||
#include <process.h>
|
||||
#include <shlobj.h>
|
||||
#include <shlwapi.h>
|
||||
#include <mmsystem.h>
|
||||
#include <winioctl.h>
|
||||
|
||||
#if JUCE_MINGW
|
||||
#include <basetyps.h>
|
||||
#include <sys/time.h>
|
||||
#ifndef alloca
|
||||
#define alloca __builtin_alloca
|
||||
#endif
|
||||
#else
|
||||
#include <crtdbg.h>
|
||||
#include <comutil.h>
|
||||
#endif
|
||||
|
||||
#ifndef S_FALSE
|
||||
#define S_FALSE (1) // (apparently some obscure win32 dev environments don't define this)
|
||||
#endif
|
||||
|
||||
#undef PACKED
|
||||
|
||||
#if JUCE_MSVC
|
||||
#pragma warning (pop)
|
||||
#pragma warning (4: 4511 4512 4100)
|
||||
#endif
|
||||
|
||||
#if ! JUCE_MINGW && ! JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES
|
||||
#pragma comment (lib, "kernel32.lib")
|
||||
#pragma comment (lib, "user32.lib")
|
||||
#pragma comment (lib, "wininet.lib")
|
||||
#pragma comment (lib, "advapi32.lib")
|
||||
#pragma comment (lib, "ws2_32.lib")
|
||||
#pragma comment (lib, "version.lib")
|
||||
#pragma comment (lib, "shlwapi.lib")
|
||||
#pragma comment (lib, "winmm.lib")
|
||||
|
||||
#ifdef _NATIVE_WCHAR_T_DEFINED
|
||||
#ifdef _DEBUG
|
||||
#pragma comment (lib, "comsuppwd.lib")
|
||||
#else
|
||||
#pragma comment (lib, "comsuppw.lib")
|
||||
#endif
|
||||
#else
|
||||
#ifdef _DEBUG
|
||||
#pragma comment (lib, "comsuppd.lib")
|
||||
#else
|
||||
#pragma comment (lib, "comsupp.lib")
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Used with DynamicLibrary to simplify importing functions from a win32 DLL.
|
||||
|
||||
dll: the DynamicLibrary object
|
||||
functionName: function to import
|
||||
localFunctionName: name you want to use to actually call it (must be different)
|
||||
returnType: the return type
|
||||
params: list of params (bracketed)
|
||||
*/
|
||||
#define JUCE_LOAD_WINAPI_FUNCTION(dll, functionName, localFunctionName, returnType, params) \
|
||||
typedef returnType (WINAPI *type##localFunctionName) params; \
|
||||
type##localFunctionName localFunctionName = (type##localFunctionName) dll.getFunction (#functionName);
|
||||
|
||||
//==============================================================================
|
||||
#elif JUCE_LINUX
|
||||
#include <arpa/inet.h>
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <fnmatch.h>
|
||||
#include <net/if.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <pthread.h>
|
||||
#include <pwd.h>
|
||||
#include <sched.h>
|
||||
#include <signal.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/dir.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/sysinfo.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/vfs.h>
|
||||
#include <sys/wait.h>
|
||||
#include <utime.h>
|
||||
#include <poll.h>
|
||||
|
||||
//==============================================================================
|
||||
#elif JUCE_BSD
|
||||
#include <arpa/inet.h>
|
||||
#include <dirent.h>
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <fnmatch.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <langinfo.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <pthread.h>
|
||||
#include <pwd.h>
|
||||
#include <sched.h>
|
||||
#include <signal.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/user.h>
|
||||
#include <sys/wait.h>
|
||||
#include <utime.h>
|
||||
#include <poll.h>
|
||||
|
||||
//==============================================================================
|
||||
#elif JUCE_ANDROID
|
||||
#include <jni.h>
|
||||
#include <pthread.h>
|
||||
#include <sched.h>
|
||||
#include <sys/time.h>
|
||||
#include <utime.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <dlfcn.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statfs.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/sysinfo.h>
|
||||
#include <sys/mman.h>
|
||||
#include <pwd.h>
|
||||
#include <dirent.h>
|
||||
#include <fnmatch.h>
|
||||
#include <sys/wait.h>
|
||||
#include <android/api-level.h>
|
||||
#include <poll.h>
|
||||
|
||||
// If you are getting include errors here, then you to re-build the Projucer
|
||||
// and re-save your .jucer file.
|
||||
#include <cpu-features.h>
|
||||
#endif
|
||||
|
||||
// Need to clear various moronic redefinitions made by system headers..
|
||||
#undef max
|
||||
#undef min
|
||||
#undef direct
|
||||
#undef check
|
||||
|
1080
deps/juce/modules/juce_core/native/juce_android_AndroidDocument.cpp
vendored
Normal file
1080
deps/juce/modules/juce_core/native/juce_android_AndroidDocument.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,44 +1,44 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
void Logger::outputDebugString (const String& text)
|
||||
{
|
||||
char* data = text.toUTF8().getAddress();
|
||||
const size_t length = CharPointer_UTF8::getBytesRequiredFor (text.getCharPointer());
|
||||
const size_t chunkSize = 1023;
|
||||
|
||||
size_t position = 0;
|
||||
size_t numToRead = jmin (chunkSize, length);
|
||||
|
||||
while (numToRead > 0)
|
||||
{
|
||||
__android_log_print (ANDROID_LOG_INFO, "JUCE", "%s", data + position);
|
||||
|
||||
position += numToRead;
|
||||
numToRead = jmin (chunkSize, length - position);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
void Logger::outputDebugString (const String& text)
|
||||
{
|
||||
char* data = text.toUTF8().getAddress();
|
||||
const size_t length = CharPointer_UTF8::getBytesRequiredFor (text.getCharPointer());
|
||||
const size_t chunkSize = 1023;
|
||||
|
||||
size_t position = 0;
|
||||
size_t numToRead = jmin (chunkSize, length);
|
||||
|
||||
while (numToRead > 0)
|
||||
{
|
||||
__android_log_print (ANDROID_LOG_INFO, "JUCE", "%s", data + position);
|
||||
|
||||
position += numToRead;
|
||||
numToRead = jmin (chunkSize, length - position);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,261 +1,261 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
static String jucePermissionToAndroidPermission (RuntimePermissions::PermissionID permission)
|
||||
{
|
||||
switch (permission)
|
||||
{
|
||||
case RuntimePermissions::recordAudio: return "android.permission.RECORD_AUDIO";
|
||||
case RuntimePermissions::bluetoothMidi: return "android.permission.ACCESS_FINE_LOCATION";
|
||||
case RuntimePermissions::readExternalStorage: return "android.permission.READ_EXTERNAL_STORAGE";
|
||||
case RuntimePermissions::writeExternalStorage: return "android.permission.WRITE_EXTERNAL_STORAGE";
|
||||
case RuntimePermissions::camera: return "android.permission.CAMERA";
|
||||
}
|
||||
|
||||
// invalid permission
|
||||
jassertfalse;
|
||||
return {};
|
||||
}
|
||||
|
||||
static RuntimePermissions::PermissionID androidPermissionToJucePermission (const String& permission)
|
||||
{
|
||||
if (permission == "android.permission.RECORD_AUDIO") return RuntimePermissions::recordAudio;
|
||||
else if (permission == "android.permission.ACCESS_FINE_LOCATION") return RuntimePermissions::bluetoothMidi;
|
||||
else if (permission == "android.permission.READ_EXTERNAL_STORAGE") return RuntimePermissions::readExternalStorage;
|
||||
else if (permission == "android.permission.WRITE_EXTERNAL_STORAGE") return RuntimePermissions::writeExternalStorage;
|
||||
else if (permission == "android.permission.CAMERA") return RuntimePermissions::camera;
|
||||
|
||||
return static_cast<RuntimePermissions::PermissionID> (-1);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
struct PermissionsRequest
|
||||
{
|
||||
PermissionsRequest() {}
|
||||
|
||||
// using "= default" on the following method triggers an internal compiler error
|
||||
// in Android NDK 17
|
||||
PermissionsRequest (const PermissionsRequest& o)
|
||||
: callback (o.callback), permission (o.permission)
|
||||
{}
|
||||
|
||||
PermissionsRequest (PermissionsRequest&& o)
|
||||
: callback (std::move (o.callback)), permission (o.permission)
|
||||
{
|
||||
o.permission = static_cast<RuntimePermissions::PermissionID> (-1);
|
||||
}
|
||||
|
||||
PermissionsRequest (RuntimePermissions::Callback && callbackToUse,
|
||||
RuntimePermissions::PermissionID permissionToRequest)
|
||||
: callback (std::move (callbackToUse)), permission (permissionToRequest)
|
||||
{}
|
||||
|
||||
PermissionsRequest& operator= (const PermissionsRequest & o)
|
||||
{
|
||||
callback = o.callback;
|
||||
permission = o.permission;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PermissionsRequest& operator= (PermissionsRequest && o)
|
||||
{
|
||||
callback = std::move (o.callback);
|
||||
permission = o.permission;
|
||||
return *this;
|
||||
}
|
||||
|
||||
RuntimePermissions::Callback callback;
|
||||
RuntimePermissions::PermissionID permission;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
struct PermissionsOverlay : FragmentOverlay
|
||||
{
|
||||
PermissionsOverlay (CriticalSection& cs) : overlayGuard (cs) {}
|
||||
~PermissionsOverlay() override = default;
|
||||
|
||||
struct PermissionResult
|
||||
{
|
||||
PermissionsRequest request;
|
||||
bool granted;
|
||||
};
|
||||
|
||||
void onStart() override { onRequestPermissionsResult (0, {}, {}); }
|
||||
|
||||
void onRequestPermissionsResult (int /*requestCode*/,
|
||||
const StringArray& permissions,
|
||||
const Array<int>& grantResults) override
|
||||
{
|
||||
std::vector<PermissionResult> results;
|
||||
|
||||
{
|
||||
ScopedLock lock (overlayGuard);
|
||||
|
||||
for (auto it = requests.begin(); it != requests.end();)
|
||||
{
|
||||
auto& request = *it;
|
||||
|
||||
if (RuntimePermissions::isGranted (request.permission))
|
||||
{
|
||||
results.push_back ({std::move (request), true});
|
||||
it = requests.erase (it);
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
auto n = permissions.size();
|
||||
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
auto permission = androidPermissionToJucePermission (permissions[i]);
|
||||
auto granted = (grantResults.getReference (i) == 0);
|
||||
|
||||
for (auto it = requests.begin(); it != requests.end();)
|
||||
{
|
||||
auto& request = *it;
|
||||
|
||||
if (request.permission == permission)
|
||||
{
|
||||
results.push_back ({std::move (request), granted});
|
||||
it = requests.erase (it);
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& result : results)
|
||||
if (result.request.callback)
|
||||
result.request.callback (result.granted);
|
||||
|
||||
{
|
||||
auto* env = getEnv();
|
||||
ScopedLock lock (overlayGuard);
|
||||
|
||||
if (requests.size() > 0)
|
||||
{
|
||||
auto &request = requests.front();
|
||||
|
||||
StringArray permissionsArray{
|
||||
jucePermissionToAndroidPermission (request.permission)};
|
||||
auto jPermissionsArray = juceStringArrayToJava (permissionsArray);
|
||||
|
||||
|
||||
auto requestPermissionsMethodID
|
||||
= env->GetMethodID(AndroidFragment, "requestPermissions", "([Ljava/lang/String;I)V");
|
||||
|
||||
// this code should only be reached for SDKs >= 23, so this method should be
|
||||
// be available
|
||||
jassert(requestPermissionsMethodID != nullptr);
|
||||
|
||||
env->CallVoidMethod (getNativeHandle(), requestPermissionsMethodID, jPermissionsArray.get (), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
getSingleton() = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static std::unique_ptr<PermissionsOverlay>& getSingleton()
|
||||
{
|
||||
static std::unique_ptr<PermissionsOverlay> instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
CriticalSection& overlayGuard;
|
||||
std::vector<PermissionsRequest> requests;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
void RuntimePermissions::request (PermissionID permission, Callback callback)
|
||||
{
|
||||
auto requestedPermission = jucePermissionToAndroidPermission (permission);
|
||||
|
||||
if (! isPermissionDeclaredInManifest (requestedPermission))
|
||||
{
|
||||
// Error! If you want to be able to request this runtime permission, you
|
||||
// also need to declare it in your app's manifest. You can do so via
|
||||
// the Projucer. Otherwise this can't work.
|
||||
jassertfalse;
|
||||
|
||||
callback (false);
|
||||
return;
|
||||
}
|
||||
|
||||
auto alreadyGranted = isGranted (permission);
|
||||
|
||||
if (alreadyGranted || getAndroidSDKVersion() < 23)
|
||||
{
|
||||
callback (alreadyGranted);
|
||||
return;
|
||||
}
|
||||
|
||||
PermissionsRequest request (std::move (callback), permission);
|
||||
|
||||
static CriticalSection overlayGuard;
|
||||
ScopedLock lock (overlayGuard);
|
||||
|
||||
std::unique_ptr<PermissionsOverlay>& overlay = PermissionsOverlay::getSingleton();
|
||||
|
||||
bool alreadyOpen = true;
|
||||
|
||||
if (overlay == nullptr)
|
||||
{
|
||||
overlay.reset (new PermissionsOverlay (overlayGuard));
|
||||
alreadyOpen = false;
|
||||
}
|
||||
|
||||
overlay->requests.push_back (std::move (request));
|
||||
|
||||
if (! alreadyOpen)
|
||||
overlay->open();
|
||||
}
|
||||
|
||||
bool RuntimePermissions::isRequired (PermissionID /*permission*/)
|
||||
{
|
||||
return getAndroidSDKVersion() >= 23;
|
||||
}
|
||||
|
||||
bool RuntimePermissions::isGranted (PermissionID permission)
|
||||
{
|
||||
auto* env = getEnv();
|
||||
|
||||
auto requestedPermission = jucePermissionToAndroidPermission (permission);
|
||||
int result = env->CallIntMethod (getAppContext().get(), AndroidContext.checkCallingOrSelfPermission,
|
||||
javaString (requestedPermission).get());
|
||||
|
||||
|
||||
return result == 0 /* PERMISSION_GRANTED */;
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
static String jucePermissionToAndroidPermission (RuntimePermissions::PermissionID permission)
|
||||
{
|
||||
switch (permission)
|
||||
{
|
||||
case RuntimePermissions::recordAudio: return "android.permission.RECORD_AUDIO";
|
||||
case RuntimePermissions::bluetoothMidi: return "android.permission.ACCESS_FINE_LOCATION";
|
||||
case RuntimePermissions::readExternalStorage: return "android.permission.READ_EXTERNAL_STORAGE";
|
||||
case RuntimePermissions::writeExternalStorage: return "android.permission.WRITE_EXTERNAL_STORAGE";
|
||||
case RuntimePermissions::camera: return "android.permission.CAMERA";
|
||||
}
|
||||
|
||||
// invalid permission
|
||||
jassertfalse;
|
||||
return {};
|
||||
}
|
||||
|
||||
static RuntimePermissions::PermissionID androidPermissionToJucePermission (const String& permission)
|
||||
{
|
||||
if (permission == "android.permission.RECORD_AUDIO") return RuntimePermissions::recordAudio;
|
||||
else if (permission == "android.permission.ACCESS_FINE_LOCATION") return RuntimePermissions::bluetoothMidi;
|
||||
else if (permission == "android.permission.READ_EXTERNAL_STORAGE") return RuntimePermissions::readExternalStorage;
|
||||
else if (permission == "android.permission.WRITE_EXTERNAL_STORAGE") return RuntimePermissions::writeExternalStorage;
|
||||
else if (permission == "android.permission.CAMERA") return RuntimePermissions::camera;
|
||||
|
||||
return static_cast<RuntimePermissions::PermissionID> (-1);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
struct PermissionsRequest
|
||||
{
|
||||
PermissionsRequest() {}
|
||||
|
||||
// using "= default" on the following method triggers an internal compiler error
|
||||
// in Android NDK 17
|
||||
PermissionsRequest (const PermissionsRequest& o)
|
||||
: callback (o.callback), permission (o.permission)
|
||||
{}
|
||||
|
||||
PermissionsRequest (PermissionsRequest&& o)
|
||||
: callback (std::move (o.callback)), permission (o.permission)
|
||||
{
|
||||
o.permission = static_cast<RuntimePermissions::PermissionID> (-1);
|
||||
}
|
||||
|
||||
PermissionsRequest (RuntimePermissions::Callback && callbackToUse,
|
||||
RuntimePermissions::PermissionID permissionToRequest)
|
||||
: callback (std::move (callbackToUse)), permission (permissionToRequest)
|
||||
{}
|
||||
|
||||
PermissionsRequest& operator= (const PermissionsRequest & o)
|
||||
{
|
||||
callback = o.callback;
|
||||
permission = o.permission;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PermissionsRequest& operator= (PermissionsRequest && o)
|
||||
{
|
||||
callback = std::move (o.callback);
|
||||
permission = o.permission;
|
||||
return *this;
|
||||
}
|
||||
|
||||
RuntimePermissions::Callback callback;
|
||||
RuntimePermissions::PermissionID permission;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
struct PermissionsOverlay : FragmentOverlay
|
||||
{
|
||||
PermissionsOverlay (CriticalSection& cs) : overlayGuard (cs) {}
|
||||
~PermissionsOverlay() override = default;
|
||||
|
||||
struct PermissionResult
|
||||
{
|
||||
PermissionsRequest request;
|
||||
bool granted;
|
||||
};
|
||||
|
||||
void onStart() override { onRequestPermissionsResult (0, {}, {}); }
|
||||
|
||||
void onRequestPermissionsResult (int /*requestCode*/,
|
||||
const StringArray& permissions,
|
||||
const Array<int>& grantResults) override
|
||||
{
|
||||
std::vector<PermissionResult> results;
|
||||
|
||||
{
|
||||
ScopedLock lock (overlayGuard);
|
||||
|
||||
for (auto it = requests.begin(); it != requests.end();)
|
||||
{
|
||||
auto& request = *it;
|
||||
|
||||
if (RuntimePermissions::isGranted (request.permission))
|
||||
{
|
||||
results.push_back ({std::move (request), true});
|
||||
it = requests.erase (it);
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
auto n = permissions.size();
|
||||
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
auto permission = androidPermissionToJucePermission (permissions[i]);
|
||||
auto granted = (grantResults.getReference (i) == 0);
|
||||
|
||||
for (auto it = requests.begin(); it != requests.end();)
|
||||
{
|
||||
auto& request = *it;
|
||||
|
||||
if (request.permission == permission)
|
||||
{
|
||||
results.push_back ({std::move (request), granted});
|
||||
it = requests.erase (it);
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& result : results)
|
||||
if (result.request.callback)
|
||||
result.request.callback (result.granted);
|
||||
|
||||
{
|
||||
auto* env = getEnv();
|
||||
ScopedLock lock (overlayGuard);
|
||||
|
||||
if (requests.size() > 0)
|
||||
{
|
||||
auto &request = requests.front();
|
||||
|
||||
StringArray permissionsArray{
|
||||
jucePermissionToAndroidPermission (request.permission)};
|
||||
auto jPermissionsArray = juceStringArrayToJava (permissionsArray);
|
||||
|
||||
|
||||
auto requestPermissionsMethodID
|
||||
= env->GetMethodID(AndroidFragment, "requestPermissions", "([Ljava/lang/String;I)V");
|
||||
|
||||
// this code should only be reached for SDKs >= 23, so this method should be
|
||||
// be available
|
||||
jassert(requestPermissionsMethodID != nullptr);
|
||||
|
||||
env->CallVoidMethod (getNativeHandle(), requestPermissionsMethodID, jPermissionsArray.get (), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
getSingleton() = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static std::unique_ptr<PermissionsOverlay>& getSingleton()
|
||||
{
|
||||
static std::unique_ptr<PermissionsOverlay> instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
CriticalSection& overlayGuard;
|
||||
std::vector<PermissionsRequest> requests;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
void RuntimePermissions::request (PermissionID permission, Callback callback)
|
||||
{
|
||||
auto requestedPermission = jucePermissionToAndroidPermission (permission);
|
||||
|
||||
if (! isPermissionDeclaredInManifest (requestedPermission))
|
||||
{
|
||||
// Error! If you want to be able to request this runtime permission, you
|
||||
// also need to declare it in your app's manifest. You can do so via
|
||||
// the Projucer. Otherwise this can't work.
|
||||
jassertfalse;
|
||||
|
||||
callback (false);
|
||||
return;
|
||||
}
|
||||
|
||||
auto alreadyGranted = isGranted (permission);
|
||||
|
||||
if (alreadyGranted || getAndroidSDKVersion() < 23)
|
||||
{
|
||||
callback (alreadyGranted);
|
||||
return;
|
||||
}
|
||||
|
||||
PermissionsRequest request (std::move (callback), permission);
|
||||
|
||||
static CriticalSection overlayGuard;
|
||||
ScopedLock lock (overlayGuard);
|
||||
|
||||
std::unique_ptr<PermissionsOverlay>& overlay = PermissionsOverlay::getSingleton();
|
||||
|
||||
bool alreadyOpen = true;
|
||||
|
||||
if (overlay == nullptr)
|
||||
{
|
||||
overlay.reset (new PermissionsOverlay (overlayGuard));
|
||||
alreadyOpen = false;
|
||||
}
|
||||
|
||||
overlay->requests.push_back (std::move (request));
|
||||
|
||||
if (! alreadyOpen)
|
||||
overlay->open();
|
||||
}
|
||||
|
||||
bool RuntimePermissions::isRequired (PermissionID /*permission*/)
|
||||
{
|
||||
return getAndroidSDKVersion() >= 23;
|
||||
}
|
||||
|
||||
bool RuntimePermissions::isGranted (PermissionID permission)
|
||||
{
|
||||
auto* env = getEnv();
|
||||
|
||||
auto requestedPermission = jucePermissionToAndroidPermission (permission);
|
||||
int result = env->CallIntMethod (getAppContext().get(), AndroidContext.checkCallingOrSelfPermission,
|
||||
javaString (requestedPermission).get());
|
||||
|
||||
|
||||
return result == 0 /* PERMISSION_GRANTED */;
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
|
@ -1,241 +1,241 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
namespace AndroidStatsHelpers
|
||||
{
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
|
||||
STATICMETHOD (getProperty, "getProperty", "(Ljava/lang/String;)Ljava/lang/String;")
|
||||
|
||||
DECLARE_JNI_CLASS (SystemClass, "java/lang/System")
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
|
||||
STATICMETHOD (getDefault, "getDefault", "()Ljava/util/Locale;") \
|
||||
METHOD (getCountry, "getCountry", "()Ljava/lang/String;") \
|
||||
METHOD (getLanguage, "getLanguage", "()Ljava/lang/String;")
|
||||
|
||||
DECLARE_JNI_CLASS (JavaLocale, "java/util/Locale")
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
static String getSystemProperty (const String& name)
|
||||
{
|
||||
return juceString (LocalRef<jstring> ((jstring) getEnv()->CallStaticObjectMethod (SystemClass,
|
||||
SystemClass.getProperty,
|
||||
javaString (name).get())));
|
||||
}
|
||||
|
||||
static String getLocaleValue (bool isRegion)
|
||||
{
|
||||
auto* env = getEnv();
|
||||
LocalRef<jobject> locale (env->CallStaticObjectMethod (JavaLocale, JavaLocale.getDefault));
|
||||
|
||||
auto stringResult = isRegion ? env->CallObjectMethod (locale.get(), JavaLocale.getCountry)
|
||||
: env->CallObjectMethod (locale.get(), JavaLocale.getLanguage);
|
||||
|
||||
return juceString (LocalRef<jstring> ((jstring) stringResult));
|
||||
}
|
||||
|
||||
static String getAndroidOsBuildValue (const char* fieldName)
|
||||
{
|
||||
return juceString (LocalRef<jstring> ((jstring) getEnv()->GetStaticObjectField (
|
||||
AndroidBuild, getEnv()->GetStaticFieldID (AndroidBuild, fieldName, "Ljava/lang/String;"))));
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
SystemStats::OperatingSystemType SystemStats::getOperatingSystemType()
|
||||
{
|
||||
return Android;
|
||||
}
|
||||
|
||||
String SystemStats::getOperatingSystemName()
|
||||
{
|
||||
return "Android " + AndroidStatsHelpers::getSystemProperty ("os.version");
|
||||
}
|
||||
|
||||
String SystemStats::getDeviceDescription()
|
||||
{
|
||||
return AndroidStatsHelpers::getAndroidOsBuildValue ("MODEL")
|
||||
+ "-" + AndroidStatsHelpers::getAndroidOsBuildValue ("SERIAL");
|
||||
}
|
||||
|
||||
String SystemStats::getDeviceManufacturer()
|
||||
{
|
||||
return AndroidStatsHelpers::getAndroidOsBuildValue ("MANUFACTURER");
|
||||
}
|
||||
|
||||
bool SystemStats::isOperatingSystem64Bit()
|
||||
{
|
||||
#if JUCE_64BIT
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
String SystemStats::getCpuVendor()
|
||||
{
|
||||
return AndroidStatsHelpers::getSystemProperty ("os.arch");
|
||||
}
|
||||
|
||||
String SystemStats::getCpuModel()
|
||||
{
|
||||
return readPosixConfigFileValue ("/proc/cpuinfo", "Hardware");
|
||||
}
|
||||
|
||||
int SystemStats::getCpuSpeedInMegahertz()
|
||||
{
|
||||
int maxFreqKHz = 0;
|
||||
|
||||
for (int i = 0; i < getNumCpus(); ++i)
|
||||
{
|
||||
int freqKHz = File ("/sys/devices/system/cpu/cpu" + String(i) + "/cpufreq/cpuinfo_max_freq")
|
||||
.loadFileAsString()
|
||||
.getIntValue();
|
||||
|
||||
maxFreqKHz = jmax (freqKHz, maxFreqKHz);
|
||||
}
|
||||
|
||||
return maxFreqKHz / 1000;
|
||||
}
|
||||
|
||||
int SystemStats::getMemorySizeInMegabytes()
|
||||
{
|
||||
#if __ANDROID_API__ >= 9
|
||||
struct sysinfo sysi;
|
||||
|
||||
if (sysinfo (&sysi) == 0)
|
||||
return static_cast<int> ((sysi.totalram * sysi.mem_unit) / (1024 * 1024));
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SystemStats::getPageSize()
|
||||
{
|
||||
return static_cast<int> (sysconf (_SC_PAGESIZE));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
String SystemStats::getLogonName()
|
||||
{
|
||||
if (const char* user = getenv ("USER"))
|
||||
return CharPointer_UTF8 (user);
|
||||
|
||||
if (struct passwd* const pw = getpwuid (getuid()))
|
||||
return CharPointer_UTF8 (pw->pw_name);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
String SystemStats::getFullUserName()
|
||||
{
|
||||
return getLogonName();
|
||||
}
|
||||
|
||||
String SystemStats::getComputerName()
|
||||
{
|
||||
char name [256] = { 0 };
|
||||
if (gethostname (name, sizeof (name) - 1) == 0)
|
||||
return name;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
String SystemStats::getUserLanguage() { return AndroidStatsHelpers::getLocaleValue (false); }
|
||||
String SystemStats::getUserRegion() { return AndroidStatsHelpers::getLocaleValue (true); }
|
||||
String SystemStats::getDisplayLanguage() { return getUserLanguage() + "-" + getUserRegion(); }
|
||||
|
||||
//==============================================================================
|
||||
void CPUInformation::initialise() noexcept
|
||||
{
|
||||
numPhysicalCPUs = numLogicalCPUs = jmax ((int) 1, (int) android_getCpuCount());
|
||||
|
||||
auto cpuFamily = android_getCpuFamily();
|
||||
auto cpuFeatures = android_getCpuFeatures();
|
||||
|
||||
if (cpuFamily == ANDROID_CPU_FAMILY_X86 || cpuFamily == ANDROID_CPU_FAMILY_X86_64)
|
||||
{
|
||||
hasMMX = hasSSE = hasSSE2 = (cpuFamily == ANDROID_CPU_FAMILY_X86_64);
|
||||
|
||||
hasSSSE3 = ((cpuFeatures & ANDROID_CPU_X86_FEATURE_SSSE3) != 0);
|
||||
hasSSE41 = ((cpuFeatures & ANDROID_CPU_X86_FEATURE_SSE4_1) != 0);
|
||||
hasSSE42 = ((cpuFeatures & ANDROID_CPU_X86_FEATURE_SSE4_2) != 0);
|
||||
hasAVX = ((cpuFeatures & ANDROID_CPU_X86_FEATURE_AVX) != 0);
|
||||
hasAVX2 = ((cpuFeatures & ANDROID_CPU_X86_FEATURE_AVX2) != 0);
|
||||
|
||||
// Google does not distinguish between MMX, SSE, SSE2, SSE3 and SSSE3. So
|
||||
// I assume (and quick Google searches seem to confirm this) that there are
|
||||
// only devices out there that either support all of this or none of this.
|
||||
if (hasSSSE3)
|
||||
hasMMX = hasSSE = hasSSE2 = hasSSE3 = true;
|
||||
}
|
||||
else if (cpuFamily == ANDROID_CPU_FAMILY_ARM)
|
||||
{
|
||||
hasNeon = ((cpuFeatures & ANDROID_CPU_ARM_FEATURE_NEON) != 0);
|
||||
}
|
||||
else if (cpuFamily == ANDROID_CPU_FAMILY_ARM64)
|
||||
{
|
||||
// all arm 64-bit cpus have neon
|
||||
hasNeon = true;
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
uint32 juce_millisecondsSinceStartup() noexcept
|
||||
{
|
||||
timespec t;
|
||||
clock_gettime (CLOCK_MONOTONIC, &t);
|
||||
|
||||
return static_cast<uint32> (t.tv_sec) * 1000U + static_cast<uint32> (t.tv_nsec) / 1000000U;
|
||||
}
|
||||
|
||||
int64 Time::getHighResolutionTicks() noexcept
|
||||
{
|
||||
timespec t;
|
||||
clock_gettime (CLOCK_MONOTONIC, &t);
|
||||
|
||||
return (t.tv_sec * (int64) 1000000) + (t.tv_nsec / 1000);
|
||||
}
|
||||
|
||||
int64 Time::getHighResolutionTicksPerSecond() noexcept
|
||||
{
|
||||
return 1000000; // (microseconds)
|
||||
}
|
||||
|
||||
double Time::getMillisecondCounterHiRes() noexcept
|
||||
{
|
||||
return (double) getHighResolutionTicks() * 0.001;
|
||||
}
|
||||
|
||||
bool Time::setSystemTimeToThisTime() const
|
||||
{
|
||||
jassertfalse;
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
namespace AndroidStatsHelpers
|
||||
{
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
|
||||
STATICMETHOD (getProperty, "getProperty", "(Ljava/lang/String;)Ljava/lang/String;")
|
||||
|
||||
DECLARE_JNI_CLASS (SystemClass, "java/lang/System")
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
|
||||
STATICMETHOD (getDefault, "getDefault", "()Ljava/util/Locale;") \
|
||||
METHOD (getCountry, "getCountry", "()Ljava/lang/String;") \
|
||||
METHOD (getLanguage, "getLanguage", "()Ljava/lang/String;")
|
||||
|
||||
DECLARE_JNI_CLASS (JavaLocale, "java/util/Locale")
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
static String getSystemProperty (const String& name)
|
||||
{
|
||||
return juceString (LocalRef<jstring> ((jstring) getEnv()->CallStaticObjectMethod (SystemClass,
|
||||
SystemClass.getProperty,
|
||||
javaString (name).get())));
|
||||
}
|
||||
|
||||
static String getLocaleValue (bool isRegion)
|
||||
{
|
||||
auto* env = getEnv();
|
||||
LocalRef<jobject> locale (env->CallStaticObjectMethod (JavaLocale, JavaLocale.getDefault));
|
||||
|
||||
auto stringResult = isRegion ? env->CallObjectMethod (locale.get(), JavaLocale.getCountry)
|
||||
: env->CallObjectMethod (locale.get(), JavaLocale.getLanguage);
|
||||
|
||||
return juceString (LocalRef<jstring> ((jstring) stringResult));
|
||||
}
|
||||
|
||||
static String getAndroidOsBuildValue (const char* fieldName)
|
||||
{
|
||||
return juceString (LocalRef<jstring> ((jstring) getEnv()->GetStaticObjectField (
|
||||
AndroidBuild, getEnv()->GetStaticFieldID (AndroidBuild, fieldName, "Ljava/lang/String;"))));
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
SystemStats::OperatingSystemType SystemStats::getOperatingSystemType()
|
||||
{
|
||||
return Android;
|
||||
}
|
||||
|
||||
String SystemStats::getOperatingSystemName()
|
||||
{
|
||||
return "Android " + AndroidStatsHelpers::getSystemProperty ("os.version");
|
||||
}
|
||||
|
||||
String SystemStats::getDeviceDescription()
|
||||
{
|
||||
return AndroidStatsHelpers::getAndroidOsBuildValue ("MODEL")
|
||||
+ "-" + AndroidStatsHelpers::getAndroidOsBuildValue ("SERIAL");
|
||||
}
|
||||
|
||||
String SystemStats::getDeviceManufacturer()
|
||||
{
|
||||
return AndroidStatsHelpers::getAndroidOsBuildValue ("MANUFACTURER");
|
||||
}
|
||||
|
||||
bool SystemStats::isOperatingSystem64Bit()
|
||||
{
|
||||
#if JUCE_64BIT
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
String SystemStats::getCpuVendor()
|
||||
{
|
||||
return AndroidStatsHelpers::getSystemProperty ("os.arch");
|
||||
}
|
||||
|
||||
String SystemStats::getCpuModel()
|
||||
{
|
||||
return readPosixConfigFileValue ("/proc/cpuinfo", "Hardware");
|
||||
}
|
||||
|
||||
int SystemStats::getCpuSpeedInMegahertz()
|
||||
{
|
||||
int maxFreqKHz = 0;
|
||||
|
||||
for (int i = 0; i < getNumCpus(); ++i)
|
||||
{
|
||||
int freqKHz = File ("/sys/devices/system/cpu/cpu" + String(i) + "/cpufreq/cpuinfo_max_freq")
|
||||
.loadFileAsString()
|
||||
.getIntValue();
|
||||
|
||||
maxFreqKHz = jmax (freqKHz, maxFreqKHz);
|
||||
}
|
||||
|
||||
return maxFreqKHz / 1000;
|
||||
}
|
||||
|
||||
int SystemStats::getMemorySizeInMegabytes()
|
||||
{
|
||||
#if __ANDROID_API__ >= 9
|
||||
struct sysinfo sysi;
|
||||
|
||||
if (sysinfo (&sysi) == 0)
|
||||
return static_cast<int> ((sysi.totalram * sysi.mem_unit) / (1024 * 1024));
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SystemStats::getPageSize()
|
||||
{
|
||||
return static_cast<int> (sysconf (_SC_PAGESIZE));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
String SystemStats::getLogonName()
|
||||
{
|
||||
if (const char* user = getenv ("USER"))
|
||||
return CharPointer_UTF8 (user);
|
||||
|
||||
if (struct passwd* const pw = getpwuid (getuid()))
|
||||
return CharPointer_UTF8 (pw->pw_name);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
String SystemStats::getFullUserName()
|
||||
{
|
||||
return getLogonName();
|
||||
}
|
||||
|
||||
String SystemStats::getComputerName()
|
||||
{
|
||||
char name [256] = { 0 };
|
||||
if (gethostname (name, sizeof (name) - 1) == 0)
|
||||
return name;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
String SystemStats::getUserLanguage() { return AndroidStatsHelpers::getLocaleValue (false); }
|
||||
String SystemStats::getUserRegion() { return AndroidStatsHelpers::getLocaleValue (true); }
|
||||
String SystemStats::getDisplayLanguage() { return getUserLanguage() + "-" + getUserRegion(); }
|
||||
|
||||
//==============================================================================
|
||||
void CPUInformation::initialise() noexcept
|
||||
{
|
||||
numPhysicalCPUs = numLogicalCPUs = jmax ((int) 1, (int) android_getCpuCount());
|
||||
|
||||
auto cpuFamily = android_getCpuFamily();
|
||||
auto cpuFeatures = android_getCpuFeatures();
|
||||
|
||||
if (cpuFamily == ANDROID_CPU_FAMILY_X86 || cpuFamily == ANDROID_CPU_FAMILY_X86_64)
|
||||
{
|
||||
hasMMX = hasSSE = hasSSE2 = (cpuFamily == ANDROID_CPU_FAMILY_X86_64);
|
||||
|
||||
hasSSSE3 = ((cpuFeatures & ANDROID_CPU_X86_FEATURE_SSSE3) != 0);
|
||||
hasSSE41 = ((cpuFeatures & ANDROID_CPU_X86_FEATURE_SSE4_1) != 0);
|
||||
hasSSE42 = ((cpuFeatures & ANDROID_CPU_X86_FEATURE_SSE4_2) != 0);
|
||||
hasAVX = ((cpuFeatures & ANDROID_CPU_X86_FEATURE_AVX) != 0);
|
||||
hasAVX2 = ((cpuFeatures & ANDROID_CPU_X86_FEATURE_AVX2) != 0);
|
||||
|
||||
// Google does not distinguish between MMX, SSE, SSE2, SSE3 and SSSE3. So
|
||||
// I assume (and quick Google searches seem to confirm this) that there are
|
||||
// only devices out there that either support all of this or none of this.
|
||||
if (hasSSSE3)
|
||||
hasMMX = hasSSE = hasSSE2 = hasSSE3 = true;
|
||||
}
|
||||
else if (cpuFamily == ANDROID_CPU_FAMILY_ARM)
|
||||
{
|
||||
hasNeon = ((cpuFeatures & ANDROID_CPU_ARM_FEATURE_NEON) != 0);
|
||||
}
|
||||
else if (cpuFamily == ANDROID_CPU_FAMILY_ARM64)
|
||||
{
|
||||
// all arm 64-bit cpus have neon
|
||||
hasNeon = true;
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
uint32 juce_millisecondsSinceStartup() noexcept
|
||||
{
|
||||
timespec t;
|
||||
clock_gettime (CLOCK_MONOTONIC, &t);
|
||||
|
||||
return static_cast<uint32> (t.tv_sec) * 1000U + static_cast<uint32> (t.tv_nsec) / 1000000U;
|
||||
}
|
||||
|
||||
int64 Time::getHighResolutionTicks() noexcept
|
||||
{
|
||||
timespec t;
|
||||
clock_gettime (CLOCK_MONOTONIC, &t);
|
||||
|
||||
return (t.tv_sec * (int64) 1000000) + (t.tv_nsec / 1000);
|
||||
}
|
||||
|
||||
int64 Time::getHighResolutionTicksPerSecond() noexcept
|
||||
{
|
||||
return 1000000; // (microseconds)
|
||||
}
|
||||
|
||||
double Time::getMillisecondCounterHiRes() noexcept
|
||||
{
|
||||
return (double) getHighResolutionTicks() * 0.001;
|
||||
}
|
||||
|
||||
bool Time::setSystemTimeToThisTime() const
|
||||
{
|
||||
jassertfalse;
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
|
@ -1,395 +1,394 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
/*
|
||||
Note that a lot of methods that you'd expect to find in this file actually
|
||||
live in juce_posix_SharedCode.h!
|
||||
*/
|
||||
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
|
||||
FIELD (activityInfo, "activityInfo", "Landroid/content/pm/ActivityInfo;")
|
||||
|
||||
DECLARE_JNI_CLASS (AndroidResolveInfo, "android/content/pm/ResolveInfo")
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
//==============================================================================
|
||||
JavaVM* androidJNIJavaVM = nullptr;
|
||||
jobject androidApkContext = nullptr;
|
||||
|
||||
//==============================================================================
|
||||
JNIEnv* getEnv() noexcept
|
||||
{
|
||||
if (androidJNIJavaVM != nullptr)
|
||||
{
|
||||
JNIEnv* env;
|
||||
androidJNIJavaVM->AttachCurrentThread (&env, nullptr);
|
||||
|
||||
return env;
|
||||
}
|
||||
|
||||
// You did not call Thread::initialiseJUCE which must be called at least once in your apk
|
||||
// before using any JUCE APIs. The Projucer will automatically generate java code
|
||||
// which will invoke Thread::initialiseJUCE for you.
|
||||
jassertfalse;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void JNICALL juce_JavainitialiseJUCE (JNIEnv* env, jobject /*jclass*/, jobject context)
|
||||
{
|
||||
Thread::initialiseJUCE (env, context);
|
||||
}
|
||||
|
||||
extern "C" jint JNIEXPORT JNI_OnLoad (JavaVM* vm, void*)
|
||||
{
|
||||
// Huh? JNI_OnLoad was called two times!
|
||||
jassert (androidJNIJavaVM == nullptr);
|
||||
|
||||
androidJNIJavaVM = vm;
|
||||
|
||||
auto* env = getEnv();
|
||||
|
||||
// register the initialisation function
|
||||
auto juceJavaClass = env->FindClass("com/rmsl/juce/Java");
|
||||
|
||||
if (juceJavaClass != nullptr)
|
||||
{
|
||||
JNINativeMethod method {"initialiseJUCE", "(Landroid/content/Context;)V",
|
||||
reinterpret_cast<void*> (juce_JavainitialiseJUCE)};
|
||||
|
||||
auto status = env->RegisterNatives (juceJavaClass, &method, 1);
|
||||
jassert (status == 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// com.rmsl.juce.Java class not found. Apparently this project is a library
|
||||
// or was not generated by the Projucer. That's ok, the user will have to
|
||||
// call Thread::initialiseJUCE manually
|
||||
env->ExceptionClear();
|
||||
}
|
||||
|
||||
JNIClassBase::initialiseAllClasses (env);
|
||||
|
||||
return JNI_VERSION_1_2;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class JuceActivityWatcher : public ActivityLifecycleCallbacks
|
||||
{
|
||||
public:
|
||||
JuceActivityWatcher()
|
||||
{
|
||||
LocalRef<jobject> appContext (getAppContext());
|
||||
|
||||
if (appContext != nullptr)
|
||||
{
|
||||
auto* env = getEnv();
|
||||
|
||||
myself = GlobalRef (CreateJavaInterface (this, "android/app/Application$ActivityLifecycleCallbacks"));
|
||||
env->CallVoidMethod (appContext.get(), AndroidApplication.registerActivityLifecycleCallbacks, myself.get());
|
||||
}
|
||||
|
||||
checkActivityIsMain (androidApkContext);
|
||||
}
|
||||
|
||||
~JuceActivityWatcher() override
|
||||
{
|
||||
LocalRef<jobject> appContext (getAppContext());
|
||||
|
||||
if (appContext != nullptr && myself != nullptr)
|
||||
{
|
||||
auto* env = getEnv();
|
||||
|
||||
env->CallVoidMethod (appContext.get(), AndroidApplication.unregisterActivityLifecycleCallbacks, myself.get());
|
||||
clear();
|
||||
myself.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void onActivityStarted (jobject activity) override
|
||||
{
|
||||
auto* env = getEnv();
|
||||
|
||||
checkActivityIsMain (activity);
|
||||
|
||||
ScopedLock lock (currentActivityLock);
|
||||
|
||||
if (currentActivity != nullptr)
|
||||
{
|
||||
// see Clarification June 2001 in JNI reference for why this is
|
||||
// necessary
|
||||
LocalRef<jobject> localStorage (env->NewLocalRef (currentActivity));
|
||||
|
||||
if (env->IsSameObject (localStorage.get(), activity) != 0)
|
||||
return;
|
||||
|
||||
env->DeleteWeakGlobalRef (currentActivity);
|
||||
currentActivity = nullptr;
|
||||
}
|
||||
|
||||
if (activity != nullptr)
|
||||
currentActivity = env->NewWeakGlobalRef (activity);
|
||||
}
|
||||
|
||||
void onActivityStopped (jobject activity) override
|
||||
{
|
||||
auto* env = getEnv();
|
||||
|
||||
ScopedLock lock (currentActivityLock);
|
||||
|
||||
if (currentActivity != nullptr)
|
||||
{
|
||||
// important that the comparison happens in this order
|
||||
// to avoid race condition where the weak reference becomes null
|
||||
// just after the first check
|
||||
if (env->IsSameObject (currentActivity, activity) != 0
|
||||
|| env->IsSameObject (currentActivity, nullptr) != 0)
|
||||
{
|
||||
env->DeleteWeakGlobalRef (currentActivity);
|
||||
currentActivity = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LocalRef<jobject> getCurrent()
|
||||
{
|
||||
ScopedLock lock (currentActivityLock);
|
||||
return LocalRef<jobject> (getEnv()->NewLocalRef (currentActivity));
|
||||
}
|
||||
|
||||
LocalRef<jobject> getMain()
|
||||
{
|
||||
ScopedLock lock (currentActivityLock);
|
||||
return LocalRef<jobject> (getEnv()->NewLocalRef (mainActivity));
|
||||
}
|
||||
|
||||
static JuceActivityWatcher& getInstance()
|
||||
{
|
||||
static JuceActivityWatcher activityWatcher;
|
||||
return activityWatcher;
|
||||
}
|
||||
|
||||
private:
|
||||
void checkActivityIsMain (jobject context)
|
||||
{
|
||||
auto* env = getEnv();
|
||||
|
||||
ScopedLock lock (currentActivityLock);
|
||||
|
||||
if (mainActivity != nullptr)
|
||||
{
|
||||
if (env->IsSameObject (mainActivity, nullptr) != 0)
|
||||
{
|
||||
env->DeleteWeakGlobalRef (mainActivity);
|
||||
mainActivity = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (mainActivity == nullptr)
|
||||
{
|
||||
LocalRef<jobject> appContext (getAppContext());
|
||||
auto mainActivityPath = getMainActivityClassPath();
|
||||
|
||||
if (mainActivityPath.isNotEmpty())
|
||||
{
|
||||
auto clasz = env->GetObjectClass (context);
|
||||
auto activityPath = juceString (LocalRef<jstring> ((jstring) env->CallObjectMethod (clasz, JavaClass.getName)));
|
||||
|
||||
// This may be problematic for apps which use several activities with the same type. We just
|
||||
// assume that the very first activity of this type is the main one
|
||||
if (activityPath == mainActivityPath)
|
||||
mainActivity = env->NewWeakGlobalRef (context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static String getMainActivityClassPath()
|
||||
{
|
||||
static String mainActivityClassPath;
|
||||
|
||||
if (mainActivityClassPath.isEmpty())
|
||||
{
|
||||
LocalRef<jobject> appContext (getAppContext());
|
||||
|
||||
if (appContext != nullptr)
|
||||
{
|
||||
auto* env = getEnv();
|
||||
|
||||
LocalRef<jobject> pkgManager (env->CallObjectMethod (appContext.get(), AndroidContext.getPackageManager));
|
||||
LocalRef<jstring> pkgName ((jstring) env->CallObjectMethod (appContext.get(), AndroidContext.getPackageName));
|
||||
|
||||
LocalRef<jobject> intent (env->NewObject (AndroidIntent, AndroidIntent.constructWithString,
|
||||
javaString ("android.intent.action.MAIN").get()));
|
||||
|
||||
intent = LocalRef<jobject> (env->CallObjectMethod (intent.get(),
|
||||
AndroidIntent.setPackage,
|
||||
pkgName.get()));
|
||||
|
||||
LocalRef<jobject> resolveInfo (env->CallObjectMethod (pkgManager.get(), AndroidPackageManager.resolveActivity, intent.get(), 0));
|
||||
|
||||
if (resolveInfo != nullptr)
|
||||
{
|
||||
LocalRef<jobject> activityInfo (env->GetObjectField (resolveInfo.get(), AndroidResolveInfo.activityInfo));
|
||||
LocalRef<jstring> jName ((jstring) env->GetObjectField (activityInfo.get(), AndroidPackageItemInfo.name));
|
||||
LocalRef<jstring> jPackage ((jstring) env->GetObjectField (activityInfo.get(), AndroidPackageItemInfo.packageName));
|
||||
|
||||
mainActivityClassPath = juceString (jName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mainActivityClassPath;
|
||||
}
|
||||
|
||||
GlobalRef myself;
|
||||
CriticalSection currentActivityLock;
|
||||
jweak currentActivity = nullptr;
|
||||
jweak mainActivity = nullptr;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_MODULE_AVAILABLE_juce_events && JUCE_ANDROID
|
||||
void juce_juceEventsAndroidStartApp();
|
||||
#endif
|
||||
|
||||
void Thread::initialiseJUCE (void* jniEnv, void* context)
|
||||
{
|
||||
static CriticalSection cs;
|
||||
ScopedLock lock (cs);
|
||||
|
||||
// jniEnv and context should not be null!
|
||||
jassert (jniEnv != nullptr && context != nullptr);
|
||||
|
||||
auto* env = static_cast<JNIEnv*> (jniEnv);
|
||||
|
||||
if (androidJNIJavaVM == nullptr)
|
||||
{
|
||||
JavaVM* javaVM = nullptr;
|
||||
|
||||
auto status = env->GetJavaVM (&javaVM);
|
||||
jassert (status == 0 && javaVM != nullptr);
|
||||
|
||||
androidJNIJavaVM = javaVM;
|
||||
}
|
||||
|
||||
static bool firstCall = true;
|
||||
|
||||
if (firstCall)
|
||||
{
|
||||
firstCall = false;
|
||||
|
||||
// if we ever support unloading then this should probably be a weak reference
|
||||
androidApkContext = env->NewGlobalRef (static_cast<jobject> (context));
|
||||
JuceActivityWatcher::getInstance();
|
||||
|
||||
#if JUCE_MODULE_AVAILABLE_juce_events && JUCE_ANDROID
|
||||
juce_juceEventsAndroidStartApp();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
LocalRef<jobject> getAppContext() noexcept
|
||||
{
|
||||
auto* env = getEnv();
|
||||
auto context = androidApkContext;
|
||||
|
||||
// You did not call Thread::initialiseJUCE which must be called at least once in your apk
|
||||
// before using any JUCE APIs. The Projucer will automatically generate java code
|
||||
// which will invoke Thread::initialiseJUCE for you.
|
||||
jassert (env != nullptr && context != nullptr);
|
||||
|
||||
if (context == nullptr)
|
||||
return LocalRef<jobject>();
|
||||
|
||||
if (env->IsInstanceOf (context, AndroidApplication) != 0)
|
||||
return LocalRef<jobject> (env->NewLocalRef (context));
|
||||
|
||||
LocalRef<jobject> applicationContext (env->CallObjectMethod (context, AndroidContext.getApplicationContext));
|
||||
|
||||
if (applicationContext == nullptr)
|
||||
return LocalRef<jobject> (env->NewLocalRef (context));
|
||||
|
||||
return applicationContext;
|
||||
}
|
||||
|
||||
LocalRef<jobject> getCurrentActivity() noexcept
|
||||
{
|
||||
return JuceActivityWatcher::getInstance().getCurrent();
|
||||
}
|
||||
|
||||
LocalRef<jobject> getMainActivity() noexcept
|
||||
{
|
||||
return JuceActivityWatcher::getInstance().getMain();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// sets the process to 0=low priority, 1=normal, 2=high, 3=realtime
|
||||
JUCE_API void JUCE_CALLTYPE Process::setPriority (ProcessPriority prior)
|
||||
{
|
||||
// TODO
|
||||
|
||||
struct sched_param param;
|
||||
int policy, maxp, minp;
|
||||
|
||||
const int p = (int) prior;
|
||||
|
||||
if (p <= 1)
|
||||
policy = SCHED_OTHER;
|
||||
else
|
||||
policy = SCHED_RR;
|
||||
|
||||
minp = sched_get_priority_min (policy);
|
||||
maxp = sched_get_priority_max (policy);
|
||||
|
||||
if (p < 2)
|
||||
param.sched_priority = 0;
|
||||
else if (p == 2 )
|
||||
// Set to middle of lower realtime priority range
|
||||
param.sched_priority = minp + (maxp - minp) / 4;
|
||||
else
|
||||
// Set to middle of higher realtime priority range
|
||||
param.sched_priority = minp + (3 * (maxp - minp) / 4);
|
||||
|
||||
pthread_setschedparam (pthread_self(), policy, ¶m);
|
||||
}
|
||||
|
||||
JUCE_API bool JUCE_CALLTYPE juce_isRunningUnderDebugger() noexcept
|
||||
{
|
||||
StringArray lines;
|
||||
File ("/proc/self/status").readLines (lines);
|
||||
|
||||
for (int i = lines.size(); --i >= 0;) // (NB - it's important that this runs in reverse order)
|
||||
if (lines[i].upToFirstOccurrenceOf (":", false, false).trim().equalsIgnoreCase ("TracerPid"))
|
||||
return (lines[i].fromFirstOccurrenceOf (":", false, false).trim().getIntValue() > 0);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
JUCE_API void JUCE_CALLTYPE Process::raisePrivilege() {}
|
||||
JUCE_API void JUCE_CALLTYPE Process::lowerPrivilege() {}
|
||||
|
||||
|
||||
|
||||
} // namespace juce
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
/*
|
||||
Note that a lot of methods that you'd expect to find in this file actually
|
||||
live in juce_posix_SharedCode.h!
|
||||
*/
|
||||
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
|
||||
FIELD (activityInfo, "activityInfo", "Landroid/content/pm/ActivityInfo;")
|
||||
|
||||
DECLARE_JNI_CLASS (AndroidResolveInfo, "android/content/pm/ResolveInfo")
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
//==============================================================================
|
||||
JavaVM* androidJNIJavaVM = nullptr;
|
||||
jobject androidApkContext = nullptr;
|
||||
|
||||
//==============================================================================
|
||||
JNIEnv* getEnv() noexcept
|
||||
{
|
||||
if (androidJNIJavaVM != nullptr)
|
||||
{
|
||||
JNIEnv* env;
|
||||
androidJNIJavaVM->AttachCurrentThread (&env, nullptr);
|
||||
|
||||
return env;
|
||||
}
|
||||
|
||||
// You did not call Thread::initialiseJUCE which must be called at least once in your apk
|
||||
// before using any JUCE APIs. The Projucer will automatically generate java code
|
||||
// which will invoke Thread::initialiseJUCE for you.
|
||||
jassertfalse;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void JNICALL juce_JavainitialiseJUCE (JNIEnv* env, jobject /*jclass*/, jobject context)
|
||||
{
|
||||
JNIClassBase::initialiseAllClasses (env, context);
|
||||
Thread::initialiseJUCE (env, context);
|
||||
}
|
||||
|
||||
extern "C" jint JNIEXPORT JNI_OnLoad (JavaVM* vm, void*)
|
||||
{
|
||||
// Huh? JNI_OnLoad was called two times!
|
||||
jassert (androidJNIJavaVM == nullptr);
|
||||
|
||||
androidJNIJavaVM = vm;
|
||||
|
||||
auto* env = getEnv();
|
||||
|
||||
// register the initialisation function
|
||||
auto juceJavaClass = env->FindClass("com/rmsl/juce/Java");
|
||||
|
||||
if (juceJavaClass != nullptr)
|
||||
{
|
||||
JNINativeMethod method {"initialiseJUCE", "(Landroid/content/Context;)V",
|
||||
reinterpret_cast<void*> (juce_JavainitialiseJUCE)};
|
||||
|
||||
auto status = env->RegisterNatives (juceJavaClass, &method, 1);
|
||||
jassert (status == 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// com.rmsl.juce.Java class not found. Apparently this project is a library
|
||||
// or was not generated by the Projucer. That's ok, the user will have to
|
||||
// call Thread::initialiseJUCE manually
|
||||
env->ExceptionClear();
|
||||
}
|
||||
|
||||
return JNI_VERSION_1_2;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class JuceActivityWatcher : public ActivityLifecycleCallbacks
|
||||
{
|
||||
public:
|
||||
JuceActivityWatcher()
|
||||
{
|
||||
LocalRef<jobject> appContext (getAppContext());
|
||||
|
||||
if (appContext != nullptr)
|
||||
{
|
||||
auto* env = getEnv();
|
||||
|
||||
myself = GlobalRef (CreateJavaInterface (this, "android/app/Application$ActivityLifecycleCallbacks"));
|
||||
env->CallVoidMethod (appContext.get(), AndroidApplication.registerActivityLifecycleCallbacks, myself.get());
|
||||
}
|
||||
|
||||
checkActivityIsMain (androidApkContext);
|
||||
}
|
||||
|
||||
~JuceActivityWatcher() override
|
||||
{
|
||||
LocalRef<jobject> appContext (getAppContext());
|
||||
|
||||
if (appContext != nullptr && myself != nullptr)
|
||||
{
|
||||
auto* env = getEnv();
|
||||
|
||||
env->CallVoidMethod (appContext.get(), AndroidApplication.unregisterActivityLifecycleCallbacks, myself.get());
|
||||
clear();
|
||||
myself.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void onActivityStarted (jobject activity) override
|
||||
{
|
||||
auto* env = getEnv();
|
||||
|
||||
checkActivityIsMain (activity);
|
||||
|
||||
ScopedLock lock (currentActivityLock);
|
||||
|
||||
if (currentActivity != nullptr)
|
||||
{
|
||||
// see Clarification June 2001 in JNI reference for why this is
|
||||
// necessary
|
||||
LocalRef<jobject> localStorage (env->NewLocalRef (currentActivity));
|
||||
|
||||
if (env->IsSameObject (localStorage.get(), activity) != 0)
|
||||
return;
|
||||
|
||||
env->DeleteWeakGlobalRef (currentActivity);
|
||||
currentActivity = nullptr;
|
||||
}
|
||||
|
||||
if (activity != nullptr)
|
||||
currentActivity = env->NewWeakGlobalRef (activity);
|
||||
}
|
||||
|
||||
void onActivityStopped (jobject activity) override
|
||||
{
|
||||
auto* env = getEnv();
|
||||
|
||||
ScopedLock lock (currentActivityLock);
|
||||
|
||||
if (currentActivity != nullptr)
|
||||
{
|
||||
// important that the comparison happens in this order
|
||||
// to avoid race condition where the weak reference becomes null
|
||||
// just after the first check
|
||||
if (env->IsSameObject (currentActivity, activity) != 0
|
||||
|| env->IsSameObject (currentActivity, nullptr) != 0)
|
||||
{
|
||||
env->DeleteWeakGlobalRef (currentActivity);
|
||||
currentActivity = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LocalRef<jobject> getCurrent()
|
||||
{
|
||||
ScopedLock lock (currentActivityLock);
|
||||
return LocalRef<jobject> (getEnv()->NewLocalRef (currentActivity));
|
||||
}
|
||||
|
||||
LocalRef<jobject> getMain()
|
||||
{
|
||||
ScopedLock lock (currentActivityLock);
|
||||
return LocalRef<jobject> (getEnv()->NewLocalRef (mainActivity));
|
||||
}
|
||||
|
||||
static JuceActivityWatcher& getInstance()
|
||||
{
|
||||
static JuceActivityWatcher activityWatcher;
|
||||
return activityWatcher;
|
||||
}
|
||||
|
||||
private:
|
||||
void checkActivityIsMain (jobject context)
|
||||
{
|
||||
auto* env = getEnv();
|
||||
|
||||
ScopedLock lock (currentActivityLock);
|
||||
|
||||
if (mainActivity != nullptr)
|
||||
{
|
||||
if (env->IsSameObject (mainActivity, nullptr) != 0)
|
||||
{
|
||||
env->DeleteWeakGlobalRef (mainActivity);
|
||||
mainActivity = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (mainActivity == nullptr)
|
||||
{
|
||||
LocalRef<jobject> appContext (getAppContext());
|
||||
auto mainActivityPath = getMainActivityClassPath();
|
||||
|
||||
if (mainActivityPath.isNotEmpty())
|
||||
{
|
||||
auto clasz = env->GetObjectClass (context);
|
||||
auto activityPath = juceString (LocalRef<jstring> ((jstring) env->CallObjectMethod (clasz, JavaClass.getName)));
|
||||
|
||||
// This may be problematic for apps which use several activities with the same type. We just
|
||||
// assume that the very first activity of this type is the main one
|
||||
if (activityPath == mainActivityPath)
|
||||
mainActivity = env->NewWeakGlobalRef (context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static String getMainActivityClassPath()
|
||||
{
|
||||
static String mainActivityClassPath;
|
||||
|
||||
if (mainActivityClassPath.isEmpty())
|
||||
{
|
||||
LocalRef<jobject> appContext (getAppContext());
|
||||
|
||||
if (appContext != nullptr)
|
||||
{
|
||||
auto* env = getEnv();
|
||||
|
||||
LocalRef<jobject> pkgManager (env->CallObjectMethod (appContext.get(), AndroidContext.getPackageManager));
|
||||
LocalRef<jstring> pkgName ((jstring) env->CallObjectMethod (appContext.get(), AndroidContext.getPackageName));
|
||||
|
||||
LocalRef<jobject> intent (env->NewObject (AndroidIntent, AndroidIntent.constructWithString,
|
||||
javaString ("android.intent.action.MAIN").get()));
|
||||
|
||||
intent = LocalRef<jobject> (env->CallObjectMethod (intent.get(),
|
||||
AndroidIntent.setPackage,
|
||||
pkgName.get()));
|
||||
|
||||
LocalRef<jobject> resolveInfo (env->CallObjectMethod (pkgManager.get(), AndroidPackageManager.resolveActivity, intent.get(), 0));
|
||||
|
||||
if (resolveInfo != nullptr)
|
||||
{
|
||||
LocalRef<jobject> activityInfo (env->GetObjectField (resolveInfo.get(), AndroidResolveInfo.activityInfo));
|
||||
LocalRef<jstring> jName ((jstring) env->GetObjectField (activityInfo.get(), AndroidPackageItemInfo.name));
|
||||
LocalRef<jstring> jPackage ((jstring) env->GetObjectField (activityInfo.get(), AndroidPackageItemInfo.packageName));
|
||||
|
||||
mainActivityClassPath = juceString (jName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mainActivityClassPath;
|
||||
}
|
||||
|
||||
GlobalRef myself;
|
||||
CriticalSection currentActivityLock;
|
||||
jweak currentActivity = nullptr;
|
||||
jweak mainActivity = nullptr;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_MODULE_AVAILABLE_juce_events && JUCE_ANDROID
|
||||
void juce_juceEventsAndroidStartApp();
|
||||
#endif
|
||||
|
||||
void Thread::initialiseJUCE (void* jniEnv, void* context)
|
||||
{
|
||||
static CriticalSection cs;
|
||||
ScopedLock lock (cs);
|
||||
|
||||
// jniEnv and context should not be null!
|
||||
jassert (jniEnv != nullptr && context != nullptr);
|
||||
|
||||
auto* env = static_cast<JNIEnv*> (jniEnv);
|
||||
|
||||
if (androidJNIJavaVM == nullptr)
|
||||
{
|
||||
JavaVM* javaVM = nullptr;
|
||||
|
||||
auto status = env->GetJavaVM (&javaVM);
|
||||
jassert (status == 0 && javaVM != nullptr);
|
||||
|
||||
androidJNIJavaVM = javaVM;
|
||||
}
|
||||
|
||||
static bool firstCall = true;
|
||||
|
||||
if (firstCall)
|
||||
{
|
||||
firstCall = false;
|
||||
|
||||
// if we ever support unloading then this should probably be a weak reference
|
||||
androidApkContext = env->NewGlobalRef (static_cast<jobject> (context));
|
||||
JuceActivityWatcher::getInstance();
|
||||
|
||||
#if JUCE_MODULE_AVAILABLE_juce_events && JUCE_ANDROID
|
||||
juce_juceEventsAndroidStartApp();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
LocalRef<jobject> getAppContext() noexcept
|
||||
{
|
||||
auto* env = getEnv();
|
||||
auto context = androidApkContext;
|
||||
|
||||
// You did not call Thread::initialiseJUCE which must be called at least once in your apk
|
||||
// before using any JUCE APIs. The Projucer will automatically generate java code
|
||||
// which will invoke Thread::initialiseJUCE for you.
|
||||
jassert (env != nullptr && context != nullptr);
|
||||
|
||||
if (context == nullptr)
|
||||
return LocalRef<jobject>();
|
||||
|
||||
if (env->IsInstanceOf (context, AndroidApplication) != 0)
|
||||
return LocalRef<jobject> (env->NewLocalRef (context));
|
||||
|
||||
LocalRef<jobject> applicationContext (env->CallObjectMethod (context, AndroidContext.getApplicationContext));
|
||||
|
||||
if (applicationContext == nullptr)
|
||||
return LocalRef<jobject> (env->NewLocalRef (context));
|
||||
|
||||
return applicationContext;
|
||||
}
|
||||
|
||||
LocalRef<jobject> getCurrentActivity() noexcept
|
||||
{
|
||||
return JuceActivityWatcher::getInstance().getCurrent();
|
||||
}
|
||||
|
||||
LocalRef<jobject> getMainActivity() noexcept
|
||||
{
|
||||
return JuceActivityWatcher::getInstance().getMain();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// sets the process to 0=low priority, 1=normal, 2=high, 3=realtime
|
||||
JUCE_API void JUCE_CALLTYPE Process::setPriority (ProcessPriority prior)
|
||||
{
|
||||
// TODO
|
||||
|
||||
struct sched_param param;
|
||||
int policy, maxp, minp;
|
||||
|
||||
const int p = (int) prior;
|
||||
|
||||
if (p <= 1)
|
||||
policy = SCHED_OTHER;
|
||||
else
|
||||
policy = SCHED_RR;
|
||||
|
||||
minp = sched_get_priority_min (policy);
|
||||
maxp = sched_get_priority_max (policy);
|
||||
|
||||
if (p < 2)
|
||||
param.sched_priority = 0;
|
||||
else if (p == 2 )
|
||||
// Set to middle of lower realtime priority range
|
||||
param.sched_priority = minp + (maxp - minp) / 4;
|
||||
else
|
||||
// Set to middle of higher realtime priority range
|
||||
param.sched_priority = minp + (3 * (maxp - minp) / 4);
|
||||
|
||||
pthread_setschedparam (pthread_self(), policy, ¶m);
|
||||
}
|
||||
|
||||
JUCE_API bool JUCE_CALLTYPE juce_isRunningUnderDebugger() noexcept
|
||||
{
|
||||
StringArray lines;
|
||||
File ("/proc/self/status").readLines (lines);
|
||||
|
||||
for (int i = lines.size(); --i >= 0;) // (NB - it's important that this runs in reverse order)
|
||||
if (lines[i].upToFirstOccurrenceOf (":", false, false).trim().equalsIgnoreCase ("TracerPid"))
|
||||
return (lines[i].fromFirstOccurrenceOf (":", false, false).trim().getIntValue() > 0);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
JUCE_API void JUCE_CALLTYPE Process::raisePrivilege() {}
|
||||
JUCE_API void JUCE_CALLTYPE Process::lowerPrivilege() {}
|
||||
|
||||
|
||||
|
||||
} // namespace juce
|
||||
|
1312
deps/juce/modules/juce_core/native/juce_curl_Network.cpp
vendored
1312
deps/juce/modules/juce_core/native/juce_curl_Network.cpp
vendored
File diff suppressed because it is too large
Load Diff
@ -1,108 +1,108 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
#if JUCE_INTEL && ! JUCE_NO_INLINE_ASM
|
||||
|
||||
namespace SystemStatsHelpers
|
||||
{
|
||||
|
||||
static void doCPUID (uint32& a, uint32& b, uint32& c, uint32& d, uint32 type)
|
||||
{
|
||||
uint32 la = a, lb = b, lc = c, ld = d;
|
||||
|
||||
#if JUCE_32BIT && defined (__pic__)
|
||||
asm ("mov %%ebx, %%edi\n"
|
||||
"cpuid\n"
|
||||
"xchg %%edi, %%ebx\n"
|
||||
: "=a" (la), "=D" (lb), "=c" (lc), "=d" (ld)
|
||||
: "a" (type), "c" (0));
|
||||
#else
|
||||
asm ("cpuid\n"
|
||||
: "=a" (la), "=b" (lb), "=c" (lc), "=d" (ld)
|
||||
: "a" (type), "c" (0));
|
||||
#endif
|
||||
|
||||
a = la; b = lb; c = lc; d = ld;
|
||||
}
|
||||
|
||||
static void getCPUInfo (bool& hasMMX,
|
||||
bool& hasSSE,
|
||||
bool& hasSSE2,
|
||||
bool& has3DNow,
|
||||
bool& hasSSE3,
|
||||
bool& hasSSSE3,
|
||||
bool& hasFMA3,
|
||||
bool& hasSSE41,
|
||||
bool& hasSSE42,
|
||||
bool& hasAVX,
|
||||
bool& hasFMA4,
|
||||
bool& hasAVX2,
|
||||
bool& hasAVX512F,
|
||||
bool& hasAVX512DQ,
|
||||
bool& hasAVX512IFMA,
|
||||
bool& hasAVX512PF,
|
||||
bool& hasAVX512ER,
|
||||
bool& hasAVX512CD,
|
||||
bool& hasAVX512BW,
|
||||
bool& hasAVX512VL,
|
||||
bool& hasAVX512VBMI,
|
||||
bool& hasAVX512VPOPCNTDQ)
|
||||
{
|
||||
uint32 a = 0, b = 0, d = 0, c = 0;
|
||||
SystemStatsHelpers::doCPUID (a, b, c, d, 1);
|
||||
|
||||
hasMMX = (d & (1u << 23)) != 0;
|
||||
hasSSE = (d & (1u << 25)) != 0;
|
||||
hasSSE2 = (d & (1u << 26)) != 0;
|
||||
has3DNow = (b & (1u << 31)) != 0;
|
||||
hasSSE3 = (c & (1u << 0)) != 0;
|
||||
hasSSSE3 = (c & (1u << 9)) != 0;
|
||||
hasFMA3 = (c & (1u << 12)) != 0;
|
||||
hasSSE41 = (c & (1u << 19)) != 0;
|
||||
hasSSE42 = (c & (1u << 20)) != 0;
|
||||
hasAVX = (c & (1u << 28)) != 0;
|
||||
|
||||
SystemStatsHelpers::doCPUID (a, b, c, d, 0x80000001);
|
||||
hasFMA4 = (c & (1u << 16)) != 0;
|
||||
|
||||
SystemStatsHelpers::doCPUID (a, b, c, d, 7);
|
||||
hasAVX2 = (b & (1u << 5)) != 0;
|
||||
hasAVX512F = (b & (1u << 16)) != 0;
|
||||
hasAVX512DQ = (b & (1u << 17)) != 0;
|
||||
hasAVX512IFMA = (b & (1u << 21)) != 0;
|
||||
hasAVX512PF = (b & (1u << 26)) != 0;
|
||||
hasAVX512ER = (b & (1u << 27)) != 0;
|
||||
hasAVX512CD = (b & (1u << 28)) != 0;
|
||||
hasAVX512BW = (b & (1u << 30)) != 0;
|
||||
hasAVX512VL = (b & (1u << 31)) != 0;
|
||||
hasAVX512VBMI = (c & (1u << 1)) != 0;
|
||||
hasAVX512VPOPCNTDQ = (c & (1u << 14)) != 0;
|
||||
}
|
||||
|
||||
} // namespace SystemStatsHelpers
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
#if JUCE_INTEL && ! JUCE_NO_INLINE_ASM
|
||||
|
||||
namespace SystemStatsHelpers
|
||||
{
|
||||
|
||||
static void doCPUID (uint32& a, uint32& b, uint32& c, uint32& d, uint32 type)
|
||||
{
|
||||
uint32 la = a, lb = b, lc = c, ld = d;
|
||||
|
||||
#if JUCE_32BIT && defined (__pic__)
|
||||
asm ("mov %%ebx, %%edi\n"
|
||||
"cpuid\n"
|
||||
"xchg %%edi, %%ebx\n"
|
||||
: "=a" (la), "=D" (lb), "=c" (lc), "=d" (ld)
|
||||
: "a" (type), "c" (0));
|
||||
#else
|
||||
asm ("cpuid\n"
|
||||
: "=a" (la), "=b" (lb), "=c" (lc), "=d" (ld)
|
||||
: "a" (type), "c" (0));
|
||||
#endif
|
||||
|
||||
a = la; b = lb; c = lc; d = ld;
|
||||
}
|
||||
|
||||
static void getCPUInfo (bool& hasMMX,
|
||||
bool& hasSSE,
|
||||
bool& hasSSE2,
|
||||
bool& has3DNow,
|
||||
bool& hasSSE3,
|
||||
bool& hasSSSE3,
|
||||
bool& hasFMA3,
|
||||
bool& hasSSE41,
|
||||
bool& hasSSE42,
|
||||
bool& hasAVX,
|
||||
bool& hasFMA4,
|
||||
bool& hasAVX2,
|
||||
bool& hasAVX512F,
|
||||
bool& hasAVX512DQ,
|
||||
bool& hasAVX512IFMA,
|
||||
bool& hasAVX512PF,
|
||||
bool& hasAVX512ER,
|
||||
bool& hasAVX512CD,
|
||||
bool& hasAVX512BW,
|
||||
bool& hasAVX512VL,
|
||||
bool& hasAVX512VBMI,
|
||||
bool& hasAVX512VPOPCNTDQ)
|
||||
{
|
||||
uint32 a = 0, b = 0, d = 0, c = 0;
|
||||
SystemStatsHelpers::doCPUID (a, b, c, d, 1);
|
||||
|
||||
hasMMX = (d & (1u << 23)) != 0;
|
||||
hasSSE = (d & (1u << 25)) != 0;
|
||||
hasSSE2 = (d & (1u << 26)) != 0;
|
||||
has3DNow = (b & (1u << 31)) != 0;
|
||||
hasSSE3 = (c & (1u << 0)) != 0;
|
||||
hasSSSE3 = (c & (1u << 9)) != 0;
|
||||
hasFMA3 = (c & (1u << 12)) != 0;
|
||||
hasSSE41 = (c & (1u << 19)) != 0;
|
||||
hasSSE42 = (c & (1u << 20)) != 0;
|
||||
hasAVX = (c & (1u << 28)) != 0;
|
||||
|
||||
SystemStatsHelpers::doCPUID (a, b, c, d, 0x80000001);
|
||||
hasFMA4 = (c & (1u << 16)) != 0;
|
||||
|
||||
SystemStatsHelpers::doCPUID (a, b, c, d, 7);
|
||||
hasAVX2 = (b & (1u << 5)) != 0;
|
||||
hasAVX512F = (b & (1u << 16)) != 0;
|
||||
hasAVX512DQ = (b & (1u << 17)) != 0;
|
||||
hasAVX512IFMA = (b & (1u << 21)) != 0;
|
||||
hasAVX512PF = (b & (1u << 26)) != 0;
|
||||
hasAVX512ER = (b & (1u << 27)) != 0;
|
||||
hasAVX512CD = (b & (1u << 28)) != 0;
|
||||
hasAVX512BW = (b & (1u << 30)) != 0;
|
||||
hasAVX512VL = (b & (1u << 31)) != 0;
|
||||
hasAVX512VBMI = (c & (1u << 1)) != 0;
|
||||
hasAVX512VPOPCNTDQ = (c & (1u << 14)) != 0;
|
||||
}
|
||||
|
||||
} // namespace SystemStatsHelpers
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
||||
|
@ -1,143 +1,143 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
bool File::copyInternal (const File& dest) const
|
||||
{
|
||||
FileInputStream in (*this);
|
||||
|
||||
if (dest.deleteFile())
|
||||
{
|
||||
{
|
||||
FileOutputStream out (dest);
|
||||
|
||||
if (out.failedToOpen())
|
||||
return false;
|
||||
|
||||
if (out.writeFromInputStream (in, -1) == getSize())
|
||||
return true;
|
||||
}
|
||||
|
||||
dest.deleteFile();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void File::findFileSystemRoots (Array<File>& destArray)
|
||||
{
|
||||
destArray.add (File ("/"));
|
||||
}
|
||||
|
||||
bool File::isHidden() const
|
||||
{
|
||||
return getFileName().startsWithChar ('.');
|
||||
}
|
||||
|
||||
bool File::isSymbolicLink() const
|
||||
{
|
||||
return getNativeLinkedTarget().isNotEmpty();
|
||||
}
|
||||
|
||||
String File::getNativeLinkedTarget() const
|
||||
{
|
||||
constexpr int bufferSize = 8194;
|
||||
HeapBlock<char> buffer (bufferSize);
|
||||
auto numBytes = (int) readlink (getFullPathName().toRawUTF8(), buffer, bufferSize - 2);
|
||||
return String::fromUTF8 (buffer, jmax (0, numBytes));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class DirectoryIterator::NativeIterator::Pimpl
|
||||
{
|
||||
public:
|
||||
Pimpl (const File& directory, const String& wc)
|
||||
: parentDir (File::addTrailingSeparator (directory.getFullPathName())),
|
||||
wildCard (wc), dir (opendir (directory.getFullPathName().toUTF8()))
|
||||
{
|
||||
}
|
||||
|
||||
~Pimpl()
|
||||
{
|
||||
if (dir != nullptr)
|
||||
closedir (dir);
|
||||
}
|
||||
|
||||
bool next (String& filenameFound,
|
||||
bool* const isDir, bool* const isHidden, int64* const fileSize,
|
||||
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
|
||||
{
|
||||
if (dir != nullptr)
|
||||
{
|
||||
const char* wildcardUTF8 = nullptr;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
struct dirent* const de = readdir (dir);
|
||||
|
||||
if (de == nullptr)
|
||||
break;
|
||||
|
||||
if (wildcardUTF8 == nullptr)
|
||||
wildcardUTF8 = wildCard.toUTF8();
|
||||
|
||||
if (fnmatch (wildcardUTF8, de->d_name, FNM_CASEFOLD) == 0)
|
||||
{
|
||||
filenameFound = CharPointer_UTF8 (de->d_name);
|
||||
|
||||
updateStatInfoForFile (parentDir + filenameFound, isDir, fileSize, modTime, creationTime, isReadOnly);
|
||||
|
||||
if (isHidden != nullptr)
|
||||
*isHidden = filenameFound.startsWithChar ('.');
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
String parentDir, wildCard;
|
||||
DIR* dir;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (Pimpl)
|
||||
};
|
||||
|
||||
DirectoryIterator::NativeIterator::NativeIterator (const File& directory, const String& wildCardStr)
|
||||
: pimpl (new DirectoryIterator::NativeIterator::Pimpl (directory, wildCardStr))
|
||||
{
|
||||
}
|
||||
|
||||
DirectoryIterator::NativeIterator::~NativeIterator() {}
|
||||
|
||||
bool DirectoryIterator::NativeIterator::next (String& filenameFound,
|
||||
bool* isDir, bool* isHidden, int64* fileSize,
|
||||
Time* modTime, Time* creationTime, bool* isReadOnly)
|
||||
{
|
||||
return pimpl->next (filenameFound, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly);
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
bool File::copyInternal (const File& dest) const
|
||||
{
|
||||
FileInputStream in (*this);
|
||||
|
||||
if (dest.deleteFile())
|
||||
{
|
||||
{
|
||||
FileOutputStream out (dest);
|
||||
|
||||
if (out.failedToOpen())
|
||||
return false;
|
||||
|
||||
if (out.writeFromInputStream (in, -1) == getSize())
|
||||
return true;
|
||||
}
|
||||
|
||||
dest.deleteFile();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void File::findFileSystemRoots (Array<File>& destArray)
|
||||
{
|
||||
destArray.add (File ("/"));
|
||||
}
|
||||
|
||||
bool File::isHidden() const
|
||||
{
|
||||
return getFileName().startsWithChar ('.');
|
||||
}
|
||||
|
||||
bool File::isSymbolicLink() const
|
||||
{
|
||||
return getNativeLinkedTarget().isNotEmpty();
|
||||
}
|
||||
|
||||
String File::getNativeLinkedTarget() const
|
||||
{
|
||||
constexpr int bufferSize = 8194;
|
||||
HeapBlock<char> buffer (bufferSize);
|
||||
auto numBytes = (int) readlink (getFullPathName().toRawUTF8(), buffer, bufferSize - 2);
|
||||
return String::fromUTF8 (buffer, jmax (0, numBytes));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class DirectoryIterator::NativeIterator::Pimpl
|
||||
{
|
||||
public:
|
||||
Pimpl (const File& directory, const String& wc)
|
||||
: parentDir (File::addTrailingSeparator (directory.getFullPathName())),
|
||||
wildCard (wc), dir (opendir (directory.getFullPathName().toUTF8()))
|
||||
{
|
||||
}
|
||||
|
||||
~Pimpl()
|
||||
{
|
||||
if (dir != nullptr)
|
||||
closedir (dir);
|
||||
}
|
||||
|
||||
bool next (String& filenameFound,
|
||||
bool* const isDir, bool* const isHidden, int64* const fileSize,
|
||||
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
|
||||
{
|
||||
if (dir != nullptr)
|
||||
{
|
||||
const char* wildcardUTF8 = nullptr;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
struct dirent* const de = readdir (dir);
|
||||
|
||||
if (de == nullptr)
|
||||
break;
|
||||
|
||||
if (wildcardUTF8 == nullptr)
|
||||
wildcardUTF8 = wildCard.toUTF8();
|
||||
|
||||
if (fnmatch (wildcardUTF8, de->d_name, FNM_CASEFOLD) == 0)
|
||||
{
|
||||
filenameFound = CharPointer_UTF8 (de->d_name);
|
||||
|
||||
updateStatInfoForFile (parentDir + filenameFound, isDir, fileSize, modTime, creationTime, isReadOnly);
|
||||
|
||||
if (isHidden != nullptr)
|
||||
*isHidden = filenameFound.startsWithChar ('.');
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
String parentDir, wildCard;
|
||||
DIR* dir;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (Pimpl)
|
||||
};
|
||||
|
||||
DirectoryIterator::NativeIterator::NativeIterator (const File& directory, const String& wildCardStr)
|
||||
: pimpl (new DirectoryIterator::NativeIterator::Pimpl (directory, wildCardStr))
|
||||
{
|
||||
}
|
||||
|
||||
DirectoryIterator::NativeIterator::~NativeIterator() {}
|
||||
|
||||
bool DirectoryIterator::NativeIterator::next (String& filenameFound,
|
||||
bool* isDir, bool* isHidden, int64* fileSize,
|
||||
Time* modTime, Time* creationTime, bool* isReadOnly)
|
||||
{
|
||||
return pimpl->next (filenameFound, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly);
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
|
@ -1,248 +1,247 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#if JUCE_BSD
|
||||
extern char** environ;
|
||||
#endif
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
enum
|
||||
{
|
||||
U_ISOFS_SUPER_MAGIC = 0x9660, // linux/iso_fs.h
|
||||
U_MSDOS_SUPER_MAGIC = 0x4d44, // linux/msdos_fs.h
|
||||
U_NFS_SUPER_MAGIC = 0x6969, // linux/nfs_fs.h
|
||||
U_SMB_SUPER_MAGIC = 0x517B // linux/smb_fs.h
|
||||
};
|
||||
|
||||
bool File::isOnCDRomDrive() const
|
||||
{
|
||||
struct statfs buf;
|
||||
|
||||
return statfs (getFullPathName().toUTF8(), &buf) == 0
|
||||
&& buf.f_type == (unsigned int) U_ISOFS_SUPER_MAGIC;
|
||||
}
|
||||
|
||||
bool File::isOnHardDisk() const
|
||||
{
|
||||
struct statfs buf;
|
||||
|
||||
if (statfs (getFullPathName().toUTF8(), &buf) == 0)
|
||||
{
|
||||
switch (buf.f_type)
|
||||
{
|
||||
case U_ISOFS_SUPER_MAGIC: // CD-ROM
|
||||
case U_MSDOS_SUPER_MAGIC: // Probably floppy (but could be mounted FAT filesystem)
|
||||
case U_NFS_SUPER_MAGIC: // Network NFS
|
||||
case U_SMB_SUPER_MAGIC: // Network Samba
|
||||
return false;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
// Assume so if this fails for some reason
|
||||
return true;
|
||||
}
|
||||
|
||||
bool File::isOnRemovableDrive() const
|
||||
{
|
||||
jassertfalse; // xxx not implemented for linux!
|
||||
return false;
|
||||
}
|
||||
|
||||
String File::getVersion() const
|
||||
{
|
||||
return {}; // xxx not yet implemented
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static File resolveXDGFolder (const char* const type, const char* const fallbackFolder)
|
||||
{
|
||||
StringArray confLines;
|
||||
File ("~/.config/user-dirs.dirs").readLines (confLines);
|
||||
|
||||
for (int i = 0; i < confLines.size(); ++i)
|
||||
{
|
||||
const String line (confLines[i].trimStart());
|
||||
|
||||
if (line.startsWith (type))
|
||||
{
|
||||
// eg. resolve XDG_MUSIC_DIR="$HOME/Music" to /home/user/Music
|
||||
const File f (line.replace ("$HOME", File ("~").getFullPathName())
|
||||
.fromFirstOccurrenceOf ("=", false, false)
|
||||
.trim().unquoted());
|
||||
|
||||
if (f.isDirectory())
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
return File (fallbackFolder);
|
||||
}
|
||||
|
||||
const char* const* juce_argv = nullptr;
|
||||
int juce_argc = 0;
|
||||
|
||||
File File::getSpecialLocation (const SpecialLocationType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case userHomeDirectory:
|
||||
{
|
||||
if (const char* homeDir = getenv ("HOME"))
|
||||
return File (CharPointer_UTF8 (homeDir));
|
||||
|
||||
if (auto* pw = getpwuid (getuid()))
|
||||
return File (CharPointer_UTF8 (pw->pw_dir));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
case userDocumentsDirectory: return resolveXDGFolder ("XDG_DOCUMENTS_DIR", "~/Documents");
|
||||
case userMusicDirectory: return resolveXDGFolder ("XDG_MUSIC_DIR", "~/Music");
|
||||
case userMoviesDirectory: return resolveXDGFolder ("XDG_VIDEOS_DIR", "~/Videos");
|
||||
case userPicturesDirectory: return resolveXDGFolder ("XDG_PICTURES_DIR", "~/Pictures");
|
||||
case userDesktopDirectory: return resolveXDGFolder ("XDG_DESKTOP_DIR", "~/Desktop");
|
||||
case userApplicationDataDirectory: return resolveXDGFolder ("XDG_CONFIG_HOME", "~/.config");
|
||||
case commonDocumentsDirectory:
|
||||
case commonApplicationDataDirectory: return File ("/opt");
|
||||
case globalApplicationsDirectory: return File ("/usr");
|
||||
|
||||
case tempDirectory:
|
||||
{
|
||||
if (const char* tmpDir = getenv ("TMPDIR"))
|
||||
return File (CharPointer_UTF8 (tmpDir));
|
||||
|
||||
return File ("/tmp");
|
||||
}
|
||||
|
||||
case invokedExecutableFile:
|
||||
if (juce_argv != nullptr && juce_argc > 0)
|
||||
return File (CharPointer_UTF8 (juce_argv[0]));
|
||||
// Falls through
|
||||
JUCE_FALLTHROUGH
|
||||
|
||||
case currentExecutableFile:
|
||||
case currentApplicationFile:
|
||||
#if ! JUCE_STANDALONE_APPLICATION
|
||||
return juce_getExecutableFile();
|
||||
#endif
|
||||
// deliberate fall-through if this is not a shared-library
|
||||
JUCE_FALLTHROUGH
|
||||
|
||||
case hostApplicationPath:
|
||||
{
|
||||
#if JUCE_BSD
|
||||
return juce_getExecutableFile();
|
||||
#else
|
||||
const File f ("/proc/self/exe");
|
||||
return f.isSymbolicLink() ? f.getLinkedTarget() : juce_getExecutableFile();
|
||||
#endif
|
||||
}
|
||||
|
||||
default:
|
||||
jassertfalse; // unknown type?
|
||||
break;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool File::moveToTrash() const
|
||||
{
|
||||
if (! exists())
|
||||
return true;
|
||||
|
||||
File trashCan ("~/.Trash");
|
||||
|
||||
if (! trashCan.isDirectory())
|
||||
trashCan = "~/.local/share/Trash/files";
|
||||
|
||||
if (! trashCan.isDirectory())
|
||||
return false;
|
||||
|
||||
return moveFileTo (trashCan.getNonexistentChildFile (getFileNameWithoutExtension(),
|
||||
getFileExtension()));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static bool isFileExecutable (const String& filename)
|
||||
{
|
||||
juce_statStruct info;
|
||||
|
||||
return juce_stat (filename, info)
|
||||
&& S_ISREG (info.st_mode)
|
||||
&& access (filename.toUTF8(), X_OK) == 0;
|
||||
}
|
||||
|
||||
bool Process::openDocument (const String& fileName, const String& parameters)
|
||||
{
|
||||
const auto cmdString = [&]
|
||||
{
|
||||
if (fileName.startsWithIgnoreCase ("file:")
|
||||
|| File::createFileWithoutCheckingPath (fileName).isDirectory()
|
||||
|| ! isFileExecutable (fileName))
|
||||
{
|
||||
const auto singleCommand = fileName.trim().quoted();
|
||||
|
||||
StringArray cmdLines;
|
||||
|
||||
for (auto browserName : { "xdg-open", "/etc/alternatives/x-www-browser", "firefox", "mozilla",
|
||||
"google-chrome", "chromium-browser", "opera", "konqueror" })
|
||||
{
|
||||
cmdLines.add (String (browserName) + " " + singleCommand);
|
||||
}
|
||||
|
||||
return cmdLines.joinIntoString (" || ");
|
||||
}
|
||||
|
||||
return (fileName.replace (" ", "\\ ", false) + " " + parameters).trim();
|
||||
}();
|
||||
|
||||
const char* const argv[] = { "/bin/sh", "-c", cmdString.toUTF8(), nullptr };
|
||||
|
||||
const auto cpid = fork();
|
||||
|
||||
if (cpid == 0)
|
||||
{
|
||||
setsid();
|
||||
|
||||
// Child process
|
||||
execve (argv[0], (char**) argv, environ);
|
||||
exit (0);
|
||||
}
|
||||
|
||||
return cpid >= 0;
|
||||
}
|
||||
|
||||
void File::revealToUser() const
|
||||
{
|
||||
if (isDirectory())
|
||||
startAsProcess();
|
||||
else if (getParentDirectory().exists())
|
||||
getParentDirectory().startAsProcess();
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#if JUCE_BSD
|
||||
extern char** environ;
|
||||
#endif
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
enum
|
||||
{
|
||||
U_ISOFS_SUPER_MAGIC = 0x9660, // linux/iso_fs.h
|
||||
U_MSDOS_SUPER_MAGIC = 0x4d44, // linux/msdos_fs.h
|
||||
U_NFS_SUPER_MAGIC = 0x6969, // linux/nfs_fs.h
|
||||
U_SMB_SUPER_MAGIC = 0x517B // linux/smb_fs.h
|
||||
};
|
||||
|
||||
bool File::isOnCDRomDrive() const
|
||||
{
|
||||
struct statfs buf;
|
||||
|
||||
return statfs (getFullPathName().toUTF8(), &buf) == 0
|
||||
&& buf.f_type == (unsigned int) U_ISOFS_SUPER_MAGIC;
|
||||
}
|
||||
|
||||
bool File::isOnHardDisk() const
|
||||
{
|
||||
struct statfs buf;
|
||||
|
||||
if (statfs (getFullPathName().toUTF8(), &buf) == 0)
|
||||
{
|
||||
switch (buf.f_type)
|
||||
{
|
||||
case U_ISOFS_SUPER_MAGIC: // CD-ROM
|
||||
case U_MSDOS_SUPER_MAGIC: // Probably floppy (but could be mounted FAT filesystem)
|
||||
case U_NFS_SUPER_MAGIC: // Network NFS
|
||||
case U_SMB_SUPER_MAGIC: // Network Samba
|
||||
return false;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
// Assume so if this fails for some reason
|
||||
return true;
|
||||
}
|
||||
|
||||
bool File::isOnRemovableDrive() const
|
||||
{
|
||||
jassertfalse; // xxx not implemented for linux!
|
||||
return false;
|
||||
}
|
||||
|
||||
String File::getVersion() const
|
||||
{
|
||||
return {}; // xxx not yet implemented
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static File resolveXDGFolder (const char* const type, const char* const fallbackFolder)
|
||||
{
|
||||
StringArray confLines;
|
||||
File ("~/.config/user-dirs.dirs").readLines (confLines);
|
||||
|
||||
for (int i = 0; i < confLines.size(); ++i)
|
||||
{
|
||||
const String line (confLines[i].trimStart());
|
||||
|
||||
if (line.startsWith (type))
|
||||
{
|
||||
// eg. resolve XDG_MUSIC_DIR="$HOME/Music" to /home/user/Music
|
||||
const File f (line.replace ("$HOME", File ("~").getFullPathName())
|
||||
.fromFirstOccurrenceOf ("=", false, false)
|
||||
.trim().unquoted());
|
||||
|
||||
if (f.isDirectory())
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
return File (fallbackFolder);
|
||||
}
|
||||
|
||||
const char* const* juce_argv = nullptr;
|
||||
int juce_argc = 0;
|
||||
|
||||
File File::getSpecialLocation (const SpecialLocationType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case userHomeDirectory:
|
||||
{
|
||||
if (const char* homeDir = getenv ("HOME"))
|
||||
return File (CharPointer_UTF8 (homeDir));
|
||||
|
||||
if (auto* pw = getpwuid (getuid()))
|
||||
return File (CharPointer_UTF8 (pw->pw_dir));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
case userDocumentsDirectory: return resolveXDGFolder ("XDG_DOCUMENTS_DIR", "~/Documents");
|
||||
case userMusicDirectory: return resolveXDGFolder ("XDG_MUSIC_DIR", "~/Music");
|
||||
case userMoviesDirectory: return resolveXDGFolder ("XDG_VIDEOS_DIR", "~/Videos");
|
||||
case userPicturesDirectory: return resolveXDGFolder ("XDG_PICTURES_DIR", "~/Pictures");
|
||||
case userDesktopDirectory: return resolveXDGFolder ("XDG_DESKTOP_DIR", "~/Desktop");
|
||||
case userApplicationDataDirectory: return resolveXDGFolder ("XDG_CONFIG_HOME", "~/.config");
|
||||
case commonDocumentsDirectory:
|
||||
case commonApplicationDataDirectory: return File ("/opt");
|
||||
case globalApplicationsDirectory: return File ("/usr");
|
||||
|
||||
case tempDirectory:
|
||||
{
|
||||
if (const char* tmpDir = getenv ("TMPDIR"))
|
||||
return File (CharPointer_UTF8 (tmpDir));
|
||||
|
||||
return File ("/tmp");
|
||||
}
|
||||
|
||||
case invokedExecutableFile:
|
||||
if (juce_argv != nullptr && juce_argc > 0)
|
||||
return File (String (CharPointer_UTF8 (juce_argv[0])));
|
||||
// Falls through
|
||||
JUCE_FALLTHROUGH
|
||||
|
||||
case currentExecutableFile:
|
||||
case currentApplicationFile:
|
||||
{
|
||||
const auto f = juce_getExecutableFile();
|
||||
return f.isSymbolicLink() ? f.getLinkedTarget() : f;
|
||||
}
|
||||
|
||||
case hostApplicationPath:
|
||||
{
|
||||
#if JUCE_BSD
|
||||
return juce_getExecutableFile();
|
||||
#else
|
||||
const File f ("/proc/self/exe");
|
||||
return f.isSymbolicLink() ? f.getLinkedTarget() : juce_getExecutableFile();
|
||||
#endif
|
||||
}
|
||||
|
||||
default:
|
||||
jassertfalse; // unknown type?
|
||||
break;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool File::moveToTrash() const
|
||||
{
|
||||
if (! exists())
|
||||
return true;
|
||||
|
||||
File trashCan ("~/.Trash");
|
||||
|
||||
if (! trashCan.isDirectory())
|
||||
trashCan = "~/.local/share/Trash/files";
|
||||
|
||||
if (! trashCan.isDirectory())
|
||||
return false;
|
||||
|
||||
return moveFileTo (trashCan.getNonexistentChildFile (getFileNameWithoutExtension(),
|
||||
getFileExtension()));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static bool isFileExecutable (const String& filename)
|
||||
{
|
||||
juce_statStruct info;
|
||||
|
||||
return juce_stat (filename, info)
|
||||
&& S_ISREG (info.st_mode)
|
||||
&& access (filename.toUTF8(), X_OK) == 0;
|
||||
}
|
||||
|
||||
bool Process::openDocument (const String& fileName, const String& parameters)
|
||||
{
|
||||
const auto cmdString = [&]
|
||||
{
|
||||
if (fileName.startsWithIgnoreCase ("file:")
|
||||
|| File::createFileWithoutCheckingPath (fileName).isDirectory()
|
||||
|| ! isFileExecutable (fileName))
|
||||
{
|
||||
const auto singleCommand = fileName.trim().quoted();
|
||||
|
||||
StringArray cmdLines;
|
||||
|
||||
for (auto browserName : { "xdg-open", "/etc/alternatives/x-www-browser", "firefox", "mozilla",
|
||||
"google-chrome", "chromium-browser", "opera", "konqueror" })
|
||||
{
|
||||
cmdLines.add (String (browserName) + " " + singleCommand);
|
||||
}
|
||||
|
||||
return cmdLines.joinIntoString (" || ");
|
||||
}
|
||||
|
||||
return (fileName.replace (" ", "\\ ", false) + " " + parameters).trim();
|
||||
}();
|
||||
|
||||
const char* const argv[] = { "/bin/sh", "-c", cmdString.toUTF8(), nullptr };
|
||||
|
||||
const auto cpid = fork();
|
||||
|
||||
if (cpid == 0)
|
||||
{
|
||||
setsid();
|
||||
|
||||
// Child process
|
||||
execve (argv[0], (char**) argv, environ);
|
||||
exit (0);
|
||||
}
|
||||
|
||||
return cpid >= 0;
|
||||
}
|
||||
|
||||
void File::revealToUser() const
|
||||
{
|
||||
if (isDirectory())
|
||||
startAsProcess();
|
||||
else if (getParentDirectory().exists())
|
||||
getParentDirectory().startAsProcess();
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,367 +1,367 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#if JUCE_BELA
|
||||
extern "C" int cobalt_thread_mode();
|
||||
#endif
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
#if ! JUCE_BSD
|
||||
static String getCpuInfo (const char* key)
|
||||
{
|
||||
return readPosixConfigFileValue ("/proc/cpuinfo", key);
|
||||
}
|
||||
|
||||
static String getLocaleValue (nl_item key)
|
||||
{
|
||||
auto oldLocale = ::setlocale (LC_ALL, "");
|
||||
auto result = String::fromUTF8 (nl_langinfo (key));
|
||||
::setlocale (LC_ALL, oldLocale);
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
void Logger::outputDebugString (const String& text)
|
||||
{
|
||||
std::cerr << text << std::endl;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
SystemStats::OperatingSystemType SystemStats::getOperatingSystemType()
|
||||
{
|
||||
return Linux;
|
||||
}
|
||||
|
||||
String SystemStats::getOperatingSystemName()
|
||||
{
|
||||
return "Linux";
|
||||
}
|
||||
|
||||
bool SystemStats::isOperatingSystem64Bit()
|
||||
{
|
||||
#if JUCE_64BIT
|
||||
return true;
|
||||
#else
|
||||
//xxx not sure how to find this out?..
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
String SystemStats::getDeviceDescription()
|
||||
{
|
||||
#if JUCE_BSD
|
||||
int mib[] = {
|
||||
CTL_HW,
|
||||
HW_MACHINE
|
||||
};
|
||||
size_t machineDescriptionLength = 0;
|
||||
auto result = sysctl (mib, numElementsInArray (mib), nullptr, &machineDescriptionLength, nullptr, 0);
|
||||
|
||||
if (result != 0 || machineDescriptionLength == 0)
|
||||
return {};
|
||||
|
||||
MemoryBlock machineDescription { machineDescriptionLength };
|
||||
result = sysctl (mib, numElementsInArray (mib), machineDescription.getData(), &machineDescriptionLength, nullptr, 0);
|
||||
return String::fromUTF8 (result == 0 ? (char*) machineDescription.getData() : "");
|
||||
#else
|
||||
return getCpuInfo ("Hardware");
|
||||
#endif
|
||||
}
|
||||
|
||||
String SystemStats::getDeviceManufacturer()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
String SystemStats::getCpuVendor()
|
||||
{
|
||||
#if JUCE_BSD
|
||||
return {};
|
||||
#else
|
||||
auto v = getCpuInfo ("vendor_id");
|
||||
|
||||
if (v.isEmpty())
|
||||
v = getCpuInfo ("model name");
|
||||
|
||||
return v;
|
||||
#endif
|
||||
}
|
||||
|
||||
String SystemStats::getCpuModel()
|
||||
{
|
||||
#if JUCE_BSD
|
||||
int mib[] = {
|
||||
CTL_HW,
|
||||
HW_MODEL
|
||||
};
|
||||
size_t modelLength = 0;
|
||||
auto result = sysctl (mib, numElementsInArray (mib), nullptr, &modelLength, nullptr, 0);
|
||||
|
||||
if (result != 0 || modelLength == 0)
|
||||
return {};
|
||||
|
||||
MemoryBlock model { modelLength };
|
||||
result = sysctl (mib, numElementsInArray (mib), model.getData(), &modelLength, nullptr, 0);
|
||||
return String::fromUTF8 (result == 0 ? (char*) model.getData() : "");
|
||||
#else
|
||||
return getCpuInfo ("model name");
|
||||
#endif
|
||||
}
|
||||
|
||||
int SystemStats::getCpuSpeedInMegahertz()
|
||||
{
|
||||
#if JUCE_BSD
|
||||
int32 clockRate = 0;
|
||||
auto clockRateSize = sizeof (clockRate);
|
||||
auto result = sysctlbyname ("hw.clockrate", &clockRate, &clockRateSize, nullptr, 0);
|
||||
return result == 0 ? clockRate : 0;
|
||||
#else
|
||||
return roundToInt (getCpuInfo ("cpu MHz").getFloatValue());
|
||||
#endif
|
||||
}
|
||||
|
||||
int SystemStats::getMemorySizeInMegabytes()
|
||||
{
|
||||
#if JUCE_BSD
|
||||
int mib[] = {
|
||||
CTL_HW,
|
||||
HW_PHYSMEM
|
||||
};
|
||||
int64 memory = 0;
|
||||
auto memorySize = sizeof (memory);
|
||||
auto result = sysctl (mib, numElementsInArray (mib), &memory, &memorySize, nullptr, 0);
|
||||
return result == 0 ? (int) (memory / 1e6) : 0;
|
||||
#else
|
||||
struct sysinfo sysi;
|
||||
|
||||
if (sysinfo (&sysi) == 0)
|
||||
return (int) (sysi.totalram * sysi.mem_unit / (1024 * 1024));
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int SystemStats::getPageSize()
|
||||
{
|
||||
return (int) sysconf (_SC_PAGESIZE);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
String SystemStats::getLogonName()
|
||||
{
|
||||
if (auto user = getenv ("USER"))
|
||||
return String::fromUTF8 (user);
|
||||
|
||||
if (auto pw = getpwuid (getuid()))
|
||||
return String::fromUTF8 (pw->pw_name);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
String SystemStats::getFullUserName()
|
||||
{
|
||||
return getLogonName();
|
||||
}
|
||||
|
||||
String SystemStats::getComputerName()
|
||||
{
|
||||
char name[256] = {};
|
||||
|
||||
if (gethostname (name, sizeof (name) - 1) == 0)
|
||||
return name;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
String SystemStats::getUserLanguage()
|
||||
{
|
||||
#if JUCE_BSD
|
||||
if (auto langEnv = getenv ("LANG"))
|
||||
return String::fromUTF8 (langEnv).upToLastOccurrenceOf (".UTF-8", false, true);
|
||||
|
||||
return {};
|
||||
#else
|
||||
return getLocaleValue (_NL_IDENTIFICATION_LANGUAGE);
|
||||
#endif
|
||||
}
|
||||
|
||||
String SystemStats::getUserRegion()
|
||||
{
|
||||
#if JUCE_BSD
|
||||
return {};
|
||||
#else
|
||||
return getLocaleValue (_NL_IDENTIFICATION_TERRITORY);
|
||||
#endif
|
||||
}
|
||||
|
||||
String SystemStats::getDisplayLanguage()
|
||||
{
|
||||
auto result = getUserLanguage();
|
||||
auto region = getUserRegion();
|
||||
|
||||
if (region.isNotEmpty())
|
||||
result << "-" << region;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void CPUInformation::initialise() noexcept
|
||||
{
|
||||
#if JUCE_BSD
|
||||
#if JUCE_INTEL && ! JUCE_NO_INLINE_ASM
|
||||
SystemStatsHelpers::getCPUInfo (hasMMX,
|
||||
hasSSE,
|
||||
hasSSE2,
|
||||
has3DNow,
|
||||
hasSSE3,
|
||||
hasSSSE3,
|
||||
hasFMA3,
|
||||
hasSSE41,
|
||||
hasSSE42,
|
||||
hasAVX,
|
||||
hasFMA4,
|
||||
hasAVX2,
|
||||
hasAVX512F,
|
||||
hasAVX512DQ,
|
||||
hasAVX512IFMA,
|
||||
hasAVX512PF,
|
||||
hasAVX512ER,
|
||||
hasAVX512CD,
|
||||
hasAVX512BW,
|
||||
hasAVX512VL,
|
||||
hasAVX512VBMI,
|
||||
hasAVX512VPOPCNTDQ);
|
||||
#endif
|
||||
|
||||
numLogicalCPUs = numPhysicalCPUs = []
|
||||
{
|
||||
int mib[] = {
|
||||
CTL_HW,
|
||||
HW_NCPU
|
||||
};
|
||||
int32 numCPUs = 1;
|
||||
auto numCPUsSize = sizeof (numCPUs);
|
||||
auto result = sysctl (mib, numElementsInArray (mib), &numCPUs, &numCPUsSize, nullptr, 0);
|
||||
return result == 0 ? numCPUs : 1;
|
||||
}();
|
||||
#else
|
||||
auto flags = getCpuInfo ("flags");
|
||||
|
||||
hasMMX = flags.contains ("mmx");
|
||||
hasFMA3 = flags.contains ("fma");
|
||||
hasFMA4 = flags.contains ("fma4");
|
||||
hasSSE = flags.contains ("sse");
|
||||
hasSSE2 = flags.contains ("sse2");
|
||||
hasSSE3 = flags.contains ("sse3");
|
||||
has3DNow = flags.contains ("3dnow");
|
||||
hasSSSE3 = flags.contains ("ssse3");
|
||||
hasSSE41 = flags.contains ("sse4_1");
|
||||
hasSSE42 = flags.contains ("sse4_2");
|
||||
hasAVX = flags.contains ("avx");
|
||||
hasAVX2 = flags.contains ("avx2");
|
||||
hasAVX512F = flags.contains ("avx512f");
|
||||
hasAVX512BW = flags.contains ("avx512bw");
|
||||
hasAVX512CD = flags.contains ("avx512cd");
|
||||
hasAVX512DQ = flags.contains ("avx512dq");
|
||||
hasAVX512ER = flags.contains ("avx512er");
|
||||
hasAVX512IFMA = flags.contains ("avx512ifma");
|
||||
hasAVX512PF = flags.contains ("avx512pf");
|
||||
hasAVX512VBMI = flags.contains ("avx512vbmi");
|
||||
hasAVX512VL = flags.contains ("avx512vl");
|
||||
hasAVX512VPOPCNTDQ = flags.contains ("avx512_vpopcntdq");
|
||||
|
||||
numLogicalCPUs = getCpuInfo ("processor").getIntValue() + 1;
|
||||
|
||||
// Assume CPUs in all sockets have the same number of cores
|
||||
numPhysicalCPUs = getCpuInfo ("cpu cores").getIntValue() * (getCpuInfo ("physical id").getIntValue() + 1);
|
||||
|
||||
if (numPhysicalCPUs <= 0)
|
||||
numPhysicalCPUs = numLogicalCPUs;
|
||||
#endif
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
uint32 juce_millisecondsSinceStartup() noexcept
|
||||
{
|
||||
return (uint32) (Time::getHighResolutionTicks() / 1000);
|
||||
}
|
||||
|
||||
int64 Time::getHighResolutionTicks() noexcept
|
||||
{
|
||||
timespec t;
|
||||
|
||||
#if JUCE_BELA
|
||||
if (cobalt_thread_mode() == 0x200 /*XNRELAX*/)
|
||||
clock_gettime (CLOCK_MONOTONIC, &t);
|
||||
else
|
||||
__wrap_clock_gettime (CLOCK_MONOTONIC, &t);
|
||||
#else
|
||||
clock_gettime (CLOCK_MONOTONIC, &t);
|
||||
#endif
|
||||
|
||||
return (t.tv_sec * (int64) 1000000) + (t.tv_nsec / 1000);
|
||||
}
|
||||
|
||||
int64 Time::getHighResolutionTicksPerSecond() noexcept
|
||||
{
|
||||
return 1000000; // (microseconds)
|
||||
}
|
||||
|
||||
double Time::getMillisecondCounterHiRes() noexcept
|
||||
{
|
||||
return (double) getHighResolutionTicks() * 0.001;
|
||||
}
|
||||
|
||||
bool Time::setSystemTimeToThisTime() const
|
||||
{
|
||||
timeval t;
|
||||
t.tv_sec = decltype (timeval::tv_sec) (millisSinceEpoch / 1000);
|
||||
t.tv_usec = decltype (timeval::tv_usec) ((millisSinceEpoch - t.tv_sec * 1000) * 1000);
|
||||
|
||||
return settimeofday (&t, nullptr) == 0;
|
||||
}
|
||||
|
||||
JUCE_API bool JUCE_CALLTYPE juce_isRunningUnderDebugger() noexcept
|
||||
{
|
||||
#if JUCE_BSD
|
||||
int mib[] =
|
||||
{
|
||||
CTL_KERN,
|
||||
KERN_PROC,
|
||||
KERN_PROC_PID,
|
||||
::getpid()
|
||||
};
|
||||
struct kinfo_proc info;
|
||||
auto infoSize = sizeof (info);
|
||||
auto result = sysctl (mib, numElementsInArray (mib), &info, &infoSize, nullptr, 0);
|
||||
return result == 0 ? ((info.ki_flag & P_TRACED) != 0) : false;
|
||||
#else
|
||||
return readPosixConfigFileValue ("/proc/self/status", "TracerPid").getIntValue() > 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#if JUCE_BELA
|
||||
extern "C" int cobalt_thread_mode();
|
||||
#endif
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
#if ! JUCE_BSD
|
||||
static String getCpuInfo (const char* key)
|
||||
{
|
||||
return readPosixConfigFileValue ("/proc/cpuinfo", key);
|
||||
}
|
||||
|
||||
static String getLocaleValue (nl_item key)
|
||||
{
|
||||
auto oldLocale = ::setlocale (LC_ALL, "");
|
||||
auto result = String::fromUTF8 (nl_langinfo (key));
|
||||
::setlocale (LC_ALL, oldLocale);
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
void Logger::outputDebugString (const String& text)
|
||||
{
|
||||
std::cerr << text << std::endl;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
SystemStats::OperatingSystemType SystemStats::getOperatingSystemType()
|
||||
{
|
||||
return Linux;
|
||||
}
|
||||
|
||||
String SystemStats::getOperatingSystemName()
|
||||
{
|
||||
return "Linux";
|
||||
}
|
||||
|
||||
bool SystemStats::isOperatingSystem64Bit()
|
||||
{
|
||||
#if JUCE_64BIT
|
||||
return true;
|
||||
#else
|
||||
//xxx not sure how to find this out?..
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
String SystemStats::getDeviceDescription()
|
||||
{
|
||||
#if JUCE_BSD
|
||||
int mib[] = {
|
||||
CTL_HW,
|
||||
HW_MACHINE
|
||||
};
|
||||
size_t machineDescriptionLength = 0;
|
||||
auto result = sysctl (mib, numElementsInArray (mib), nullptr, &machineDescriptionLength, nullptr, 0);
|
||||
|
||||
if (result != 0 || machineDescriptionLength == 0)
|
||||
return {};
|
||||
|
||||
MemoryBlock machineDescription { machineDescriptionLength };
|
||||
result = sysctl (mib, numElementsInArray (mib), machineDescription.getData(), &machineDescriptionLength, nullptr, 0);
|
||||
return String::fromUTF8 (result == 0 ? (char*) machineDescription.getData() : "");
|
||||
#else
|
||||
return getCpuInfo ("Hardware");
|
||||
#endif
|
||||
}
|
||||
|
||||
String SystemStats::getDeviceManufacturer()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
String SystemStats::getCpuVendor()
|
||||
{
|
||||
#if JUCE_BSD
|
||||
return {};
|
||||
#else
|
||||
auto v = getCpuInfo ("vendor_id");
|
||||
|
||||
if (v.isEmpty())
|
||||
v = getCpuInfo ("model name");
|
||||
|
||||
return v;
|
||||
#endif
|
||||
}
|
||||
|
||||
String SystemStats::getCpuModel()
|
||||
{
|
||||
#if JUCE_BSD
|
||||
int mib[] = {
|
||||
CTL_HW,
|
||||
HW_MODEL
|
||||
};
|
||||
size_t modelLength = 0;
|
||||
auto result = sysctl (mib, numElementsInArray (mib), nullptr, &modelLength, nullptr, 0);
|
||||
|
||||
if (result != 0 || modelLength == 0)
|
||||
return {};
|
||||
|
||||
MemoryBlock model { modelLength };
|
||||
result = sysctl (mib, numElementsInArray (mib), model.getData(), &modelLength, nullptr, 0);
|
||||
return String::fromUTF8 (result == 0 ? (char*) model.getData() : "");
|
||||
#else
|
||||
return getCpuInfo ("model name");
|
||||
#endif
|
||||
}
|
||||
|
||||
int SystemStats::getCpuSpeedInMegahertz()
|
||||
{
|
||||
#if JUCE_BSD
|
||||
int32 clockRate = 0;
|
||||
auto clockRateSize = sizeof (clockRate);
|
||||
auto result = sysctlbyname ("hw.clockrate", &clockRate, &clockRateSize, nullptr, 0);
|
||||
return result == 0 ? clockRate : 0;
|
||||
#else
|
||||
return roundToInt (getCpuInfo ("cpu MHz").getFloatValue());
|
||||
#endif
|
||||
}
|
||||
|
||||
int SystemStats::getMemorySizeInMegabytes()
|
||||
{
|
||||
#if JUCE_BSD
|
||||
int mib[] = {
|
||||
CTL_HW,
|
||||
HW_PHYSMEM
|
||||
};
|
||||
int64 memory = 0;
|
||||
auto memorySize = sizeof (memory);
|
||||
auto result = sysctl (mib, numElementsInArray (mib), &memory, &memorySize, nullptr, 0);
|
||||
return result == 0 ? (int) (memory / 1e6) : 0;
|
||||
#else
|
||||
struct sysinfo sysi;
|
||||
|
||||
if (sysinfo (&sysi) == 0)
|
||||
return (int) (sysi.totalram * sysi.mem_unit / (1024 * 1024));
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int SystemStats::getPageSize()
|
||||
{
|
||||
return (int) sysconf (_SC_PAGESIZE);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
String SystemStats::getLogonName()
|
||||
{
|
||||
if (auto user = getenv ("USER"))
|
||||
return String::fromUTF8 (user);
|
||||
|
||||
if (auto pw = getpwuid (getuid()))
|
||||
return String::fromUTF8 (pw->pw_name);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
String SystemStats::getFullUserName()
|
||||
{
|
||||
return getLogonName();
|
||||
}
|
||||
|
||||
String SystemStats::getComputerName()
|
||||
{
|
||||
char name[256] = {};
|
||||
|
||||
if (gethostname (name, sizeof (name) - 1) == 0)
|
||||
return name;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
String SystemStats::getUserLanguage()
|
||||
{
|
||||
#if JUCE_BSD
|
||||
if (auto langEnv = getenv ("LANG"))
|
||||
return String::fromUTF8 (langEnv).upToLastOccurrenceOf (".UTF-8", false, true);
|
||||
|
||||
return {};
|
||||
#else
|
||||
return getLocaleValue (_NL_IDENTIFICATION_LANGUAGE);
|
||||
#endif
|
||||
}
|
||||
|
||||
String SystemStats::getUserRegion()
|
||||
{
|
||||
#if JUCE_BSD
|
||||
return {};
|
||||
#else
|
||||
return getLocaleValue (_NL_IDENTIFICATION_TERRITORY);
|
||||
#endif
|
||||
}
|
||||
|
||||
String SystemStats::getDisplayLanguage()
|
||||
{
|
||||
auto result = getUserLanguage();
|
||||
auto region = getUserRegion();
|
||||
|
||||
if (region.isNotEmpty())
|
||||
result << "-" << region;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void CPUInformation::initialise() noexcept
|
||||
{
|
||||
#if JUCE_BSD
|
||||
#if JUCE_INTEL && ! JUCE_NO_INLINE_ASM
|
||||
SystemStatsHelpers::getCPUInfo (hasMMX,
|
||||
hasSSE,
|
||||
hasSSE2,
|
||||
has3DNow,
|
||||
hasSSE3,
|
||||
hasSSSE3,
|
||||
hasFMA3,
|
||||
hasSSE41,
|
||||
hasSSE42,
|
||||
hasAVX,
|
||||
hasFMA4,
|
||||
hasAVX2,
|
||||
hasAVX512F,
|
||||
hasAVX512DQ,
|
||||
hasAVX512IFMA,
|
||||
hasAVX512PF,
|
||||
hasAVX512ER,
|
||||
hasAVX512CD,
|
||||
hasAVX512BW,
|
||||
hasAVX512VL,
|
||||
hasAVX512VBMI,
|
||||
hasAVX512VPOPCNTDQ);
|
||||
#endif
|
||||
|
||||
numLogicalCPUs = numPhysicalCPUs = []
|
||||
{
|
||||
int mib[] = {
|
||||
CTL_HW,
|
||||
HW_NCPU
|
||||
};
|
||||
int32 numCPUs = 1;
|
||||
auto numCPUsSize = sizeof (numCPUs);
|
||||
auto result = sysctl (mib, numElementsInArray (mib), &numCPUs, &numCPUsSize, nullptr, 0);
|
||||
return result == 0 ? numCPUs : 1;
|
||||
}();
|
||||
#else
|
||||
auto flags = getCpuInfo ("flags");
|
||||
|
||||
hasMMX = flags.contains ("mmx");
|
||||
hasFMA3 = flags.contains ("fma");
|
||||
hasFMA4 = flags.contains ("fma4");
|
||||
hasSSE = flags.contains ("sse");
|
||||
hasSSE2 = flags.contains ("sse2");
|
||||
hasSSE3 = flags.contains ("sse3");
|
||||
has3DNow = flags.contains ("3dnow");
|
||||
hasSSSE3 = flags.contains ("ssse3");
|
||||
hasSSE41 = flags.contains ("sse4_1");
|
||||
hasSSE42 = flags.contains ("sse4_2");
|
||||
hasAVX = flags.contains ("avx");
|
||||
hasAVX2 = flags.contains ("avx2");
|
||||
hasAVX512F = flags.contains ("avx512f");
|
||||
hasAVX512BW = flags.contains ("avx512bw");
|
||||
hasAVX512CD = flags.contains ("avx512cd");
|
||||
hasAVX512DQ = flags.contains ("avx512dq");
|
||||
hasAVX512ER = flags.contains ("avx512er");
|
||||
hasAVX512IFMA = flags.contains ("avx512ifma");
|
||||
hasAVX512PF = flags.contains ("avx512pf");
|
||||
hasAVX512VBMI = flags.contains ("avx512vbmi");
|
||||
hasAVX512VL = flags.contains ("avx512vl");
|
||||
hasAVX512VPOPCNTDQ = flags.contains ("avx512_vpopcntdq");
|
||||
|
||||
numLogicalCPUs = getCpuInfo ("processor").getIntValue() + 1;
|
||||
|
||||
// Assume CPUs in all sockets have the same number of cores
|
||||
numPhysicalCPUs = getCpuInfo ("cpu cores").getIntValue() * (getCpuInfo ("physical id").getIntValue() + 1);
|
||||
|
||||
if (numPhysicalCPUs <= 0)
|
||||
numPhysicalCPUs = numLogicalCPUs;
|
||||
#endif
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
uint32 juce_millisecondsSinceStartup() noexcept
|
||||
{
|
||||
return (uint32) (Time::getHighResolutionTicks() / 1000);
|
||||
}
|
||||
|
||||
int64 Time::getHighResolutionTicks() noexcept
|
||||
{
|
||||
timespec t;
|
||||
|
||||
#if JUCE_BELA
|
||||
if (cobalt_thread_mode() == 0x200 /*XNRELAX*/)
|
||||
clock_gettime (CLOCK_MONOTONIC, &t);
|
||||
else
|
||||
__wrap_clock_gettime (CLOCK_MONOTONIC, &t);
|
||||
#else
|
||||
clock_gettime (CLOCK_MONOTONIC, &t);
|
||||
#endif
|
||||
|
||||
return (t.tv_sec * (int64) 1000000) + (t.tv_nsec / 1000);
|
||||
}
|
||||
|
||||
int64 Time::getHighResolutionTicksPerSecond() noexcept
|
||||
{
|
||||
return 1000000; // (microseconds)
|
||||
}
|
||||
|
||||
double Time::getMillisecondCounterHiRes() noexcept
|
||||
{
|
||||
return (double) getHighResolutionTicks() * 0.001;
|
||||
}
|
||||
|
||||
bool Time::setSystemTimeToThisTime() const
|
||||
{
|
||||
timeval t;
|
||||
t.tv_sec = decltype (timeval::tv_sec) (millisSinceEpoch / 1000);
|
||||
t.tv_usec = decltype (timeval::tv_usec) ((millisSinceEpoch - t.tv_sec * 1000) * 1000);
|
||||
|
||||
return settimeofday (&t, nullptr) == 0;
|
||||
}
|
||||
|
||||
JUCE_API bool JUCE_CALLTYPE juce_isRunningUnderDebugger() noexcept
|
||||
{
|
||||
#if JUCE_BSD
|
||||
int mib[] =
|
||||
{
|
||||
CTL_KERN,
|
||||
KERN_PROC,
|
||||
KERN_PROC_PID,
|
||||
::getpid()
|
||||
};
|
||||
struct kinfo_proc info;
|
||||
auto infoSize = sizeof (info);
|
||||
auto result = sysctl (mib, numElementsInArray (mib), &info, &infoSize, nullptr, 0);
|
||||
return result == 0 ? ((info.ki_flag & P_TRACED) != 0) : false;
|
||||
#else
|
||||
return readPosixConfigFileValue ("/proc/self/status", "TracerPid").getIntValue() > 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
|
@ -1,62 +1,62 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
/*
|
||||
Note that a lot of methods that you'd expect to find in this file actually
|
||||
live in juce_posix_SharedCode.h!
|
||||
*/
|
||||
|
||||
//==============================================================================
|
||||
JUCE_API void JUCE_CALLTYPE Process::setPriority (const ProcessPriority prior)
|
||||
{
|
||||
auto policy = (prior <= NormalPriority) ? SCHED_OTHER : SCHED_RR;
|
||||
auto minp = sched_get_priority_min (policy);
|
||||
auto maxp = sched_get_priority_max (policy);
|
||||
|
||||
struct sched_param param;
|
||||
|
||||
switch (prior)
|
||||
{
|
||||
case LowPriority:
|
||||
case NormalPriority: param.sched_priority = 0; break;
|
||||
case HighPriority: param.sched_priority = minp + (maxp - minp) / 4; break;
|
||||
case RealtimePriority: param.sched_priority = minp + (3 * (maxp - minp) / 4); break;
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
|
||||
pthread_setschedparam (pthread_self(), policy, ¶m);
|
||||
}
|
||||
|
||||
static bool swapUserAndEffectiveUser()
|
||||
{
|
||||
auto result1 = setreuid (geteuid(), getuid());
|
||||
auto result2 = setregid (getegid(), getgid());
|
||||
return result1 == 0 && result2 == 0;
|
||||
}
|
||||
|
||||
JUCE_API void JUCE_CALLTYPE Process::raisePrivilege() { if (geteuid() != 0 && getuid() == 0) swapUserAndEffectiveUser(); }
|
||||
JUCE_API void JUCE_CALLTYPE Process::lowerPrivilege() { if (geteuid() == 0 && getuid() != 0) swapUserAndEffectiveUser(); }
|
||||
|
||||
} // namespace juce
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
/*
|
||||
Note that a lot of methods that you'd expect to find in this file actually
|
||||
live in juce_posix_SharedCode.h!
|
||||
*/
|
||||
|
||||
//==============================================================================
|
||||
JUCE_API void JUCE_CALLTYPE Process::setPriority (const ProcessPriority prior)
|
||||
{
|
||||
auto policy = (prior <= NormalPriority) ? SCHED_OTHER : SCHED_RR;
|
||||
auto minp = sched_get_priority_min (policy);
|
||||
auto maxp = sched_get_priority_max (policy);
|
||||
|
||||
struct sched_param param;
|
||||
|
||||
switch (prior)
|
||||
{
|
||||
case LowPriority:
|
||||
case NormalPriority: param.sched_priority = 0; break;
|
||||
case HighPriority: param.sched_priority = minp + (maxp - minp) / 4; break;
|
||||
case RealtimePriority: param.sched_priority = minp + (3 * (maxp - minp) / 4); break;
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
|
||||
pthread_setschedparam (pthread_self(), policy, ¶m);
|
||||
}
|
||||
|
||||
static bool swapUserAndEffectiveUser()
|
||||
{
|
||||
auto result1 = setreuid (geteuid(), getuid());
|
||||
auto result2 = setregid (getegid(), getgid());
|
||||
return result1 == 0 && result2 == 0;
|
||||
}
|
||||
|
||||
JUCE_API void JUCE_CALLTYPE Process::raisePrivilege() { if (geteuid() != 0 && getuid() == 0) swapUserAndEffectiveUser(); }
|
||||
JUCE_API void JUCE_CALLTYPE Process::lowerPrivilege() { if (geteuid() == 0 && getuid() != 0) swapUserAndEffectiveUser(); }
|
||||
|
||||
} // namespace juce
|
||||
|
@ -1,64 +1,64 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
/* This file contains a few helper functions that are used internally but which
|
||||
need to be kept away from the public headers because they use obj-C symbols.
|
||||
*/
|
||||
namespace juce
|
||||
{
|
||||
|
||||
template <typename CFType>
|
||||
struct CFObjectDeleter
|
||||
{
|
||||
void operator() (CFType object) const noexcept
|
||||
{
|
||||
if (object != nullptr)
|
||||
CFRelease (object);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename CFType>
|
||||
using CFUniquePtr = std::unique_ptr<typename std::remove_pointer<CFType>::type, CFObjectDeleter<CFType>>;
|
||||
|
||||
template <typename CFType>
|
||||
struct CFObjectHolder
|
||||
{
|
||||
CFObjectHolder() = default;
|
||||
explicit CFObjectHolder (CFType obj) : object (obj) {}
|
||||
|
||||
CFObjectHolder (const CFObjectHolder&) = delete;
|
||||
CFObjectHolder (CFObjectHolder&&) = delete;
|
||||
|
||||
CFObjectHolder& operator= (const CFObjectHolder&) = delete;
|
||||
CFObjectHolder& operator= (CFObjectHolder&&) = delete;
|
||||
|
||||
~CFObjectHolder() noexcept
|
||||
{
|
||||
if (object != nullptr)
|
||||
CFRelease (object);
|
||||
}
|
||||
|
||||
// Public to facilitate passing the pointer address to functions
|
||||
CFType object = nullptr;
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
/* This file contains a few helper functions that are used internally but which
|
||||
need to be kept away from the public headers because they use obj-C symbols.
|
||||
*/
|
||||
namespace juce
|
||||
{
|
||||
|
||||
template <typename CFType>
|
||||
struct CFObjectDeleter
|
||||
{
|
||||
void operator() (CFType object) const noexcept
|
||||
{
|
||||
if (object != nullptr)
|
||||
CFRelease (object);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename CFType>
|
||||
using CFUniquePtr = std::unique_ptr<typename std::remove_pointer<CFType>::type, CFObjectDeleter<CFType>>;
|
||||
|
||||
template <typename CFType>
|
||||
struct CFObjectHolder
|
||||
{
|
||||
CFObjectHolder() = default;
|
||||
explicit CFObjectHolder (CFType obj) : object (obj) {}
|
||||
|
||||
CFObjectHolder (const CFObjectHolder&) = delete;
|
||||
CFObjectHolder (CFObjectHolder&&) = delete;
|
||||
|
||||
CFObjectHolder& operator= (const CFObjectHolder&) = delete;
|
||||
CFObjectHolder& operator= (CFObjectHolder&&) = delete;
|
||||
|
||||
~CFObjectHolder() noexcept
|
||||
{
|
||||
if (object != nullptr)
|
||||
CFRelease (object);
|
||||
}
|
||||
|
||||
// Public to facilitate passing the pointer address to functions
|
||||
CFType object = nullptr;
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
|
@ -2,7 +2,7 @@
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
@ -201,7 +201,7 @@ File File::getSpecialLocation (const SpecialLocationType type)
|
||||
|
||||
case invokedExecutableFile:
|
||||
if (juce_argv != nullptr && juce_argc > 0)
|
||||
return File::getCurrentWorkingDirectory().getChildFile (CharPointer_UTF8 (juce_argv[0]));
|
||||
return File::getCurrentWorkingDirectory().getChildFile (String (CharPointer_UTF8 (juce_argv[0])));
|
||||
// deliberate fall-through...
|
||||
JUCE_FALLTHROUGH
|
||||
|
||||
@ -285,7 +285,6 @@ bool File::moveToTrash() const
|
||||
|
||||
JUCE_AUTORELEASEPOOL
|
||||
{
|
||||
#if JUCE_MAC || (JUCE_IOS && (defined (__IPHONE_11_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0))
|
||||
if (@available (macOS 10.8, iOS 11.0, *))
|
||||
{
|
||||
NSError* error = nil;
|
||||
@ -293,7 +292,6 @@ bool File::moveToTrash() const
|
||||
resultingItemURL: nil
|
||||
error: &error];
|
||||
}
|
||||
#endif
|
||||
|
||||
#if JUCE_IOS
|
||||
return deleteFile();
|
||||
@ -410,12 +408,18 @@ bool JUCE_CALLTYPE Process::openDocument (const String& fileName, const String&
|
||||
#if JUCE_IOS
|
||||
ignoreUnused (parameters);
|
||||
|
||||
#if (! defined __IPHONE_OS_VERSION_MIN_REQUIRED) || (! defined __IPHONE_10_0) || (__IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_10_0)
|
||||
if (@available (iOS 10.0, *))
|
||||
{
|
||||
[[UIApplication sharedApplication] openURL: filenameAsURL
|
||||
options: @{}
|
||||
completionHandler: nil];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
|
||||
return [[UIApplication sharedApplication] openURL: filenameAsURL];
|
||||
#else
|
||||
[[UIApplication sharedApplication] openURL: filenameAsURL options: @{} completionHandler: nil];
|
||||
return true;
|
||||
#endif
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
#else
|
||||
NSWorkspace* workspace = [NSWorkspace sharedWorkspace];
|
||||
|
||||
@ -434,16 +438,23 @@ bool JUCE_CALLTYPE Process::openDocument (const String& fileName, const String&
|
||||
for (int i = 0; i < params.size(); ++i)
|
||||
[paramArray addObject: juceStringToNS (params[i])];
|
||||
|
||||
#if (defined MAC_OS_X_VERSION_10_15) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_15
|
||||
auto config = [NSWorkspaceOpenConfiguration configuration];
|
||||
[config setCreatesNewApplicationInstance: YES];
|
||||
config.arguments = paramArray;
|
||||
#if defined (MAC_OS_X_VERSION_10_15) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_15
|
||||
if (@available (macOS 10.15, *))
|
||||
{
|
||||
auto config = [NSWorkspaceOpenConfiguration configuration];
|
||||
[config setCreatesNewApplicationInstance: YES];
|
||||
config.arguments = paramArray;
|
||||
|
||||
[workspace openApplicationAtURL: filenameAsURL
|
||||
configuration: config
|
||||
completionHandler: nil];
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
|
||||
|
||||
[workspace openApplicationAtURL: filenameAsURL
|
||||
configuration: config
|
||||
completionHandler: nil];
|
||||
return true;
|
||||
#else
|
||||
NSMutableDictionary* dict = [[NSMutableDictionary new] autorelease];
|
||||
|
||||
[dict setObject: paramArray
|
||||
@ -453,7 +464,8 @@ bool JUCE_CALLTYPE Process::openDocument (const String& fileName, const String&
|
||||
options: NSWorkspaceLaunchDefault | NSWorkspaceLaunchNewInstance
|
||||
configuration: dict
|
||||
error: nil];
|
||||
#endif
|
||||
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
}
|
||||
|
||||
if (file.exists())
|
||||
@ -512,8 +524,9 @@ void File::addToDock() const
|
||||
|
||||
File File::getContainerForSecurityApplicationGroupIdentifier (const String& appGroup)
|
||||
{
|
||||
if (auto* url = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier: juceStringToNS (appGroup)])
|
||||
return File (nsStringToJuce ([url path]));
|
||||
if (@available (macOS 10.8, *))
|
||||
if (auto* url = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier: juceStringToNS (appGroup)])
|
||||
return File (nsStringToJuce ([url path]));
|
||||
|
||||
return File();
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
@ -109,18 +109,295 @@ bool JUCE_CALLTYPE Process::openEmailWithAttachments (const String& targetEmailA
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// Unfortunately, we need to have this ugly ifdef here as long as some older OS X versions do not support NSURLSession
|
||||
#if JUCE_IOS || (defined (MAC_OS_X_VERSION_10_10) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10)
|
||||
|
||||
//==============================================================================
|
||||
class URLConnectionState : private Thread
|
||||
class URLConnectionStateBase : public Thread
|
||||
{
|
||||
public:
|
||||
URLConnectionState (NSURLRequest* req, const int maxRedirects)
|
||||
explicit URLConnectionStateBase (NSURLRequest* req, int maxRedirects)
|
||||
: Thread ("http connection"),
|
||||
request ([req retain]),
|
||||
data ([[NSMutableData data] retain]),
|
||||
numRedirectsToFollow (maxRedirects)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~URLConnectionStateBase() = default;
|
||||
|
||||
virtual void cancel() = 0;
|
||||
virtual bool start (WebInputStream&, WebInputStream::Listener*) = 0;
|
||||
virtual int read (char* dest, int numBytes) = 0;
|
||||
|
||||
int64 getContentLength() const noexcept { return contentLength; }
|
||||
NSDictionary* getHeaders() const noexcept { return headers; }
|
||||
int getStatusCode() const noexcept { return statusCode; }
|
||||
NSInteger getErrorCode() const noexcept { return nsUrlErrorCode; }
|
||||
|
||||
protected:
|
||||
CriticalSection dataLock, createConnectionLock;
|
||||
id delegate = nil;
|
||||
NSDictionary* headers = nil;
|
||||
NSURLRequest* request = nil;
|
||||
NSMutableData* data = nil;
|
||||
int64 contentLength = -1;
|
||||
int statusCode = 0;
|
||||
NSInteger nsUrlErrorCode = 0;
|
||||
|
||||
std::atomic<bool> initialised { false }, hasFailed { false }, hasFinished { false };
|
||||
const int numRedirectsToFollow;
|
||||
int numRedirects = 0;
|
||||
int64 latestTotalBytes = 0;
|
||||
bool hasBeenCancelled = false;
|
||||
|
||||
private:
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (URLConnectionStateBase)
|
||||
};
|
||||
|
||||
#if JUCE_MAC
|
||||
// This version is only used for backwards-compatibility with older OSX targets,
|
||||
// so we'll turn off deprecation warnings. This code will be removed at some point
|
||||
// in the future.
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated")
|
||||
class URLConnectionStatePreYosemite : public URLConnectionStateBase
|
||||
{
|
||||
public:
|
||||
URLConnectionStatePreYosemite (NSURLRequest* req, const int maxRedirects)
|
||||
: URLConnectionStateBase (req, maxRedirects)
|
||||
{
|
||||
static DelegateClass cls;
|
||||
delegate = [cls.createInstance() init];
|
||||
DelegateClass::setState (delegate, this);
|
||||
}
|
||||
|
||||
~URLConnectionStatePreYosemite() override
|
||||
{
|
||||
stop();
|
||||
|
||||
[connection release];
|
||||
[request release];
|
||||
[headers release];
|
||||
[delegate release];
|
||||
[data release];
|
||||
}
|
||||
|
||||
bool start (WebInputStream& inputStream, WebInputStream::Listener* listener) override
|
||||
{
|
||||
startThread();
|
||||
|
||||
while (isThreadRunning() && ! initialised)
|
||||
{
|
||||
if (listener != nullptr)
|
||||
if (! listener->postDataSendProgress (inputStream, (int) latestTotalBytes, (int) [[request HTTPBody] length]))
|
||||
return false;
|
||||
|
||||
Thread::sleep (1);
|
||||
}
|
||||
|
||||
return connection != nil && ! hasFailed;
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
{
|
||||
const ScopedLock dLock (dataLock);
|
||||
const ScopedLock connectionLock (createConnectionLock);
|
||||
|
||||
hasBeenCancelled = true;
|
||||
|
||||
if (connection != nil)
|
||||
[connection cancel];
|
||||
}
|
||||
|
||||
stopThread (10000);
|
||||
}
|
||||
|
||||
void cancel() override
|
||||
{
|
||||
hasFinished = hasFailed = true;
|
||||
stop();
|
||||
}
|
||||
|
||||
int read (char* dest, int numBytes) override
|
||||
{
|
||||
int numDone = 0;
|
||||
|
||||
while (numBytes > 0)
|
||||
{
|
||||
const ScopedLock sl (dataLock);
|
||||
auto available = jmin (numBytes, (int) [data length]);
|
||||
|
||||
if (available > 0)
|
||||
{
|
||||
[data getBytes: dest length: (NSUInteger) available];
|
||||
[data replaceBytesInRange: NSMakeRange (0, (NSUInteger) available) withBytes: nil length: 0];
|
||||
|
||||
numDone += available;
|
||||
numBytes -= available;
|
||||
dest += available;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hasFailed || hasFinished)
|
||||
break;
|
||||
|
||||
const ScopedUnlock sul (dataLock);
|
||||
Thread::sleep (1);
|
||||
}
|
||||
}
|
||||
|
||||
return numDone;
|
||||
}
|
||||
|
||||
void didReceiveResponse (NSURLResponse* response)
|
||||
{
|
||||
{
|
||||
const ScopedLock sl (dataLock);
|
||||
[data setLength: 0];
|
||||
}
|
||||
|
||||
contentLength = [response expectedContentLength];
|
||||
|
||||
[headers release];
|
||||
headers = nil;
|
||||
|
||||
if ([response isKindOfClass: [NSHTTPURLResponse class]])
|
||||
{
|
||||
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*) response;
|
||||
headers = [[httpResponse allHeaderFields] retain];
|
||||
statusCode = (int) [httpResponse statusCode];
|
||||
}
|
||||
|
||||
initialised = true;
|
||||
}
|
||||
|
||||
NSURLRequest* willSendRequest (NSURLRequest* newRequest, NSURLResponse* redirectResponse)
|
||||
{
|
||||
if (redirectResponse != nullptr)
|
||||
{
|
||||
if (numRedirects >= numRedirectsToFollow)
|
||||
return nil; // Cancel redirect and allow connection to continue
|
||||
|
||||
++numRedirects;
|
||||
}
|
||||
|
||||
return newRequest;
|
||||
}
|
||||
|
||||
void didFailWithError (NSError* error)
|
||||
{
|
||||
DBG (nsStringToJuce ([error description])); ignoreUnused (error);
|
||||
nsUrlErrorCode = [error code];
|
||||
hasFailed = true;
|
||||
initialised = true;
|
||||
signalThreadShouldExit();
|
||||
}
|
||||
|
||||
void didReceiveData (NSData* newData)
|
||||
{
|
||||
const ScopedLock sl (dataLock);
|
||||
[data appendData: newData];
|
||||
initialised = true;
|
||||
}
|
||||
|
||||
void didSendBodyData (NSInteger totalBytesWritten, NSInteger /*totalBytesExpected*/)
|
||||
{
|
||||
latestTotalBytes = static_cast<int> (totalBytesWritten);
|
||||
}
|
||||
|
||||
void finishedLoading()
|
||||
{
|
||||
hasFinished = true;
|
||||
initialised = true;
|
||||
signalThreadShouldExit();
|
||||
}
|
||||
|
||||
void run() override
|
||||
{
|
||||
{
|
||||
const ScopedLock lock (createConnectionLock);
|
||||
|
||||
if (hasBeenCancelled)
|
||||
return;
|
||||
|
||||
connection = [[NSURLConnection alloc] initWithRequest: request
|
||||
delegate: delegate];
|
||||
}
|
||||
|
||||
while (! threadShouldExit())
|
||||
{
|
||||
JUCE_AUTORELEASEPOOL
|
||||
{
|
||||
[[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
struct DelegateClass : public ObjCClass<NSObject>
|
||||
{
|
||||
DelegateClass() : ObjCClass<NSObject> ("JUCENetworkDelegate_")
|
||||
{
|
||||
addIvar<URLConnectionStatePreYosemite*> ("state");
|
||||
|
||||
addMethod (@selector (connection:didReceiveResponse:), didReceiveResponse);
|
||||
addMethod (@selector (connection:didFailWithError:), didFailWithError);
|
||||
addMethod (@selector (connection:didReceiveData:), didReceiveData);
|
||||
addMethod (@selector (connection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite:),
|
||||
connectionDidSendBodyData);
|
||||
addMethod (@selector (connectionDidFinishLoading:), connectionDidFinishLoading);
|
||||
addMethod (@selector (connection:willSendRequest:redirectResponse:), willSendRequest);
|
||||
|
||||
registerClass();
|
||||
}
|
||||
|
||||
static void setState (id self, URLConnectionStatePreYosemite* state) { object_setInstanceVariable (self, "state", state); }
|
||||
static URLConnectionStatePreYosemite* getState (id self) { return getIvar<URLConnectionStatePreYosemite*> (self, "state"); }
|
||||
|
||||
private:
|
||||
static void didReceiveResponse (id self, SEL, NSURLConnection*, NSURLResponse* response)
|
||||
{
|
||||
getState (self)->didReceiveResponse (response);
|
||||
}
|
||||
|
||||
static void didFailWithError (id self, SEL, NSURLConnection*, NSError* error)
|
||||
{
|
||||
getState (self)->didFailWithError (error);
|
||||
}
|
||||
|
||||
static void didReceiveData (id self, SEL, NSURLConnection*, NSData* newData)
|
||||
{
|
||||
getState (self)->didReceiveData (newData);
|
||||
}
|
||||
|
||||
static NSURLRequest* willSendRequest (id self, SEL, NSURLConnection*, NSURLRequest* request, NSURLResponse* response)
|
||||
{
|
||||
return getState (self)->willSendRequest (request, response);
|
||||
}
|
||||
|
||||
static void connectionDidSendBodyData (id self, SEL, NSURLConnection*, NSInteger, NSInteger totalBytesWritten, NSInteger totalBytesExpected)
|
||||
{
|
||||
getState (self)->didSendBodyData (totalBytesWritten, totalBytesExpected);
|
||||
}
|
||||
|
||||
static void connectionDidFinishLoading (id self, SEL, NSURLConnection*)
|
||||
{
|
||||
getState (self)->finishedLoading();
|
||||
}
|
||||
};
|
||||
|
||||
NSURLConnection* connection = nil;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (URLConnectionStatePreYosemite)
|
||||
};
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
class API_AVAILABLE (macos (10.9)) URLConnectionState : public URLConnectionStateBase
|
||||
{
|
||||
public:
|
||||
URLConnectionState (NSURLRequest* req, const int maxRedirects)
|
||||
: URLConnectionStateBase (req, maxRedirects)
|
||||
{
|
||||
static DelegateClass cls;
|
||||
delegate = [cls.createInstance() init];
|
||||
@ -151,11 +428,10 @@ public:
|
||||
[data release];
|
||||
}
|
||||
|
||||
void cancel()
|
||||
void cancel() override
|
||||
{
|
||||
{
|
||||
const ScopedLock lock (createTaskLock);
|
||||
|
||||
const ScopedLock lock (createConnectionLock);
|
||||
hasBeenCancelled = true;
|
||||
}
|
||||
|
||||
@ -163,10 +439,10 @@ public:
|
||||
stopThread (10000);
|
||||
}
|
||||
|
||||
bool start (WebInputStream& inputStream, WebInputStream::Listener* listener)
|
||||
bool start (WebInputStream& inputStream, WebInputStream::Listener* listener) override
|
||||
{
|
||||
{
|
||||
const ScopedLock lock (createTaskLock);
|
||||
const ScopedLock lock (createConnectionLock);
|
||||
|
||||
if (hasBeenCancelled)
|
||||
return false;
|
||||
@ -186,7 +462,7 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
int read (char* dest, int numBytes)
|
||||
int read (char* dest, int numBytes) override
|
||||
{
|
||||
int numDone = 0;
|
||||
|
||||
@ -304,7 +580,7 @@ public:
|
||||
delegateQueue: [NSOperationQueue currentQueue]] retain];
|
||||
|
||||
{
|
||||
const ScopedLock lock (createTaskLock);
|
||||
const ScopedLock lock (createConnectionLock);
|
||||
|
||||
if (! hasBeenCancelled)
|
||||
task = [session dataTaskWithRequest: request];
|
||||
@ -323,23 +599,6 @@ public:
|
||||
initialised = true;
|
||||
}
|
||||
|
||||
int64 contentLength = -1;
|
||||
CriticalSection dataLock;
|
||||
id delegate = nil;
|
||||
NSURLRequest* request = nil;
|
||||
NSURLSession* session = nil;
|
||||
NSURLSessionTask* task = nil;
|
||||
NSMutableData* data = nil;
|
||||
NSDictionary* headers = nil;
|
||||
int statusCode = 0;
|
||||
std::atomic<bool> initialised { false }, hasFailed { false }, hasFinished { false };
|
||||
bool isBeingDeleted = false;
|
||||
const int numRedirectsToFollow;
|
||||
int numRedirects = 0;
|
||||
int64 latestTotalBytes = 0;
|
||||
CriticalSection createTaskLock;
|
||||
bool hasBeenCancelled = false;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
struct DelegateClass : public ObjCClass<NSObject>
|
||||
@ -349,14 +608,14 @@ private:
|
||||
addIvar<URLConnectionState*> ("state");
|
||||
|
||||
addMethod (@selector (URLSession:dataTask:didReceiveResponse:completionHandler:),
|
||||
didReceiveResponse, "v@:@@@@");
|
||||
addMethod (@selector (URLSession:didBecomeInvalidWithError:), didBecomeInvalidWithError, "v@:@@");
|
||||
addMethod (@selector (URLSession:dataTask:didReceiveData:), didReceiveData, "v@:@@@");
|
||||
didReceiveResponse);
|
||||
addMethod (@selector (URLSession:didBecomeInvalidWithError:), didBecomeInvalidWithError);
|
||||
addMethod (@selector (URLSession:dataTask:didReceiveData:), didReceiveData);
|
||||
addMethod (@selector (URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:),
|
||||
didSendBodyData, "v@:@@qqq");
|
||||
didSendBodyData);
|
||||
addMethod (@selector (URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:),
|
||||
willPerformHTTPRedirection, "v@:@@@@@");
|
||||
addMethod (@selector (URLSession:task:didCompleteWithError:), didCompleteWithError, "v@:@@@");
|
||||
willPerformHTTPRedirection);
|
||||
addMethod (@selector (URLSession:task:didCompleteWithError:), didCompleteWithError);
|
||||
|
||||
registerClass();
|
||||
}
|
||||
@ -403,6 +662,10 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
NSURLSession* session = nil;
|
||||
NSURLSessionTask* task = nil;
|
||||
bool isBeingDeleted = false;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (URLConnectionState)
|
||||
};
|
||||
|
||||
@ -609,11 +872,10 @@ struct BackgroundDownloadTask : public URL::DownloadTask
|
||||
{
|
||||
addIvar<BackgroundDownloadTask*> ("state");
|
||||
|
||||
addMethod (@selector (URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:),
|
||||
didWriteData, "v@:@@qqq");
|
||||
addMethod (@selector (URLSession:downloadTask:didFinishDownloadingToURL:), didFinishDownloadingToURL, "v@:@@@");
|
||||
addMethod (@selector (URLSession:task:didCompleteWithError:), didCompleteWithError, "v@:@@@");
|
||||
addMethod (@selector (URLSession:didBecomeInvalidWithError:), didBecomeInvalidWithError, "v@:@@@");
|
||||
addMethod (@selector (URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:), didWriteData);
|
||||
addMethod (@selector (URLSession:downloadTask:didFinishDownloadingToURL:), didFinishDownloadingToURL);
|
||||
addMethod (@selector (URLSession:task:didCompleteWithError:), didCompleteWithError);
|
||||
addMethod (@selector (URLSession:didBecomeInvalidWithError:), didBecomeInvalidWithError);
|
||||
|
||||
registerClass();
|
||||
}
|
||||
@ -671,276 +933,6 @@ std::unique_ptr<URL::DownloadTask> URL::downloadToFile (const File& targetLocati
|
||||
}
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
#else
|
||||
|
||||
// This version is only used for backwards-compatibility with older OSX targets,
|
||||
// so we'll turn off deprecation warnings. This code will be removed at some point
|
||||
// in the future.
|
||||
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated")
|
||||
|
||||
//==============================================================================
|
||||
class URLConnectionState : public Thread
|
||||
{
|
||||
public:
|
||||
URLConnectionState (NSURLRequest* req, const int maxRedirects)
|
||||
: Thread ("http connection"),
|
||||
request ([req retain]),
|
||||
data ([[NSMutableData data] retain]),
|
||||
numRedirectsToFollow (maxRedirects)
|
||||
{
|
||||
static DelegateClass cls;
|
||||
delegate = [cls.createInstance() init];
|
||||
DelegateClass::setState (delegate, this);
|
||||
}
|
||||
|
||||
~URLConnectionState() override
|
||||
{
|
||||
stop();
|
||||
|
||||
[connection release];
|
||||
[request release];
|
||||
[headers release];
|
||||
[delegate release];
|
||||
[data release];
|
||||
}
|
||||
|
||||
bool start (WebInputStream& inputStream, WebInputStream::Listener* listener)
|
||||
{
|
||||
startThread();
|
||||
|
||||
while (isThreadRunning() && ! initialised)
|
||||
{
|
||||
if (listener != nullptr)
|
||||
if (! listener->postDataSendProgress (inputStream, latestTotalBytes, (int) [[request HTTPBody] length]))
|
||||
return false;
|
||||
|
||||
Thread::sleep (1);
|
||||
}
|
||||
|
||||
return connection != nil && ! hasFailed;
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
{
|
||||
const ScopedLock dLock (dataLock);
|
||||
const ScopedLock connectionLock (createConnectionLock);
|
||||
|
||||
hasBeenCancelled = true;
|
||||
|
||||
if (connection != nil)
|
||||
[connection cancel];
|
||||
}
|
||||
|
||||
stopThread (10000);
|
||||
}
|
||||
|
||||
void cancel()
|
||||
{
|
||||
hasFinished = hasFailed = true;
|
||||
stop();
|
||||
}
|
||||
|
||||
int read (char* dest, int numBytes)
|
||||
{
|
||||
int numDone = 0;
|
||||
|
||||
while (numBytes > 0)
|
||||
{
|
||||
const ScopedLock sl (dataLock);
|
||||
auto available = jmin (numBytes, (int) [data length]);
|
||||
|
||||
if (available > 0)
|
||||
{
|
||||
[data getBytes: dest length: (NSUInteger) available];
|
||||
[data replaceBytesInRange: NSMakeRange (0, (NSUInteger) available) withBytes: nil length: 0];
|
||||
|
||||
numDone += available;
|
||||
numBytes -= available;
|
||||
dest += available;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hasFailed || hasFinished)
|
||||
break;
|
||||
|
||||
const ScopedUnlock sul (dataLock);
|
||||
Thread::sleep (1);
|
||||
}
|
||||
}
|
||||
|
||||
return numDone;
|
||||
}
|
||||
|
||||
void didReceiveResponse (NSURLResponse* response)
|
||||
{
|
||||
{
|
||||
const ScopedLock sl (dataLock);
|
||||
[data setLength: 0];
|
||||
}
|
||||
|
||||
contentLength = [response expectedContentLength];
|
||||
|
||||
[headers release];
|
||||
headers = nil;
|
||||
|
||||
if ([response isKindOfClass: [NSHTTPURLResponse class]])
|
||||
{
|
||||
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*) response;
|
||||
headers = [[httpResponse allHeaderFields] retain];
|
||||
statusCode = (int) [httpResponse statusCode];
|
||||
}
|
||||
|
||||
initialised = true;
|
||||
}
|
||||
|
||||
NSURLRequest* willSendRequest (NSURLRequest* newRequest, NSURLResponse* redirectResponse)
|
||||
{
|
||||
if (redirectResponse != nullptr)
|
||||
{
|
||||
if (numRedirects >= numRedirectsToFollow)
|
||||
return nil; // Cancel redirect and allow connection to continue
|
||||
|
||||
++numRedirects;
|
||||
}
|
||||
|
||||
return newRequest;
|
||||
}
|
||||
|
||||
void didFailWithError (NSError* error)
|
||||
{
|
||||
DBG (nsStringToJuce ([error description])); ignoreUnused (error);
|
||||
nsUrlErrorCode = [error code];
|
||||
hasFailed = true;
|
||||
initialised = true;
|
||||
signalThreadShouldExit();
|
||||
}
|
||||
|
||||
void didReceiveData (NSData* newData)
|
||||
{
|
||||
const ScopedLock sl (dataLock);
|
||||
[data appendData: newData];
|
||||
initialised = true;
|
||||
}
|
||||
|
||||
void didSendBodyData (NSInteger totalBytesWritten, NSInteger /*totalBytesExpected*/)
|
||||
{
|
||||
latestTotalBytes = static_cast<int> (totalBytesWritten);
|
||||
}
|
||||
|
||||
void finishedLoading()
|
||||
{
|
||||
hasFinished = true;
|
||||
initialised = true;
|
||||
signalThreadShouldExit();
|
||||
}
|
||||
|
||||
void run() override
|
||||
{
|
||||
{
|
||||
const ScopedLock lock (createConnectionLock);
|
||||
|
||||
if (hasBeenCancelled)
|
||||
return;
|
||||
|
||||
connection = [[NSURLConnection alloc] initWithRequest: request
|
||||
delegate: delegate];
|
||||
}
|
||||
|
||||
while (! threadShouldExit())
|
||||
{
|
||||
JUCE_AUTORELEASEPOOL
|
||||
{
|
||||
[[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int64 contentLength = -1;
|
||||
CriticalSection dataLock;
|
||||
NSObject* delegate = nil;
|
||||
NSURLRequest* request = nil;
|
||||
NSURLConnection* connection = nil;
|
||||
NSMutableData* data = nil;
|
||||
NSDictionary* headers = nil;
|
||||
NSInteger nsUrlErrorCode = 0;
|
||||
int statusCode = 0;
|
||||
std::atomic<bool> initialised { false }, hasFailed { false }, hasFinished { false };
|
||||
const int numRedirectsToFollow;
|
||||
int numRedirects = 0;
|
||||
int latestTotalBytes = 0;
|
||||
CriticalSection createConnectionLock;
|
||||
bool hasBeenCancelled = false;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
struct DelegateClass : public ObjCClass<NSObject>
|
||||
{
|
||||
DelegateClass() : ObjCClass<NSObject> ("JUCENetworkDelegate_")
|
||||
{
|
||||
addIvar<URLConnectionState*> ("state");
|
||||
|
||||
addMethod (@selector (connection:didReceiveResponse:), didReceiveResponse, "v@:@@");
|
||||
addMethod (@selector (connection:didFailWithError:), didFailWithError, "v@:@@");
|
||||
addMethod (@selector (connection:didReceiveData:), didReceiveData, "v@:@@");
|
||||
addMethod (@selector (connection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite:),
|
||||
connectionDidSendBodyData, "v@:@iii");
|
||||
addMethod (@selector (connectionDidFinishLoading:), connectionDidFinishLoading, "v@:@");
|
||||
addMethod (@selector (connection:willSendRequest:redirectResponse:), willSendRequest, "@@:@@@");
|
||||
|
||||
registerClass();
|
||||
}
|
||||
|
||||
static void setState (id self, URLConnectionState* state) { object_setInstanceVariable (self, "state", state); }
|
||||
static URLConnectionState* getState (id self) { return getIvar<URLConnectionState*> (self, "state"); }
|
||||
|
||||
private:
|
||||
static void didReceiveResponse (id self, SEL, NSURLConnection*, NSURLResponse* response)
|
||||
{
|
||||
getState (self)->didReceiveResponse (response);
|
||||
}
|
||||
|
||||
static void didFailWithError (id self, SEL, NSURLConnection*, NSError* error)
|
||||
{
|
||||
getState (self)->didFailWithError (error);
|
||||
}
|
||||
|
||||
static void didReceiveData (id self, SEL, NSURLConnection*, NSData* newData)
|
||||
{
|
||||
getState (self)->didReceiveData (newData);
|
||||
}
|
||||
|
||||
static NSURLRequest* willSendRequest (id self, SEL, NSURLConnection*, NSURLRequest* request, NSURLResponse* response)
|
||||
{
|
||||
return getState (self)->willSendRequest (request, response);
|
||||
}
|
||||
|
||||
static void connectionDidSendBodyData (id self, SEL, NSURLConnection*, NSInteger, NSInteger totalBytesWritten, NSInteger totalBytesExpected)
|
||||
{
|
||||
getState (self)->didSendBodyData (totalBytesWritten, totalBytesExpected);
|
||||
}
|
||||
|
||||
static void connectionDidFinishLoading (id self, SEL, NSURLConnection*)
|
||||
{
|
||||
getState (self)->finishedLoading();
|
||||
}
|
||||
};
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (URLConnectionState)
|
||||
};
|
||||
|
||||
std::unique_ptr<URL::DownloadTask> URL::downloadToFile (const File& targetLocation, const DownloadTaskOptions& options)
|
||||
{
|
||||
return URL::DownloadTask::createFallbackDownloader (*this, targetLocation, options);
|
||||
}
|
||||
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class WebInputStream::Pimpl
|
||||
{
|
||||
@ -977,28 +969,29 @@ public:
|
||||
|
||||
if (! connection->start (owner, webInputListener))
|
||||
{
|
||||
// Workaround for deployment targets below 10.10 where HTTPS POST requests with keep-alive fail with the NSURLErrorNetworkConnectionLost error code.
|
||||
#if ! (JUCE_IOS || (defined (MAC_OS_X_VERSION_10_10) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10))
|
||||
if (numRetries == 0 && connection->nsUrlErrorCode == NSURLErrorNetworkConnectionLost)
|
||||
{
|
||||
connection.reset();
|
||||
return connect (webInputListener, ++numRetries);
|
||||
}
|
||||
#endif
|
||||
|
||||
const auto errorCode = connection->getErrorCode();
|
||||
connection.reset();
|
||||
|
||||
if (@available (macOS 10.10, *))
|
||||
return false;
|
||||
|
||||
// Workaround for macOS versions below 10.10 where HTTPS POST requests with keep-alive
|
||||
// fail with the NSURLErrorNetworkConnectionLost error code.
|
||||
if (numRetries == 0 && errorCode == NSURLErrorNetworkConnectionLost)
|
||||
return connect (webInputListener, ++numRetries);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (connection->headers != nil)
|
||||
if (auto* connectionHeaders = connection->getHeaders())
|
||||
{
|
||||
statusCode = connection->statusCode;
|
||||
statusCode = connection->getStatusCode();
|
||||
|
||||
NSEnumerator* enumerator = [connection->headers keyEnumerator];
|
||||
NSEnumerator* enumerator = [connectionHeaders keyEnumerator];
|
||||
|
||||
while (NSString* key = [enumerator nextObject])
|
||||
responseHeaders.set (nsStringToJuce (key),
|
||||
nsStringToJuce ((NSString*) [connection->headers objectForKey: key]));
|
||||
nsStringToJuce ((NSString*) [connectionHeaders objectForKey: key]));
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1038,10 +1031,9 @@ public:
|
||||
StringPairArray getResponseHeaders() const { return responseHeaders; }
|
||||
int getStatusCode() const { return statusCode; }
|
||||
|
||||
|
||||
//==============================================================================
|
||||
bool isError() const { return (connection == nullptr || connection->headers == nullptr); }
|
||||
int64 getTotalLength() { return connection == nullptr ? -1 : connection->contentLength; }
|
||||
bool isError() const { return (connection == nullptr || connection->getHeaders() == nullptr); }
|
||||
int64 getTotalLength() { return connection == nullptr ? -1 : connection->getContentLength(); }
|
||||
bool isExhausted() { return finished; }
|
||||
int64 getPosition() { return position; }
|
||||
|
||||
@ -1089,7 +1081,7 @@ public:
|
||||
private:
|
||||
WebInputStream& owner;
|
||||
URL url;
|
||||
std::unique_ptr<URLConnectionState> connection;
|
||||
std::unique_ptr<URLConnectionStateBase> connection;
|
||||
String headers;
|
||||
MemoryBlock postData;
|
||||
int64 position = 0;
|
||||
@ -1152,7 +1144,12 @@ private:
|
||||
// Workaround for an Apple bug. See https://github.com/AFNetworking/AFNetworking/issues/2334
|
||||
[req HTTPBody];
|
||||
|
||||
connection.reset (new URLConnectionState (req, numRedirectsToFollow));
|
||||
if (@available (macOS 10.10, *))
|
||||
connection = std::make_unique<URLConnectionState> (req, numRedirectsToFollow);
|
||||
#if JUCE_MAC
|
||||
else
|
||||
connection = std::make_unique<URLConnectionStatePreYosemite> (req, numRedirectsToFollow);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -2,7 +2,7 @@
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
@ -2,7 +2,7 @@
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
@ -69,6 +69,8 @@ void CPUInformation::initialise() noexcept
|
||||
hasAVX512VL,
|
||||
hasAVX512VBMI,
|
||||
hasAVX512VPOPCNTDQ);
|
||||
#elif JUCE_ARM && __ARM_ARCH > 7
|
||||
hasNeon = true;
|
||||
#endif
|
||||
|
||||
numLogicalCPUs = (int) [[NSProcessInfo processInfo] activeProcessorCount];
|
||||
@ -89,15 +91,19 @@ static String getOSXVersion()
|
||||
{
|
||||
JUCE_AUTORELEASEPOOL
|
||||
{
|
||||
const String systemVersionPlist ("/System/Library/CoreServices/SystemVersion.plist");
|
||||
const auto* dict = []
|
||||
{
|
||||
const String systemVersionPlist ("/System/Library/CoreServices/SystemVersion.plist");
|
||||
|
||||
#if (defined (MAC_OS_X_VERSION_10_13) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_13)
|
||||
NSError* error = nullptr;
|
||||
NSDictionary* dict = [NSDictionary dictionaryWithContentsOfURL: createNSURLFromFile (systemVersionPlist)
|
||||
error: &error];
|
||||
#else
|
||||
NSDictionary* dict = [NSDictionary dictionaryWithContentsOfFile: juceStringToNS (systemVersionPlist)];
|
||||
#endif
|
||||
if (@available (macOS 10.13, *))
|
||||
{
|
||||
NSError* error = nullptr;
|
||||
return [NSDictionary dictionaryWithContentsOfURL: createNSURLFromFile (systemVersionPlist)
|
||||
error: &error];
|
||||
}
|
||||
|
||||
return [NSDictionary dictionaryWithContentsOfFile: juceStringToNS (systemVersionPlist)];
|
||||
}();
|
||||
|
||||
if (dict != nullptr)
|
||||
return nsStringToJuce ([dict objectForKey: nsStringLiteral ("ProductVersion")]);
|
||||
|
@ -2,7 +2,7 @@
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
@ -1,150 +1,140 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
struct InterfaceInfo
|
||||
{
|
||||
IPAddress interfaceAddress, broadcastAddress;
|
||||
String name;
|
||||
};
|
||||
|
||||
inline bool operator== (const InterfaceInfo& lhs, const InterfaceInfo& rhs)
|
||||
{
|
||||
return lhs.interfaceAddress == rhs.interfaceAddress
|
||||
&& lhs.broadcastAddress == rhs.broadcastAddress;
|
||||
}
|
||||
|
||||
#if ! JUCE_WASM
|
||||
static IPAddress makeAddress (const sockaddr_in6* addr_in)
|
||||
{
|
||||
if (addr_in == nullptr)
|
||||
return {};
|
||||
|
||||
auto addr = addr_in->sin6_addr;
|
||||
|
||||
IPAddressByteUnion temp;
|
||||
uint16 arr[8];
|
||||
|
||||
for (int i = 0; i < 8; ++i) // Swap bytes from network to host order
|
||||
{
|
||||
temp.split[0] = addr.s6_addr[i * 2 + 1];
|
||||
temp.split[1] = addr.s6_addr[i * 2];
|
||||
|
||||
arr[i] = temp.combined;
|
||||
}
|
||||
|
||||
return IPAddress (arr);
|
||||
}
|
||||
|
||||
static IPAddress makeAddress (const sockaddr_in* addr_in)
|
||||
{
|
||||
if (addr_in->sin_addr.s_addr == INADDR_NONE)
|
||||
return {};
|
||||
|
||||
return IPAddress (ntohl (addr_in->sin_addr.s_addr));
|
||||
}
|
||||
|
||||
bool populateInterfaceInfo (struct ifaddrs* ifa, InterfaceInfo& interfaceInfo)
|
||||
{
|
||||
if (ifa->ifa_addr != nullptr)
|
||||
{
|
||||
if (ifa->ifa_addr->sa_family == AF_INET)
|
||||
{
|
||||
auto interfaceAddressInfo = unalignedPointerCast<sockaddr_in*> (ifa->ifa_addr);
|
||||
auto broadcastAddressInfo = unalignedPointerCast<sockaddr_in*> (ifa->ifa_dstaddr);
|
||||
|
||||
if (interfaceAddressInfo->sin_addr.s_addr != INADDR_NONE)
|
||||
{
|
||||
interfaceInfo.interfaceAddress = makeAddress (interfaceAddressInfo);
|
||||
interfaceInfo.broadcastAddress = makeAddress (broadcastAddressInfo);
|
||||
interfaceInfo.name = ifa->ifa_name;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (ifa->ifa_addr->sa_family == AF_INET6)
|
||||
{
|
||||
interfaceInfo.interfaceAddress = makeAddress (unalignedPointerCast<sockaddr_in6*> (ifa->ifa_addr));
|
||||
interfaceInfo.broadcastAddress = makeAddress (unalignedPointerCast<sockaddr_in6*> (ifa->ifa_dstaddr));
|
||||
interfaceInfo.name = ifa->ifa_name;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
Array<InterfaceInfo> getAllInterfaceInfo()
|
||||
{
|
||||
Array<InterfaceInfo> interfaces;
|
||||
|
||||
#if JUCE_WASM
|
||||
// TODO
|
||||
#else
|
||||
struct ifaddrs* ifaddr = nullptr;
|
||||
|
||||
if (getifaddrs (&ifaddr) != -1)
|
||||
{
|
||||
for (auto* ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next)
|
||||
{
|
||||
InterfaceInfo i;
|
||||
|
||||
if (populateInterfaceInfo (ifa, i))
|
||||
interfaces.addIfNotAlreadyThere (i);
|
||||
}
|
||||
|
||||
freeifaddrs (ifaddr);
|
||||
}
|
||||
#endif
|
||||
|
||||
return interfaces;
|
||||
}
|
||||
}
|
||||
|
||||
void IPAddress::findAllAddresses (Array<IPAddress>& result, bool includeIPv6)
|
||||
{
|
||||
for (auto& i : getAllInterfaceInfo())
|
||||
if (includeIPv6 || ! i.interfaceAddress.isIPv6)
|
||||
result.addIfNotAlreadyThere (i.interfaceAddress);
|
||||
}
|
||||
|
||||
void IPAddress::findAllInterfaceAddresses (Array<IPAddressInterfaceNamePair>& result, bool includeIPv6)
|
||||
{
|
||||
for (auto& i : getAllInterfaceInfo())
|
||||
if (includeIPv6 || ! i.interfaceAddress.isIPv6)
|
||||
result.addIfNotAlreadyThere (IPAddressInterfaceNamePair(i.interfaceAddress, i.name));
|
||||
}
|
||||
|
||||
IPAddress IPAddress::getInterfaceBroadcastAddress (const IPAddress& interfaceAddress)
|
||||
{
|
||||
for (auto& i : getAllInterfaceInfo())
|
||||
if (i.interfaceAddress == interfaceAddress)
|
||||
return i.broadcastAddress;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
struct InterfaceInfo
|
||||
{
|
||||
IPAddress interfaceAddress, broadcastAddress;
|
||||
};
|
||||
|
||||
inline bool operator== (const InterfaceInfo& lhs, const InterfaceInfo& rhs)
|
||||
{
|
||||
return lhs.interfaceAddress == rhs.interfaceAddress
|
||||
&& lhs.broadcastAddress == rhs.broadcastAddress;
|
||||
}
|
||||
|
||||
#if ! JUCE_WASM
|
||||
static IPAddress makeAddress (const sockaddr_in6* addr_in)
|
||||
{
|
||||
if (addr_in == nullptr)
|
||||
return {};
|
||||
|
||||
auto addr = addr_in->sin6_addr;
|
||||
|
||||
IPAddressByteUnion temp;
|
||||
uint16 arr[8];
|
||||
|
||||
for (int i = 0; i < 8; ++i) // Swap bytes from network to host order
|
||||
{
|
||||
temp.split[0] = addr.s6_addr[i * 2 + 1];
|
||||
temp.split[1] = addr.s6_addr[i * 2];
|
||||
|
||||
arr[i] = temp.combined;
|
||||
}
|
||||
|
||||
return IPAddress (arr);
|
||||
}
|
||||
|
||||
static IPAddress makeAddress (const sockaddr_in* addr_in)
|
||||
{
|
||||
if (addr_in->sin_addr.s_addr == INADDR_NONE)
|
||||
return {};
|
||||
|
||||
return IPAddress (ntohl (addr_in->sin_addr.s_addr));
|
||||
}
|
||||
|
||||
bool populateInterfaceInfo (struct ifaddrs* ifa, InterfaceInfo& interfaceInfo)
|
||||
{
|
||||
if (ifa->ifa_addr != nullptr)
|
||||
{
|
||||
if (ifa->ifa_addr->sa_family == AF_INET)
|
||||
{
|
||||
auto interfaceAddressInfo = unalignedPointerCast<sockaddr_in*> (ifa->ifa_addr);
|
||||
auto broadcastAddressInfo = unalignedPointerCast<sockaddr_in*> (ifa->ifa_dstaddr);
|
||||
|
||||
if (interfaceAddressInfo->sin_addr.s_addr != INADDR_NONE)
|
||||
{
|
||||
interfaceInfo.interfaceAddress = makeAddress (interfaceAddressInfo);
|
||||
interfaceInfo.broadcastAddress = makeAddress (broadcastAddressInfo);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (ifa->ifa_addr->sa_family == AF_INET6)
|
||||
{
|
||||
interfaceInfo.interfaceAddress = makeAddress (unalignedPointerCast<sockaddr_in6*> (ifa->ifa_addr));
|
||||
interfaceInfo.broadcastAddress = makeAddress (unalignedPointerCast<sockaddr_in6*> (ifa->ifa_dstaddr));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
Array<InterfaceInfo> getAllInterfaceInfo()
|
||||
{
|
||||
Array<InterfaceInfo> interfaces;
|
||||
|
||||
#if JUCE_WASM
|
||||
// TODO
|
||||
#else
|
||||
struct ifaddrs* ifaddr = nullptr;
|
||||
|
||||
if (getifaddrs (&ifaddr) != -1)
|
||||
{
|
||||
for (auto* ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next)
|
||||
{
|
||||
InterfaceInfo i;
|
||||
|
||||
if (populateInterfaceInfo (ifa, i))
|
||||
interfaces.addIfNotAlreadyThere (i);
|
||||
}
|
||||
|
||||
freeifaddrs (ifaddr);
|
||||
}
|
||||
#endif
|
||||
|
||||
return interfaces;
|
||||
}
|
||||
}
|
||||
|
||||
void IPAddress::findAllAddresses (Array<IPAddress>& result, bool includeIPv6)
|
||||
{
|
||||
for (auto& i : getAllInterfaceInfo())
|
||||
if (includeIPv6 || ! i.interfaceAddress.isIPv6)
|
||||
result.addIfNotAlreadyThere (i.interfaceAddress);
|
||||
}
|
||||
|
||||
IPAddress IPAddress::getInterfaceBroadcastAddress (const IPAddress& interfaceAddress)
|
||||
{
|
||||
for (auto& i : getAllInterfaceInfo())
|
||||
if (i.interfaceAddress == interfaceAddress)
|
||||
return i.broadcastAddress;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
|
@ -1,248 +1,311 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
#if ! JUCE_WASM
|
||||
|
||||
class NamedPipe::Pimpl
|
||||
{
|
||||
public:
|
||||
Pimpl (const String& pipePath, bool createPipe)
|
||||
: pipeInName (pipePath + "_in"),
|
||||
pipeOutName (pipePath + "_out"),
|
||||
createdPipe (createPipe)
|
||||
{
|
||||
signal (SIGPIPE, signalHandler);
|
||||
juce_siginterrupt (SIGPIPE, 1);
|
||||
}
|
||||
|
||||
~Pimpl()
|
||||
{
|
||||
if (pipeIn != -1) ::close (pipeIn);
|
||||
if (pipeOut != -1) ::close (pipeOut);
|
||||
|
||||
if (createdPipe)
|
||||
{
|
||||
if (createdFifoIn) unlink (pipeInName.toUTF8());
|
||||
if (createdFifoOut) unlink (pipeOutName.toUTF8());
|
||||
}
|
||||
}
|
||||
|
||||
bool connect (int timeOutMilliseconds)
|
||||
{
|
||||
return openPipe (true, getTimeoutEnd (timeOutMilliseconds));
|
||||
}
|
||||
|
||||
int read (char* destBuffer, int maxBytesToRead, int timeOutMilliseconds)
|
||||
{
|
||||
auto timeoutEnd = getTimeoutEnd (timeOutMilliseconds);
|
||||
int bytesRead = 0;
|
||||
|
||||
while (bytesRead < maxBytesToRead)
|
||||
{
|
||||
auto bytesThisTime = maxBytesToRead - bytesRead;
|
||||
auto numRead = (int) ::read (pipeIn, destBuffer, (size_t) bytesThisTime);
|
||||
|
||||
if (numRead <= 0)
|
||||
{
|
||||
if (errno != EWOULDBLOCK || stopReadOperation.load() || hasExpired (timeoutEnd))
|
||||
return -1;
|
||||
|
||||
const int maxWaitingTime = 30;
|
||||
waitForInput (pipeIn, timeoutEnd == 0 ? maxWaitingTime
|
||||
: jmin (maxWaitingTime,
|
||||
(int) (timeoutEnd - Time::getMillisecondCounter())));
|
||||
continue;
|
||||
}
|
||||
|
||||
bytesRead += numRead;
|
||||
destBuffer += numRead;
|
||||
}
|
||||
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
int write (const char* sourceBuffer, int numBytesToWrite, int timeOutMilliseconds)
|
||||
{
|
||||
auto timeoutEnd = getTimeoutEnd (timeOutMilliseconds);
|
||||
|
||||
if (! openPipe (false, timeoutEnd))
|
||||
return -1;
|
||||
|
||||
int bytesWritten = 0;
|
||||
|
||||
while (bytesWritten < numBytesToWrite && ! hasExpired (timeoutEnd))
|
||||
{
|
||||
auto bytesThisTime = numBytesToWrite - bytesWritten;
|
||||
auto numWritten = (int) ::write (pipeOut, sourceBuffer, (size_t) bytesThisTime);
|
||||
|
||||
if (numWritten <= 0)
|
||||
return -1;
|
||||
|
||||
bytesWritten += numWritten;
|
||||
sourceBuffer += numWritten;
|
||||
}
|
||||
|
||||
return bytesWritten;
|
||||
}
|
||||
|
||||
static bool createFifo (const String& name, bool mustNotExist)
|
||||
{
|
||||
return mkfifo (name.toUTF8(), 0666) == 0 || ((! mustNotExist) && errno == EEXIST);
|
||||
}
|
||||
|
||||
bool createFifos (bool mustNotExist)
|
||||
{
|
||||
createdFifoIn = createFifo (pipeInName, mustNotExist);
|
||||
createdFifoOut = createFifo (pipeOutName, mustNotExist);
|
||||
|
||||
return createdFifoIn && createdFifoOut;
|
||||
}
|
||||
|
||||
const String pipeInName, pipeOutName;
|
||||
int pipeIn = -1, pipeOut = -1;
|
||||
bool createdFifoIn = false, createdFifoOut = false;
|
||||
|
||||
const bool createdPipe;
|
||||
std::atomic<bool> stopReadOperation { false };
|
||||
|
||||
private:
|
||||
static void signalHandler (int) {}
|
||||
|
||||
static uint32 getTimeoutEnd (int timeOutMilliseconds)
|
||||
{
|
||||
return timeOutMilliseconds >= 0 ? Time::getMillisecondCounter() + (uint32) timeOutMilliseconds : 0;
|
||||
}
|
||||
|
||||
static bool hasExpired (uint32 timeoutEnd)
|
||||
{
|
||||
return timeoutEnd != 0 && Time::getMillisecondCounter() >= timeoutEnd;
|
||||
}
|
||||
|
||||
int openPipe (const String& name, int flags, uint32 timeoutEnd)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
auto p = ::open (name.toUTF8(), flags);
|
||||
|
||||
if (p != -1 || hasExpired (timeoutEnd) || stopReadOperation.load())
|
||||
return p;
|
||||
|
||||
Thread::sleep (2);
|
||||
}
|
||||
}
|
||||
|
||||
bool openPipe (bool isInput, uint32 timeoutEnd)
|
||||
{
|
||||
auto& pipe = isInput ? pipeIn : pipeOut;
|
||||
int flags = (isInput ? O_RDWR : O_WRONLY) | O_NONBLOCK;
|
||||
|
||||
const String& pipeName = isInput ? (createdPipe ? pipeInName : pipeOutName)
|
||||
: (createdPipe ? pipeOutName : pipeInName);
|
||||
|
||||
if (pipe == -1)
|
||||
{
|
||||
pipe = openPipe (pipeName, flags, timeoutEnd);
|
||||
|
||||
if (pipe == -1)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void waitForInput (int handle, int timeoutMsecs) noexcept
|
||||
{
|
||||
pollfd pfd { handle, POLLIN, 0 };
|
||||
poll (&pfd, 1, timeoutMsecs);
|
||||
}
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
|
||||
};
|
||||
|
||||
void NamedPipe::close()
|
||||
{
|
||||
{
|
||||
ScopedReadLock sl (lock);
|
||||
|
||||
if (pimpl != nullptr)
|
||||
{
|
||||
pimpl->stopReadOperation = true;
|
||||
|
||||
char buffer[1] = { 0 };
|
||||
ssize_t done = ::write (pimpl->pipeIn, buffer, 1);
|
||||
ignoreUnused (done);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
ScopedWriteLock sl (lock);
|
||||
pimpl.reset();
|
||||
}
|
||||
}
|
||||
|
||||
bool NamedPipe::openInternal (const String& pipeName, bool createPipe, bool mustNotExist)
|
||||
{
|
||||
#if JUCE_IOS
|
||||
pimpl.reset (new Pimpl (File::getSpecialLocation (File::tempDirectory)
|
||||
.getChildFile (File::createLegalFileName (pipeName)).getFullPathName(), createPipe));
|
||||
#else
|
||||
auto file = pipeName;
|
||||
|
||||
if (! File::isAbsolutePath (file))
|
||||
file = "/tmp/" + File::createLegalFileName (file);
|
||||
|
||||
pimpl.reset (new Pimpl (file, createPipe));
|
||||
#endif
|
||||
|
||||
if (createPipe && ! pimpl->createFifos (mustNotExist))
|
||||
{
|
||||
pimpl.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! pimpl->connect (200))
|
||||
{
|
||||
pimpl.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int NamedPipe::read (void* destBuffer, int maxBytesToRead, int timeOutMilliseconds)
|
||||
{
|
||||
ScopedReadLock sl (lock);
|
||||
return pimpl != nullptr ? pimpl->read (static_cast<char*> (destBuffer), maxBytesToRead, timeOutMilliseconds) : -1;
|
||||
}
|
||||
|
||||
int NamedPipe::write (const void* sourceBuffer, int numBytesToWrite, int timeOutMilliseconds)
|
||||
{
|
||||
ScopedReadLock sl (lock);
|
||||
return pimpl != nullptr ? pimpl->write (static_cast<const char*> (sourceBuffer), numBytesToWrite, timeOutMilliseconds) : -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
#if ! JUCE_WASM
|
||||
|
||||
class NamedPipe::Pimpl
|
||||
{
|
||||
public:
|
||||
Pimpl (const String& pipePath, bool createPipe)
|
||||
: pipeInName (pipePath + "_in"),
|
||||
pipeOutName (pipePath + "_out"),
|
||||
createdPipe (createPipe)
|
||||
{
|
||||
signal (SIGPIPE, signalHandler);
|
||||
juce_siginterrupt (SIGPIPE, 1);
|
||||
}
|
||||
|
||||
~Pimpl()
|
||||
{
|
||||
pipeIn .close();
|
||||
pipeOut.close();
|
||||
|
||||
if (createdPipe)
|
||||
{
|
||||
if (createdFifoIn) unlink (pipeInName.toUTF8());
|
||||
if (createdFifoOut) unlink (pipeOutName.toUTF8());
|
||||
}
|
||||
}
|
||||
|
||||
bool connect (int timeOutMilliseconds)
|
||||
{
|
||||
return openPipe (true, getTimeoutEnd (timeOutMilliseconds)) != invalidPipe;
|
||||
}
|
||||
|
||||
int read (char* destBuffer, int maxBytesToRead, int timeOutMilliseconds)
|
||||
{
|
||||
auto timeoutEnd = getTimeoutEnd (timeOutMilliseconds);
|
||||
int bytesRead = 0;
|
||||
|
||||
while (bytesRead < maxBytesToRead)
|
||||
{
|
||||
const auto pipe = pipeIn.get();
|
||||
|
||||
auto bytesThisTime = maxBytesToRead - bytesRead;
|
||||
auto numRead = (int) ::read (pipe, destBuffer, (size_t) bytesThisTime);
|
||||
|
||||
if (numRead <= 0)
|
||||
{
|
||||
const auto error = errno;
|
||||
|
||||
if (! (error == EWOULDBLOCK || error == EAGAIN) || stopReadOperation.load() || hasExpired (timeoutEnd))
|
||||
return -1;
|
||||
|
||||
const int maxWaitingTime = 30;
|
||||
waitForInput (pipe, timeoutEnd == 0 ? maxWaitingTime
|
||||
: jmin (maxWaitingTime,
|
||||
(int) (timeoutEnd - Time::getMillisecondCounter())));
|
||||
continue;
|
||||
}
|
||||
|
||||
bytesRead += numRead;
|
||||
destBuffer += numRead;
|
||||
}
|
||||
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
int write (const char* sourceBuffer, int numBytesToWrite, int timeOutMilliseconds)
|
||||
{
|
||||
auto timeoutEnd = getTimeoutEnd (timeOutMilliseconds);
|
||||
|
||||
const auto pipe = openPipe (false, timeoutEnd);
|
||||
|
||||
if (pipe == invalidPipe)
|
||||
return -1;
|
||||
|
||||
int bytesWritten = 0;
|
||||
|
||||
while (bytesWritten < numBytesToWrite && ! hasExpired (timeoutEnd))
|
||||
{
|
||||
auto bytesThisTime = numBytesToWrite - bytesWritten;
|
||||
auto numWritten = (int) ::write (pipe, sourceBuffer, (size_t) bytesThisTime);
|
||||
|
||||
if (numWritten < 0)
|
||||
{
|
||||
const auto error = errno;
|
||||
const int maxWaitingTime = 30;
|
||||
|
||||
if (error == EWOULDBLOCK || error == EAGAIN)
|
||||
waitToWrite (pipe, timeoutEnd == 0 ? maxWaitingTime
|
||||
: jmin (maxWaitingTime,
|
||||
(int) (timeoutEnd - Time::getMillisecondCounter())));
|
||||
else
|
||||
return -1;
|
||||
|
||||
numWritten = 0;
|
||||
}
|
||||
|
||||
bytesWritten += numWritten;
|
||||
sourceBuffer += numWritten;
|
||||
}
|
||||
|
||||
return bytesWritten;
|
||||
}
|
||||
|
||||
static bool createFifo (const String& name, bool mustNotExist)
|
||||
{
|
||||
return mkfifo (name.toUTF8(), 0666) == 0 || ((! mustNotExist) && errno == EEXIST);
|
||||
}
|
||||
|
||||
bool createFifos (bool mustNotExist)
|
||||
{
|
||||
createdFifoIn = createFifo (pipeInName, mustNotExist);
|
||||
createdFifoOut = createFifo (pipeOutName, mustNotExist);
|
||||
|
||||
return createdFifoIn && createdFifoOut;
|
||||
}
|
||||
|
||||
static constexpr auto invalidPipe = -1;
|
||||
|
||||
class PipeDescriptor
|
||||
{
|
||||
public:
|
||||
template <typename Fn>
|
||||
int get (Fn&& fn)
|
||||
{
|
||||
{
|
||||
const ScopedReadLock l (mutex);
|
||||
|
||||
if (descriptor != invalidPipe)
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
const ScopedWriteLock l (mutex);
|
||||
return descriptor = fn();
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
{
|
||||
const ScopedReadLock l (mutex);
|
||||
|
||||
if (descriptor == invalidPipe)
|
||||
return;
|
||||
}
|
||||
|
||||
const ScopedWriteLock l (mutex);
|
||||
::close (descriptor);
|
||||
descriptor = invalidPipe;
|
||||
}
|
||||
|
||||
int get()
|
||||
{
|
||||
const ScopedReadLock l (mutex);
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
private:
|
||||
ReadWriteLock mutex;
|
||||
int descriptor = invalidPipe;
|
||||
};
|
||||
|
||||
const String pipeInName, pipeOutName;
|
||||
PipeDescriptor pipeIn, pipeOut;
|
||||
bool createdFifoIn = false, createdFifoOut = false;
|
||||
|
||||
const bool createdPipe;
|
||||
std::atomic<bool> stopReadOperation { false };
|
||||
|
||||
private:
|
||||
static void signalHandler (int) {}
|
||||
|
||||
static uint32 getTimeoutEnd (int timeOutMilliseconds)
|
||||
{
|
||||
return timeOutMilliseconds >= 0 ? Time::getMillisecondCounter() + (uint32) timeOutMilliseconds : 0;
|
||||
}
|
||||
|
||||
static bool hasExpired (uint32 timeoutEnd)
|
||||
{
|
||||
return timeoutEnd != 0 && Time::getMillisecondCounter() >= timeoutEnd;
|
||||
}
|
||||
|
||||
int openPipe (const String& name, int flags, uint32 timeoutEnd)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
auto p = ::open (name.toUTF8(), flags);
|
||||
|
||||
if (p != invalidPipe || hasExpired (timeoutEnd) || stopReadOperation.load())
|
||||
return p;
|
||||
|
||||
Thread::sleep (2);
|
||||
}
|
||||
}
|
||||
|
||||
int openPipe (bool isInput, uint32 timeoutEnd)
|
||||
{
|
||||
auto& pipe = isInput ? pipeIn : pipeOut;
|
||||
const auto flags = (isInput ? O_RDWR : O_WRONLY) | O_NONBLOCK;
|
||||
|
||||
const String& pipeName = isInput ? (createdPipe ? pipeInName : pipeOutName)
|
||||
: (createdPipe ? pipeOutName : pipeInName);
|
||||
|
||||
return pipe.get ([this, &pipeName, &flags, &timeoutEnd]
|
||||
{
|
||||
return openPipe (pipeName, flags, timeoutEnd);
|
||||
});
|
||||
}
|
||||
|
||||
static void waitForInput (int handle, int timeoutMsecs) noexcept
|
||||
{
|
||||
pollfd pfd { handle, POLLIN, 0 };
|
||||
poll (&pfd, 1, timeoutMsecs);
|
||||
}
|
||||
|
||||
static void waitToWrite (int handle, int timeoutMsecs) noexcept
|
||||
{
|
||||
pollfd pfd { handle, POLLOUT, 0 };
|
||||
poll (&pfd, 1, timeoutMsecs);
|
||||
}
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
|
||||
};
|
||||
|
||||
void NamedPipe::close()
|
||||
{
|
||||
{
|
||||
const ScopedReadLock sl (lock);
|
||||
|
||||
if (pimpl != nullptr)
|
||||
{
|
||||
pimpl->stopReadOperation = true;
|
||||
|
||||
const char buffer[] { 0 };
|
||||
const auto done = ::write (pimpl->pipeIn.get(), buffer, numElementsInArray (buffer));
|
||||
ignoreUnused (done);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const ScopedWriteLock sl (lock);
|
||||
pimpl.reset();
|
||||
}
|
||||
}
|
||||
|
||||
bool NamedPipe::openInternal (const String& pipeName, bool createPipe, bool mustNotExist)
|
||||
{
|
||||
#if JUCE_IOS
|
||||
pimpl.reset (new Pimpl (File::getSpecialLocation (File::tempDirectory)
|
||||
.getChildFile (File::createLegalFileName (pipeName)).getFullPathName(), createPipe));
|
||||
#else
|
||||
auto file = pipeName;
|
||||
|
||||
if (! File::isAbsolutePath (file))
|
||||
file = "/tmp/" + File::createLegalFileName (file);
|
||||
|
||||
pimpl.reset (new Pimpl (file, createPipe));
|
||||
#endif
|
||||
|
||||
if (createPipe && ! pimpl->createFifos (mustNotExist))
|
||||
{
|
||||
pimpl.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! pimpl->connect (200))
|
||||
{
|
||||
pimpl.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int NamedPipe::read (void* destBuffer, int maxBytesToRead, int timeOutMilliseconds)
|
||||
{
|
||||
ScopedReadLock sl (lock);
|
||||
return pimpl != nullptr ? pimpl->read (static_cast<char*> (destBuffer), maxBytesToRead, timeOutMilliseconds) : -1;
|
||||
}
|
||||
|
||||
int NamedPipe::write (const void* sourceBuffer, int numBytesToWrite, int timeOutMilliseconds)
|
||||
{
|
||||
ScopedReadLock sl (lock);
|
||||
return pimpl != nullptr ? pimpl->write (static_cast<const char*> (sourceBuffer), numBytesToWrite, timeOutMilliseconds) : -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace juce
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,87 +1,87 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
void Logger::outputDebugString (const String& text)
|
||||
{
|
||||
std::cerr << text << std::endl;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
SystemStats::OperatingSystemType SystemStats::getOperatingSystemType() { return WASM; }
|
||||
String SystemStats::getOperatingSystemName() { return "WASM"; }
|
||||
bool SystemStats::isOperatingSystem64Bit() { return true; }
|
||||
String SystemStats::getDeviceDescription() { return "Web-browser"; }
|
||||
String SystemStats::getDeviceManufacturer() { return {}; }
|
||||
String SystemStats::getCpuVendor() { return {}; }
|
||||
String SystemStats::getCpuModel() { return {}; }
|
||||
int SystemStats::getCpuSpeedInMegahertz() { return 0; }
|
||||
int SystemStats::getMemorySizeInMegabytes() { return 0; }
|
||||
int SystemStats::getPageSize() { return 0; }
|
||||
String SystemStats::getLogonName() { return {}; }
|
||||
String SystemStats::getFullUserName() { return {}; }
|
||||
String SystemStats::getComputerName() { return {}; }
|
||||
String SystemStats::getUserLanguage() { return {}; }
|
||||
String SystemStats::getUserRegion() { return {}; }
|
||||
String SystemStats::getDisplayLanguage() { return {}; }
|
||||
|
||||
//==============================================================================
|
||||
void CPUInformation::initialise() noexcept
|
||||
{
|
||||
numLogicalCPUs = 1;
|
||||
numPhysicalCPUs = 1;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
uint32 juce_millisecondsSinceStartup() noexcept
|
||||
{
|
||||
return static_cast<uint32> (emscripten_get_now());
|
||||
}
|
||||
|
||||
int64 Time::getHighResolutionTicks() noexcept
|
||||
{
|
||||
return static_cast<int64> (emscripten_get_now() * 1000.0);
|
||||
}
|
||||
|
||||
int64 Time::getHighResolutionTicksPerSecond() noexcept
|
||||
{
|
||||
return 1000000; // (microseconds)
|
||||
}
|
||||
|
||||
double Time::getMillisecondCounterHiRes() noexcept
|
||||
{
|
||||
return emscripten_get_now();
|
||||
}
|
||||
|
||||
bool Time::setSystemTimeToThisTime() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
JUCE_API bool JUCE_CALLTYPE juce_isRunningUnderDebugger() noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
void Logger::outputDebugString (const String& text)
|
||||
{
|
||||
std::cerr << text << std::endl;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
SystemStats::OperatingSystemType SystemStats::getOperatingSystemType() { return WASM; }
|
||||
String SystemStats::getOperatingSystemName() { return "WASM"; }
|
||||
bool SystemStats::isOperatingSystem64Bit() { return true; }
|
||||
String SystemStats::getDeviceDescription() { return "Web-browser"; }
|
||||
String SystemStats::getDeviceManufacturer() { return {}; }
|
||||
String SystemStats::getCpuVendor() { return {}; }
|
||||
String SystemStats::getCpuModel() { return {}; }
|
||||
int SystemStats::getCpuSpeedInMegahertz() { return 0; }
|
||||
int SystemStats::getMemorySizeInMegabytes() { return 0; }
|
||||
int SystemStats::getPageSize() { return 0; }
|
||||
String SystemStats::getLogonName() { return {}; }
|
||||
String SystemStats::getFullUserName() { return {}; }
|
||||
String SystemStats::getComputerName() { return {}; }
|
||||
String SystemStats::getUserLanguage() { return {}; }
|
||||
String SystemStats::getUserRegion() { return {}; }
|
||||
String SystemStats::getDisplayLanguage() { return {}; }
|
||||
|
||||
//==============================================================================
|
||||
void CPUInformation::initialise() noexcept
|
||||
{
|
||||
numLogicalCPUs = 1;
|
||||
numPhysicalCPUs = 1;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
uint32 juce_millisecondsSinceStartup() noexcept
|
||||
{
|
||||
return static_cast<uint32> (emscripten_get_now());
|
||||
}
|
||||
|
||||
int64 Time::getHighResolutionTicks() noexcept
|
||||
{
|
||||
return static_cast<int64> (emscripten_get_now() * 1000.0);
|
||||
}
|
||||
|
||||
int64 Time::getHighResolutionTicksPerSecond() noexcept
|
||||
{
|
||||
return 1000000; // (microseconds)
|
||||
}
|
||||
|
||||
double Time::getMillisecondCounterHiRes() noexcept
|
||||
{
|
||||
return emscripten_get_now();
|
||||
}
|
||||
|
||||
bool Time::setSystemTimeToThisTime() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
JUCE_API bool JUCE_CALLTYPE juce_isRunningUnderDebugger() noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
|
@ -1,230 +1,230 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
#if JUCE_MINGW || (! (defined (_MSC_VER) || defined (__uuidof)))
|
||||
#ifdef __uuidof
|
||||
#undef __uuidof
|
||||
#endif
|
||||
|
||||
template <typename Type> struct UUIDGetter { static CLSID get() { jassertfalse; return {}; } };
|
||||
#define __uuidof(x) UUIDGetter<x>::get()
|
||||
|
||||
template <>
|
||||
struct UUIDGetter<::IUnknown>
|
||||
{
|
||||
static CLSID get() { return { 0, 0, 0, { 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 } }; }
|
||||
};
|
||||
|
||||
#define JUCE_DECLARE_UUID_GETTER(name, uuid) \
|
||||
template <> struct UUIDGetter<name> { static CLSID get() { return uuidFromString (uuid); } };
|
||||
|
||||
#define JUCE_COMCLASS(name, guid) \
|
||||
struct name; \
|
||||
JUCE_DECLARE_UUID_GETTER (name, guid) \
|
||||
struct name
|
||||
|
||||
#else
|
||||
#define JUCE_DECLARE_UUID_GETTER(name, uuid)
|
||||
#define JUCE_COMCLASS(name, guid) struct __declspec (uuid (guid)) name
|
||||
#endif
|
||||
|
||||
#define JUCE_IUNKNOWNCLASS(name, guid) JUCE_COMCLASS(name, guid) : public IUnknown
|
||||
#define JUCE_COMRESULT HRESULT STDMETHODCALLTYPE
|
||||
#define JUCE_COMCALL virtual HRESULT STDMETHODCALLTYPE
|
||||
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
|
||||
|
||||
inline GUID uuidFromString (const char* s) noexcept
|
||||
{
|
||||
uint32 ints[4] = {};
|
||||
|
||||
for (uint32 digitIndex = 0; digitIndex < 32;)
|
||||
{
|
||||
auto c = (uint32) *s++;
|
||||
uint32 digit;
|
||||
|
||||
if (c >= '0' && c <= '9') digit = c - '0';
|
||||
else if (c >= 'a' && c <= 'f') digit = c - 'a' + 10;
|
||||
else if (c >= 'A' && c <= 'F') digit = c - 'A' + 10;
|
||||
else if (c == '-') continue;
|
||||
else break;
|
||||
|
||||
ints[digitIndex / 8] |= (digit << 4 * (7 - (digitIndex & 7)));
|
||||
++digitIndex;
|
||||
}
|
||||
|
||||
return { ints[0],
|
||||
(uint16) (ints[1] >> 16),
|
||||
(uint16) ints[1],
|
||||
{ (uint8) (ints[2] >> 24), (uint8) (ints[2] >> 16), (uint8) (ints[2] >> 8), (uint8) ints[2],
|
||||
(uint8) (ints[3] >> 24), (uint8) (ints[3] >> 16), (uint8) (ints[3] >> 8), (uint8) ints[3] }};
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** A simple COM smart pointer.
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
template <class ComClass>
|
||||
class ComSmartPtr
|
||||
{
|
||||
public:
|
||||
ComSmartPtr() noexcept {}
|
||||
ComSmartPtr (ComClass* obj) : p (obj) { if (p) p->AddRef(); }
|
||||
ComSmartPtr (const ComSmartPtr& other) : p (other.p) { if (p) p->AddRef(); }
|
||||
~ComSmartPtr() { release(); }
|
||||
|
||||
operator ComClass*() const noexcept { return p; }
|
||||
ComClass& operator*() const noexcept { return *p; }
|
||||
ComClass* operator->() const noexcept { return p; }
|
||||
|
||||
ComSmartPtr& operator= (ComClass* const newP)
|
||||
{
|
||||
if (newP != nullptr) newP->AddRef();
|
||||
release();
|
||||
p = newP;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ComSmartPtr& operator= (const ComSmartPtr& newP) { return operator= (newP.p); }
|
||||
|
||||
// Releases and nullifies this pointer and returns its address
|
||||
ComClass** resetAndGetPointerAddress()
|
||||
{
|
||||
release();
|
||||
p = nullptr;
|
||||
return &p;
|
||||
}
|
||||
|
||||
HRESULT CoCreateInstance (REFCLSID classUUID, DWORD dwClsContext = CLSCTX_INPROC_SERVER)
|
||||
{
|
||||
auto hr = ::CoCreateInstance (classUUID, nullptr, dwClsContext, __uuidof (ComClass), (void**) resetAndGetPointerAddress());
|
||||
jassert (hr != CO_E_NOTINITIALIZED); // You haven't called CoInitialize for the current thread!
|
||||
return hr;
|
||||
}
|
||||
|
||||
template <class OtherComClass>
|
||||
HRESULT QueryInterface (REFCLSID classUUID, ComSmartPtr<OtherComClass>& destObject) const
|
||||
{
|
||||
if (p == nullptr)
|
||||
return E_POINTER;
|
||||
|
||||
return p->QueryInterface (classUUID, (void**) destObject.resetAndGetPointerAddress());
|
||||
}
|
||||
|
||||
template <class OtherComClass>
|
||||
HRESULT QueryInterface (ComSmartPtr<OtherComClass>& destObject) const
|
||||
{
|
||||
return this->QueryInterface (__uuidof (OtherComClass), destObject);
|
||||
}
|
||||
|
||||
template <class OtherComClass>
|
||||
ComSmartPtr<OtherComClass> getInterface() const
|
||||
{
|
||||
ComSmartPtr<OtherComClass> destObject;
|
||||
|
||||
if (QueryInterface (destObject) == S_OK)
|
||||
return destObject;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
ComClass* p = nullptr;
|
||||
|
||||
void release() { if (p != nullptr) p->Release(); }
|
||||
|
||||
ComClass** operator&() noexcept; // private to avoid it being used accidentally
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
template <class First, class... ComClasses>
|
||||
class ComBaseClassHelperBase : public First, public ComClasses...
|
||||
{
|
||||
public:
|
||||
ComBaseClassHelperBase (unsigned int initialRefCount) : refCount (initialRefCount) {}
|
||||
virtual ~ComBaseClassHelperBase() = default;
|
||||
|
||||
ULONG STDMETHODCALLTYPE AddRef() { return ++refCount; }
|
||||
ULONG STDMETHODCALLTYPE Release() { auto r = --refCount; if (r == 0) delete this; return r; }
|
||||
|
||||
protected:
|
||||
ULONG refCount;
|
||||
|
||||
JUCE_COMRESULT QueryInterface (REFIID refId, void** result)
|
||||
{
|
||||
if (refId == __uuidof (IUnknown))
|
||||
return castToType<First> (result);
|
||||
|
||||
*result = nullptr;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
JUCE_COMRESULT castToType (void** result)
|
||||
{
|
||||
this->AddRef();
|
||||
*result = dynamic_cast<Type*> (this);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
};
|
||||
|
||||
/** Handy base class for writing COM objects, providing ref-counting and a basic QueryInterface method.
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
template <class... ComClasses>
|
||||
class ComBaseClassHelper : public ComBaseClassHelperBase<ComClasses...>
|
||||
{
|
||||
public:
|
||||
explicit ComBaseClassHelper (unsigned int initialRefCount = 1)
|
||||
: ComBaseClassHelperBase<ComClasses...> (initialRefCount) {}
|
||||
|
||||
JUCE_COMRESULT QueryInterface (REFIID refId, void** result)
|
||||
{
|
||||
const std::tuple<IID, void*> bases[]
|
||||
{
|
||||
std::make_tuple (__uuidof (ComClasses),
|
||||
static_cast<void*> (static_cast<ComClasses*> (this)))...
|
||||
};
|
||||
|
||||
for (const auto& base : bases)
|
||||
{
|
||||
if (refId == std::get<0> (base))
|
||||
{
|
||||
this->AddRef();
|
||||
*result = std::get<1> (base);
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return ComBaseClassHelperBase<ComClasses...>::QueryInterface (refId, result);
|
||||
}
|
||||
};
|
||||
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
|
||||
} // namespace juce
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
#if (JUCE_MINGW && JUCE_32BIT) || (! defined (_MSC_VER) && ! defined (__uuidof))
|
||||
#ifdef __uuidof
|
||||
#undef __uuidof
|
||||
#endif
|
||||
|
||||
template <typename Type> struct UUIDGetter { static CLSID get() { jassertfalse; return {}; } };
|
||||
#define __uuidof(x) UUIDGetter<x>::get()
|
||||
|
||||
template <>
|
||||
struct UUIDGetter<::IUnknown>
|
||||
{
|
||||
static CLSID get() { return { 0, 0, 0, { 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 } }; }
|
||||
};
|
||||
|
||||
#define JUCE_DECLARE_UUID_GETTER(name, uuid) \
|
||||
template <> struct UUIDGetter<name> { static CLSID get() { return uuidFromString (uuid); } };
|
||||
|
||||
#define JUCE_COMCLASS(name, guid) \
|
||||
struct name; \
|
||||
JUCE_DECLARE_UUID_GETTER (name, guid) \
|
||||
struct name
|
||||
|
||||
#else
|
||||
#define JUCE_DECLARE_UUID_GETTER(name, uuid)
|
||||
#define JUCE_COMCLASS(name, guid) struct DECLSPEC_UUID (guid) name
|
||||
#endif
|
||||
|
||||
#define JUCE_IUNKNOWNCLASS(name, guid) JUCE_COMCLASS(name, guid) : public IUnknown
|
||||
#define JUCE_COMRESULT HRESULT STDMETHODCALLTYPE
|
||||
#define JUCE_COMCALL virtual HRESULT STDMETHODCALLTYPE
|
||||
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
|
||||
|
||||
inline GUID uuidFromString (const char* s) noexcept
|
||||
{
|
||||
uint32 ints[4] = {};
|
||||
|
||||
for (uint32 digitIndex = 0; digitIndex < 32;)
|
||||
{
|
||||
auto c = (uint32) *s++;
|
||||
uint32 digit;
|
||||
|
||||
if (c >= '0' && c <= '9') digit = c - '0';
|
||||
else if (c >= 'a' && c <= 'f') digit = c - 'a' + 10;
|
||||
else if (c >= 'A' && c <= 'F') digit = c - 'A' + 10;
|
||||
else if (c == '-') continue;
|
||||
else break;
|
||||
|
||||
ints[digitIndex / 8] |= (digit << 4 * (7 - (digitIndex & 7)));
|
||||
++digitIndex;
|
||||
}
|
||||
|
||||
return { ints[0],
|
||||
(uint16) (ints[1] >> 16),
|
||||
(uint16) ints[1],
|
||||
{ (uint8) (ints[2] >> 24), (uint8) (ints[2] >> 16), (uint8) (ints[2] >> 8), (uint8) ints[2],
|
||||
(uint8) (ints[3] >> 24), (uint8) (ints[3] >> 16), (uint8) (ints[3] >> 8), (uint8) ints[3] }};
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** A simple COM smart pointer.
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
template <class ComClass>
|
||||
class ComSmartPtr
|
||||
{
|
||||
public:
|
||||
ComSmartPtr() noexcept {}
|
||||
ComSmartPtr (ComClass* obj) : p (obj) { if (p) p->AddRef(); }
|
||||
ComSmartPtr (const ComSmartPtr& other) : p (other.p) { if (p) p->AddRef(); }
|
||||
~ComSmartPtr() { release(); }
|
||||
|
||||
operator ComClass*() const noexcept { return p; }
|
||||
ComClass& operator*() const noexcept { return *p; }
|
||||
ComClass* operator->() const noexcept { return p; }
|
||||
|
||||
ComSmartPtr& operator= (ComClass* const newP)
|
||||
{
|
||||
if (newP != nullptr) newP->AddRef();
|
||||
release();
|
||||
p = newP;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ComSmartPtr& operator= (const ComSmartPtr& newP) { return operator= (newP.p); }
|
||||
|
||||
// Releases and nullifies this pointer and returns its address
|
||||
ComClass** resetAndGetPointerAddress()
|
||||
{
|
||||
release();
|
||||
p = nullptr;
|
||||
return &p;
|
||||
}
|
||||
|
||||
HRESULT CoCreateInstance (REFCLSID classUUID, DWORD dwClsContext = CLSCTX_INPROC_SERVER)
|
||||
{
|
||||
auto hr = ::CoCreateInstance (classUUID, nullptr, dwClsContext, __uuidof (ComClass), (void**) resetAndGetPointerAddress());
|
||||
jassert (hr != CO_E_NOTINITIALIZED); // You haven't called CoInitialize for the current thread!
|
||||
return hr;
|
||||
}
|
||||
|
||||
template <class OtherComClass>
|
||||
HRESULT QueryInterface (REFCLSID classUUID, ComSmartPtr<OtherComClass>& destObject) const
|
||||
{
|
||||
if (p == nullptr)
|
||||
return E_POINTER;
|
||||
|
||||
return p->QueryInterface (classUUID, (void**) destObject.resetAndGetPointerAddress());
|
||||
}
|
||||
|
||||
template <class OtherComClass>
|
||||
HRESULT QueryInterface (ComSmartPtr<OtherComClass>& destObject) const
|
||||
{
|
||||
return this->QueryInterface (__uuidof (OtherComClass), destObject);
|
||||
}
|
||||
|
||||
template <class OtherComClass>
|
||||
ComSmartPtr<OtherComClass> getInterface() const
|
||||
{
|
||||
ComSmartPtr<OtherComClass> destObject;
|
||||
|
||||
if (QueryInterface (destObject) == S_OK)
|
||||
return destObject;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
ComClass* p = nullptr;
|
||||
|
||||
void release() { if (p != nullptr) p->Release(); }
|
||||
|
||||
ComClass** operator&() noexcept; // private to avoid it being used accidentally
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
template <class First, class... ComClasses>
|
||||
class ComBaseClassHelperBase : public First, public ComClasses...
|
||||
{
|
||||
public:
|
||||
ComBaseClassHelperBase (unsigned int initialRefCount) : refCount (initialRefCount) {}
|
||||
virtual ~ComBaseClassHelperBase() = default;
|
||||
|
||||
ULONG STDMETHODCALLTYPE AddRef() { return ++refCount; }
|
||||
ULONG STDMETHODCALLTYPE Release() { auto r = --refCount; if (r == 0) delete this; return r; }
|
||||
|
||||
protected:
|
||||
ULONG refCount;
|
||||
|
||||
JUCE_COMRESULT QueryInterface (REFIID refId, void** result)
|
||||
{
|
||||
if (refId == __uuidof (IUnknown))
|
||||
return castToType<First> (result);
|
||||
|
||||
*result = nullptr;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
JUCE_COMRESULT castToType (void** result)
|
||||
{
|
||||
this->AddRef();
|
||||
*result = dynamic_cast<Type*> (this);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
};
|
||||
|
||||
/** Handy base class for writing COM objects, providing ref-counting and a basic QueryInterface method.
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
template <class... ComClasses>
|
||||
class ComBaseClassHelper : public ComBaseClassHelperBase<ComClasses...>
|
||||
{
|
||||
public:
|
||||
explicit ComBaseClassHelper (unsigned int initialRefCount = 1)
|
||||
: ComBaseClassHelperBase<ComClasses...> (initialRefCount) {}
|
||||
|
||||
JUCE_COMRESULT QueryInterface (REFIID refId, void** result)
|
||||
{
|
||||
const std::tuple<IID, void*> bases[]
|
||||
{
|
||||
std::make_tuple (__uuidof (ComClasses),
|
||||
static_cast<void*> (static_cast<ComClasses*> (this)))...
|
||||
};
|
||||
|
||||
for (const auto& base : bases)
|
||||
{
|
||||
if (refId == std::get<0> (base))
|
||||
{
|
||||
this->AddRef();
|
||||
*result = std::get<1> (base);
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return ComBaseClassHelperBase<ComClasses...>::QueryInterface (refId, result);
|
||||
}
|
||||
};
|
||||
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
|
||||
} // namespace juce
|
||||
|
2555
deps/juce/modules/juce_core/native/juce_win32_Files.cpp
vendored
2555
deps/juce/modules/juce_core/native/juce_win32_Files.cpp
vendored
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,251 +1,251 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
struct RegistryKeyWrapper
|
||||
{
|
||||
RegistryKeyWrapper (String name, bool createForWriting, DWORD wow64Flags)
|
||||
{
|
||||
if (HKEY rootKey = getRootKey (name))
|
||||
{
|
||||
name = name.substring (name.indexOfChar ('\\') + 1);
|
||||
|
||||
auto lastSlash = name.lastIndexOfChar ('\\');
|
||||
valueName = name.substring (lastSlash + 1);
|
||||
wideCharValueName = valueName.toWideCharPointer();
|
||||
|
||||
name = name.substring (0, lastSlash);
|
||||
auto wideCharName = name.toWideCharPointer();
|
||||
DWORD result;
|
||||
|
||||
if (createForWriting)
|
||||
RegCreateKeyEx (rootKey, wideCharName, 0, nullptr, REG_OPTION_NON_VOLATILE,
|
||||
KEY_WRITE | KEY_QUERY_VALUE | wow64Flags, nullptr, &key, &result);
|
||||
else
|
||||
RegOpenKeyEx (rootKey, wideCharName, 0, KEY_READ | wow64Flags, &key);
|
||||
}
|
||||
}
|
||||
|
||||
~RegistryKeyWrapper()
|
||||
{
|
||||
if (key != nullptr)
|
||||
RegCloseKey (key);
|
||||
}
|
||||
|
||||
static HKEY getRootKey (const String& name) noexcept
|
||||
{
|
||||
if (name.startsWithIgnoreCase ("HKEY_CURRENT_USER\\")) return HKEY_CURRENT_USER;
|
||||
if (name.startsWithIgnoreCase ("HKCU\\")) return HKEY_CURRENT_USER;
|
||||
if (name.startsWithIgnoreCase ("HKEY_LOCAL_MACHINE\\")) return HKEY_LOCAL_MACHINE;
|
||||
if (name.startsWithIgnoreCase ("HKLM\\")) return HKEY_LOCAL_MACHINE;
|
||||
if (name.startsWithIgnoreCase ("HKEY_CLASSES_ROOT\\")) return HKEY_CLASSES_ROOT;
|
||||
if (name.startsWithIgnoreCase ("HKCR\\")) return HKEY_CLASSES_ROOT;
|
||||
if (name.startsWithIgnoreCase ("HKEY_USERS\\")) return HKEY_USERS;
|
||||
if (name.startsWithIgnoreCase ("HKU\\")) return HKEY_USERS;
|
||||
|
||||
jassertfalse; // The name starts with an unknown root key (or maybe an old Win9x type)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool setValue (const String& regValuePath, const DWORD type,
|
||||
const void* data, size_t dataSize, const DWORD wow64Flags)
|
||||
{
|
||||
const RegistryKeyWrapper key (regValuePath, true, wow64Flags);
|
||||
|
||||
return key.key != nullptr
|
||||
&& RegSetValueEx (key.key, key.wideCharValueName, 0, type,
|
||||
reinterpret_cast<const BYTE*> (data),
|
||||
(DWORD) dataSize) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static uint32 getBinaryValue (const String& regValuePath, MemoryBlock& result, DWORD wow64Flags)
|
||||
{
|
||||
const RegistryKeyWrapper key (regValuePath, false, wow64Flags);
|
||||
|
||||
if (key.key != nullptr)
|
||||
{
|
||||
for (unsigned long bufferSize = 1024; ; bufferSize *= 2)
|
||||
{
|
||||
result.setSize (bufferSize, false);
|
||||
DWORD type = REG_NONE;
|
||||
|
||||
auto err = RegQueryValueEx (key.key, key.wideCharValueName, nullptr, &type,
|
||||
(LPBYTE) result.getData(), &bufferSize);
|
||||
|
||||
if (err == ERROR_SUCCESS)
|
||||
{
|
||||
result.setSize (bufferSize, false);
|
||||
return type;
|
||||
}
|
||||
|
||||
if (err != ERROR_MORE_DATA)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return REG_NONE;
|
||||
}
|
||||
|
||||
static String getValue (const String& regValuePath, const String& defaultValue, DWORD wow64Flags)
|
||||
{
|
||||
MemoryBlock buffer;
|
||||
|
||||
switch (getBinaryValue (regValuePath, buffer, wow64Flags))
|
||||
{
|
||||
case REG_SZ: return static_cast<const WCHAR*> (buffer.getData());
|
||||
case REG_DWORD: return String ((int) *reinterpret_cast<const DWORD*> (buffer.getData()));
|
||||
default: break;
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
static bool keyExists (const String& regKeyPath, const DWORD wow64Flags)
|
||||
{
|
||||
return RegistryKeyWrapper (regKeyPath + "\\", false, wow64Flags).key != nullptr;
|
||||
}
|
||||
|
||||
static bool valueExists (const String& regValuePath, const DWORD wow64Flags)
|
||||
{
|
||||
const RegistryKeyWrapper key (regValuePath, false, wow64Flags);
|
||||
|
||||
if (key.key == nullptr)
|
||||
return false;
|
||||
|
||||
unsigned char buffer [512];
|
||||
unsigned long bufferSize = sizeof (buffer);
|
||||
DWORD type = 0;
|
||||
|
||||
auto result = RegQueryValueEx (key.key, key.wideCharValueName,
|
||||
nullptr, &type, buffer, &bufferSize);
|
||||
|
||||
return result == ERROR_SUCCESS || result == ERROR_MORE_DATA;
|
||||
}
|
||||
|
||||
HKEY key = nullptr;
|
||||
const wchar_t* wideCharValueName = nullptr;
|
||||
String valueName;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (RegistryKeyWrapper)
|
||||
};
|
||||
|
||||
uint32 JUCE_CALLTYPE WindowsRegistry::getBinaryValue (const String& regValuePath, MemoryBlock& result, WoW64Mode mode)
|
||||
{
|
||||
return RegistryKeyWrapper::getBinaryValue (regValuePath, result, (DWORD) mode);
|
||||
}
|
||||
|
||||
String JUCE_CALLTYPE WindowsRegistry::getValue (const String& regValuePath, const String& defaultValue, WoW64Mode mode)
|
||||
{
|
||||
return RegistryKeyWrapper::getValue (regValuePath, defaultValue, (DWORD) mode);
|
||||
}
|
||||
|
||||
bool JUCE_CALLTYPE WindowsRegistry::setValue (const String& regValuePath, const String& value, WoW64Mode mode)
|
||||
{
|
||||
return RegistryKeyWrapper::setValue (regValuePath, REG_SZ, value.toWideCharPointer(),
|
||||
CharPointer_UTF16::getBytesRequiredFor (value.getCharPointer()), mode);
|
||||
}
|
||||
|
||||
bool JUCE_CALLTYPE WindowsRegistry::setValue (const String& regValuePath, const uint32 value, WoW64Mode mode)
|
||||
{
|
||||
return RegistryKeyWrapper::setValue (regValuePath, REG_DWORD, &value, sizeof (value), (DWORD) mode);
|
||||
}
|
||||
|
||||
bool JUCE_CALLTYPE WindowsRegistry::setValue (const String& regValuePath, const uint64 value, WoW64Mode mode)
|
||||
{
|
||||
return RegistryKeyWrapper::setValue (regValuePath, REG_QWORD, &value, sizeof (value), (DWORD) mode);
|
||||
}
|
||||
|
||||
bool JUCE_CALLTYPE WindowsRegistry::setValue (const String& regValuePath, const MemoryBlock& value, WoW64Mode mode)
|
||||
{
|
||||
return RegistryKeyWrapper::setValue (regValuePath, REG_BINARY, value.getData(), value.getSize(), (DWORD) mode);
|
||||
}
|
||||
|
||||
bool JUCE_CALLTYPE WindowsRegistry::valueExists (const String& regValuePath, WoW64Mode mode)
|
||||
{
|
||||
return RegistryKeyWrapper::valueExists (regValuePath, (DWORD) mode);
|
||||
}
|
||||
|
||||
bool JUCE_CALLTYPE WindowsRegistry::keyExists (const String& regKeyPath, WoW64Mode mode)
|
||||
{
|
||||
return RegistryKeyWrapper::keyExists (regKeyPath, (DWORD) mode);
|
||||
}
|
||||
|
||||
bool JUCE_CALLTYPE WindowsRegistry::deleteValue (const String& regValuePath, WoW64Mode mode)
|
||||
{
|
||||
const RegistryKeyWrapper key (regValuePath, true, (DWORD) mode);
|
||||
|
||||
return key.key != nullptr && RegDeleteValue (key.key, key.wideCharValueName) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static bool deleteKeyNonRecursive (const String& regKeyPath, WindowsRegistry::WoW64Mode mode)
|
||||
{
|
||||
const RegistryKeyWrapper key (regKeyPath, true, (DWORD) mode);
|
||||
|
||||
return key.key != nullptr && RegDeleteKey (key.key, key.wideCharValueName) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
bool JUCE_CALLTYPE WindowsRegistry::deleteKey (const String& regKeyPath, WoW64Mode mode)
|
||||
{
|
||||
if (deleteKeyNonRecursive (regKeyPath, mode))
|
||||
return true;
|
||||
|
||||
for (const RegistryKeyWrapper key (regKeyPath + "\\", false, (DWORD) mode);;)
|
||||
{
|
||||
wchar_t subKey[MAX_PATH + 1] = {};
|
||||
DWORD subKeySize = MAX_PATH;
|
||||
|
||||
if (RegEnumKeyEx (key.key, 0, subKey, &subKeySize, nullptr, nullptr, nullptr, nullptr) != ERROR_SUCCESS
|
||||
|| ! deleteKey (regKeyPath + "\\" + String (subKey), mode))
|
||||
break;
|
||||
}
|
||||
|
||||
return deleteKeyNonRecursive (regKeyPath, mode);
|
||||
}
|
||||
|
||||
bool JUCE_CALLTYPE WindowsRegistry::registerFileAssociation (const String& fileExtension,
|
||||
const String& symbolicDescription,
|
||||
const String& fullDescription,
|
||||
const File& targetExecutable,
|
||||
const int iconResourceNumber,
|
||||
const bool registerForCurrentUserOnly,
|
||||
WoW64Mode mode)
|
||||
{
|
||||
auto root = registerForCurrentUserOnly ? "HKEY_CURRENT_USER\\Software\\Classes\\"
|
||||
: "HKEY_CLASSES_ROOT\\";
|
||||
auto key = root + symbolicDescription;
|
||||
|
||||
return setValue (root + fileExtension + "\\", symbolicDescription, mode)
|
||||
&& setValue (key + "\\", fullDescription, mode)
|
||||
&& setValue (key + "\\shell\\open\\command\\", targetExecutable.getFullPathName() + " \"%1\"", mode)
|
||||
&& (iconResourceNumber == 0
|
||||
|| setValue (key + "\\DefaultIcon\\",
|
||||
targetExecutable.getFullPathName() + "," + String (iconResourceNumber)));
|
||||
}
|
||||
|
||||
// These methods are deprecated:
|
||||
String WindowsRegistry::getValueWow64 (const String& p, const String& defVal) { return getValue (p, defVal, WoW64_64bit); }
|
||||
bool WindowsRegistry::valueExistsWow64 (const String& p) { return valueExists (p, WoW64_64bit); }
|
||||
bool WindowsRegistry::keyExistsWow64 (const String& p) { return keyExists (p, WoW64_64bit); }
|
||||
|
||||
} // namespace juce
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
struct RegistryKeyWrapper
|
||||
{
|
||||
RegistryKeyWrapper (String name, bool createForWriting, DWORD wow64Flags)
|
||||
{
|
||||
if (HKEY rootKey = getRootKey (name))
|
||||
{
|
||||
name = name.substring (name.indexOfChar ('\\') + 1);
|
||||
|
||||
auto lastSlash = name.lastIndexOfChar ('\\');
|
||||
valueName = name.substring (lastSlash + 1);
|
||||
wideCharValueName = valueName.toWideCharPointer();
|
||||
|
||||
name = name.substring (0, lastSlash);
|
||||
auto wideCharName = name.toWideCharPointer();
|
||||
DWORD result;
|
||||
|
||||
if (createForWriting)
|
||||
RegCreateKeyEx (rootKey, wideCharName, 0, nullptr, REG_OPTION_NON_VOLATILE,
|
||||
KEY_WRITE | KEY_QUERY_VALUE | wow64Flags, nullptr, &key, &result);
|
||||
else
|
||||
RegOpenKeyEx (rootKey, wideCharName, 0, KEY_READ | wow64Flags, &key);
|
||||
}
|
||||
}
|
||||
|
||||
~RegistryKeyWrapper()
|
||||
{
|
||||
if (key != nullptr)
|
||||
RegCloseKey (key);
|
||||
}
|
||||
|
||||
static HKEY getRootKey (const String& name) noexcept
|
||||
{
|
||||
if (name.startsWithIgnoreCase ("HKEY_CURRENT_USER\\")) return HKEY_CURRENT_USER;
|
||||
if (name.startsWithIgnoreCase ("HKCU\\")) return HKEY_CURRENT_USER;
|
||||
if (name.startsWithIgnoreCase ("HKEY_LOCAL_MACHINE\\")) return HKEY_LOCAL_MACHINE;
|
||||
if (name.startsWithIgnoreCase ("HKLM\\")) return HKEY_LOCAL_MACHINE;
|
||||
if (name.startsWithIgnoreCase ("HKEY_CLASSES_ROOT\\")) return HKEY_CLASSES_ROOT;
|
||||
if (name.startsWithIgnoreCase ("HKCR\\")) return HKEY_CLASSES_ROOT;
|
||||
if (name.startsWithIgnoreCase ("HKEY_USERS\\")) return HKEY_USERS;
|
||||
if (name.startsWithIgnoreCase ("HKU\\")) return HKEY_USERS;
|
||||
|
||||
jassertfalse; // The name starts with an unknown root key (or maybe an old Win9x type)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool setValue (const String& regValuePath, const DWORD type,
|
||||
const void* data, size_t dataSize, const DWORD wow64Flags)
|
||||
{
|
||||
const RegistryKeyWrapper key (regValuePath, true, wow64Flags);
|
||||
|
||||
return key.key != nullptr
|
||||
&& RegSetValueEx (key.key, key.wideCharValueName, 0, type,
|
||||
reinterpret_cast<const BYTE*> (data),
|
||||
(DWORD) dataSize) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static uint32 getBinaryValue (const String& regValuePath, MemoryBlock& result, DWORD wow64Flags)
|
||||
{
|
||||
const RegistryKeyWrapper key (regValuePath, false, wow64Flags);
|
||||
|
||||
if (key.key != nullptr)
|
||||
{
|
||||
for (unsigned long bufferSize = 1024; ; bufferSize *= 2)
|
||||
{
|
||||
result.setSize (bufferSize, false);
|
||||
DWORD type = REG_NONE;
|
||||
|
||||
auto err = RegQueryValueEx (key.key, key.wideCharValueName, nullptr, &type,
|
||||
(LPBYTE) result.getData(), &bufferSize);
|
||||
|
||||
if (err == ERROR_SUCCESS)
|
||||
{
|
||||
result.setSize (bufferSize, false);
|
||||
return type;
|
||||
}
|
||||
|
||||
if (err != ERROR_MORE_DATA)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return REG_NONE;
|
||||
}
|
||||
|
||||
static String getValue (const String& regValuePath, const String& defaultValue, DWORD wow64Flags)
|
||||
{
|
||||
MemoryBlock buffer;
|
||||
|
||||
switch (getBinaryValue (regValuePath, buffer, wow64Flags))
|
||||
{
|
||||
case REG_SZ: return static_cast<const WCHAR*> (buffer.getData());
|
||||
case REG_DWORD: return String ((int) *reinterpret_cast<const DWORD*> (buffer.getData()));
|
||||
default: break;
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
static bool keyExists (const String& regKeyPath, const DWORD wow64Flags)
|
||||
{
|
||||
return RegistryKeyWrapper (regKeyPath + "\\", false, wow64Flags).key != nullptr;
|
||||
}
|
||||
|
||||
static bool valueExists (const String& regValuePath, const DWORD wow64Flags)
|
||||
{
|
||||
const RegistryKeyWrapper key (regValuePath, false, wow64Flags);
|
||||
|
||||
if (key.key == nullptr)
|
||||
return false;
|
||||
|
||||
unsigned char buffer [512];
|
||||
unsigned long bufferSize = sizeof (buffer);
|
||||
DWORD type = 0;
|
||||
|
||||
auto result = RegQueryValueEx (key.key, key.wideCharValueName,
|
||||
nullptr, &type, buffer, &bufferSize);
|
||||
|
||||
return result == ERROR_SUCCESS || result == ERROR_MORE_DATA;
|
||||
}
|
||||
|
||||
HKEY key = nullptr;
|
||||
const wchar_t* wideCharValueName = nullptr;
|
||||
String valueName;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (RegistryKeyWrapper)
|
||||
};
|
||||
|
||||
uint32 JUCE_CALLTYPE WindowsRegistry::getBinaryValue (const String& regValuePath, MemoryBlock& result, WoW64Mode mode)
|
||||
{
|
||||
return RegistryKeyWrapper::getBinaryValue (regValuePath, result, (DWORD) mode);
|
||||
}
|
||||
|
||||
String JUCE_CALLTYPE WindowsRegistry::getValue (const String& regValuePath, const String& defaultValue, WoW64Mode mode)
|
||||
{
|
||||
return RegistryKeyWrapper::getValue (regValuePath, defaultValue, (DWORD) mode);
|
||||
}
|
||||
|
||||
bool JUCE_CALLTYPE WindowsRegistry::setValue (const String& regValuePath, const String& value, WoW64Mode mode)
|
||||
{
|
||||
return RegistryKeyWrapper::setValue (regValuePath, REG_SZ, value.toWideCharPointer(),
|
||||
CharPointer_UTF16::getBytesRequiredFor (value.getCharPointer()), mode);
|
||||
}
|
||||
|
||||
bool JUCE_CALLTYPE WindowsRegistry::setValue (const String& regValuePath, const uint32 value, WoW64Mode mode)
|
||||
{
|
||||
return RegistryKeyWrapper::setValue (regValuePath, REG_DWORD, &value, sizeof (value), (DWORD) mode);
|
||||
}
|
||||
|
||||
bool JUCE_CALLTYPE WindowsRegistry::setValue (const String& regValuePath, const uint64 value, WoW64Mode mode)
|
||||
{
|
||||
return RegistryKeyWrapper::setValue (regValuePath, REG_QWORD, &value, sizeof (value), (DWORD) mode);
|
||||
}
|
||||
|
||||
bool JUCE_CALLTYPE WindowsRegistry::setValue (const String& regValuePath, const MemoryBlock& value, WoW64Mode mode)
|
||||
{
|
||||
return RegistryKeyWrapper::setValue (regValuePath, REG_BINARY, value.getData(), value.getSize(), (DWORD) mode);
|
||||
}
|
||||
|
||||
bool JUCE_CALLTYPE WindowsRegistry::valueExists (const String& regValuePath, WoW64Mode mode)
|
||||
{
|
||||
return RegistryKeyWrapper::valueExists (regValuePath, (DWORD) mode);
|
||||
}
|
||||
|
||||
bool JUCE_CALLTYPE WindowsRegistry::keyExists (const String& regKeyPath, WoW64Mode mode)
|
||||
{
|
||||
return RegistryKeyWrapper::keyExists (regKeyPath, (DWORD) mode);
|
||||
}
|
||||
|
||||
bool JUCE_CALLTYPE WindowsRegistry::deleteValue (const String& regValuePath, WoW64Mode mode)
|
||||
{
|
||||
const RegistryKeyWrapper key (regValuePath, true, (DWORD) mode);
|
||||
|
||||
return key.key != nullptr && RegDeleteValue (key.key, key.wideCharValueName) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static bool deleteKeyNonRecursive (const String& regKeyPath, WindowsRegistry::WoW64Mode mode)
|
||||
{
|
||||
const RegistryKeyWrapper key (regKeyPath, true, (DWORD) mode);
|
||||
|
||||
return key.key != nullptr && RegDeleteKey (key.key, key.wideCharValueName) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
bool JUCE_CALLTYPE WindowsRegistry::deleteKey (const String& regKeyPath, WoW64Mode mode)
|
||||
{
|
||||
if (deleteKeyNonRecursive (regKeyPath, mode))
|
||||
return true;
|
||||
|
||||
for (const RegistryKeyWrapper key (regKeyPath + "\\", false, (DWORD) mode);;)
|
||||
{
|
||||
wchar_t subKey[MAX_PATH + 1] = {};
|
||||
DWORD subKeySize = MAX_PATH;
|
||||
|
||||
if (RegEnumKeyEx (key.key, 0, subKey, &subKeySize, nullptr, nullptr, nullptr, nullptr) != ERROR_SUCCESS
|
||||
|| ! deleteKey (regKeyPath + "\\" + String (subKey), mode))
|
||||
break;
|
||||
}
|
||||
|
||||
return deleteKeyNonRecursive (regKeyPath, mode);
|
||||
}
|
||||
|
||||
bool JUCE_CALLTYPE WindowsRegistry::registerFileAssociation (const String& fileExtension,
|
||||
const String& symbolicDescription,
|
||||
const String& fullDescription,
|
||||
const File& targetExecutable,
|
||||
const int iconResourceNumber,
|
||||
const bool registerForCurrentUserOnly,
|
||||
WoW64Mode mode)
|
||||
{
|
||||
auto root = registerForCurrentUserOnly ? "HKEY_CURRENT_USER\\Software\\Classes\\"
|
||||
: "HKEY_CLASSES_ROOT\\";
|
||||
auto key = root + symbolicDescription;
|
||||
|
||||
return setValue (root + fileExtension + "\\", symbolicDescription, mode)
|
||||
&& setValue (key + "\\", fullDescription, mode)
|
||||
&& setValue (key + "\\shell\\open\\command\\", targetExecutable.getFullPathName() + " \"%1\"", mode)
|
||||
&& (iconResourceNumber == 0
|
||||
|| setValue (key + "\\DefaultIcon\\",
|
||||
targetExecutable.getFullPathName() + "," + String (iconResourceNumber)));
|
||||
}
|
||||
|
||||
// These methods are deprecated:
|
||||
String WindowsRegistry::getValueWow64 (const String& p, const String& defVal) { return getValue (p, defVal, WoW64_64bit); }
|
||||
bool WindowsRegistry::valueExistsWow64 (const String& p) { return valueExists (p, WoW64_64bit); }
|
||||
bool WindowsRegistry::keyExistsWow64 (const String& p) { return keyExists (p, WoW64_64bit); }
|
||||
|
||||
} // namespace juce
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user