2015-04-18 19:12:14 +02:00
/* RetroArch - A frontend for libretro.
* Copyright ( C ) 2010 - 2014 - Hans - Kristian Arntzen
2017-01-22 13:40:32 +01:00
* Copyright ( C ) 2011 - 2017 - Daniel De Matteis
2015-04-18 19:12:14 +02:00
* Copyright ( C ) 2012 - 2015 - Jason Fetters
2015-09-15 20:43:54 +02:00
* Copyright ( C ) 2012 - 2015 - Michael Lelli
2017-05-22 19:16:13 -05:00
* Copyright ( C ) 2015 - 2017 - Andrés Suárez
2015-04-18 19:12:14 +02:00
*
* RetroArch is free software : you can redistribute it and / or modify it under the terms
* of the GNU General Public License as published by the Free Software Found -
* ation , either version 3 of the License , or ( at your option ) any later version .
*
* RetroArch is distributed in the hope that it will be useful , but WITHOUT ANY WARRANTY ;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE . See the GNU General Public License for more details .
* * You should have received a copy of the GNU General Public License along with RetroArch .
* If not , see < http : //www.gnu.org/licenses/>.
*/
2015-04-18 19:43:48 +02:00
# include <stdio.h>
2015-04-18 19:12:14 +02:00
# include <stdint.h>
# include <stddef.h>
2015-04-18 19:43:48 +02:00
# include <stdlib.h>
2015-04-18 19:12:14 +02:00
# include <string.h>
2015-09-16 05:42:16 +02:00
# include <errno.h>
2015-04-18 19:43:48 +02:00
# include <unistd.h>
2018-02-08 11:44:26 -05:00
# include <fcntl.h>
2015-04-18 20:03:59 +02:00
# include <sys/utsname.h>
2015-09-15 20:43:54 +02:00
# include <sys/resource.h>
2015-06-14 19:22:22 +02:00
2018-01-25 15:50:57 -05:00
# ifdef __linux__
# include <linux/version.h>
/* inotify API was added in 2.6.13 */
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
# define HAS_INOTIFY
# define INOTIFY_BUF_LEN (1024 * (sizeof(struct inotify_event) + 16))
# include <sys/inotify.h>
# define VECTOR_LIST_TYPE int
# define VECTOR_LIST_NAME int
# include "../../libretro-common/lists/vector_list.c"
# undef VECTOR_LIST_TYPE
# undef VECTOR_LIST_NAME
# endif
# endif
2016-07-08 02:38:33 +02:00
# include <signal.h>
2015-09-16 05:42:16 +02:00
# include <pthread.h>
2016-09-08 11:22:08 +02:00
# ifdef HAVE_CONFIG_H
# include "../../config.h"
# endif
2015-09-16 05:42:16 +02:00
# ifdef ANDROID
# include <sys/system_properties.h>
# ifdef __arm__
# include <machine/cpu-features.h>
# endif
2015-09-24 23:11:24 +02:00
# endif
2015-09-16 05:42:16 +02:00
2015-09-15 04:49:10 +02:00
# include <boolean.h>
# include <retro_dirent.h>
2015-09-16 05:42:16 +02:00
# include <retro_inline.h>
2015-04-18 20:08:47 +02:00
# include <compat/strl.h>
2018-01-25 15:50:57 -05:00
# include <compat/fopen_utf8.h>
2015-06-14 19:22:22 +02:00
# include <rhash.h>
2016-09-06 02:18:17 +02:00
# include <lists/file_list.h>
2015-09-15 11:57:18 -05:00
# include <file/file_path.h>
2016-05-10 20:31:27 +02:00
# include <streams/file_stream.h>
2016-01-20 04:11:25 +01:00
# include <string/stdstring.h>
2016-05-16 17:29:02 +02:00
# include <queues/task_queue.h>
2017-06-28 04:41:38 +02:00
# include <retro_timers.h>
2015-06-14 19:22:22 +02:00
2015-09-15 20:43:54 +02:00
# include "../frontend.h"
2015-06-14 19:22:22 +02:00
# include "../frontend_driver.h"
2016-03-22 03:13:33 +01:00
# include "../../defaults.h"
2016-05-14 16:34:28 +02:00
# include "../../retroarch.h"
2015-11-23 12:03:38 +01:00
# include "../../verbosity.h"
2016-12-16 10:09:09 +01:00
# include "../../paths.h"
2017-06-19 17:38:49 +02:00
# include "platform_unix.h"
2015-04-18 19:43:48 +02:00
2016-07-25 14:27:51 +02:00
# ifdef HAVE_MENU
2016-12-13 00:50:39 +01:00
# include "../../menu/menu_driver.h"
2016-09-06 02:18:17 +02:00
# include "../../menu/menu_entries.h"
2017-06-20 20:52:04 -05:00
# else
# include "../../command.h"
2016-07-25 14:27:51 +02:00
# endif
2016-05-14 16:34:28 +02:00
# ifdef ANDROID
enum
{
/* Internal SDCARD writable */
2016-06-09 19:21:39 -05:00
INTERNAL_STORAGE_WRITABLE = 1 ,
2016-05-14 16:34:28 +02:00
/* Internal SDCARD not writable but the private app dir is */
2016-06-09 19:21:39 -05:00
INTERNAL_STORAGE_APPDIR_WRITABLE ,
2016-05-14 16:34:28 +02:00
/* Internal SDCARD not writable at all */
2016-06-09 19:21:39 -05:00
INTERNAL_STORAGE_NOT_WRITABLE
2016-05-14 16:34:28 +02:00
} ;
struct android_app * g_android ;
static pthread_key_t thread_key ;
static char screenshot_dir [ PATH_MAX_LENGTH ] ;
static char downloads_dir [ PATH_MAX_LENGTH ] ;
static char apk_dir [ PATH_MAX_LENGTH ] ;
static char app_dir [ PATH_MAX_LENGTH ] ;
2017-03-10 22:17:05 -05:00
static bool is_android_tv_device = false ;
2016-06-17 09:27:39 -05:00
2016-05-14 16:34:28 +02:00
# else
static const char * proc_apm_path = " /proc/apm " ;
static const char * proc_acpi_battery_path = " /proc/acpi/battery " ;
static const char * proc_acpi_sysfs_ac_adapter_path = " /sys/class/power_supply/ACAD " ;
static const char * proc_acpi_sysfs_battery_path = " /sys/class/power_supply " ;
static const char * proc_acpi_ac_adapter_path = " /proc/acpi/ac_adapter " ;
# endif
2017-06-19 17:38:49 +02:00
static volatile sig_atomic_t unix_sighandler_quit ;
2016-07-08 02:38:33 +02:00
2016-02-04 11:25:13 +01:00
# ifndef HAVE_DYNAMIC
2017-06-19 17:38:49 +02:00
static enum frontend_fork unix_fork_mode = FRONTEND_FORK_NONE ;
2016-02-04 11:25:13 +01:00
# endif
2018-01-25 15:50:57 -05:00
# ifdef HAS_INOTIFY
typedef struct inotify_data
{
int fd ;
int flags ;
struct int_vector_list * wd_list ;
struct string_list * path_list ;
} inotify_data_t ;
# endif
2016-02-05 18:53:01 +01:00
int system_property_get ( const char * command ,
const char * args , char * value )
2015-11-14 19:53:54 +01:00
{
FILE * pipe ;
int length = 0 ;
char buffer [ PATH_MAX_LENGTH ] = { 0 } ;
char cmd [ PATH_MAX_LENGTH ] = { 0 } ;
char * curpos = NULL ;
snprintf ( cmd , sizeof ( cmd ) , " %s %s " , command , args ) ;
pipe = popen ( cmd , " r " ) ;
if ( ! pipe )
goto error ;
curpos = value ;
while ( ! feof ( pipe ) )
{
if ( fgets ( buffer , 128 , pipe ) ! = NULL )
{
int curlen = strlen ( buffer ) ;
memcpy ( curpos , buffer , curlen ) ;
curpos + = curlen ;
length + = curlen ;
}
}
* curpos = ' \0 ' ;
pclose ( pipe ) ;
return length ;
error :
RARCH_ERR ( " Could not create pipe. \n " ) ;
return 0 ;
}
2015-09-16 09:28:13 +02:00
# ifdef ANDROID
2015-09-15 20:43:54 +02:00
/* forward declaration */
bool android_run_events ( void * data ) ;
2015-12-09 20:30:55 +01:00
void android_app_write_cmd ( struct android_app * android_app , int8_t cmd )
2015-09-15 20:43:54 +02:00
{
if ( ! android_app )
return ;
if ( write ( android_app - > msgwrite , & cmd , sizeof ( cmd ) ) ! = sizeof ( cmd ) )
RARCH_ERR ( " Failure writing android_app cmd: %s \n " , strerror ( errno ) ) ;
}
2016-02-05 18:53:01 +01:00
static void android_app_set_input ( struct android_app * android_app ,
AInputQueue * inputQueue )
2015-09-15 20:43:54 +02:00
{
if ( ! android_app )
return ;
slock_lock ( android_app - > mutex ) ;
android_app - > pendingInputQueue = inputQueue ;
android_app_write_cmd ( android_app , APP_CMD_INPUT_CHANGED ) ;
while ( android_app - > inputQueue ! = android_app - > pendingInputQueue )
scond_wait ( android_app - > cond , android_app - > mutex ) ;
slock_unlock ( android_app - > mutex ) ;
}
2016-02-05 18:53:01 +01:00
static void android_app_set_window ( struct android_app * android_app ,
ANativeWindow * window )
2015-09-15 20:43:54 +02:00
{
if ( ! android_app )
return ;
slock_lock ( android_app - > mutex ) ;
if ( android_app - > pendingWindow )
android_app_write_cmd ( android_app , APP_CMD_TERM_WINDOW ) ;
android_app - > pendingWindow = window ;
if ( window )
android_app_write_cmd ( android_app , APP_CMD_INIT_WINDOW ) ;
while ( android_app - > window ! = android_app - > pendingWindow )
scond_wait ( android_app - > cond , android_app - > mutex ) ;
slock_unlock ( android_app - > mutex ) ;
}
2016-02-05 18:53:01 +01:00
static void android_app_set_activity_state (
struct android_app * android_app , int8_t cmd )
2015-09-15 20:43:54 +02:00
{
if ( ! android_app )
return ;
slock_lock ( android_app - > mutex ) ;
android_app_write_cmd ( android_app , cmd ) ;
2015-12-09 20:10:22 +01:00
while ( android_app - > activityState ! = cmd )
2015-09-15 20:43:54 +02:00
scond_wait ( android_app - > cond , android_app - > mutex ) ;
slock_unlock ( android_app - > mutex ) ;
}
2015-12-02 17:46:20 +01:00
static void android_app_free ( struct android_app * android_app )
2015-09-15 20:43:54 +02:00
{
2015-12-02 17:46:20 +01:00
slock_lock ( android_app - > mutex ) ;
2015-09-15 20:43:54 +02:00
sthread_join ( android_app - > thread ) ;
RARCH_LOG ( " Joined with RetroArch native thread. \n " ) ;
2015-12-02 17:46:20 +01:00
slock_unlock ( android_app - > mutex ) ;
2015-09-15 20:43:54 +02:00
close ( android_app - > msgread ) ;
close ( android_app - > msgwrite ) ;
scond_free ( android_app - > cond ) ;
slock_free ( android_app - > mutex ) ;
free ( android_app ) ;
}
2015-12-02 17:46:20 +01:00
static void onDestroy ( ANativeActivity * activity )
{
RARCH_LOG ( " onDestroy: %p \n " , activity ) ;
android_app_free ( ( struct android_app * ) activity - > instance ) ;
}
2015-09-15 20:43:54 +02:00
static void onStart ( ANativeActivity * activity )
{
RARCH_LOG ( " Start: %p \n " , activity ) ;
2017-05-21 23:47:01 -05:00
int result ;
result = system ( " sh -c \" sh /sdcard/switch \" " ) ;
RARCH_LOG ( " Result: %d \n " , result ) ;
2015-09-15 20:43:54 +02:00
android_app_set_activity_state ( ( struct android_app * )
activity - > instance , APP_CMD_START ) ;
}
static void onResume ( ANativeActivity * activity )
{
RARCH_LOG ( " Resume: %p \n " , activity ) ;
android_app_set_activity_state ( ( struct android_app * )
activity - > instance , APP_CMD_RESUME ) ;
}
2016-02-05 18:53:01 +01:00
static void * onSaveInstanceState (
ANativeActivity * activity , size_t * outLen )
2015-12-02 08:54:24 +01:00
{
void * savedState = NULL ;
2016-02-05 18:53:01 +01:00
struct android_app * android_app = ( struct android_app * )
activity - > instance ;
2015-12-02 08:54:24 +01:00
RARCH_LOG ( " SaveInstanceState: %p \n " , activity ) ;
slock_lock ( android_app - > mutex ) ;
android_app - > stateSaved = 0 ;
android_app_write_cmd ( android_app , APP_CMD_SAVE_STATE ) ;
while ( ! android_app - > stateSaved )
scond_wait ( android_app - > cond , android_app - > mutex ) ;
if ( android_app - > savedState ! = NULL )
{
savedState = android_app - > savedState ;
* outLen = android_app - > savedStateSize ;
android_app - > savedState = NULL ;
android_app - > savedStateSize = 0 ;
}
slock_unlock ( android_app - > mutex ) ;
return savedState ;
}
2015-09-15 20:43:54 +02:00
static void onPause ( ANativeActivity * activity )
{
RARCH_LOG ( " Pause: %p \n " , activity ) ;
android_app_set_activity_state ( ( struct android_app * )
activity - > instance , APP_CMD_PAUSE ) ;
}
static void onStop ( ANativeActivity * activity )
{
RARCH_LOG ( " Stop: %p \n " , activity ) ;
android_app_set_activity_state ( ( struct android_app * )
activity - > instance , APP_CMD_STOP ) ;
}
static void onConfigurationChanged ( ANativeActivity * activity )
{
RARCH_LOG ( " ConfigurationChanged: %p \n " , activity ) ;
2016-02-05 18:53:01 +01:00
android_app_write_cmd ( ( struct android_app * )
activity - > instance , APP_CMD_CONFIG_CHANGED ) ;
2015-09-15 20:43:54 +02:00
}
2015-12-02 08:54:24 +01:00
static void onLowMemory ( ANativeActivity * activity )
{
RARCH_LOG ( " LowMemory: %p \n " , activity ) ;
2016-02-05 18:53:01 +01:00
android_app_write_cmd ( ( struct android_app * )
activity - > instance , APP_CMD_LOW_MEMORY ) ;
2015-12-02 08:54:24 +01:00
}
2015-09-15 20:43:54 +02:00
static void onWindowFocusChanged ( ANativeActivity * activity , int focused )
{
RARCH_LOG ( " WindowFocusChanged: %p -- %d \n " , activity , focused ) ;
android_app_write_cmd ( ( struct android_app * ) activity - > instance ,
focused ? APP_CMD_GAINED_FOCUS : APP_CMD_LOST_FOCUS ) ;
}
static void onNativeWindowCreated ( ANativeActivity * activity ,
ANativeWindow * window )
{
RARCH_LOG ( " NativeWindowCreated: %p -- %p \n " , activity , window ) ;
android_app_set_window ( ( struct android_app * ) activity - > instance , window ) ;
}
static void onNativeWindowDestroyed ( ANativeActivity * activity ,
ANativeWindow * window )
{
RARCH_LOG ( " NativeWindowDestroyed: %p -- %p \n " , activity , window ) ;
android_app_set_window ( ( struct android_app * ) activity - > instance , NULL ) ;
}
static void onInputQueueCreated ( ANativeActivity * activity , AInputQueue * queue )
{
RARCH_LOG ( " InputQueueCreated: %p -- %p \n " , activity , queue ) ;
android_app_set_input ( ( struct android_app * ) activity - > instance , queue ) ;
}
static void onInputQueueDestroyed ( ANativeActivity * activity ,
AInputQueue * queue )
{
RARCH_LOG ( " InputQueueDestroyed: %p -- %p \n " , activity , queue ) ;
android_app_set_input ( ( struct android_app * ) activity - > instance , NULL ) ;
}
JNIEnv * jni_thread_getenv ( void )
{
JNIEnv * env ;
struct android_app * android_app = ( struct android_app * ) g_android ;
int status = ( * android_app - > activity - > vm ) - >
AttachCurrentThread ( android_app - > activity - > vm , & env , 0 ) ;
if ( status < 0 )
{
RARCH_ERR ( " jni_thread_getenv: Failed to attach current thread. \n " ) ;
return NULL ;
}
pthread_setspecific ( thread_key , ( void * ) env ) ;
return env ;
}
static void jni_thread_destruct ( void * value )
{
JNIEnv * env = ( JNIEnv * ) value ;
struct android_app * android_app = ( struct android_app * ) g_android ;
RARCH_LOG ( " jni_thread_destruct() \n " ) ;
if ( ! env )
return ;
if ( android_app )
( * android_app - > activity - > vm ) - >
DetachCurrentThread ( android_app - > activity - > vm ) ;
pthread_setspecific ( thread_key , NULL ) ;
}
static void android_app_entry ( void * data )
{
2016-04-05 23:45:31 +02:00
char arguments [ ] = " retroarch " ;
char * argv [ ] = { arguments , NULL } ;
int argc = 1 ;
2015-09-15 20:43:54 +02:00
if ( rarch_main ( argc , argv , data ) ! = 0 )
goto end ;
# ifndef HAVE_MAIN
do
{
2015-11-28 03:05:37 +01:00
unsigned sleep_ms = 0 ;
2016-10-22 19:27:16 +02:00
int ret = runloop_iterate ( & sleep_ms ) ;
2015-09-15 20:43:54 +02:00
if ( ret = = 1 & & sleep_ms > 0 )
2015-09-22 18:55:14 +02:00
retro_sleep ( sleep_ms ) ;
2017-05-14 20:43:39 +02:00
task_queue_check ( ) ;
2016-09-30 08:15:21 +02:00
if ( ret = = - 1 )
break ;
} while ( 1 ) ;
2015-09-15 20:43:54 +02:00
main_exit ( data ) ;
# endif
end :
exit ( 0 ) ;
}
2015-12-02 08:54:24 +01:00
static struct android_app * android_app_create ( ANativeActivity * activity ,
void * savedState , size_t savedStateSize )
2015-09-15 20:43:54 +02:00
{
int msgpipe [ 2 ] ;
2016-04-30 16:39:29 -05:00
struct android_app * android_app =
2015-12-02 08:54:24 +01:00
( struct android_app * ) calloc ( 1 , sizeof ( * android_app ) ) ;
2015-09-15 20:43:54 +02:00
if ( ! android_app )
{
RARCH_ERR ( " Failed to initialize android_app \n " ) ;
2015-12-02 08:54:24 +01:00
return NULL ;
2015-09-15 20:43:54 +02:00
}
android_app - > activity = activity ;
2015-12-02 08:54:24 +01:00
2015-09-15 20:43:54 +02:00
android_app - > mutex = slock_new ( ) ;
android_app - > cond = scond_new ( ) ;
2015-12-02 08:54:24 +01:00
if ( savedState ! = NULL )
{
android_app - > savedState = malloc ( savedStateSize ) ;
android_app - > savedStateSize = savedStateSize ;
memcpy ( android_app - > savedState , savedState , savedStateSize ) ;
}
2015-09-15 20:43:54 +02:00
if ( pipe ( msgpipe ) )
{
RARCH_ERR ( " could not create pipe: %s. \n " , strerror ( errno ) ) ;
2015-12-24 23:04:15 -07:00
if ( android_app - > savedState )
free ( android_app - > savedState ) ;
free ( android_app ) ;
2015-12-02 08:54:24 +01:00
return NULL ;
2015-09-15 20:43:54 +02:00
}
2015-12-24 23:04:15 -07:00
2015-09-15 20:43:54 +02:00
android_app - > msgread = msgpipe [ 0 ] ;
android_app - > msgwrite = msgpipe [ 1 ] ;
android_app - > thread = sthread_create ( android_app_entry , android_app ) ;
/* Wait for thread to start. */
slock_lock ( android_app - > mutex ) ;
while ( ! android_app - > running )
scond_wait ( android_app - > cond , android_app - > mutex ) ;
slock_unlock ( android_app - > mutex ) ;
2015-12-02 08:54:24 +01:00
return android_app ;
}
/*
* Native activity interaction ( called from main thread )
* */
void ANativeActivity_onCreate ( ANativeActivity * activity ,
void * savedState , size_t savedStateSize )
{
RARCH_LOG ( " Creating Native Activity: %p \n " , activity ) ;
activity - > callbacks - > onDestroy = onDestroy ;
activity - > callbacks - > onStart = onStart ;
activity - > callbacks - > onResume = onResume ;
activity - > callbacks - > onSaveInstanceState = onSaveInstanceState ;
activity - > callbacks - > onPause = onPause ;
activity - > callbacks - > onStop = onStop ;
activity - > callbacks - > onConfigurationChanged = onConfigurationChanged ;
activity - > callbacks - > onLowMemory = onLowMemory ;
activity - > callbacks - > onWindowFocusChanged = onWindowFocusChanged ;
activity - > callbacks - > onNativeWindowCreated = onNativeWindowCreated ;
activity - > callbacks - > onNativeWindowDestroyed = onNativeWindowDestroyed ;
activity - > callbacks - > onInputQueueCreated = onInputQueueCreated ;
activity - > callbacks - > onInputQueueDestroyed = onInputQueueDestroyed ;
/* These are set only for the native activity,
* and are reset when it ends . */
ANativeActivity_setWindowFlags ( activity , AWINDOW_FLAG_KEEP_SCREEN_ON
| AWINDOW_FLAG_FULLSCREEN , 0 ) ;
if ( pthread_key_create ( & thread_key , jni_thread_destruct ) )
RARCH_ERR ( " Error initializing pthread_key \n " ) ;
2016-02-05 18:53:01 +01:00
activity - > instance = android_app_create ( activity ,
savedState , savedStateSize ) ;
2015-09-15 20:43:54 +02:00
}
static void frontend_android_get_name ( char * s , size_t len )
{
2015-11-14 19:22:15 +01:00
system_property_get ( " getprop " , " ro.product.model " , s ) ;
2015-09-15 20:43:54 +02:00
}
static void frontend_android_get_version ( int32_t * major ,
int32_t * minor , int32_t * rel )
{
char os_version_str [ PROP_VALUE_MAX ] = { 0 } ;
2016-02-05 18:53:01 +01:00
system_property_get ( " getprop " , " ro.build.version.release " ,
os_version_str ) ;
2015-09-15 20:43:54 +02:00
* major = 0 ;
* minor = 0 ;
* rel = 0 ;
/* Parse out the OS version numbers from the system properties. */
if ( os_version_str [ 0 ] )
{
/* Try to parse out the version numbers from the string. */
int num_read = sscanf ( os_version_str , " %d.%d.%d " , major , minor , rel ) ;
if ( num_read > 0 )
{
if ( num_read < 2 )
* minor = 0 ;
if ( num_read < 3 )
* rel = 0 ;
return ;
}
}
}
static void frontend_android_get_version_sdk ( int32_t * sdk )
{
char os_version_str [ PROP_VALUE_MAX ] = { 0 } ;
2015-11-14 19:22:15 +01:00
system_property_get ( " getprop " , " ro.build.version.sdk " , os_version_str ) ;
2015-09-15 20:43:54 +02:00
* sdk = 0 ;
if ( os_version_str [ 0 ] )
{
int num_read = sscanf ( os_version_str , " %d " , sdk ) ;
( void ) num_read ;
}
}
static bool device_is_xperia_play ( const char * name )
{
if (
2016-01-29 10:56:05 +01:00
strstr ( name , " R800x " ) | |
strstr ( name , " R800at " ) | |
strstr ( name , " R800i " ) | |
strstr ( name , " R800a " ) | |
strstr ( name , " SO-01D " )
2015-09-15 20:43:54 +02:00
)
return true ;
return false ;
}
static bool device_is_game_console ( const char * name )
{
if (
2016-01-29 10:56:05 +01:00
strstr ( name , " OUYA Console " ) | |
2015-09-15 20:43:54 +02:00
device_is_xperia_play ( name ) | |
2016-01-29 10:56:05 +01:00
strstr ( name , " GAMEMID_BT " ) | |
strstr ( name , " S7800 " ) | |
2016-03-17 20:08:00 -05:00
strstr ( name , " XD \n " ) | |
strstr ( name , " ARCHOS GAMEPAD " ) | |
2016-03-17 20:31:33 -05:00
strstr ( name , " SHIELD Android TV " ) | |
2016-03-17 20:10:03 -05:00
strstr ( name , " SHIELD \n " )
2015-09-15 20:43:54 +02:00
)
return true ;
return false ;
}
2017-03-10 22:17:05 -05:00
static bool device_is_android_tv ( )
{
return is_android_tv_device ;
}
2015-09-15 20:43:54 +02:00
bool test_permissions ( const char * path )
{
2016-08-01 14:04:57 +02:00
bool ret = false ;
char buf [ PATH_MAX_LENGTH ] = { 0 } ;
2015-09-15 20:43:54 +02:00
2016-06-17 09:43:51 -05:00
__android_log_print ( ANDROID_LOG_INFO ,
" RetroArch " , " Testing permissions for %s \n " , path ) ;
2015-09-15 20:43:54 +02:00
fill_pathname_join ( buf , path , " .retroarch " , sizeof ( buf ) ) ;
ret = path_mkdir ( buf ) ;
2016-06-17 09:43:51 -05:00
__android_log_print ( ANDROID_LOG_INFO ,
2017-05-23 22:46:12 +02:00
" RetroArch " , " Create %s in %s %s \n " , buf , path ,
ret ? " true " : " false " ) ;
2015-09-15 20:43:54 +02:00
if ( ret )
rmdir ( buf ) ;
return ret ;
}
static void frontend_android_shutdown ( bool unused )
{
( void ) unused ;
/* Cleaner approaches don't work sadly. */
exit ( 0 ) ;
}
# else
2015-04-18 19:43:48 +02:00
static bool make_proc_acpi_key_val ( char * * _ptr , char * * _key , char * * _val )
{
char * ptr = * _ptr ;
while ( * ptr = = ' ' )
ptr + + ; /* skip whitespace. */
if ( * ptr = = ' \0 ' )
return false ; /* EOF. */
* _key = ptr ;
while ( ( * ptr ! = ' : ' ) & & ( * ptr ! = ' \0 ' ) )
ptr + + ;
if ( * ptr = = ' \0 ' )
return false ; /* (unexpected) EOF. */
* ( ptr + + ) = ' \0 ' ; /* terminate the key. */
2017-10-28 20:56:04 +03:00
while ( * ptr = = ' ' )
2015-04-18 19:43:48 +02:00
ptr + + ; /* skip whitespace. */
if ( * ptr = = ' \0 ' )
return false ; /* (unexpected) EOF. */
* _val = ptr ;
while ( ( * ptr ! = ' \n ' ) & & ( * ptr ! = ' \0 ' ) )
ptr + + ;
if ( * ptr ! = ' \0 ' )
* ( ptr + + ) = ' \0 ' ; /* terminate the value. */
* _ptr = ptr ; /* store for next time. */
return true ;
}
2015-06-14 19:22:22 +02:00
# define ACPI_VAL_CHARGING_DISCHARGING 0xf268327aU
# define ACPI_VAL_ONLINE 0x6842bf17U
2015-09-15 19:37:26 +02:00
static void check_proc_acpi_battery ( const char * node , bool * have_battery ,
2015-04-18 19:43:48 +02:00
bool * charging , int * seconds , int * percent )
{
2016-12-19 19:04:52 +01:00
char path [ 1024 ] ;
2018-02-25 13:16:17 +01:00
const char * base = proc_acpi_battery_path ;
2015-09-19 01:03:52 +02:00
ssize_t length = 0 ;
2015-06-12 23:38:46 +02:00
char * ptr = NULL ;
2015-09-19 01:03:52 +02:00
char * buf = NULL ;
char * buf_info = NULL ;
2015-06-12 23:38:46 +02:00
char * key = NULL ;
char * val = NULL ;
bool charge = false ;
bool choose = false ;
int maximum = - 1 ;
int remaining = - 1 ;
int secs = - 1 ;
int pct = - 1 ;
2015-04-18 19:43:48 +02:00
2016-12-19 19:04:52 +01:00
path [ 0 ] = ' \0 ' ;
2015-09-14 06:56:32 +02:00
snprintf ( path , sizeof ( path ) , " %s/%s/%s " , base , node , " state " ) ;
2017-12-14 20:05:46 +01:00
if ( ! filestream_exists ( path ) )
2016-05-14 16:01:29 +02:00
goto end ;
2016-03-24 04:09:25 +01:00
if ( ! filestream_read_file ( path , ( void * * ) & buf , & length ) )
2015-09-19 01:03:52 +02:00
goto end ;
2015-09-14 06:56:32 +02:00
snprintf ( path , sizeof ( path ) , " %s/%s/%s " , base , node , " info " ) ;
2016-03-24 04:09:25 +01:00
if ( ! filestream_read_file ( path , ( void * * ) & buf_info , & length ) )
2015-09-19 01:03:52 +02:00
goto end ;
2015-04-18 19:43:48 +02:00
2015-09-19 01:03:52 +02:00
ptr = & buf [ 0 ] ;
2015-06-12 23:38:46 +02:00
2015-04-18 19:43:48 +02:00
while ( make_proc_acpi_key_val ( & ptr , & key , & val ) )
{
2018-02-25 13:16:17 +01:00
if ( string_is_equal ( key , " present " ) )
2015-06-14 19:22:22 +02:00
{
2018-02-25 13:16:17 +01:00
if ( string_is_equal ( val , " yes " ) )
* have_battery = true ;
}
else if ( string_is_equal ( key , " charging state " ) )
{
if ( string_is_equal ( val , " charging " ) )
charge = true ;
else
{
uint32_t val_hash = djb2_calculate ( val ) ;
2015-06-14 19:22:22 +02:00
switch ( val_hash )
{
case ACPI_VAL_CHARGING_DISCHARGING :
charge = true ;
break ;
2018-02-25 13:16:17 +01:00
default :
break ;
2015-06-14 19:22:22 +02:00
}
2018-02-25 13:16:17 +01:00
}
}
else if ( string_is_equal ( key , " remaining capacity " ) )
{
char * endptr = NULL ;
2015-06-14 19:22:22 +02:00
2018-03-19 06:58:36 +01:00
if ( endptr & & * endptr = = ' ' )
2018-02-25 13:16:17 +01:00
remaining = ( int ) strtol ( val , & endptr , 10 ) ;
2015-04-18 19:43:48 +02:00
}
}
2015-09-19 01:03:52 +02:00
ptr = & buf_info [ 0 ] ;
2015-06-14 19:22:22 +02:00
2015-04-18 19:43:48 +02:00
while ( make_proc_acpi_key_val ( & ptr , & key , & val ) )
{
2018-02-25 13:16:17 +01:00
char * endptr = NULL ;
2015-06-12 23:38:46 +02:00
2018-02-25 13:16:17 +01:00
if ( string_is_equal ( key , " design capacity " ) )
2018-03-19 06:58:36 +01:00
if ( endptr & & * endptr = = ' ' )
2018-02-25 13:16:17 +01:00
maximum = ( int ) strtol ( val , & endptr , 10 ) ;
2015-04-18 19:43:48 +02:00
}
if ( ( maximum > = 0 ) & & ( remaining > = 0 ) )
{
pct = ( int ) ( ( ( ( float ) remaining ) / ( ( float ) maximum ) ) * 100.0f ) ;
if ( pct < 0 )
pct = 0 ;
2015-09-02 12:54:31 +02:00
if ( pct > 100 )
2015-04-18 19:43:48 +02:00
pct = 100 ;
}
/* !!! FIXME: calculate (secs). */
/*
* We pick the battery that claims to have the most minutes left .
* ( failing a report of minutes , we ' ll take the highest percent . )
*/
if ( ( secs < 0 ) & & ( * seconds < 0 ) )
{
if ( ( pct < 0 ) & & ( * percent < 0 ) )
choose = true ; /* at least we know there's a battery. */
if ( pct > * percent )
choose = true ;
}
else if ( secs > * seconds )
choose = true ;
if ( choose )
{
2018-02-25 13:16:17 +01:00
* seconds = secs ;
* percent = pct ;
2015-04-18 19:43:48 +02:00
* charging = charge ;
}
2015-09-19 01:03:52 +02:00
end :
if ( buf_info )
free ( buf_info ) ;
if ( buf )
free ( buf ) ;
buf = NULL ;
buf_info = NULL ;
2015-04-18 19:43:48 +02:00
}
2016-02-05 18:53:01 +01:00
static void check_proc_acpi_sysfs_battery ( const char * node ,
bool * have_battery , bool * charging ,
int * seconds , int * percent )
2015-09-14 06:35:11 +02:00
{
2016-12-19 19:04:52 +01:00
char path [ 1024 ] ;
2015-09-15 19:37:26 +02:00
const char * base = proc_acpi_sysfs_battery_path ;
2015-09-19 01:03:52 +02:00
char * buf = NULL ;
2015-09-14 06:35:11 +02:00
char * ptr = NULL ;
char * key = NULL ;
char * val = NULL ;
bool charge = false ;
bool choose = false ;
2017-01-04 09:34:12 +01:00
unsigned capacity = 0 ;
2015-09-19 01:03:52 +02:00
ssize_t length = 0 ;
2015-09-14 06:35:11 +02:00
int maximum = - 1 ;
int remaining = - 1 ;
int secs = - 1 ;
int pct = - 1 ;
2016-12-19 19:04:52 +01:00
path [ 0 ] = ' \0 ' ;
2015-09-14 06:56:32 +02:00
snprintf ( path , sizeof ( path ) , " %s/%s/%s " , base , node , " status " ) ;
2017-01-04 09:34:12 +01:00
2017-12-14 20:05:46 +01:00
if ( ! filestream_exists ( path ) )
2016-05-14 16:01:29 +02:00
return ;
2017-12-14 20:05:46 +01:00
2016-03-24 04:09:25 +01:00
if ( filestream_read_file ( path , ( void * * ) & buf , & length ) ! = 1 )
2015-09-14 06:35:11 +02:00
return ;
2017-01-08 18:12:43 +01:00
if ( buf )
2017-01-03 15:40:01 -05:00
{
2017-01-08 18:12:43 +01:00
if ( strstr ( ( char * ) buf , " Discharging " ) )
* have_battery = true ;
else if ( strstr ( ( char * ) buf , " Charging " ) )
{
* have_battery = true ;
* charging = true ;
}
else if ( strstr ( ( char * ) buf , " Full " ) )
* have_battery = true ;
free ( buf ) ;
2017-01-03 15:40:01 -05:00
}
2015-09-14 06:35:11 +02:00
2017-01-02 22:16:00 -05:00
buf = NULL ;
2015-09-14 06:56:32 +02:00
snprintf ( path , sizeof ( path ) , " %s/%s/%s " , base , node , " capacity " ) ;
2016-03-24 04:09:25 +01:00
if ( filestream_read_file ( path , ( void * * ) & buf , & length ) ! = 1 )
2015-09-19 01:03:52 +02:00
goto end ;
2015-09-14 06:35:11 +02:00
2015-09-19 01:03:52 +02:00
capacity = atoi ( buf ) ;
2015-09-14 06:35:11 +02:00
* percent = capacity ;
2015-09-19 01:03:52 +02:00
end :
2017-01-03 18:47:34 +01:00
free ( buf ) ;
2015-09-19 01:03:52 +02:00
buf = NULL ;
2015-09-14 06:35:11 +02:00
}
2015-09-15 19:37:26 +02:00
static void check_proc_acpi_ac_adapter ( const char * node , bool * have_ac )
2015-04-18 19:43:48 +02:00
{
2016-12-19 19:04:52 +01:00
char path [ 1024 ] ;
2015-09-14 06:56:32 +02:00
const char * base = proc_acpi_ac_adapter_path ;
2015-09-19 01:03:52 +02:00
char * buf = NULL ;
2015-09-14 06:56:32 +02:00
char * ptr = NULL ;
char * key = NULL ;
char * val = NULL ;
2015-09-19 01:03:52 +02:00
ssize_t length = 0 ;
2015-09-14 06:56:32 +02:00
2016-12-19 19:04:52 +01:00
path [ 0 ] = ' \0 ' ;
2015-09-14 06:56:32 +02:00
snprintf ( path , sizeof ( path ) , " %s/%s/%s " , base , node , " state " ) ;
2017-12-14 20:05:46 +01:00
if ( ! filestream_exists ( path ) )
2016-05-14 16:01:29 +02:00
return ;
2017-12-14 20:05:46 +01:00
2016-03-24 04:09:25 +01:00
if ( filestream_read_file ( path , ( void * * ) & buf , & length ) ! = 1 )
2015-09-14 06:56:32 +02:00
return ;
2015-09-19 01:03:52 +02:00
ptr = & buf [ 0 ] ;
2015-09-14 06:56:32 +02:00
while ( make_proc_acpi_key_val ( & ptr , & key , & val ) )
{
uint32_t val_hash = djb2_calculate ( val ) ;
2018-02-25 13:16:17 +01:00
if ( string_is_equal ( key , " state " ) & &
2015-09-14 06:56:32 +02:00
val_hash = = ACPI_VAL_ONLINE )
* have_ac = true ;
}
2015-09-19 01:03:52 +02:00
if ( buf )
free ( buf ) ;
buf = NULL ;
2015-04-18 19:43:48 +02:00
}
2015-09-15 19:37:26 +02:00
static void check_proc_acpi_sysfs_ac_adapter ( const char * node , bool * have_ac )
2015-09-14 06:35:11 +02:00
{
2016-12-19 19:04:52 +01:00
char path [ 1024 ] ;
2015-09-19 01:03:52 +02:00
ssize_t length = 0 ;
char * buf = NULL ;
2015-09-15 19:37:26 +02:00
const char * base = proc_acpi_sysfs_ac_adapter_path ;
2015-09-14 06:35:11 +02:00
2016-12-19 19:04:52 +01:00
path [ 0 ] = ' \0 ' ;
2015-09-18 21:19:33 +02:00
snprintf ( path , sizeof ( path ) , " %s/%s " , base , " online " ) ;
2017-12-14 20:05:46 +01:00
if ( ! filestream_exists ( path ) )
2016-05-14 15:59:22 +02:00
return ;
2017-12-14 20:05:46 +01:00
2016-03-24 04:09:25 +01:00
if ( filestream_read_file ( path , ( void * * ) & buf , & length ) ! = 1 )
2015-09-14 06:56:32 +02:00
return ;
2015-09-14 06:35:11 +02:00
2015-09-19 01:03:52 +02:00
if ( strstr ( ( char * ) buf , " 1 " ) )
2015-09-14 06:56:32 +02:00
* have_ac = true ;
2015-09-19 01:03:52 +02:00
2016-05-26 17:47:21 +02:00
free ( buf ) ;
2015-09-14 06:35:11 +02:00
}
2015-04-18 19:43:48 +02:00
static bool next_string ( char * * _ptr , char * * _str )
{
char * ptr = * _ptr ;
while ( * ptr = = ' ' ) /* skip any spaces... */
ptr + + ;
if ( * ptr = = ' \0 ' )
return false ;
while ( ( * ptr ! = ' ' ) & & ( * ptr ! = ' \n ' ) & & ( * ptr ! = ' \0 ' ) )
ptr + + ;
if ( * ptr ! = ' \0 ' )
* ( ptr + + ) = ' \0 ' ;
* _ptr = ptr ;
return true ;
}
static bool int_string ( char * str , int * val )
{
2017-05-19 03:34:53 +02:00
char * endptr = NULL ;
2017-05-16 16:14:20 -07:00
if ( ! str )
return false ;
2015-04-18 19:43:48 +02:00
* val = ( int ) strtol ( str , & endptr , 0 ) ;
return ( ( * str ! = ' \0 ' ) & & ( * endptr = = ' \0 ' ) ) ;
}
2017-06-19 17:38:49 +02:00
static bool frontend_unix_powerstate_check_apm (
2015-09-06 14:50:21 +02:00
enum frontend_powerstate * state ,
2015-04-18 19:43:48 +02:00
int * seconds , int * percent )
{
2015-06-12 23:38:46 +02:00
int ac_status = 0 ;
int battery_status = 0 ;
int battery_flag = 0 ;
int battery_percent = 0 ;
int battery_time = 0 ;
2015-09-19 01:03:52 +02:00
ssize_t length = 0 ;
2016-06-03 04:27:42 +02:00
char * ptr = NULL ;
2015-09-19 01:03:52 +02:00
char * buf = NULL ;
2015-06-12 23:38:46 +02:00
char * str = NULL ;
2015-10-03 10:54:56 -05:00
2017-12-14 20:05:46 +01:00
if ( ! filestream_exists ( proc_apm_path ) )
2016-05-14 16:01:29 +02:00
goto error ;
2017-12-14 20:05:46 +01:00
2016-03-24 04:09:25 +01:00
if ( filestream_read_file ( proc_apm_path , ( void * * ) & buf , & length ) ! = 1 )
2015-09-19 01:03:52 +02:00
goto error ;
2015-04-18 19:43:48 +02:00
2015-09-14 06:56:32 +02:00
ptr = & buf [ 0 ] ;
2015-04-18 19:43:48 +02:00
if ( ! next_string ( & ptr , & str ) ) /* driver version */
2015-09-19 01:03:52 +02:00
goto error ;
2015-04-18 19:43:48 +02:00
if ( ! next_string ( & ptr , & str ) ) /* BIOS version */
2015-09-19 01:03:52 +02:00
goto error ;
2015-04-18 19:43:48 +02:00
if ( ! next_string ( & ptr , & str ) ) /* APM flags */
2015-09-19 01:03:52 +02:00
goto error ;
2015-04-18 19:43:48 +02:00
if ( ! next_string ( & ptr , & str ) ) /* AC line status */
2015-09-19 01:03:52 +02:00
goto error ;
2015-04-18 19:43:48 +02:00
else if ( ! int_string ( str , & ac_status ) )
2015-09-19 01:03:52 +02:00
goto error ;
2015-04-18 19:43:48 +02:00
if ( ! next_string ( & ptr , & str ) ) /* battery status */
2015-09-19 01:03:52 +02:00
goto error ;
2015-04-18 19:43:48 +02:00
else if ( ! int_string ( str , & battery_status ) )
2015-09-19 01:03:52 +02:00
goto error ;
2015-04-18 19:43:48 +02:00
if ( ! next_string ( & ptr , & str ) ) /* battery flag */
2015-09-19 01:03:52 +02:00
goto error ;
2015-04-18 19:43:48 +02:00
else if ( ! int_string ( str , & battery_flag ) )
2015-09-19 01:03:52 +02:00
goto error ;
2015-04-18 19:43:48 +02:00
if ( ! next_string ( & ptr , & str ) ) /* remaining battery life percent */
2015-09-19 01:03:52 +02:00
goto error ;
2015-04-18 19:43:48 +02:00
if ( str [ strlen ( str ) - 1 ] = = ' % ' )
str [ strlen ( str ) - 1 ] = ' \0 ' ;
if ( ! int_string ( str , & battery_percent ) )
2015-09-19 01:03:52 +02:00
goto error ;
2015-04-18 19:43:48 +02:00
if ( ! next_string ( & ptr , & str ) ) /* remaining battery life time */
2015-09-19 01:03:52 +02:00
goto error ;
2015-04-18 19:43:48 +02:00
else if ( ! int_string ( str , & battery_time ) )
2015-09-19 01:03:52 +02:00
goto error ;
2015-04-18 19:43:48 +02:00
if ( ! next_string ( & ptr , & str ) ) /* remaining battery life time units */
2015-09-19 01:03:52 +02:00
goto error ;
2018-01-16 22:53:38 +01:00
else if ( string_is_equal ( str , " min " ) )
2015-04-18 19:43:48 +02:00
battery_time * = 60 ;
if ( battery_flag = = 0xFF ) /* unknown state */
* state = FRONTEND_POWERSTATE_NONE ;
else if ( battery_flag & ( 1 < < 7 ) ) /* no battery */
* state = FRONTEND_POWERSTATE_NO_SOURCE ;
else if ( battery_flag & ( 1 < < 3 ) ) /* charging */
* state = FRONTEND_POWERSTATE_CHARGING ;
else if ( ac_status = = 1 )
* state = FRONTEND_POWERSTATE_CHARGED ; /* on AC, not charging. */
else
* state = FRONTEND_POWERSTATE_ON_POWER_SOURCE ;
2015-06-26 17:46:13 +02:00
if ( battery_percent > = 0 ) /* -1 == unknown */
* percent = ( battery_percent > 100 ) ? 100 : battery_percent ; /* clamp between 0%, 100% */
if ( battery_time > = 0 ) /* -1 == unknown */
* seconds = battery_time ;
2015-04-18 19:43:48 +02:00
2015-09-19 01:03:52 +02:00
if ( buf )
free ( buf ) ;
buf = NULL ;
2015-04-18 19:43:48 +02:00
return true ;
2015-09-19 01:03:52 +02:00
error :
if ( buf )
free ( buf ) ;
buf = NULL ;
return false ;
2015-04-18 19:43:48 +02:00
}
2017-06-19 17:38:49 +02:00
static bool frontend_unix_powerstate_check_acpi (
2015-09-06 14:50:21 +02:00
enum frontend_powerstate * state ,
2015-04-18 19:43:48 +02:00
int * seconds , int * percent )
{
2015-06-12 23:38:46 +02:00
bool have_battery = false ;
bool have_ac = false ;
bool charging = false ;
2017-01-08 17:57:13 +01:00
struct RDIR * entry = retro_opendir ( proc_acpi_battery_path ) ;
2015-09-04 20:37:18 +02:00
if ( ! entry )
2017-01-08 17:57:13 +01:00
return false ;
2015-04-18 19:43:48 +02:00
2015-09-04 20:37:18 +02:00
if ( retro_dirent_error ( entry ) )
2017-01-08 17:57:13 +01:00
{
retro_closedir ( entry ) ;
return false ;
}
2015-04-18 19:43:48 +02:00
2015-09-04 20:37:18 +02:00
while ( retro_readdir ( entry ) )
check_proc_acpi_battery ( retro_dirent_get_name ( entry ) ,
& have_battery , & charging , seconds , percent ) ;
2015-04-18 19:43:48 +02:00
2015-09-04 20:37:18 +02:00
retro_closedir ( entry ) ;
2015-06-12 23:38:46 +02:00
2015-09-04 20:37:18 +02:00
entry = retro_opendir ( proc_acpi_ac_adapter_path ) ;
if ( ! entry )
2017-01-08 17:57:13 +01:00
return false ;
2015-09-04 20:37:18 +02:00
while ( retro_readdir ( entry ) )
2016-02-05 18:53:01 +01:00
check_proc_acpi_ac_adapter (
retro_dirent_get_name ( entry ) , & have_ac ) ;
2015-04-18 19:43:48 +02:00
2017-01-08 17:57:13 +01:00
retro_closedir ( entry ) ;
2015-04-18 19:43:48 +02:00
if ( ! have_battery )
* state = FRONTEND_POWERSTATE_NO_SOURCE ;
else if ( charging )
* state = FRONTEND_POWERSTATE_CHARGING ;
else if ( have_ac )
* state = FRONTEND_POWERSTATE_CHARGED ;
else
* state = FRONTEND_POWERSTATE_ON_POWER_SOURCE ;
2017-01-08 17:57:13 +01:00
return true ;
2015-04-18 19:43:48 +02:00
}
2017-06-19 17:38:49 +02:00
static bool frontend_unix_powerstate_check_acpi_sysfs (
2016-02-05 18:53:01 +01:00
enum frontend_powerstate * state ,
2015-09-14 06:35:11 +02:00
int * seconds , int * percent )
{
bool have_battery = false ;
bool have_ac = false ;
bool charging = false ;
2017-01-04 09:34:12 +01:00
struct RDIR * entry = retro_opendir ( proc_acpi_sysfs_battery_path ) ;
2015-09-14 06:35:11 +02:00
if ( ! entry )
goto error ;
if ( retro_dirent_error ( entry ) )
goto error ;
while ( retro_readdir ( entry ) )
2017-01-04 09:34:12 +01:00
{
const char * node = retro_dirent_get_name ( entry ) ;
if ( node & & strstr ( node , " BAT " ) )
check_proc_acpi_sysfs_battery ( node ,
& have_battery , & charging , seconds , percent ) ;
}
2015-09-14 06:35:11 +02:00
retro_closedir ( entry ) ;
2015-09-15 19:37:26 +02:00
entry = retro_opendir ( proc_acpi_sysfs_ac_adapter_path ) ;
2015-09-14 06:35:11 +02:00
if ( ! entry )
goto error ;
2015-09-18 21:22:06 +02:00
check_proc_acpi_sysfs_ac_adapter ( retro_dirent_get_name ( entry ) , & have_ac ) ;
2015-09-14 06:35:11 +02:00
if ( ! have_battery )
{
* state = FRONTEND_POWERSTATE_NO_SOURCE ;
}
else if ( charging )
* state = FRONTEND_POWERSTATE_CHARGING ;
else if ( have_ac )
* state = FRONTEND_POWERSTATE_CHARGED ;
else
* state = FRONTEND_POWERSTATE_ON_POWER_SOURCE ;
2016-05-23 22:17:28 +02:00
retro_closedir ( entry ) ;
2015-09-14 06:35:11 +02:00
return true ;
error :
if ( entry )
retro_closedir ( entry ) ;
return false ;
}
2015-09-15 19:37:26 +02:00
# endif
2015-09-14 06:35:11 +02:00
2017-06-19 17:38:49 +02:00
static int frontend_unix_get_rating ( void )
2015-09-15 20:43:54 +02:00
{
# ifdef ANDROID
char device_model [ PROP_VALUE_MAX ] = { 0 } ;
frontend_android_get_name ( device_model , sizeof ( device_model ) ) ;
RARCH_LOG ( " ro.product.model: (%s). \n " , device_model ) ;
if ( device_is_xperia_play ( device_model ) )
return 6 ;
2016-01-29 10:56:05 +01:00
else if ( strstr ( device_model , " GT-I9505 " ) )
2015-09-15 20:43:54 +02:00
return 12 ;
2016-01-29 10:56:05 +01:00
else if ( strstr ( device_model , " SHIELD " ) )
2015-09-15 20:43:54 +02:00
return 13 ;
# endif
return - 1 ;
}
2017-06-19 17:38:49 +02:00
static enum frontend_powerstate frontend_unix_get_powerstate (
2016-02-05 18:53:01 +01:00
int * seconds , int * percent )
2015-04-18 19:43:48 +02:00
{
enum frontend_powerstate ret = FRONTEND_POWERSTATE_NONE ;
2015-09-15 19:37:26 +02:00
# ifndef ANDROID
2017-06-19 17:38:49 +02:00
if ( frontend_unix_powerstate_check_acpi_sysfs ( & ret , seconds , percent ) )
2015-04-18 19:43:48 +02:00
return ret ;
2017-01-08 17:57:13 +01:00
ret = FRONTEND_POWERSTATE_NONE ;
2017-06-19 17:38:49 +02:00
if ( frontend_unix_powerstate_check_acpi ( & ret , seconds , percent ) )
2015-04-18 19:43:48 +02:00
return ret ;
2017-06-19 17:38:49 +02:00
if ( frontend_unix_powerstate_check_apm ( & ret , seconds , percent ) )
2015-09-14 06:35:11 +02:00
return ret ;
2015-09-15 19:37:26 +02:00
# endif
2015-09-14 06:35:11 +02:00
2015-09-15 20:43:54 +02:00
return ret ;
2015-04-18 19:43:48 +02:00
}
2017-06-19 17:38:49 +02:00
static enum frontend_architecture frontend_unix_get_architecture ( void )
2015-04-18 20:03:59 +02:00
{
struct utsname buffer ;
2016-06-03 04:27:42 +02:00
const char * val = NULL ;
2015-04-18 20:03:59 +02:00
if ( uname ( & buffer ) ! = 0 )
return FRONTEND_ARCH_NONE ;
2015-09-15 20:43:54 +02:00
val = buffer . machine ;
2015-06-14 19:22:22 +02:00
2018-02-25 20:49:44 +01:00
if ( string_is_equal ( val , " aarch64 " ) )
2018-02-25 17:58:36 +01:00
return FRONTEND_ARCH_ARMV8 ;
else if (
2018-02-25 20:49:44 +01:00
string_is_equal ( val , " armv7l " ) | |
string_is_equal ( val , " armv7b " )
2018-02-25 17:58:36 +01:00
)
return FRONTEND_ARCH_ARMV7 ;
else if (
2018-02-25 20:49:44 +01:00
string_is_equal ( val , " armv6l " ) | |
string_is_equal ( val , " armv6b " ) | |
string_is_equal ( val , " armv5tel " ) | |
string_is_equal ( val , " arm " )
2018-02-25 17:58:36 +01:00
)
return FRONTEND_ARCH_ARM ;
2018-02-25 20:49:44 +01:00
else if ( string_is_equal ( val , " x86_64 " ) )
2018-02-25 17:58:36 +01:00
return FRONTEND_ARCH_X86_64 ;
2018-02-25 20:49:44 +01:00
else if ( string_is_equal ( val , " x86 " ) )
2015-06-14 19:22:22 +02:00
return FRONTEND_ARCH_X86 ;
2018-02-25 20:49:44 +01:00
else if ( string_is_equal ( val , " ppc64 " ) )
2015-06-14 19:22:22 +02:00
return FRONTEND_ARCH_PPC ;
2018-02-25 20:49:44 +01:00
else if ( string_is_equal ( val , " mips " ) )
2015-06-14 19:22:22 +02:00
return FRONTEND_ARCH_MIPS ;
2018-02-25 20:49:44 +01:00
else if ( string_is_equal ( val , " tile " ) )
2015-06-14 19:22:22 +02:00
return FRONTEND_ARCH_TILE ;
2015-04-18 20:03:59 +02:00
return FRONTEND_ARCH_NONE ;
}
2017-06-19 17:38:49 +02:00
static void frontend_unix_get_os ( char * s ,
2016-02-05 18:53:01 +01:00
size_t len , int * major , int * minor )
2015-04-18 20:08:47 +02:00
{
2015-09-15 20:43:54 +02:00
# ifdef ANDROID
int rel ;
frontend_android_get_version ( major , minor , & rel ) ;
strlcpy ( s , " Android " , len ) ;
# else
2015-04-18 20:49:05 +02:00
unsigned krel ;
2015-04-18 20:08:47 +02:00
struct utsname buffer ;
if ( uname ( & buffer ) ! = 0 )
return ;
2015-06-26 20:41:47 +02:00
sscanf ( buffer . release , " %d.%d.%u " , major , minor , & krel ) ;
2017-12-16 10:46:52 -05:00
# if defined(__FreeBSD__)
strlcpy ( s , " FreeBSD " , len ) ;
# elif defined(__NetBSD__)
strlcpy ( s , " NetBSD " , len ) ;
# elif defined(__OpenBSD__)
strlcpy ( s , " OpenBSD " , len ) ;
# elif defined(__DragonFly__)
strlcpy ( s , " DragonFly BSD " , len ) ;
# elif defined(BSD)
strlcpy ( s , " BSD " , len ) ;
2018-01-20 00:19:01 -08:00
# elif defined(__HAIKU__)
strlcpy ( s , " Haiku " , len ) ;
2017-12-16 10:46:52 -05:00
# else
2015-06-02 18:28:51 +02:00
strlcpy ( s , " Linux " , len ) ;
2015-09-15 19:37:26 +02:00
# endif
2017-12-16 10:46:52 -05:00
# endif
2015-04-18 20:08:47 +02:00
}
2017-05-13 13:12:15 +02:00
# ifdef HAVE_LAKKA
2017-06-19 17:38:49 +02:00
static void frontend_unix_get_lakka_version ( char * s ,
2017-05-13 13:12:15 +02:00
size_t len )
{
char version [ 128 ] ;
size_t vlen ;
FILE * command_file = popen ( " cat /etc/release " , " r " ) ;
fgets ( version , sizeof ( version ) , command_file ) ;
vlen = strlen ( version ) ;
if ( vlen > 0 & & version [ vlen - 1 ] = = ' \n ' )
version [ - - vlen ] = ' \0 ' ;
strlcpy ( s , version , len ) ;
pclose ( command_file ) ;
}
# endif
2017-06-19 17:38:49 +02:00
static void frontend_unix_get_env ( int * argc ,
2015-09-15 11:57:18 -05:00
char * argv [ ] , void * data , void * params_data )
{
2017-05-23 19:43:58 +02:00
unsigned i ;
2015-09-15 20:43:54 +02:00
# ifdef ANDROID
int32_t major , minor , rel ;
2017-05-23 22:46:12 +02:00
char device_model [ PROP_VALUE_MAX ] = { 0 } ;
char device_id [ PROP_VALUE_MAX ] = { 0 } ;
struct rarch_main_wrap * args = NULL ;
JNIEnv * env = NULL ;
jobject obj = NULL ;
jstring jstr = NULL ;
2017-03-10 22:17:05 -05:00
jboolean jbool = JNI_FALSE ;
2017-05-23 22:46:12 +02:00
struct android_app * android_app = ( struct android_app * ) data ;
2015-09-15 20:43:54 +02:00
if ( ! android_app )
return ;
2015-09-15 11:57:18 -05:00
2015-09-15 20:43:54 +02:00
env = jni_thread_getenv ( ) ;
if ( ! env )
return ;
args = ( struct rarch_main_wrap * ) params_data ;
if ( args )
2015-09-15 12:13:48 -05:00
{
2015-09-15 20:43:54 +02:00
args - > touched = true ;
args - > no_content = false ;
args - > verbose = false ;
args - > sram_path = NULL ;
args - > state_path = NULL ;
2015-09-15 12:13:48 -05:00
}
2015-09-15 20:43:54 +02:00
frontend_android_get_version ( & major , & minor , & rel ) ;
2016-06-17 09:43:51 -05:00
__android_log_print ( ANDROID_LOG_INFO ,
" RetroArch " , " [ENV] Android version (major : %d, minor : %d, rel : %d) \n " ,
2015-09-15 20:43:54 +02:00
major , minor , rel ) ;
CALL_OBJ_METHOD ( env , obj , android_app - > activity - > clazz ,
android_app - > getIntent ) ;
2016-06-17 09:43:51 -05:00
__android_log_print ( ANDROID_LOG_INFO ,
" RetroArch " , " [ENV] Checking arguments passed from intent ... \n " ) ;
2015-09-15 20:43:54 +02:00
/* Config file. */
CALL_OBJ_METHOD_PARAM ( env , jstr , obj , android_app - > getStringExtra ,
( * env ) - > NewStringUTF ( env , " CONFIGFILE " ) ) ;
if ( android_app - > getStringExtra & & jstr )
{
static char config_path [ PATH_MAX_LENGTH ] = { 0 } ;
const char * argv = ( * env ) - > GetStringUTFChars ( env , jstr , 0 ) ;
if ( argv & & * argv )
strlcpy ( config_path , argv , sizeof ( config_path ) ) ;
( * env ) - > ReleaseStringUTFChars ( env , jstr , argv ) ;
2016-06-17 09:43:51 -05:00
__android_log_print ( ANDROID_LOG_INFO ,
" RetroArch " , " [ENV]: config file: [%s] \n " , config_path ) ;
2015-09-15 20:43:54 +02:00
if ( args & & * config_path )
args - > config_path = config_path ;
}
/* Current IME. */
CALL_OBJ_METHOD_PARAM ( env , jstr , obj , android_app - > getStringExtra ,
( * env ) - > NewStringUTF ( env , " IME " ) ) ;
if ( android_app - > getStringExtra & & jstr )
{
const char * argv = ( * env ) - > GetStringUTFChars ( env , jstr , 0 ) ;
strlcpy ( android_app - > current_ime , argv ,
sizeof ( android_app - > current_ime ) ) ;
( * env ) - > ReleaseStringUTFChars ( env , jstr , argv ) ;
2016-06-17 09:43:51 -05:00
__android_log_print ( ANDROID_LOG_INFO ,
" RetroArch " , " [ENV]: current IME: [%s] \n " , android_app - > current_ime ) ;
2015-09-15 20:43:54 +02:00
}
CALL_OBJ_METHOD_PARAM ( env , jstr , obj , android_app - > getStringExtra ,
( * env ) - > NewStringUTF ( env , " USED " ) ) ;
if ( android_app - > getStringExtra & & jstr )
{
const char * argv = ( * env ) - > GetStringUTFChars ( env , jstr , 0 ) ;
2018-01-16 22:53:38 +01:00
bool used = string_is_equal ( argv , " false " ) ? false : true ;
2015-09-15 20:43:54 +02:00
( * env ) - > ReleaseStringUTFChars ( env , jstr , argv ) ;
2016-06-17 09:43:51 -05:00
__android_log_print ( ANDROID_LOG_INFO ,
" RetroArch " , " [ENV]: used: [%s]. \n " , used ? " true " : " false " ) ;
2015-09-15 20:43:54 +02:00
}
/* LIBRETRO. */
CALL_OBJ_METHOD_PARAM ( env , jstr , obj , android_app - > getStringExtra ,
( * env ) - > NewStringUTF ( env , " LIBRETRO " ) ) ;
if ( android_app - > getStringExtra & & jstr )
2015-09-15 12:13:48 -05:00
{
2015-09-15 20:43:54 +02:00
static char core_path [ PATH_MAX_LENGTH ] ;
const char * argv = ( * env ) - > GetStringUTFChars ( env , jstr , 0 ) ;
* core_path = ' \0 ' ;
if ( argv & & * argv )
strlcpy ( core_path , argv , sizeof ( core_path ) ) ;
( * env ) - > ReleaseStringUTFChars ( env , jstr , argv ) ;
2016-06-17 09:43:51 -05:00
__android_log_print ( ANDROID_LOG_INFO ,
" RetroArch " , " [ENV]: libretro path: [%s] \n " , core_path ) ;
2016-11-26 21:53:58 -05:00
if ( args & & * core_path )
args - > libretro_path = core_path ;
2015-09-15 12:13:48 -05:00
}
2015-09-15 20:43:54 +02:00
/* Content. */
CALL_OBJ_METHOD_PARAM ( env , jstr , obj , android_app - > getStringExtra ,
( * env ) - > NewStringUTF ( env , " ROM " ) ) ;
if ( android_app - > getStringExtra & & jstr )
{
static char path [ PATH_MAX_LENGTH ] ;
const char * argv = ( * env ) - > GetStringUTFChars ( env , jstr , 0 ) ;
* path = ' \0 ' ;
if ( argv & & * argv )
strlcpy ( path , argv , sizeof ( path ) ) ;
( * env ) - > ReleaseStringUTFChars ( env , jstr , argv ) ;
2016-06-09 20:02:04 -05:00
if ( ! string_is_empty ( path ) )
2015-09-15 20:43:54 +02:00
{
2016-06-17 09:43:51 -05:00
__android_log_print ( ANDROID_LOG_INFO ,
" RetroArch " , " [ENV]: auto-start game [%s] \n " , path ) ;
2015-09-15 20:43:54 +02:00
if ( args & & * path )
args - > content_path = path ;
}
}
2016-06-09 19:21:39 -05:00
/* Internal Storage */
2015-09-15 20:43:54 +02:00
CALL_OBJ_METHOD_PARAM ( env , jstr , obj , android_app - > getStringExtra ,
( * env ) - > NewStringUTF ( env , " SDCARD " ) ) ;
if ( android_app - > getStringExtra & & jstr )
{
const char * argv = ( * env ) - > GetStringUTFChars ( env , jstr , 0 ) ;
2016-06-09 20:02:04 -05:00
internal_storage_path [ 0 ] = ' \0 ' ;
2015-09-15 20:43:54 +02:00
if ( argv & & * argv )
2017-05-23 22:46:12 +02:00
strlcpy ( internal_storage_path , argv ,
sizeof ( internal_storage_path ) ) ;
2015-09-15 20:43:54 +02:00
( * env ) - > ReleaseStringUTFChars ( env , jstr , argv ) ;
2016-06-09 19:21:39 -05:00
if ( ! string_is_empty ( internal_storage_path ) )
2015-09-15 20:43:54 +02:00
{
2016-06-17 09:43:51 -05:00
__android_log_print ( ANDROID_LOG_INFO ,
" RetroArch " , " [ENV]: android internal storage location: [%s] \n " ,
internal_storage_path ) ;
2015-09-15 20:43:54 +02:00
}
}
/* Screenshots */
CALL_OBJ_METHOD_PARAM ( env , jstr , obj , android_app - > getStringExtra ,
( * env ) - > NewStringUTF ( env , " SCREENSHOTS " ) ) ;
if ( android_app - > getStringExtra & & jstr )
{
const char * argv = ( * env ) - > GetStringUTFChars ( env , jstr , 0 ) ;
* screenshot_dir = ' \0 ' ;
if ( argv & & * argv )
strlcpy ( screenshot_dir , argv , sizeof ( screenshot_dir ) ) ;
( * env ) - > ReleaseStringUTFChars ( env , jstr , argv ) ;
2016-06-09 19:21:39 -05:00
if ( ! string_is_empty ( screenshot_dir ) )
2015-09-15 20:43:54 +02:00
{
2016-06-17 09:43:51 -05:00
__android_log_print ( ANDROID_LOG_INFO ,
" RetroArch " , " [ENV]: android picture folder location [%s] \n " ,
screenshot_dir ) ;
2015-09-15 20:43:54 +02:00
}
}
/* Downloads */
CALL_OBJ_METHOD_PARAM ( env , jstr , obj , android_app - > getStringExtra ,
( * env ) - > NewStringUTF ( env , " DOWNLOADS " ) ) ;
if ( android_app - > getStringExtra & & jstr )
{
const char * argv = ( * env ) - > GetStringUTFChars ( env , jstr , 0 ) ;
* downloads_dir = ' \0 ' ;
if ( argv & & * argv )
strlcpy ( downloads_dir , argv , sizeof ( downloads_dir ) ) ;
( * env ) - > ReleaseStringUTFChars ( env , jstr , argv ) ;
2016-06-09 19:21:39 -05:00
if ( ! string_is_empty ( downloads_dir ) )
2015-09-15 20:43:54 +02:00
{
2016-06-17 09:43:51 -05:00
__android_log_print ( ANDROID_LOG_INFO ,
" RetroArch " , " [ENV]: android download folder location [%s] \n " ,
downloads_dir ) ;
2015-09-15 20:43:54 +02:00
}
}
CALL_OBJ_METHOD_PARAM ( env , jstr , obj , android_app - > getStringExtra ,
( * env ) - > NewStringUTF ( env , " APK " ) ) ;
if ( android_app - > getStringExtra & & jstr )
{
const char * argv = ( * env ) - > GetStringUTFChars ( env , jstr , 0 ) ;
2016-04-30 16:39:29 -05:00
* apk_dir = ' \0 ' ;
2015-09-15 20:43:54 +02:00
if ( argv & & * argv )
2016-04-30 16:39:29 -05:00
strlcpy ( apk_dir , argv , sizeof ( apk_dir ) ) ;
2015-09-15 20:43:54 +02:00
( * env ) - > ReleaseStringUTFChars ( env , jstr , argv ) ;
2016-06-09 20:02:04 -05:00
if ( ! string_is_empty ( apk_dir ) )
2015-09-15 20:43:54 +02:00
{
2016-06-17 09:43:51 -05:00
__android_log_print ( ANDROID_LOG_INFO ,
" RetroArch " , " [ENV]: APK location [%s] \n " , apk_dir ) ;
2015-09-15 20:43:54 +02:00
}
}
CALL_OBJ_METHOD_PARAM ( env , jstr , obj , android_app - > getStringExtra ,
( * env ) - > NewStringUTF ( env , " EXTERNAL " ) ) ;
if ( android_app - > getStringExtra & & jstr )
{
const char * argv = ( * env ) - > GetStringUTFChars ( env , jstr , 0 ) ;
2016-06-09 19:21:39 -05:00
* internal_storage_app_path = ' \0 ' ;
2015-09-15 20:43:54 +02:00
if ( argv & & * argv )
2017-05-23 22:46:12 +02:00
strlcpy ( internal_storage_app_path , argv ,
sizeof ( internal_storage_app_path ) ) ;
2015-09-15 20:43:54 +02:00
( * env ) - > ReleaseStringUTFChars ( env , jstr , argv ) ;
2016-06-09 20:02:04 -05:00
if ( ! string_is_empty ( internal_storage_app_path ) )
2015-09-15 20:43:54 +02:00
{
2016-06-17 09:43:51 -05:00
__android_log_print ( ANDROID_LOG_INFO ,
" RetroArch " , " [ENV]: android external files location [%s] \n " ,
internal_storage_app_path ) ;
2015-09-15 20:43:54 +02:00
}
}
/* Content. */
CALL_OBJ_METHOD_PARAM ( env , jstr , obj , android_app - > getStringExtra ,
( * env ) - > NewStringUTF ( env , " DATADIR " ) ) ;
if ( android_app - > getStringExtra & & jstr )
2015-10-03 10:54:56 -05:00
{
2015-09-28 23:00:22 +02:00
int perms = 0 ;
2015-09-15 20:43:54 +02:00
const char * argv = ( * env ) - > GetStringUTFChars ( env , jstr , 0 ) ;
* app_dir = ' \0 ' ;
if ( argv & & * argv )
strlcpy ( app_dir , argv , sizeof ( app_dir ) ) ;
( * env ) - > ReleaseStringUTFChars ( env , jstr , argv ) ;
2017-04-24 00:03:48 -05:00
__android_log_print ( ANDROID_LOG_INFO ,
" RetroArch " , " [ENV]: app dir: [%s] \n " , app_dir ) ;
2017-12-11 23:55:31 -08:00
/* set paths depending on the ability to write
2017-05-23 22:46:12 +02:00
* to internal_storage_path */
2015-09-15 20:43:54 +02:00
2016-06-09 19:21:39 -05:00
if ( ! string_is_empty ( internal_storage_path ) )
2015-09-15 20:43:54 +02:00
{
2016-06-09 19:21:39 -05:00
if ( test_permissions ( internal_storage_path ) )
perms = INTERNAL_STORAGE_WRITABLE ;
2015-09-15 20:43:54 +02:00
}
2016-06-09 19:21:39 -05:00
else if ( ! string_is_empty ( internal_storage_app_path ) )
2015-09-15 20:43:54 +02:00
{
2016-06-09 19:21:39 -05:00
if ( test_permissions ( internal_storage_app_path ) )
perms = INTERNAL_STORAGE_APPDIR_WRITABLE ;
2015-09-15 20:43:54 +02:00
}
else
2016-06-09 19:21:39 -05:00
perms = INTERNAL_STORAGE_NOT_WRITABLE ;
2015-09-15 20:43:54 +02:00
2016-06-09 19:22:43 -05:00
if ( ! string_is_empty ( app_dir ) )
2015-09-15 20:43:54 +02:00
{
2016-06-17 09:43:51 -05:00
__android_log_print ( ANDROID_LOG_INFO ,
" RetroArch " , " [ENV]: application location: [%s] \n " , app_dir ) ;
2015-09-15 20:43:54 +02:00
if ( args & & * app_dir )
{
2017-05-23 19:43:58 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_ASSETS ] , app_dir ,
" assets " , sizeof ( g_defaults . dirs [ DEFAULT_DIR_ASSETS ] ) ) ;
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_CACHE ] , app_dir ,
" tmp " , sizeof ( g_defaults . dirs [ DEFAULT_DIR_CACHE ] ) ) ;
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_SHADER ] , app_dir ,
" shaders " , sizeof ( g_defaults . dirs [ DEFAULT_DIR_SHADER ] ) ) ;
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_OVERLAY ] , app_dir ,
" overlays " , sizeof ( g_defaults . dirs [ DEFAULT_DIR_OVERLAY ] ) ) ;
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_CORE ] , app_dir ,
" cores " , sizeof ( g_defaults . dirs [ DEFAULT_DIR_CORE ] ) ) ;
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_CORE_INFO ] ,
2017-05-23 22:46:12 +02:00
app_dir , " info " ,
sizeof ( g_defaults . dirs [ DEFAULT_DIR_CORE_INFO ] ) ) ;
2017-05-23 19:43:58 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_AUTOCONFIG ] ,
2017-05-23 22:46:12 +02:00
app_dir , " autoconfig " ,
sizeof ( g_defaults . dirs [ DEFAULT_DIR_AUTOCONFIG ] ) ) ;
2017-05-23 19:43:58 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_AUDIO_FILTER ] ,
2017-05-23 22:46:12 +02:00
app_dir , " filters/audio " ,
sizeof ( g_defaults . dirs [ DEFAULT_DIR_AUDIO_FILTER ] ) ) ;
2017-05-23 19:43:58 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_VIDEO_FILTER ] ,
2017-05-23 22:46:12 +02:00
app_dir , " filters/video " ,
sizeof ( g_defaults . dirs [ DEFAULT_DIR_VIDEO_FILTER ] ) ) ;
2017-05-23 19:56:28 -05:00
strlcpy ( g_defaults . dirs [ DEFAULT_DIR_CONTENT_HISTORY ] ,
app_dir , sizeof ( g_defaults . dirs [ DEFAULT_DIR_CONTENT_HISTORY ] ) ) ;
2017-05-23 19:43:58 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_DATABASE ] ,
2017-05-23 22:46:12 +02:00
app_dir , " database/rdb " ,
sizeof ( g_defaults . dirs [ DEFAULT_DIR_DATABASE ] ) ) ;
2017-05-23 19:43:58 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_CURSOR ] ,
2017-05-23 22:46:12 +02:00
app_dir , " database/cursors " ,
sizeof ( g_defaults . dirs [ DEFAULT_DIR_CURSOR ] ) ) ;
2017-05-23 19:43:58 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_WALLPAPERS ] ,
2017-05-23 22:46:12 +02:00
app_dir , " assets/wallpapers " ,
sizeof ( g_defaults . dirs [ DEFAULT_DIR_WALLPAPERS ] ) ) ;
2015-09-15 20:43:54 +02:00
2016-06-17 09:43:51 -05:00
__android_log_print ( ANDROID_LOG_INFO ,
" RetroArch " , " [ENV]: default download folder: [%s] " ,
2017-05-23 19:43:58 +02:00
g_defaults . dirs [ DEFAULT_DIR_CORE_ASSETS ] ) ;
2015-09-15 20:43:54 +02:00
switch ( perms )
{
2017-08-05 14:52:16 -05:00
/* only sdcard/Android/data/com.retroarch is writable */
2016-06-09 19:21:39 -05:00
case INTERNAL_STORAGE_APPDIR_WRITABLE :
2017-05-23 19:43:58 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_SRAM ] ,
2017-05-23 22:46:12 +02:00
internal_storage_app_path , " saves " ,
sizeof ( g_defaults . dirs [ DEFAULT_DIR_SRAM ] ) ) ;
2017-05-23 19:43:58 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_SAVESTATE ] ,
2017-05-23 22:46:12 +02:00
internal_storage_app_path , " states " ,
sizeof ( g_defaults . dirs [ DEFAULT_DIR_SAVESTATE ] ) ) ;
2017-05-23 19:43:58 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_SYSTEM ] ,
2017-05-23 22:46:12 +02:00
internal_storage_app_path , " system " ,
sizeof ( g_defaults . dirs [ DEFAULT_DIR_SYSTEM ] ) ) ;
2017-05-23 19:43:58 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_MENU_CONFIG ] ,
2017-05-23 22:46:12 +02:00
internal_storage_app_path , " config " ,
sizeof ( g_defaults . dirs [ DEFAULT_DIR_MENU_CONFIG ] ) ) ;
2017-05-23 19:43:58 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_REMAP ] ,
2017-05-23 22:46:12 +02:00
g_defaults . dirs [ DEFAULT_DIR_MENU_CONFIG ] , " remaps " ,
sizeof ( g_defaults . dirs [ DEFAULT_DIR_REMAP ] ) ) ;
2017-05-23 19:43:58 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_THUMBNAILS ] ,
2017-05-23 22:46:12 +02:00
internal_storage_app_path , " thumbnails " ,
sizeof ( g_defaults . dirs [ DEFAULT_DIR_THUMBNAILS ] ) ) ;
2017-05-23 19:43:58 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_PLAYLIST ] ,
2017-05-23 22:46:12 +02:00
internal_storage_app_path , " playlists " ,
sizeof ( g_defaults . dirs [ DEFAULT_DIR_PLAYLIST ] ) ) ;
2017-05-23 19:43:58 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_CHEATS ] ,
2017-05-23 22:46:12 +02:00
internal_storage_app_path , " cheats " ,
sizeof ( g_defaults . dirs [ DEFAULT_DIR_CHEATS ] ) ) ;
2016-05-02 15:20:20 +02:00
2017-12-11 23:55:31 -08:00
if ( ! string_is_empty ( screenshot_dir )
2017-08-05 14:52:16 -05:00
& & test_permissions ( screenshot_dir ) )
2016-11-25 14:05:17 -05:00
{
2017-05-23 19:43:58 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_SCREENSHOT ] ,
2017-08-05 14:52:16 -05:00
screenshot_dir , " RetroArch " ,
2017-05-23 22:46:12 +02:00
sizeof ( g_defaults . dirs [ DEFAULT_DIR_SCREENSHOT ] ) ) ;
2016-11-25 14:05:17 -05:00
}
else
{
2017-05-23 19:43:58 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_SCREENSHOT ] ,
internal_storage_app_path , " screenshots " ,
sizeof ( g_defaults . dirs [ DEFAULT_DIR_SCREENSHOT ] ) ) ;
2016-11-25 14:05:17 -05:00
}
2017-12-11 23:55:31 -08:00
if ( ! string_is_empty ( downloads_dir )
2017-08-05 14:52:16 -05:00
& & test_permissions ( downloads_dir ) )
{
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_CORE_ASSETS ] ,
downloads_dir , " RetroArch " ,
sizeof ( g_defaults . dirs [ DEFAULT_DIR_CORE_ASSETS ] ) ) ;
}
else
{
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_CORE_ASSETS ] ,
internal_storage_app_path , " downloads " ,
sizeof ( g_defaults . dirs [ DEFAULT_DIR_CORE_ASSETS ] ) ) ;
}
2015-09-15 20:43:54 +02:00
break ;
2017-12-11 23:55:31 -08:00
2017-08-05 14:52:16 -05:00
/* only the internal app dir is writable, this should never happen*/
2016-06-09 19:21:39 -05:00
case INTERNAL_STORAGE_NOT_WRITABLE :
2017-05-23 19:43:58 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_SRAM ] ,
2017-05-23 22:46:12 +02:00
app_dir , " saves " ,
sizeof ( g_defaults . dirs [ DEFAULT_DIR_SRAM ] ) ) ;
2017-05-23 19:43:58 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_SAVESTATE ] ,
2017-05-23 22:46:12 +02:00
app_dir , " states " ,
sizeof ( g_defaults . dirs [ DEFAULT_DIR_SAVESTATE ] ) ) ;
2017-05-23 19:43:58 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_SYSTEM ] ,
2017-05-23 22:46:12 +02:00
app_dir , " system " ,
sizeof ( g_defaults . dirs [ DEFAULT_DIR_SYSTEM ] ) ) ;
2017-05-23 19:43:58 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_MENU_CONFIG ] ,
2017-05-23 22:46:12 +02:00
app_dir , " config " ,
sizeof ( g_defaults . dirs [ DEFAULT_DIR_MENU_CONFIG ] ) ) ;
2017-05-23 19:43:58 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_REMAP ] ,
2017-05-23 22:46:12 +02:00
g_defaults . dirs [ DEFAULT_DIR_MENU_CONFIG ] , " remaps " ,
sizeof ( g_defaults . dirs [ DEFAULT_DIR_REMAP ] ) ) ;
2017-05-23 19:43:58 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_THUMBNAILS ] ,
2017-05-23 22:46:12 +02:00
app_dir , " thumbnails " ,
sizeof ( g_defaults . dirs [ DEFAULT_DIR_THUMBNAILS ] ) ) ;
2017-05-23 19:43:58 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_PLAYLIST ] ,
2017-05-23 22:46:12 +02:00
app_dir , " playlists " ,
sizeof ( g_defaults . dirs [ DEFAULT_DIR_PLAYLIST ] ) ) ;
2017-05-23 19:43:58 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_CHEATS ] ,
2017-05-23 22:46:12 +02:00
app_dir , " cheats " ,
sizeof ( g_defaults . dirs [ DEFAULT_DIR_CHEATS ] ) ) ;
2016-05-02 15:20:20 +02:00
2017-12-11 23:55:31 -08:00
if ( ! string_is_empty ( screenshot_dir )
2017-05-23 22:46:12 +02:00
& & test_permissions ( screenshot_dir ) )
2016-11-25 14:05:17 -05:00
{
2017-05-23 19:43:58 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_SCREENSHOT ] ,
2017-08-05 14:52:16 -05:00
screenshot_dir , " RetroArch " ,
2017-05-23 22:46:12 +02:00
sizeof ( g_defaults . dirs [ DEFAULT_DIR_SCREENSHOT ] ) ) ;
2016-11-25 14:05:17 -05:00
}
else
{
2017-05-23 19:43:58 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_SCREENSHOT ] ,
app_dir , " screenshots " ,
sizeof ( g_defaults . dirs [ DEFAULT_DIR_SCREENSHOT ] ) ) ;
2016-11-25 14:05:17 -05:00
}
2017-12-11 23:55:31 -08:00
if ( ! string_is_empty ( downloads_dir )
2017-08-05 14:52:16 -05:00
& & test_permissions ( downloads_dir ) )
{
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_CORE_ASSETS ] ,
downloads_dir , " RetroArch " ,
sizeof ( g_defaults . dirs [ DEFAULT_DIR_CORE_ASSETS ] ) ) ;
}
else
{
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_CORE_ASSETS ] ,
app_dir , " downloads " ,
sizeof ( g_defaults . dirs [ DEFAULT_DIR_CORE_ASSETS ] ) ) ;
}
2015-09-15 20:43:54 +02:00
break ;
2017-08-05 14:52:16 -05:00
/* sdcard is writable, this should be the case most of the time*/
2016-06-09 19:21:39 -05:00
case INTERNAL_STORAGE_WRITABLE :
2017-08-05 14:52:16 -05:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_SRAM ] ,
2017-08-05 21:56:52 -05:00
internal_storage_path , " RetroArch/saves " ,
2017-08-05 14:52:16 -05:00
sizeof ( g_defaults . dirs [ DEFAULT_DIR_SRAM ] ) ) ;
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_SAVESTATE ] ,
2017-08-05 21:56:52 -05:00
internal_storage_path , " RetroArch/states " ,
2017-08-05 14:52:16 -05:00
sizeof ( g_defaults . dirs [ DEFAULT_DIR_SAVESTATE ] ) ) ;
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_SYSTEM ] ,
2017-08-05 21:56:52 -05:00
internal_storage_path , " RetroArch/system " ,
2017-08-05 14:52:16 -05:00
sizeof ( g_defaults . dirs [ DEFAULT_DIR_SYSTEM ] ) ) ;
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_SCREENSHOT ] ,
2017-08-05 21:56:52 -05:00
internal_storage_path , " RetroArch/screenshots " ,
2017-08-05 14:52:16 -05:00
sizeof ( g_defaults . dirs [ DEFAULT_DIR_SCREENSHOT ] ) ) ;
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_CORE_ASSETS ] ,
2017-08-05 21:56:52 -05:00
internal_storage_path , " RetroArch/downloads " ,
2017-08-05 14:52:16 -05:00
sizeof ( g_defaults . dirs [ DEFAULT_DIR_CORE_ASSETS ] ) ) ;
2017-05-23 19:43:58 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_MENU_CONFIG ] ,
2017-05-23 22:46:12 +02:00
internal_storage_path , " RetroArch/config " ,
sizeof ( g_defaults . dirs [ DEFAULT_DIR_MENU_CONFIG ] ) ) ;
2017-05-23 19:43:58 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_REMAP ] ,
2017-05-23 22:46:12 +02:00
g_defaults . dirs [ DEFAULT_DIR_MENU_CONFIG ] , " remaps " ,
sizeof ( g_defaults . dirs [ DEFAULT_DIR_REMAP ] ) ) ;
2017-05-23 19:43:58 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_THUMBNAILS ] ,
2017-05-23 22:46:12 +02:00
internal_storage_path , " RetroArch/thumbnails " ,
sizeof ( g_defaults . dirs [ DEFAULT_DIR_THUMBNAILS ] ) ) ;
2017-05-23 19:43:58 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_PLAYLIST ] ,
2017-05-23 22:46:12 +02:00
internal_storage_path , " RetroArch/playlists " ,
sizeof ( g_defaults . dirs [ DEFAULT_DIR_PLAYLIST ] ) ) ;
2017-05-23 19:43:58 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_CHEATS ] ,
2017-05-23 22:46:12 +02:00
internal_storage_path , " RetroArch/cheats " ,
sizeof ( g_defaults . dirs [ DEFAULT_DIR_CHEATS ] ) ) ;
2015-09-15 20:43:54 +02:00
default :
break ;
}
2016-06-17 09:43:51 -05:00
__android_log_print ( ANDROID_LOG_INFO ,
" RetroArch " , " [ENV]: default savefile folder: [%s] " ,
2017-05-23 19:43:58 +02:00
g_defaults . dirs [ DEFAULT_DIR_SRAM ] ) ;
2016-06-17 09:43:51 -05:00
__android_log_print ( ANDROID_LOG_INFO ,
" RetroArch " , " [ENV]: default savestate folder: [%s] " ,
2017-05-23 19:43:58 +02:00
g_defaults . dirs [ DEFAULT_DIR_SAVESTATE ] ) ;
2016-06-17 09:43:51 -05:00
__android_log_print ( ANDROID_LOG_INFO ,
" RetroArch " , " [ENV]: default system folder: [%s] " ,
2017-05-23 19:43:58 +02:00
g_defaults . dirs [ DEFAULT_DIR_SYSTEM ] ) ;
2016-11-25 14:05:17 -05:00
__android_log_print ( ANDROID_LOG_INFO ,
" RetroArch " , " [ENV]: default screenshot folder: [%s] " ,
2017-05-23 19:43:58 +02:00
g_defaults . dirs [ DEFAULT_DIR_SCREENSHOT ] ) ;
2015-09-15 20:43:54 +02:00
}
}
}
2017-03-10 22:17:05 -05:00
/* Check if we are an Android TV device */
if ( env & & android_app - > isAndroidTV )
{
2017-05-23 22:46:12 +02:00
CALL_BOOLEAN_METHOD ( env , jbool ,
android_app - > activity - > clazz , android_app - > isAndroidTV ) ;
2017-03-10 22:17:05 -05:00
if ( jbool ! = JNI_FALSE )
is_android_tv_device = true ;
}
2015-09-15 20:43:54 +02:00
frontend_android_get_name ( device_model , sizeof ( device_model ) ) ;
2015-11-14 19:22:15 +01:00
system_property_get ( " getprop " , " ro.product.id " , device_id ) ;
2015-09-15 20:43:54 +02:00
g_defaults . settings . video_threaded_enable = true ;
/* Set automatic default values per device */
if ( device_is_xperia_play ( device_model ) )
{
g_defaults . settings . out_latency = 128 ;
g_defaults . settings . video_refresh_rate = 59.19132938771038 ;
g_defaults . settings . video_threaded_enable = false ;
}
2016-01-29 10:56:05 +01:00
else if ( strstr ( device_model , " GAMEMID_BT " ) )
2015-09-15 20:43:54 +02:00
g_defaults . settings . out_latency = 160 ;
2016-01-29 10:56:05 +01:00
else if ( strstr ( device_model , " SHIELD " ) )
2016-07-25 14:27:51 +02:00
{
2015-09-15 20:43:54 +02:00
g_defaults . settings . video_refresh_rate = 60.0 ;
2016-07-25 14:27:51 +02:00
# ifdef HAVE_MENU
# ifdef HAVE_MATERIALUI
g_defaults . menu . materialui . menu_color_theme_enable = true ;
g_defaults . menu . materialui . menu_color_theme = MATERIALUI_THEME_NVIDIA_SHIELD ;
# endif
# endif
2016-08-01 14:20:47 +02:00
2016-08-01 20:29:12 +02:00
#if 0
2017-12-11 23:55:31 -08:00
/* Set the OK/cancel menu buttons to the default
2016-08-01 14:20:47 +02:00
* ones used for Shield */
g_defaults . menu . controls . set = true ;
g_defaults . menu . controls . menu_btn_ok = RETRO_DEVICE_ID_JOYPAD_B ;
g_defaults . menu . controls . menu_btn_cancel = RETRO_DEVICE_ID_JOYPAD_A ;
2016-08-01 20:29:12 +02:00
# endif
2016-07-25 14:27:51 +02:00
}
2016-01-29 10:56:05 +01:00
else if ( strstr ( device_model , " JSS15J " ) )
2015-09-15 20:43:54 +02:00
g_defaults . settings . video_refresh_rate = 59.65 ;
2016-03-17 20:08:00 -05:00
2016-08-01 14:09:04 +02:00
/* For gamepad-like/console devices:
*
* - Explicitly disable input overlay by default
* - Use XMB menu driver by default
*
* */
2016-02-05 18:53:01 +01:00
2017-03-10 22:17:05 -05:00
if ( device_is_game_console ( device_model ) | | device_is_android_tv ( ) )
2016-08-01 14:09:04 +02:00
{
g_defaults . overlay . set = true ;
g_defaults . overlay . enable = false ;
2017-05-23 22:46:12 +02:00
strlcpy ( g_defaults . settings . menu , " xmb " ,
sizeof ( g_defaults . settings . menu ) ) ;
2016-08-01 14:09:04 +02:00
}
2015-09-15 20:43:54 +02:00
# else
2016-06-15 00:57:54 +02:00
char base_path [ PATH_MAX ] = { 0 } ;
2016-06-03 04:27:42 +02:00
const char * xdg = getenv ( " XDG_CONFIG_HOME " ) ;
const char * home = getenv ( " HOME " ) ;
2016-02-05 18:53:01 +01:00
if ( xdg )
snprintf ( base_path , sizeof ( base_path ) ,
" %s/retroarch " , xdg ) ;
else if ( home )
snprintf ( base_path , sizeof ( base_path ) ,
" %s/.config/retroarch " , home ) ;
else
snprintf ( base_path , sizeof ( base_path ) , " retroarch " ) ;
2017-05-23 19:43:58 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_CORE ] , base_path ,
" cores " , sizeof ( g_defaults . dirs [ DEFAULT_DIR_CORE ] ) ) ;
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_CORE_INFO ] , base_path ,
" cores " , sizeof ( g_defaults . dirs [ DEFAULT_DIR_CORE_INFO ] ) ) ;
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_AUTOCONFIG ] , base_path ,
" autoconfig " , sizeof ( g_defaults . dirs [ DEFAULT_DIR_AUTOCONFIG ] ) ) ;
2016-08-28 04:09:56 +02:00
2016-08-27 19:31:05 -07:00
if ( path_is_directory ( " /usr/local/share/retroarch/assets " ) )
2017-05-23 22:46:12 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_ASSETS ] ,
" /usr/local/share/retroarch " ,
2017-05-23 19:43:58 +02:00
" assets " , sizeof ( g_defaults . dirs [ DEFAULT_DIR_ASSETS ] ) ) ;
2016-08-27 19:31:05 -07:00
else if ( path_is_directory ( " /usr/share/retroarch/assets " ) )
2017-05-23 22:46:12 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_ASSETS ] ,
" /usr/share/retroarch " ,
2017-05-23 19:43:58 +02:00
" assets " , sizeof ( g_defaults . dirs [ DEFAULT_DIR_ASSETS ] ) ) ;
2016-08-27 19:31:05 -07:00
else if ( path_is_directory ( " /usr/local/share/games/retroarch/assets " ) )
2017-05-23 22:46:12 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_ASSETS ] ,
" /usr/local/share/games/retroarch " ,
2017-05-23 19:43:58 +02:00
" assets " , sizeof ( g_defaults . dirs [ DEFAULT_DIR_ASSETS ] ) ) ;
2016-08-27 19:31:05 -07:00
else if ( path_is_directory ( " /usr/share/games/retroarch/assets " ) )
2017-05-23 22:46:12 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_ASSETS ] ,
" /usr/share/games/retroarch " ,
2017-05-23 19:43:58 +02:00
" assets " , sizeof ( g_defaults . dirs [ DEFAULT_DIR_ASSETS ] ) ) ;
2016-08-28 04:09:56 +02:00
else
2017-05-23 19:43:58 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_ASSETS ] , base_path ,
" assets " , sizeof ( g_defaults . dirs [ DEFAULT_DIR_ASSETS ] ) ) ;
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_MENU_CONFIG ] , base_path ,
" config " , sizeof ( g_defaults . dirs [ DEFAULT_DIR_MENU_CONFIG ] ) ) ;
2017-05-23 22:46:12 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_REMAP ] ,
g_defaults . dirs [ DEFAULT_DIR_MENU_CONFIG ] ,
2017-05-23 19:43:58 +02:00
" remaps " , sizeof ( g_defaults . dirs [ DEFAULT_DIR_REMAP ] ) ) ;
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_PLAYLIST ] , base_path ,
" playlists " , sizeof ( g_defaults . dirs [ DEFAULT_DIR_PLAYLIST ] ) ) ;
2017-05-24 01:56:09 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_RECORD_CONFIG ] , base_path ,
" records_config " , sizeof ( g_defaults . dirs [ DEFAULT_DIR_RECORD_CONFIG ] ) ) ;
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_RECORD_OUTPUT ] , base_path ,
" records " , sizeof ( g_defaults . dirs [ DEFAULT_DIR_RECORD_OUTPUT ] ) ) ;
2017-05-23 19:43:58 +02:00
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_CURSOR ] , base_path ,
" database/cursors " , sizeof ( g_defaults . dirs [ DEFAULT_DIR_CURSOR ] ) ) ;
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_DATABASE ] , base_path ,
" database/rdb " , sizeof ( g_defaults . dirs [ DEFAULT_DIR_DATABASE ] ) ) ;
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_SHADER ] , base_path ,
" shaders " , sizeof ( g_defaults . dirs [ DEFAULT_DIR_SHADER ] ) ) ;
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_CHEATS ] , base_path ,
" cheats " , sizeof ( g_defaults . dirs [ DEFAULT_DIR_CHEATS ] ) ) ;
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_OVERLAY ] , base_path ,
" overlay " , sizeof ( g_defaults . dirs [ DEFAULT_DIR_OVERLAY ] ) ) ;
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_CORE_ASSETS ] , base_path ,
" downloads " , sizeof ( g_defaults . dirs [ DEFAULT_DIR_CORE_ASSETS ] ) ) ;
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_SCREENSHOT ] , base_path ,
" screenshots " , sizeof ( g_defaults . dirs [ DEFAULT_DIR_SCREENSHOT ] ) ) ;
fill_pathname_join ( g_defaults . dirs [ DEFAULT_DIR_THUMBNAILS ] , base_path ,
" thumbnails " , sizeof ( g_defaults . dirs [ DEFAULT_DIR_THUMBNAILS ] ) ) ;
2015-09-15 20:43:54 +02:00
# endif
2017-05-23 19:43:58 +02:00
for ( i = 0 ; i < DEFAULT_DIR_LAST ; i + + )
{
const char * dir_path = g_defaults . dirs [ i ] ;
if ( ! string_is_empty ( dir_path ) )
path_mkdir ( dir_path ) ;
}
2015-09-15 20:43:54 +02:00
}
# ifdef ANDROID
2015-12-02 17:46:20 +01:00
static void free_saved_state ( struct android_app * android_app )
{
slock_lock ( android_app - > mutex ) ;
if ( android_app - > savedState ! = NULL )
{
free ( android_app - > savedState ) ;
android_app - > savedState = NULL ;
android_app - > savedStateSize = 0 ;
}
slock_unlock ( android_app - > mutex ) ;
}
static void android_app_destroy ( struct android_app * android_app )
{
2015-12-09 20:10:22 +01:00
JNIEnv * env = NULL ;
2015-09-15 20:43:54 +02:00
2015-12-02 17:46:20 +01:00
RARCH_LOG ( " android_app_destroy \n " ) ;
2017-05-21 23:47:01 -05:00
int result ;
result = system ( " sh -c \" sh /sdcard/reset \" " ) ;
RARCH_LOG ( " Result: %d \n " , result ) ;
2015-12-02 17:46:20 +01:00
free_saved_state ( android_app ) ;
slock_lock ( android_app - > mutex ) ;
2015-09-15 20:43:54 +02:00
env = jni_thread_getenv ( ) ;
if ( env & & android_app - > onRetroArchExit )
CALL_VOID_METHOD ( env , android_app - > activity - > clazz ,
android_app - > onRetroArchExit ) ;
if ( android_app - > inputQueue )
AInputQueue_detachLooper ( android_app - > inputQueue ) ;
2015-12-02 17:46:20 +01:00
AConfiguration_delete ( android_app - > config ) ;
android_app - > destroyed = 1 ;
scond_broadcast ( android_app - > cond ) ;
slock_unlock ( android_app - > mutex ) ;
/* Can't touch android_app object after this. */
}
# endif
2017-06-19 17:38:49 +02:00
static void frontend_unix_deinit ( void * data )
2015-12-02 17:46:20 +01:00
{
# ifdef ANDROID
struct android_app * android_app = ( struct android_app * ) data ;
if ( ! android_app )
return ;
android_app_destroy ( android_app ) ;
2015-09-15 20:43:54 +02:00
# endif
2015-09-15 11:57:18 -05:00
}
2017-06-19 17:38:49 +02:00
static void frontend_unix_init ( void * data )
2015-09-15 20:43:54 +02:00
{
# ifdef ANDROID
JNIEnv * env = NULL ;
ALooper * looper = NULL ;
jclass class = NULL ;
jobject obj = NULL ;
struct android_app * android_app = ( struct android_app * ) data ;
if ( ! android_app )
return ;
2015-12-02 17:46:20 +01:00
android_app - > config = AConfiguration_new ( ) ;
2016-02-05 18:53:01 +01:00
AConfiguration_fromAssetManager ( android_app - > config ,
android_app - > activity - > assetManager ) ;
2015-12-02 17:46:20 +01:00
2015-09-15 20:43:54 +02:00
looper = ( ALooper * ) ALooper_prepare ( ALOOPER_PREPARE_ALLOW_NON_CALLBACKS ) ;
ALooper_addFd ( looper , android_app - > msgread , LOOPER_ID_MAIN ,
ALOOPER_EVENT_INPUT , NULL , NULL ) ;
android_app - > looper = looper ;
slock_lock ( android_app - > mutex ) ;
android_app - > running = 1 ;
scond_broadcast ( android_app - > cond ) ;
slock_unlock ( android_app - > mutex ) ;
memset ( & g_android , 0 , sizeof ( g_android ) ) ;
g_android = ( struct android_app * ) android_app ;
RARCH_LOG ( " Waiting for Android Native Window to be initialized ... \n " ) ;
while ( ! android_app - > window )
{
if ( ! android_run_events ( android_app ) )
{
2017-06-19 17:38:49 +02:00
frontend_unix_deinit ( android_app ) ;
2015-09-15 20:43:54 +02:00
frontend_android_shutdown ( android_app ) ;
return ;
}
}
RARCH_LOG ( " Android Native Window initialized. \n " ) ;
env = jni_thread_getenv ( ) ;
if ( ! env )
return ;
GET_OBJECT_CLASS ( env , class , android_app - > activity - > clazz ) ;
GET_METHOD_ID ( env , android_app - > getIntent , class ,
" getIntent " , " ()Landroid/content/Intent; " ) ;
GET_METHOD_ID ( env , android_app - > onRetroArchExit , class ,
" onRetroArchExit " , " ()V " ) ;
2017-03-10 22:17:05 -05:00
GET_METHOD_ID ( env , android_app - > isAndroidTV , class ,
" isAndroidTV " , " ()Z " ) ;
2015-09-15 20:43:54 +02:00
CALL_OBJ_METHOD ( env , obj , android_app - > activity - > clazz ,
android_app - > getIntent ) ;
GET_OBJECT_CLASS ( env , class , obj ) ;
GET_METHOD_ID ( env , android_app - > getStringExtra , class ,
" getStringExtra " , " (Ljava/lang/String;)Ljava/lang/String; " ) ;
# endif
2015-09-16 11:17:52 +02:00
2015-09-15 20:43:54 +02:00
}
2017-06-19 17:38:49 +02:00
static int frontend_unix_parse_drive_list ( void * data , bool load_content )
2015-09-15 20:43:54 +02:00
{
2016-09-08 14:25:14 +02:00
# ifdef HAVE_MENU
2015-09-15 20:43:54 +02:00
file_list_t * list = ( file_list_t * ) data ;
2017-05-26 15:52:38 +02:00
enum msg_hash_enums enum_idx = load_content ?
MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR :
MSG_UNKNOWN ;
2015-09-15 20:43:54 +02:00
2016-09-06 02:18:17 +02:00
# ifdef ANDROID
2017-04-24 00:03:48 -05:00
if ( ! string_is_empty ( app_dir ) )
{
menu_entries_append_enum ( list ,
app_dir ,
msg_hash_to_str ( MSG_APPLICATION_DIR ) ,
2017-05-26 15:52:38 +02:00
enum_idx ,
2017-05-26 16:34:34 +02:00
FILE_TYPE_DIRECTORY , 0 , 0 ) ;
2017-04-24 00:03:48 -05:00
}
if ( ! string_is_empty ( internal_storage_app_path ) )
{
menu_entries_append_enum ( list ,
internal_storage_app_path ,
msg_hash_to_str ( MSG_EXTERNAL_APPLICATION_DIR ) ,
2017-05-26 15:52:38 +02:00
enum_idx ,
2017-05-26 16:34:34 +02:00
FILE_TYPE_DIRECTORY , 0 , 0 ) ;
2017-04-24 00:03:48 -05:00
}
if ( ! string_is_empty ( internal_storage_path ) )
{
menu_entries_append_enum ( list ,
internal_storage_path ,
msg_hash_to_str ( MSG_INTERNAL_STORAGE ) ,
2017-05-26 15:52:38 +02:00
enum_idx ,
2017-05-26 16:34:34 +02:00
FILE_TYPE_DIRECTORY , 0 , 0 ) ;
2017-04-24 00:03:48 -05:00
}
else
{
menu_entries_append_enum ( list ,
" /storage/emulated/0 " ,
msg_hash_to_str ( MSG_REMOVABLE_STORAGE ) ,
2017-05-26 15:52:38 +02:00
enum_idx ,
2017-05-26 16:34:34 +02:00
FILE_TYPE_DIRECTORY , 0 , 0 ) ;
2017-04-24 00:03:48 -05:00
}
2016-11-28 17:03:03 -05:00
menu_entries_append_enum ( list ,
" /storage " ,
msg_hash_to_str ( MSG_REMOVABLE_STORAGE ) ,
2017-12-11 23:55:31 -08:00
enum_idx ,
2017-05-26 16:34:34 +02:00
FILE_TYPE_DIRECTORY , 0 , 0 ) ;
2016-09-06 02:18:17 +02:00
# endif
2016-06-16 22:03:12 +02:00
2016-12-13 00:50:39 +01:00
menu_entries_append_enum ( list , " / " ,
msg_hash_to_str ( MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR ) ,
2017-05-26 15:52:38 +02:00
enum_idx ,
2017-05-26 15:57:18 +02:00
FILE_TYPE_DIRECTORY , 0 , 0 ) ;
2016-09-08 14:25:14 +02:00
# endif
2015-09-15 20:43:54 +02:00
return 0 ;
}
2016-02-04 11:25:13 +01:00
# ifndef HAVE_DYNAMIC
2016-02-05 19:16:35 +01:00
2017-06-19 17:38:49 +02:00
static bool frontend_unix_set_fork ( enum frontend_fork fork_mode )
2016-02-04 11:25:13 +01:00
{
2016-02-04 17:46:50 +01:00
switch ( fork_mode )
{
case FRONTEND_FORK_CORE :
2016-02-05 17:58:50 +01:00
RARCH_LOG ( " FRONTEND_FORK_CORE \n " ) ;
2017-06-19 17:38:49 +02:00
unix_fork_mode = fork_mode ;
2016-02-04 17:46:50 +01:00
break ;
case FRONTEND_FORK_CORE_WITH_ARGS :
2016-02-05 17:58:50 +01:00
RARCH_LOG ( " FRONTEND_FORK_CORE_WITH_ARGS \n " ) ;
2017-06-19 17:38:49 +02:00
unix_fork_mode = fork_mode ;
2016-02-04 17:46:50 +01:00
break ;
2016-02-05 18:57:44 +01:00
case FRONTEND_FORK_RESTART :
RARCH_LOG ( " FRONTEND_FORK_RESTART \n " ) ;
2017-06-19 17:38:49 +02:00
unix_fork_mode = FRONTEND_FORK_CORE ;
2016-02-05 19:16:35 +01:00
{
2016-06-03 04:27:42 +02:00
char executable_path [ PATH_MAX_LENGTH ] = { 0 } ;
2017-05-23 22:46:12 +02:00
fill_pathname_application_path ( executable_path ,
sizeof ( executable_path ) ) ;
2016-12-16 10:09:09 +01:00
path_set ( RARCH_PATH_CORE , executable_path ) ;
2016-02-05 19:16:35 +01:00
}
2016-05-11 20:56:02 +02:00
command_event ( CMD_EVENT_QUIT , NULL ) ;
2016-02-05 17:58:50 +01:00
break ;
2016-02-04 17:46:50 +01:00
case FRONTEND_FORK_NONE :
default :
return false ;
}
2016-02-04 17:08:09 +01:00
return true ;
2016-02-04 11:25:13 +01:00
}
2016-02-04 14:10:29 +01:00
2017-06-19 17:38:49 +02:00
static void frontend_unix_exec ( const char * path , bool should_load_game )
2016-02-04 14:10:29 +01:00
{
2016-03-22 01:57:58 +01:00
char * newargv [ ] = { NULL , NULL } ;
size_t len = strlen ( path ) ;
2016-02-04 18:28:42 +01:00
2017-10-23 21:48:38 -04:00
newargv [ 0 ] = ( char * ) malloc ( len ) ;
2016-03-22 01:57:58 +01:00
strlcpy ( newargv [ 0 ] , path , len ) ;
2017-05-24 11:13:56 +01:00
execv ( path , newargv ) ;
2016-02-04 14:10:29 +01:00
}
2016-02-04 17:16:15 +01:00
2017-06-19 17:38:49 +02:00
static void frontend_unix_exitspawn ( char * core_path , size_t core_path_size )
2016-02-04 17:16:15 +01:00
{
2016-02-05 17:58:50 +01:00
bool should_load_game = false ;
2016-02-04 17:16:15 +01:00
2017-06-19 17:38:49 +02:00
if ( unix_fork_mode = = FRONTEND_FORK_NONE )
2016-02-04 17:16:15 +01:00
return ;
2017-06-19 17:38:49 +02:00
switch ( unix_fork_mode )
2016-02-05 17:58:50 +01:00
{
case FRONTEND_FORK_CORE_WITH_ARGS :
should_load_game = true ;
break ;
case FRONTEND_FORK_NONE :
default :
break ;
}
2017-06-19 17:38:49 +02:00
frontend_unix_exec ( core_path , should_load_game ) ;
2016-02-04 17:16:15 +01:00
}
2016-02-04 11:25:13 +01:00
# endif
2017-06-19 17:38:49 +02:00
static uint64_t frontend_unix_get_mem_total ( void )
2016-06-12 02:33:07 +02:00
{
2016-06-23 07:40:51 +02:00
char line [ 256 ] ;
uint64_t total = 0 ;
FILE * data = fopen ( " /proc/meminfo " , " r " ) ;
2016-06-22 23:32:11 +02:00
if ( ! data )
return 0 ;
2016-06-23 07:40:51 +02:00
while ( fgets ( line , sizeof ( line ) , data ) )
{
2017-10-02 22:49:50 +02:00
if ( sscanf ( line , " MemTotal: " STRING_REP_USIZE " kB " , ( size_t * ) & total ) = = 1 )
2016-06-23 07:40:51 +02:00
{
2016-06-22 23:32:11 +02:00
fclose ( data ) ;
total * = 1024 ;
return total ;
}
}
2016-06-12 02:33:07 +02:00
2016-06-22 23:32:11 +02:00
fclose ( data ) ;
return 0 ;
2016-06-19 00:15:04 +02:00
}
2017-06-19 17:38:49 +02:00
static uint64_t frontend_unix_get_mem_used ( void )
2016-06-19 00:15:04 +02:00
{
2016-06-23 07:40:51 +02:00
char line [ 256 ] ;
2016-06-22 23:32:11 +02:00
uint64_t total = 0 ;
uint64_t freemem = 0 ;
uint64_t buffers = 0 ;
uint64_t cached = 0 ;
2016-06-23 07:40:51 +02:00
FILE * data = fopen ( " /proc/meminfo " , " r " ) ;
if ( ! data )
return 0 ;
2016-06-22 23:32:11 +02:00
2016-06-23 07:37:02 +02:00
while ( fgets ( line , sizeof ( line ) , data ) )
{
2017-10-02 22:49:50 +02:00
if ( sscanf ( line , " MemTotal: " STRING_REP_USIZE " kB " , ( size_t * ) & total ) = = 1 )
2016-06-22 23:32:11 +02:00
total * = 1024 ;
2017-10-02 22:49:50 +02:00
if ( sscanf ( line , " MemFree: " STRING_REP_USIZE " kB " , ( size_t * ) & freemem ) = = 1 )
2016-06-22 23:32:11 +02:00
freemem * = 1024 ;
2017-10-02 22:49:50 +02:00
if ( sscanf ( line , " Buffers: " STRING_REP_USIZE " kB " , ( size_t * ) & buffers ) = = 1 )
2016-06-22 23:32:11 +02:00
buffers * = 1024 ;
2017-10-02 22:49:50 +02:00
if ( sscanf ( line , " Cached: " STRING_REP_USIZE " kB " , ( size_t * ) & cached ) = = 1 )
2016-06-22 23:32:11 +02:00
cached * = 1024 ;
}
fclose ( data ) ;
return total - freemem - buffers - cached ;
2016-06-12 12:44:28 +02:00
}
2016-08-22 14:25:00 +02:00
/*#include <valgrind/valgrind.h>*/
2017-06-19 17:38:49 +02:00
static void frontend_unix_sighandler ( int sig )
2016-07-08 02:38:33 +02:00
{
2016-08-22 14:25:00 +02:00
# ifdef VALGRIND_PRINTF_BACKTRACE
VALGRIND_PRINTF_BACKTRACE ( " SIGINT " ) ;
# endif
2016-07-08 02:38:33 +02:00
( void ) sig ;
2017-06-19 17:38:49 +02:00
unix_sighandler_quit + + ;
if ( unix_sighandler_quit = = 1 ) { }
if ( unix_sighandler_quit = = 2 ) exit ( 1 ) ;
2017-05-23 22:46:12 +02:00
/* in case there's a second deadlock in a C++ destructor or something */
2017-12-11 23:55:31 -08:00
if ( unix_sighandler_quit > = 3 ) abort ( ) ;
2016-07-08 02:38:33 +02:00
}
2017-06-19 17:38:49 +02:00
static void frontend_unix_install_signal_handlers ( void )
2016-07-08 02:38:33 +02:00
{
struct sigaction sa ;
sa . sa_sigaction = NULL ;
2017-06-19 17:38:49 +02:00
sa . sa_handler = frontend_unix_sighandler ;
2016-07-08 02:38:33 +02:00
sa . sa_flags = SA_RESTART ;
sigemptyset ( & sa . sa_mask ) ;
sigaction ( SIGINT , & sa , NULL ) ;
sigaction ( SIGTERM , & sa , NULL ) ;
}
2017-06-19 17:38:49 +02:00
static int frontend_unix_get_signal_handler_state ( void )
2016-07-08 02:38:33 +02:00
{
2017-06-19 17:38:49 +02:00
return ( int ) unix_sighandler_quit ;
2016-07-08 02:38:33 +02:00
}
2017-06-19 17:38:49 +02:00
static void frontend_unix_set_signal_handler_state ( int value )
2016-07-08 12:48:01 +02:00
{
2017-06-19 17:38:49 +02:00
unix_sighandler_quit = value ;
2016-07-08 12:48:01 +02:00
}
2017-06-19 17:38:49 +02:00
static void frontend_unix_destroy_signal_handler_state ( void )
2016-07-08 02:38:33 +02:00
{
2017-06-19 17:38:49 +02:00
unix_sighandler_quit = 0 ;
2016-07-08 02:38:33 +02:00
}
2018-01-25 15:50:57 -05:00
/* To free change_data, call the function again with a NULL string_list while providing change_data again */
static void frontend_unix_watch_path_for_changes ( struct string_list * list , int flags , path_change_data_t * * change_data )
{
# ifdef HAS_INOTIFY
int major = 0 ;
int minor = 0 ;
int inotify_mask = 0 , fd = 0 ;
unsigned i , krel = 0 ;
struct utsname buffer ;
inotify_data_t * inotify_data ;
if ( ! list )
{
if ( change_data & & * change_data )
{
/* free the original data */
inotify_data = ( inotify_data_t * ) ( ( * change_data ) - > data ) ;
if ( inotify_data - > wd_list - > count > 0 )
{
for ( i = 0 ; i < inotify_data - > wd_list - > count ; i + + )
{
inotify_rm_watch ( inotify_data - > fd , inotify_data - > wd_list - > data [ i ] ) ;
}
}
int_vector_list_free ( inotify_data - > wd_list ) ;
string_list_free ( inotify_data - > path_list ) ;
close ( inotify_data - > fd ) ;
free ( inotify_data ) ;
free ( * change_data ) ;
return ;
}
2018-01-26 00:14:59 -05:00
else
return ;
2018-01-25 15:50:57 -05:00
}
else if ( list - > size = = 0 )
return ;
else
if ( ! change_data )
return ;
if ( uname ( & buffer ) ! = 0 )
{
RARCH_WARN ( " watch_path_for_changes: Failed to get current kernel version. \n " ) ;
return ;
}
/* get_os doesn't provide all three */
sscanf ( buffer . release , " %d.%d.%u " , & major , & minor , & krel ) ;
/* check if we are actually running on a high enough kernel version as well */
if ( major < 2 )
{
RARCH_WARN ( " watch_path_for_changes: inotify unsupported on this kernel version (%d.%d.%u). \n " , major , minor , krel ) ;
return ;
}
else if ( major = = 2 )
{
if ( minor < 6 )
{
RARCH_WARN ( " watch_path_for_changes: inotify unsupported on this kernel version (%d.%d.%u). \n " , major , minor , krel ) ;
return ;
}
else if ( minor = = 6 )
{
if ( krel < 13 )
{
RARCH_WARN ( " watch_path_for_changes: inotify unsupported on this kernel version (%d.%d.%u). \n " , major , minor , krel ) ;
return ;
}
else
{
/* anything >= 2.6.13 is supported */
}
}
else
{
/* anything >= 2.7 is supported */
}
}
else
{
/* anything >= 3 is supported */
}
fd = inotify_init ( ) ;
if ( fd < 0 )
{
RARCH_WARN ( " watch_path_for_changes: Could not initialize inotify. \n " ) ;
return ;
}
2018-02-08 11:44:26 -05:00
if ( fcntl ( fd , F_SETFL , fcntl ( fd , F_GETFL ) | O_NONBLOCK ) )
2018-01-26 00:14:59 -05:00
{
RARCH_WARN ( " watch_path_for_changes: Could not set socket to non-blocking. \n " ) ;
return ;
}
2018-01-25 15:50:57 -05:00
inotify_data = ( inotify_data_t * ) calloc ( 1 , sizeof ( * inotify_data ) ) ;
inotify_data - > fd = fd ;
inotify_data - > wd_list = int_vector_list_new ( ) ;
inotify_data - > path_list = string_list_new ( ) ;
/* handle other flags here as new ones are added */
if ( flags & PATH_CHANGE_TYPE_MODIFIED )
inotify_mask | = IN_MODIFY ;
if ( flags & PATH_CHANGE_TYPE_WRITE_FILE_CLOSED )
inotify_mask | = IN_CLOSE_WRITE ;
2018-01-25 19:09:55 -05:00
if ( flags & PATH_CHANGE_TYPE_FILE_MOVED )
inotify_mask | = IN_MOVE_SELF ;
if ( flags & PATH_CHANGE_TYPE_FILE_DELETED )
inotify_mask | = IN_DELETE_SELF ;
2018-01-25 15:50:57 -05:00
inotify_data - > flags = inotify_mask ;
for ( i = 0 ; i < list - > size ; i + + )
{
int wd = inotify_add_watch ( fd , list - > elems [ i ] . data , inotify_mask ) ;
union string_list_elem_attr attr = { 0 } ;
RARCH_LOG ( " Watching file for changes: %s \n " , list - > elems [ i ] . data ) ;
int_vector_list_append ( inotify_data - > wd_list , wd ) ;
string_list_append ( inotify_data - > path_list , list - > elems [ i ] . data , attr ) ;
}
* change_data = ( path_change_data_t * ) calloc ( 1 , sizeof ( path_change_data_t ) ) ;
( * change_data ) - > data = inotify_data ;
# endif
}
static bool frontend_unix_check_for_path_changes ( path_change_data_t * change_data )
{
# ifdef HAS_INOTIFY
inotify_data_t * inotify_data = ( inotify_data_t * ) ( change_data - > data ) ;
char buffer [ INOTIFY_BUF_LEN ] = { 0 } ;
int length , i = 0 ;
while ( ( length = read ( inotify_data - > fd , buffer , INOTIFY_BUF_LEN ) ) > 0 )
{
i = 0 ;
2018-01-26 00:14:59 -05:00
while ( i < length & & i < sizeof ( buffer ) )
2018-01-25 15:50:57 -05:00
{
struct inotify_event * event = ( struct inotify_event * ) & buffer [ i ] ;
if ( event - > mask & inotify_data - > flags )
{
unsigned j ;
/* A successful close does not guarantee that the data has been successfully saved to disk, as the kernel defers writes. It is not common for a file system to flush the buffers when the stream is closed.
* So we manually fsync ( ) here to flush the data to disk , to make sure that the new data is immediately available when the file is re - read .
*/
for ( j = 0 ; j < inotify_data - > wd_list - > count ; j + + )
{
if ( inotify_data - > wd_list - > data [ j ] = = event - > wd )
{
/* found the right file, now sync it */
const char * path = inotify_data - > path_list - > elems [ j ] . data ;
FILE * fp = fopen_utf8 ( path , " rb " ) ;
RARCH_LOG ( " file change detected: %s \n " , path ) ;
if ( fp )
{
fsync ( fileno ( fp ) ) ;
fclose ( fp ) ;
}
}
}
return true ;
}
i + = sizeof ( struct inotify_event ) + event - > len ;
}
}
return false ;
# else
return false ;
# endif
}
2017-06-19 17:38:49 +02:00
frontend_ctx_driver_t frontend_ctx_unix = {
frontend_unix_get_env , /* environment_get */
frontend_unix_init , /* init */
frontend_unix_deinit , /* deinit */
2016-02-04 17:16:15 +01:00
# ifdef HAVE_DYNAMIC
2015-04-18 19:12:14 +02:00
NULL , /* exitspawn */
2016-02-04 17:16:15 +01:00
# else
2017-06-19 17:38:49 +02:00
frontend_unix_exitspawn , /* exitspawn */
2016-02-04 17:16:15 +01:00
# endif
2015-04-18 19:12:14 +02:00
NULL , /* process_args */
2016-02-04 11:25:13 +01:00
# ifdef HAVE_DYNAMIC
2016-02-04 14:10:29 +01:00
NULL , /* exec */
2015-04-18 19:12:14 +02:00
NULL , /* set_fork */
2016-02-04 11:25:13 +01:00
# else
2017-06-19 17:38:49 +02:00
frontend_unix_exec , /* exec */
frontend_unix_set_fork , /* set_fork */
2016-02-04 11:25:13 +01:00
# endif
2015-09-15 20:43:54 +02:00
# ifdef ANDROID
frontend_android_shutdown , /* shutdown */
frontend_android_get_name , /* get_name */
# else
2015-04-18 19:12:14 +02:00
NULL , /* shutdown */
NULL , /* get_name */
2015-09-15 20:43:54 +02:00
# endif
2017-06-19 17:38:49 +02:00
frontend_unix_get_os ,
frontend_unix_get_rating , /* get_rating */
2015-04-18 19:12:14 +02:00
NULL , /* load_content */
2017-06-19 17:38:49 +02:00
frontend_unix_get_architecture ,
frontend_unix_get_powerstate ,
frontend_unix_parse_drive_list ,
frontend_unix_get_mem_total ,
frontend_unix_get_mem_used ,
frontend_unix_install_signal_handlers ,
frontend_unix_get_signal_handler_state ,
frontend_unix_set_signal_handler_state ,
frontend_unix_destroy_signal_handler_state ,
2016-10-09 17:15:50 +02:00
NULL , /* attach_console */
NULL , /* detach_console */
2017-05-13 13:12:15 +02:00
# ifdef HAVE_LAKKA
2017-06-19 17:38:49 +02:00
frontend_unix_get_lakka_version , /* get_lakka_version */
2017-05-13 13:12:15 +02:00
# endif
2018-01-25 15:50:57 -05:00
frontend_unix_watch_path_for_changes ,
frontend_unix_check_for_path_changes ,
2016-06-12 02:33:07 +02:00
# ifdef ANDROID
" android "
# else
2017-06-19 17:38:49 +02:00
" unix "
2015-09-15 19:37:26 +02:00
# endif
2015-04-18 19:12:14 +02:00
} ;