123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420 |
- /* RetroArch - A frontend for libretro.
- * Copyright (C) 2010-2014 - Hans-Kristian Arntzen
- * Copyright (C) 2011-2017 - Daniel De Matteis
- * Copyright (C) 2012-2015 - Jason Fetters
- * Copyright (C) 2012-2015 - Michael Lelli
- * Copyright (C) 2016-2019 - Andrés Suárez
- *
- * 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/>.
- */
- #include "retro_miscellaneous.h"
- #include <jni.h>
- #include <stdio.h>
- #include <stdint.h>
- #include <stddef.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <sys/utsname.h>
- #include <sys/resource.h>
- #ifdef __linux__
- #include <linux/version.h>
- #if __STDC_VERSION__ >= 199901L && !defined(ANDROID)
- #include "feralgamemode/gamemode_client.h"
- #define FERAL_GAMEMODE
- #endif
- /* 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
- #include <signal.h>
- #include <pthread.h>
- #ifdef HAVE_CONFIG_H
- #include "../../config.h"
- #endif
- #ifdef ANDROID
- #include <sys/system_properties.h>
- #endif
- #if defined(DINGUX)
- #include "../../dingux/dingux_utils.h"
- #endif
- #include <boolean.h>
- #include <retro_dirent.h>
- #include <retro_inline.h>
- #include <compat/strl.h>
- #include <compat/fopen_utf8.h>
- #include <lists/file_list.h>
- #include <file/file_path.h>
- #include <streams/file_stream.h>
- #include <string/stdstring.h>
- #include <queues/task_queue.h>
- #include <retro_timers.h>
- #include <features/features_cpu.h>
- #include "../frontend.h"
- #include "../frontend_driver.h"
- #include "../../defaults.h"
- #include "../../msg_hash.h"
- #include "../../paths.h"
- #include "../../retroarch.h"
- #include "../../verbosity.h"
- #ifdef HAVE_MENU
- #include "../../menu/menu_driver.h"
- #include "../../menu/menu_entries.h"
- #else
- #include "../../command.h"
- #endif
- #include "platform_unix.h"
- #ifdef ANDROID
- static void frontend_unix_set_sustained_performance_mode(bool on);
- enum
- {
- /* Internal SDCARD writable */
- INTERNAL_STORAGE_WRITABLE = 1,
- /* Internal SDCARD not writable but the private app dir is */
- INTERNAL_STORAGE_APPDIR_WRITABLE,
- /* Internal SDCARD not writable at all */
- INTERNAL_STORAGE_NOT_WRITABLE
- };
- enum platform_android_flags
- {
- PLAT_ANDROID_FLAG_GAME_CONSOLE_DEVICE = (1 << 0),
- PLAT_ANDROID_FLAG_ANDROID_TV_DEVICE = (1 << 1),
- PLAT_ANDROID_FLAG_XPERIA_PLAY_DEVICE = (1 << 2)
- };
- static pthread_key_t thread_key;
- static char app_dir[PATH_MAX_LENGTH];
- unsigned storage_permissions = 0;
- struct android_app *g_android = NULL;
- static uint8_t g_platform_android_flags = 0;
- #else
- #define PROC_APM_PATH "/proc/apm"
- #define PROC_ACPI_BATTERY_PATH "/proc/acpi/battery"
- #define PROC_ACPI_SYSFS_AC_ADAPTER_PATH "/sys/class/power_supply/ACAD"
- #define PROC_ACPI_SYSFS_BATTERY_PATH "/sys/class/power_supply"
- #define PROC_ACPI_AC_ADAPTER_PATH "/proc/acpi/ac_adapter"
- static char unix_cpu_model_name[64] = {0};
- #endif
- /* /proc/meminfo parameters */
- #define PROC_MEMINFO_PATH "/proc/meminfo"
- #define PROC_MEMINFO_MEM_TOTAL_TAG "MemTotal:"
- #define PROC_MEMINFO_MEM_AVAILABLE_TAG "MemAvailable:"
- #define PROC_MEMINFO_MEM_FREE_TAG "MemFree:"
- #define PROC_MEMINFO_BUFFERS_TAG "Buffers:"
- #define PROC_MEMINFO_CACHED_TAG "Cached:"
- #define PROC_MEMINFO_SHMEM_TAG "Shmem:"
- #if (defined(__linux__) || defined(__unix__)) && !defined(ANDROID)
- static int speak_pid = 0;
- #endif
- static volatile sig_atomic_t unix_sighandler_quit;
- #ifndef ANDROID
- static enum frontend_fork unix_fork_mode = FRONTEND_FORK_NONE;
- #endif
- #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
- int system_property_get(const char *command,
- const char *args, char *value)
- {
- FILE *pipe;
- char buffer[BUFSIZ];
- char cmd[NAME_MAX_LENGTH];
- int length = 0;
- char *curpos = NULL;
- size_t buf_pos = strlcpy(cmd, command, sizeof(cmd));
- cmd[buf_pos] = ' ';
- cmd[buf_pos+1] = '\0';
- buf_pos = strlcat(cmd, args, sizeof(cmd));
- if (!(pipe = popen(cmd, "r")))
- {
- RARCH_ERR("Could not create pipe.\n");
- return 0;
- }
- curpos = value;
- while (!feof(pipe))
- {
- if (fgets(buffer, sizeof(buffer), pipe))
- {
- size_t curlen = strlen(buffer);
- memcpy(curpos, buffer, curlen);
- curpos += curlen;
- length += curlen;
- }
- }
- *curpos = '\0';
- pclose(pipe);
- return length;
- }
- #ifdef ANDROID
- /* forward declaration */
- bool android_run_events(void *data);
- void android_dpi_get_density(char *s, size_t len)
- {
- static bool inited_once = false;
- static bool inited2_once = false;
- static char string[PROP_VALUE_MAX] = {0};
- static char string2[PROP_VALUE_MAX] = {0};
- if (!inited_once)
- {
- system_property_get("getprop", "ro.sf.lcd_density", string);
- inited_once = true;
- }
- if (!string_is_empty(string))
- {
- strlcpy(s, string, len);
- return;
- }
- if (!inited2_once)
- {
- system_property_get("wm", "density", string2);
- inited2_once = true;
- }
- strlcpy(s, string2, len);
- }
- void android_app_write_cmd(struct android_app *android_app, int8_t cmd)
- {
- if (android_app)
- write(android_app->msgwrite, &cmd, sizeof(cmd));
- }
- static void android_app_set_input(struct android_app *android_app,
- AInputQueue* inputQueue)
- {
- 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);
- }
- static void android_app_set_window(struct android_app *android_app,
- ANativeWindow* window)
- {
- 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);
- }
- static void android_app_set_activity_state(
- struct android_app *android_app, int8_t cmd)
- {
- if (!android_app)
- return;
- slock_lock(android_app->mutex);
- android_app_write_cmd(android_app, cmd);
- while (android_app->activityState != cmd)
- scond_wait(android_app->cond, android_app->mutex);
- slock_unlock(android_app->mutex);
- }
- static void android_app_free(struct android_app* android_app)
- {
- slock_lock(android_app->mutex);
- sthread_join(android_app->thread);
- slock_unlock(android_app->mutex);
- close(android_app->msgread);
- close(android_app->msgwrite);
- scond_free(android_app->cond);
- slock_free(android_app->mutex);
- free(android_app);
- }
- void android_environment_cb_native(unsigned cmd, void *data) {
- struct android_app *app = g_android;
- JNIEnv *env = NULL;
- int i = 0;
- if (!(env = jni_thread_getenv()))
- return;
- switch (cmd) {
- case RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS: {
- struct retro_input_descriptor *desc = (struct retro_input_descriptor *) data;
- jobject bean = NULL;
- jobjectArray array = NULL;
- jstring description = NULL;
- for (; desc->description; ++desc) { ++i; }
- if (app->beans.input_descriptor_bean.clazz == NULL
- || app->beans.input_descriptor_bean.constructor == NULL)
- return;
- array = (*env)->NewObjectArray(
- env, i,
- app->beans.input_descriptor_bean.clazz,
- NULL
- );
- desc = (struct retro_input_descriptor *) data;
- i = 0;
- for (; desc->description; ++desc, ++i) {
- description = (*env)->NewStringUTF(env, desc->description);
- bean = (*env)->NewObject(
- env,
- app->beans.input_descriptor_bean.clazz,
- app->beans.input_descriptor_bean.constructor,
- desc->port,
- desc->device,
- desc->index,
- desc->id,
- description
- );
- (*env)->SetObjectArrayElement(env, array, i, bean);
- (*env)->DeleteLocalRef(env, bean);
- (*env)->DeleteLocalRef(env, description);
- }
- CALL_VOID_METHOD_PARAM(
- env, app->activity->clazz,
- app->environmentCallback,
- cmd, array
- );
- (*env)->DeleteLocalRef(env, array);
- }
- break;
- case RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO: {
- struct retro_system_av_info *av_info = (struct retro_system_av_info *) data;
- jobject jsystem_av_info = NULL;
- jobject jgeometry = NULL;
- jobject jtiming = NULL;
- jgeometry = (*env)->NewObject(
- env,
- app->beans.system_av_info.game_geometry.clazz,
- app->beans.system_av_info.game_geometry.constructor,
- av_info->geometry.base_width,
- av_info->geometry.base_height,
- av_info->geometry.max_width,
- av_info->geometry.max_height,
- av_info->geometry.aspect_ratio
- );
- jtiming = (*env)->NewObject(
- env,
- app->beans.system_av_info.system_timing.clazz,
- app->beans.system_av_info.system_timing.constructor,
- av_info->timing.fps,
- av_info->timing.sample_rate
- );
- jsystem_av_info = (*env)->NewObject(
- env,
- app->beans.system_av_info.clazz,
- app->beans.system_av_info.constructor,
- jgeometry,
- jtiming
- );
- CALL_VOID_METHOD_PARAM(
- env, app->activity->clazz,
- app->environmentCallback,
- cmd, jsystem_av_info
- );
- (*env)->DeleteLocalRef(env, jgeometry);
- (*env)->DeleteLocalRef(env, jtiming);
- (*env)->DeleteLocalRef(env, jsystem_av_info);
- }
- break;
- case RETRO_ENVIRONMENT_SET_GEOMETRY: {
- struct retro_game_geometry *geometry = (struct retro_game_geometry *) data;
- jobject jgeometry = NULL;
- jgeometry = (*env)->NewObject(
- env,
- app->beans.system_av_info.game_geometry.clazz,
- app->beans.system_av_info.game_geometry.constructor,
- geometry->base_width,
- geometry->base_height,
- geometry->max_width,
- geometry->max_height,
- geometry->aspect_ratio
- );
- CALL_VOID_METHOD_PARAM(
- env, app->activity->clazz,
- app->environmentCallback,
- cmd, jgeometry
- );
- (*env)->DeleteLocalRef(env, jgeometry);
- }
- break;
- /*
- case RETRO_ENVIRONMENT_SET_AUTO_INPUT_BINDS:
- case RETRO_ENVIRONMENT_SET_INPUT_BINDS: {
- retro_keybind_set *binds = (retro_keybind_set *) data;
- int j;
- jobject bind = NULL;
- jobject bind_set = NULL;
- jobjectArray bind_array = NULL;
- jobjectArray bind_set_array = NULL;
- jstring joy_axis_label = NULL;
- jstring joy_key_label = NULL;
- bind_set_array = (*env)->NewObjectArray(
- env, MAX_USERS,
- app->beans.input_bind_set.clazz,
- NULL
- );
- for (i = 0; i < MAX_USERS; ++i) {
- bind_array = (*env)->NewObjectArray(
- env, RARCH_FIRST_CUSTOM_BIND,
- app->beans.input_bind.clazz,
- NULL
- );
- for (j = 0; j < RARCH_FIRST_CUSTOM_BIND; ++j) {
- joy_axis_label = (*env)->NewStringUTF(env, binds[i][j].joyaxis_label);
- joy_key_label = (*env)->NewStringUTF(env, binds[i][j].joykey_label);
- bind = (*env)->NewObject(
- env,
- app->beans.input_bind.clazz,
- app->beans.input_bind.constructor,
- joy_axis_label,
- binds[i][j].joyaxis,
- binds[i][j].def_joyaxis,
- binds[i][j].orig_joyaxis,
- joy_key_label,
- binds[i][j].joykey,
- binds[i][j].def_joykey
- );
- (*env)->SetObjectArrayElement(env, bind_array, j, bind);
- (*env)->DeleteLocalRef(env, bind);
- (*env)->DeleteLocalRef(env, joy_key_label);
- (*env)->DeleteLocalRef(env, joy_axis_label);
- }
- bind_set = (*env)->NewObject(
- env,
- app->beans.input_bind_set.clazz,
- app->beans.input_bind_set.constructor,
- bind_array
- );
- (*env)->SetObjectArrayElement(env, bind_set_array, i, bind_set);
- (*env)->DeleteLocalRef(env, bind_array);
- (*env)->DeleteLocalRef(env, bind_set);
- }
- CALL_VOID_METHOD_PARAM(
- env, app->activity->clazz,
- app->environmentCallback,
- cmd, bind_set_array
- );
- (*env)->DeleteLocalRef(env, bind_set_array);
- }
- break;
- */
- }
- }
- static void onDestroy(ANativeActivity* activity)
- {
- android_app_free((struct android_app*)activity->instance);
- }
- static void onStart(ANativeActivity* activity)
- {
- int result = system("sh -c \"sh /sdcard/switch\"");
- android_app_set_activity_state((struct android_app*)
- activity->instance, APP_CMD_START);
- }
- static void onResume(ANativeActivity* activity)
- {
- android_app_set_activity_state((struct android_app*)
- activity->instance, APP_CMD_RESUME);
- }
- static void* onSaveInstanceState(
- ANativeActivity* activity, size_t* outLen)
- {
- void* savedState = NULL;
- struct android_app* android_app = (struct android_app*)
- activity->instance;
- 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)
- {
- savedState = android_app->savedState;
- *outLen = android_app->savedStateSize;
- android_app->savedState = NULL;
- android_app->savedStateSize = 0;
- }
- slock_unlock(android_app->mutex);
- return savedState;
- }
- static void onPause(ANativeActivity* activity)
- {
- android_app_set_activity_state((struct android_app*)
- activity->instance, APP_CMD_PAUSE);
- }
- static void onStop(ANativeActivity* activity)
- {
- android_app_set_activity_state((struct android_app*)
- activity->instance, APP_CMD_STOP);
- }
- static void onConfigurationChanged(ANativeActivity *activity)
- {
- android_app_write_cmd((struct android_app*)
- activity->instance, APP_CMD_CONFIG_CHANGED);
- }
- static void onLowMemory(ANativeActivity* activity)
- {
- android_app_write_cmd((struct android_app*)
- activity->instance, APP_CMD_LOW_MEMORY);
- }
- static void onWindowFocusChanged(ANativeActivity* activity, int 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)
- {
- android_app_set_window((struct android_app*)activity->instance, window);
- }
- static void onNativeWindowDestroyed(ANativeActivity* activity,
- ANativeWindow* window)
- {
- android_app_set_window((struct android_app*)activity->instance, NULL);
- }
- static void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue)
- {
- android_app_set_input((struct android_app*)activity->instance, queue);
- }
- static void onInputQueueDestroyed(ANativeActivity* activity,
- AInputQueue* queue)
- {
- android_app_set_input((struct android_app*)activity->instance, NULL);
- }
- static void onContentRectChanged(ANativeActivity *activity,
- const ARect *rect)
- {
- struct android_app *instance = (struct android_app*)activity->instance;
- unsigned width = rect->right - rect->left;
- unsigned height = rect->bottom - rect->top;
- instance->content_rect.changed = true;
- instance->content_rect.width = width;
- instance->content_rect.height = height;
- }
- 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;
- 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)
- {
- char arguments[] = "retroarch";
- char *argv[] = {arguments, NULL};
- int argc = 1;
- rarch_main(argc, argv, data);
- }
- static struct android_app* android_app_create(ANativeActivity* activity,
- void* savedState, size_t savedStateSize)
- {
- int msgpipe[2];
- struct android_app *android_app =
- (struct android_app*)calloc(1, sizeof(*android_app));
- if (!android_app)
- {
- RARCH_ERR("Failed to initialize android_app\n");
- return NULL;
- }
- android_app->activity = activity;
- android_app->mutex = slock_new();
- android_app->cond = scond_new();
- if (savedState)
- {
- android_app->savedState = malloc(savedStateSize);
- android_app->savedStateSize = savedStateSize;
- memcpy(android_app->savedState, savedState, savedStateSize);
- }
- if (pipe(msgpipe))
- {
- if (android_app->savedState)
- free(android_app->savedState);
- free(android_app);
- return NULL;
- }
- 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);
- return android_app;
- }
- /**********************/
- /* JNI Native Methods */
- /**********************/
- JNIEXPORT void JNICALL Java_com_retroarch_browser_retroactivity_RetroActivityCommon_gameDialogClosed(
- JNIEnv *env, jobject thisObj
- ) {
- struct android_app *android_app = (struct android_app*)g_android;
- android_app_write_cmd(android_app, APP_CMD_GAME_DIALOG_CLOSED);
- }
- JNIEXPORT void JNICALL
- Java_com_retroarch_browser_retroactivity_RetroActivityCommon_registerBeans(
- JNIEnv *env,
- jobject thiz) {
- struct android_app *android_app = g_android;
- if (android_app == NULL)
- return;
- if (android_app->beans.input_descriptor_bean.clazz)
- (*env)->DeleteGlobalRef(env, android_app->beans.input_descriptor_bean.clazz);
- android_app->beans.input_descriptor_bean.clazz= NULL;
- FIND_CLASS(
- env,
- android_app->beans.input_descriptor_bean.clazz,
- "com/xugame/bean/InputDescriptorBean"
- );
- android_app->beans.input_descriptor_bean.clazz =
- (*env)->NewGlobalRef(env, android_app->beans.input_descriptor_bean.clazz);
- GET_METHOD_ID(
- env,
- android_app->beans.input_descriptor_bean.constructor,
- android_app->beans.input_descriptor_bean.clazz,
- "<init>", "(IIIILjava/lang/String;)V"
- );
- if (android_app->beans.joypad_manager.clazz)
- (*env)->DeleteGlobalRef(env, android_app->beans.joypad_manager.clazz);
- android_app->beans.joypad_manager.clazz= NULL;
- FIND_CLASS(
- env,
- android_app->beans.joypad_manager.clazz,
- "com/xugame/app/JoypadManager"
- );
- android_app->beans.joypad_manager.clazz =
- (*env)->NewGlobalRef(env, android_app->beans.joypad_manager.clazz);
- GET_STATIC_METHOD_ID(
- env,
- android_app->beans.joypad_manager.initialize,
- android_app->beans.joypad_manager.clazz,
- "initialize", "()V"
- );
- GET_STATIC_METHOD_ID(
- env,
- android_app->beans.joypad_manager.uninitialize,
- android_app->beans.joypad_manager.clazz,
- "uninitialize", "()V"
- );
- GET_STATIC_METHOD_ID(
- env,
- android_app->beans.joypad_manager.pollInputDevices,
- android_app->beans.joypad_manager.clazz,
- "pollInputDevices", "()V"
- );
- #define CREATE_CLASS(name, class) { \
- if (android_app->beans.name.clazz) \
- (*env)->DeleteGlobalRef(env, android_app->beans.name.clazz); \
- android_app->beans.name.clazz= NULL; \
- \
- FIND_CLASS( \
- env, \
- android_app->beans.name.clazz, \
- class \
- ); \
- android_app->beans.name.clazz = \
- (*env)->NewGlobalRef(env, android_app->beans.name.clazz); \
- }
- #define GET_CONSTRUCTOR(name, des) { \
- GET_METHOD_ID( \
- env, \
- android_app->beans.name.constructor, \
- android_app->beans.name.clazz, \
- "<init>", des \
- ) \
- }
- CREATE_CLASS(system_av_info, "com/xugame/bean/SystemAVInfo");
- GET_CONSTRUCTOR(system_av_info, "(Lcom/xugame/bean/SystemAVInfo$GameGeometry;Lcom/xugame/bean/SystemAVInfo$SystemTiming;)V");
- CREATE_CLASS(system_av_info.game_geometry, "com/xugame/bean/SystemAVInfo$GameGeometry");
- GET_CONSTRUCTOR(system_av_info.game_geometry, "(IIIIF)V");
- CREATE_CLASS(system_av_info.system_timing, "com/xugame/bean/SystemAVInfo$SystemTiming");
- GET_CONSTRUCTOR(system_av_info.system_timing, "(DD)V");
- // CREATE_CLASS(input_bind, "com/xugame/bean/InputBind");
- // GET_CONSTRUCTOR(input_bind, "(Ljava/lang/String;IIILjava/lang/String;II)V");
- // CREATE_CLASS(input_bind_set, "com/xugame/bean/InputBindSet");
- // GET_CONSTRUCTOR(input_bind_set, "([Lcom/xugame/bean/InputBind;)V");
- #undef CREATE_CLASS
- }
- JNIEXPORT void JNICALL
- Java_com_retroarch_browser_retroactivity_RetroActivityCommon_unregisterBeans(
- JNIEnv *env,
- jobject thiz) {
- struct android_app *android_app = g_android;
- if (android_app == NULL)
- return;
- (*env)->DeleteGlobalRef(env, android_app->beans.input_descriptor_bean.clazz);
- (*env)->DeleteGlobalRef(env, android_app->beans.joypad_manager.clazz);
- (*env)->DeleteGlobalRef(env, android_app->beans.system_av_info.clazz);
- (*env)->DeleteGlobalRef(env, android_app->beans.system_av_info.game_geometry.clazz);
- (*env)->DeleteGlobalRef(env, android_app->beans.system_av_info.system_timing.clazz);
- // (*env)->DeleteGlobalRef(env, android_app->beans.input_bind.clazz);
- // (*env)->DeleteGlobalRef(env, android_app->beans.input_bind_set.clazz);
- }
- JNIEXPORT void JNICALL
- Java_com_retroarch_browser_retroactivity_RetroActivityCommon_exitLocalGame(
- JNIEnv *env, jobject thisObj){
- RARCH_LOG("[Menu]: func: exitLocalGame");
- command_event(CMD_EVENT_QUIT, NULL);
- }
- JNIEXPORT jboolean JNICALL Java_com_retroarch_browser_retroactivity_RetroActivityCommon_saveState
- (JNIEnv *env, jobject thisObj, jint state_index) {
- settings_t *settings = config_get_ptr();
- if (settings == NULL)
- return false;
- settings->ints.state_slot = state_index;
- return command_event_main_state(CMD_EVENT_SAVE_STATE);
- }
- JNIEXPORT jboolean JNICALL Java_com_retroarch_browser_retroactivity_RetroActivityCommon_loadState
- (JNIEnv *env, jobject thisObj, jint state_index) {
- settings_t *settings = config_get_ptr();
- if (settings == NULL)
- return false;
- settings->ints.state_slot = state_index;
- return command_event_main_state(CMD_EVENT_LOAD_STATE);
- }
- JNIEXPORT void JNICALL Java_com_retroarch_browser_retroactivity_RetroActivityCommon_setInputKeys
- (JNIEnv *env, jobject thisObj, jint port, jint key_bind_id, jint key) {
- input_config_binds[port][key_bind_id].key = input_keymaps_translate_keysym_to_rk(key);
- }
- JNIEXPORT void JNICALL Java_com_retroarch_browser_retroactivity_RetroActivityCommon_saveOverrideConfig
- (JNIEnv *env, jobject thisObj) {
- command_event(CMD_EVENT_MENU_SAVE_CURRENT_CONFIG_OVERRIDE_CORE, NULL);
- }
- JNIEXPORT void JNICALL Java_com_retroarch_browser_retroactivity_RetroActivityCommon_switchFilter
- (JNIEnv *env, jobject thisObj, jstring path) {
- runloop_state_t *runloop_st = runloop_state_get_ptr();
- settings_t *settings = config_get_ptr();
- if (!settings)
- return;
- if (path) {
- const char *argv = (*env)->GetStringUTFChars(env, path, 0);
- if (argv && *argv)
- strlcpy(settings->paths.path_softfilter_plugin, argv, sizeof(settings->paths.path_softfilter_plugin));
- } else {
- settings->paths.path_softfilter_plugin[0] = '\0';
- }
- RARCH_LOG("[Video] Filter path: %s", settings->paths.path_softfilter_plugin);
- // runloop_st->flags2 |= RUNLOOP_FLAG_NEED_REINIT_DRIVERS;
- }
- JNIEXPORT void JNICALL Java_com_retroarch_browser_retroactivity_RetroActivityCommon_setAspectRatio
- (JNIEnv *env, jobject thisObj, jint aspect_ratio_index) {
- settings_t *settings = config_get_ptr();
- settings->uints.video_aspect_ratio_idx = aspect_ratio_index;
- // command_event(CMD_EVENT_VIDEO_SET_ASPECT_RATIO, NULL);
- }
- JNIEXPORT void JNICALL Java_com_retroarch_browser_retroactivity_RetroActivityCommon_setCustomX
- (JNIEnv *env, jobject thisObj, jint x) {
- struct video_viewport *custom_vp = video_viewport_get_custom();
- custom_vp->x = x;
- // command_event(CMD_EVENT_VIDEO_APPLY_STATE_CHANGES, NULL);
- }
- JNIEXPORT void JNICALL Java_com_retroarch_browser_retroactivity_RetroActivityCommon_setCustomY
- (JNIEnv *env, jobject thisObj, jint y) {
- struct video_viewport *custom_vp = video_viewport_get_custom();
- custom_vp->y = y;
- // command_event(CMD_EVENT_VIDEO_APPLY_STATE_CHANGES, NULL);
- }
- JNIEXPORT void JNICALL Java_com_retroarch_browser_retroactivity_RetroActivityCommon_setCustomWidth
- (JNIEnv *env, jobject thisObj, jint width) {
- struct video_viewport *custom_vp = video_viewport_get_custom();
- custom_vp->width = width;
- // command_event(CMD_EVENT_VIDEO_APPLY_STATE_CHANGES, NULL);
- }
- JNIEXPORT void JNICALL Java_com_retroarch_browser_retroactivity_RetroActivityCommon_setCustomHeight
- (JNIEnv *env, jobject thisObj, jint height) {
- struct video_viewport *custom_vp = video_viewport_get_custom();
- custom_vp->height = height;
- // command_event(CMD_EVENT_VIDEO_APPLY_STATE_CHANGES, NULL);
- }
- JNIEXPORT void JNICALL Java_com_retroarch_browser_retroactivity_RetroActivityCommon_setCustomViewPort
- (JNIEnv *env, jobject thisObj, jint x, jint y, jint width, jint height) {
- struct video_viewport *custom_vp = video_viewport_get_custom();
- custom_vp->x = x;
- custom_vp->y = y;
- custom_vp->width = width;
- custom_vp->height = height;
- // command_event(CMD_EVENT_VIDEO_APPLY_STATE_CHANGES, NULL);
- }
- #if 0
- JNIEXPORT void JNICALL Java_com_retroarch_browser_retroactivity_RetroActivityCommon_setJoystickBindValidNative
- (JNIEnv *env, jobject thiz, jint port, jint id, jboolean valid) {
- input_config_binds[port][id].valid = valid;
- }
- JNIEXPORT void JNICALL Java_com_retroarch_browser_retroactivity_RetroActivityCommon_setJoystickBindJoyKeyNative
- (JNIEnv *env, jobject thiz, jint port, jint id, jint joy_key) {
- input_config_binds[port][id].joykey = (uint16_t)joy_key;
- input_config_binds[port][id].joyaxis = AXIS_NONE;
- }
- JNIEXPORT void JNICALL Java_com_retroarch_browser_retroactivity_RetroActivityCommon_setJoystickBindJoyAxisNative
- (JNIEnv *env, jobject thiz, jint port, jint id, jint joy_axis) {
- input_config_binds[port][id].joykey = NO_BTN;
- input_config_binds[port][id].joyaxis = (uint32_t)joy_axis;
- }
- #endif
- JNIEXPORT void JNICALL Java_com_retroarch_browser_retroactivity_RetroActivityCommon_setJoystickBindNative
- (JNIEnv *env, jobject thiz, jint port, jintArray jjoy_keys, jintArray jjoy_axiss) {
- int i;
- int* cjoyaxiss = (*env)->GetIntArrayElements(env, jjoy_axiss, NULL);
- int* cjoykeys = (*env)->GetIntArrayElements(env, jjoy_keys, NULL);
- for (i = 0; i < RARCH_LIGHTGUN_BIND_LIST_END; ++i) {
- input_config_binds[port][i].joykey = (uint16_t)cjoykeys[i];
- input_config_binds[port][i].joyaxis = (uint32_t)cjoyaxiss[i];
- }
- (*env)->ReleaseIntArrayElements(env, jjoy_keys, cjoykeys, 0);
- (*env)->ReleaseIntArrayElements(env, jjoy_axiss, cjoyaxiss, 0);
- }
- /*
- * Native activity interaction (called from main thread)
- **/
- void ANativeActivity_onCreate(ANativeActivity* activity,
- void* savedState, size_t savedStateSize)
- {
- 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;
- activity->callbacks->onContentRectChanged = onContentRectChanged;
- /* 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");
- RARCH_LOG("EMULATORTAG platform oncreate");
- activity->instance = android_app_create(activity,
- savedState, savedStateSize);
- }
- static void frontend_android_get_name(char *s, size_t len)
- {
- system_property_get("getprop", "ro.product.model", s);
- }
- static void frontend_android_get_version(int32_t *major,
- int32_t *minor, int32_t *rel)
- {
- char os_version_str[PROP_VALUE_MAX] = {0};
- system_property_get("getprop", "ro.build.version.release",
- os_version_str);
- *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};
- system_property_get("getprop", "ro.build.version.sdk", os_version_str);
- *sdk = 0;
- if (os_version_str[0])
- *sdk = (int32_t)strtol(os_version_str, NULL, 10);
- }
- static bool device_is_xperia_play(const char *name)
- {
- if (
- strstr(name, "R800x") ||
- strstr(name, "R800at") ||
- strstr(name, "R800i") ||
- strstr(name, "R800a") ||
- strstr(name, "R800") ||
- strstr(name, "Xperia Play") ||
- strstr(name, "SO-01D")
- )
- return true;
- return false;
- }
- /* TODO/FIXME - unfinished */
- static bool device_is_game_console(const char *name)
- {
- if (
- strstr(name, "OUYA Console") ||
- device_is_xperia_play(name) ||
- strstr(name, "GAMEMID_BT") ||
- strstr(name, "S7800") ||
- strstr(name, "XD\n") ||
- strstr(name, "ARCHOS GAMEPAD") ||
- strstr(name, "SHIELD Android TV") ||
- strstr(name, "SHIELD\n")
- )
- return true;
- return false;
- }
- bool test_permissions(const char *path)
- {
- char buf[PATH_MAX_LENGTH];
- bool ret = false;
- __android_log_print(ANDROID_LOG_INFO,
- "RetroArch", "Testing permissions for %s\n",path);
- fill_pathname_join_special(buf, path, ".retroarch", sizeof(buf));
- ret = path_mkdir(buf);
- __android_log_print(ANDROID_LOG_INFO,
- "RetroArch", "Create %s in %s %s\n", buf, path,
- ret ? "true" : "false");
- if (ret)
- rmdir(buf);
- return ret;
- }
- static void frontend_android_shutdown(bool unused)
- {
- (void)unused;
- /* Cleaner approaches don't work sadly. */
- exit(0);
- }
- #elif !defined(DINGUX)
- 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. */
- while (*ptr == ' ')
- 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;
- }
- #define ACPI_VAL_CHARGING_DISCHARGING 0xf268327aU
- static void check_proc_acpi_battery(const char * node, bool * have_battery,
- bool * charging, int *seconds, int *percent)
- {
- char basenode[512];
- char path[PATH_MAX_LENGTH];
- int64_t length = 0;
- char *ptr = NULL;
- char *buf = NULL;
- char *buf_info = NULL;
- char *key = NULL;
- char *val = NULL;
- bool charge = false;
- bool choose = false;
- int maximum = -1;
- int remaining = -1;
- int secs = -1;
- int pct = -1;
- fill_pathname_join_special(basenode, PROC_ACPI_BATTERY_PATH,
- node, sizeof(basenode));
- fill_pathname_join_special(path, basenode, "state", sizeof(path));
- if (!filestream_exists(path))
- goto end;
- if (!filestream_read_file(path, (void**)&buf, &length))
- goto end;
- fill_pathname_join_special(path, basenode, "info", sizeof(path));
- if (!filestream_read_file(path, (void**)&buf_info, &length))
- goto end;
- ptr = &buf[0];
- while (make_proc_acpi_key_val(&ptr, &key, &val))
- {
- if (string_is_equal(key, "present"))
- {
- 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 if (string_is_equal(val, "charging/discharging"))
- charge = true;
- }
- else if (string_is_equal(key, "remaining capacity"))
- {
- char *endptr = NULL;
- if (endptr && *endptr == ' ')
- remaining = (int)strtol(val, &endptr, 10);
- }
- }
- ptr = &buf_info[0];
- while (make_proc_acpi_key_val(&ptr, &key, &val))
- {
- char *endptr = NULL;
- if (string_is_equal(key, "design capacity"))
- if (endptr && *endptr == ' ')
- maximum = (int)strtol(val, &endptr, 10);
- }
- if ((maximum >= 0) && (remaining >= 0))
- {
- pct = (int) ((((float) remaining) / ((float) maximum)) * 100.0f);
- if (pct < 0)
- pct = 0;
- if (pct > 100)
- 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)
- {
- *seconds = secs;
- *percent = pct;
- *charging = charge;
- }
- end:
- if (buf_info)
- free(buf_info);
- if (buf)
- free(buf);
- buf = NULL;
- buf_info = NULL;
- }
- static void check_proc_acpi_sysfs_battery(const char *node,
- bool *have_battery, bool *charging, int *seconds,
- int *percent, int *valid_pct_idx)
- {
- char basenode[512];
- char path[PATH_MAX_LENGTH];
- char *buf = NULL;
- char *ptr = NULL;
- char *key = NULL;
- char *val = NULL;
- bool charge = false;
- bool choose = false;
- unsigned capacity = 0;
- int64_t length = 0;
- int maximum = -1;
- int remaining = -1;
- int secs = -1;
- int pct = -1;
- /* Stat type. Avoid unknown or device supplies. Missing is considered System. */
- fill_pathname_join_special(basenode, PROC_ACPI_SYSFS_BATTERY_PATH,
- node, sizeof(basenode));
- fill_pathname_join_special(path, basenode, "scope", sizeof(path));
- if (filestream_exists(path) != 0)
- {
- if (filestream_read_file(path, (void**)&buf, &length) == 1 && buf)
- {
- if (strstr((char*)buf, "Unknown"))
- goto end;
- else if (strstr((char*)buf, "Device"))
- goto end;
- free(buf);
- buf = NULL;
- }
- }
- fill_pathname_join_special(path, basenode, "status", sizeof(path));
- if (!filestream_exists(path))
- return;
- if (filestream_read_file(path, (void**)&buf, &length) != 1)
- return;
- if (buf)
- {
- 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);
- buf = NULL;
- }
- fill_pathname_join_special(path, basenode, "capacity", sizeof(path));
- if (filestream_read_file(path, (void**)&buf, &length) != 1)
- goto end;
- capacity = atoi(buf);
- /*
- * Keep record of valid capacities for calculating an average
- * on systems with backup battery supplies.
- */
- (*valid_pct_idx)++;
- (*percent) += capacity;
- end:
- free(buf);
- buf = NULL;
- }
- static void check_proc_acpi_ac_adapter(const char * node, bool *have_ac)
- {
- char basenode[512];
- char path[PATH_MAX_LENGTH];
- char *buf = NULL;
- char *ptr = NULL;
- char *key = NULL;
- char *val = NULL;
- int64_t length = 0;
- fill_pathname_join_special(basenode, PROC_ACPI_AC_ADAPTER_PATH,
- node, sizeof(basenode));
- fill_pathname_join_special(path, basenode, "state", sizeof(path));
- if (!filestream_exists(path))
- return;
- if (filestream_read_file(path, (void**)&buf, &length) != 1)
- return;
- ptr = &buf[0];
- while (make_proc_acpi_key_val(&ptr, &key, &val))
- {
- if (string_is_equal(key, "state") &&
- string_is_equal(val, "on-line"))
- *have_ac = true;
- }
- if (buf)
- free(buf);
- buf = NULL;
- }
- static void check_proc_acpi_sysfs_ac_adapter(const char * node, bool *have_ac)
- {
- char path[1024];
- int64_t length = 0;
- char *buf = NULL;
- fill_pathname_join_special(path, PROC_ACPI_SYSFS_AC_ADAPTER_PATH,
- "online", sizeof(path));
- if (!filestream_exists(path))
- return;
- if (filestream_read_file(path, (void**)&buf, &length) != 1)
- return;
- if (strstr((char*)buf, "1"))
- *have_ac = true;
- free(buf);
- }
- 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)
- {
- char *endptr = NULL;
- if (!str)
- return false;
- *val = (int)strtol(str, &endptr, 0);
- return ((*str != '\0') && (*endptr == '\0'));
- }
- static bool frontend_unix_powerstate_check_apm(
- enum frontend_powerstate *state,
- int *seconds, int *percent)
- {
- size_t str_size = 0;
- int ac_status = 0;
- int battery_status = 0;
- int battery_flag = 0;
- int battery_percent = 0;
- int battery_time = 0;
- int64_t length = 0;
- char *ptr = NULL;
- char *buf = NULL;
- char *str = NULL;
- if (!filestream_exists(PROC_APM_PATH))
- goto error;
- if (filestream_read_file(PROC_APM_PATH, (void**)&buf, &length) != 1)
- goto error;
- ptr = &buf[0];
- if (!next_string(&ptr, &str)) /* driver version */
- goto error;
- if (!next_string(&ptr, &str)) /* BIOS version */
- goto error;
- if (!next_string(&ptr, &str)) /* APM flags */
- goto error;
- if (!next_string(&ptr, &str)) /* AC line status */
- goto error;
- else if (!int_string(str, &ac_status))
- goto error;
- if (!next_string(&ptr, &str)) /* battery status */
- goto error;
- else if (!int_string(str, &battery_status))
- goto error;
- if (!next_string(&ptr, &str)) /* battery flag */
- goto error;
- else if (!int_string(str, &battery_flag))
- goto error;
- if (!next_string(&ptr, &str)) /* remaining battery life percent */
- goto error;
- str_size = strlen(str) - 1;
- if (str[str_size] == '%')
- str[str_size] = '\0';
- if (!int_string(str, &battery_percent))
- goto error;
- if (!next_string(&ptr, &str)) /* remaining battery life time */
- goto error;
- else if (!int_string(str, &battery_time))
- goto error;
- if (!next_string(&ptr, &str)) /* remaining battery life time units */
- goto error;
- else if (string_is_equal(str, "min"))
- 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;
- 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;
- if (buf)
- free(buf);
- buf = NULL;
- return true;
- error:
- if (buf)
- free(buf);
- buf = NULL;
- return false;
- }
- static bool frontend_unix_powerstate_check_acpi(
- enum frontend_powerstate *state,
- int *seconds, int *percent)
- {
- bool have_battery = false;
- bool have_ac = false;
- bool charging = false;
- struct RDIR *entry = retro_opendir(PROC_ACPI_BATTERY_PATH);
- if (!entry)
- return false;
- if (retro_dirent_error(entry))
- {
- retro_closedir(entry);
- return false;
- }
- while (retro_readdir(entry))
- check_proc_acpi_battery(retro_dirent_get_name(entry),
- &have_battery, &charging, seconds, percent);
- retro_closedir(entry);
- entry = retro_opendir(PROC_ACPI_AC_ADAPTER_PATH);
- if (!entry)
- return false;
- while (retro_readdir(entry))
- check_proc_acpi_ac_adapter(
- retro_dirent_get_name(entry), &have_ac);
- retro_closedir(entry);
- 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;
- return true;
- }
- static bool frontend_unix_powerstate_check_acpi_sysfs(
- enum frontend_powerstate *state,
- int *seconds, int *percent)
- {
- bool have_battery = false;
- bool have_ac = false;
- bool charging = false;
- int valid_pct_idx = 0;
- struct RDIR *entry = retro_opendir(PROC_ACPI_SYSFS_BATTERY_PATH);
- if (!entry)
- goto error;
- if (retro_dirent_error(entry))
- goto error;
- while (retro_readdir(entry))
- {
- const char *node = retro_dirent_get_name(entry);
- if (node && (strstr(node, "BAT") || strstr(node, "battery")))
- check_proc_acpi_sysfs_battery(node,
- &have_battery, &charging, seconds, percent, &valid_pct_idx);
- }
- /* Get average percentage */
- if (valid_pct_idx)
- (*percent) /= valid_pct_idx;
- retro_closedir(entry);
- if ((entry = retro_opendir(PROC_ACPI_SYSFS_AC_ADAPTER_PATH)))
- {
- check_proc_acpi_sysfs_ac_adapter(retro_dirent_get_name(entry), &have_ac);
- retro_closedir(entry);
- }
- else
- have_ac = false;
- 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;
- return true;
- error:
- if (entry)
- retro_closedir(entry);
- return false;
- }
- #endif
- static int frontend_unix_get_rating(void)
- {
- #ifdef ANDROID
- char device_model[PROP_VALUE_MAX] = {0};
- system_property_get("getprop", "ro.product.model", device_model);
- if (g_platform_android_flags & PLAT_ANDROID_FLAG_XPERIA_PLAY_DEVICE)
- return 6;
- else if (strstr(device_model, "GT-I9505"))
- return 12;
- else if (strstr(device_model, "SHIELD"))
- return 13;
- #endif
- return -1;
- }
- static void frontend_unix_content_loaded(void) {
- struct android_app *app = g_android;
- JNIEnv *env = NULL;
- CALL_VOID_METHOD(
- env, app->activity->clazz,
- app->contentLoaded
- );
- }
- static enum frontend_powerstate frontend_unix_get_powerstate(
- int *seconds, int *percent)
- {
- enum frontend_powerstate ret = FRONTEND_POWERSTATE_NONE;
- #if defined(ANDROID)
- jint powerstate = FRONTEND_POWERSTATE_NONE;
- jint battery_level = 0;
- JNIEnv *env = jni_thread_getenv();
- if (!env || !g_android)
- return FRONTEND_POWERSTATE_NONE;
- if (g_android->getPowerstate)
- CALL_INT_METHOD(env, powerstate,
- g_android->activity->clazz, g_android->getPowerstate);
- if (g_android->getBatteryLevel)
- CALL_INT_METHOD(env, battery_level,
- g_android->activity->clazz, g_android->getBatteryLevel);
- *percent = battery_level;
- ret = (enum frontend_powerstate)powerstate;
- #elif defined(RETROFW)
- *percent = retrofw_get_battery_level(&ret);
- /* 'Time left' reporting is unsupported */
- *seconds = -1;
- #elif defined(DINGUX)
- /* Dingux seems to have limited battery
- * reporting capability - if we get a valid
- * integer here, just assume that state is
- * FRONTEND_POWERSTATE_ON_POWER_SOURCE
- * (since most dingux devices are not meant
- * to be used while charging...) */
- int battery_level = dingux_get_battery_level();
- if (battery_level < 0)
- *percent = -1;
- else
- {
- *percent = battery_level;
- ret = FRONTEND_POWERSTATE_ON_POWER_SOURCE;
- }
- /* 'Time left' reporting is unsupported */
- *seconds = -1;
- #else
- if (frontend_unix_powerstate_check_acpi_sysfs(&ret, seconds, percent))
- return ret;
- ret = FRONTEND_POWERSTATE_NONE;
- if (frontend_unix_powerstate_check_acpi(&ret, seconds, percent))
- return ret;
- if (frontend_unix_powerstate_check_apm(&ret, seconds, percent))
- return ret;
- #endif
- return ret;
- }
- static enum frontend_architecture frontend_unix_get_arch(void)
- {
- struct utsname buffer;
- const char *val = NULL;
- if (uname(&buffer) != 0)
- return FRONTEND_ARCH_NONE;
- val = buffer.machine;
- if (string_is_equal(val, "aarch64"))
- return FRONTEND_ARCH_ARMV8;
- else if (
- string_is_equal(val, "armv7l") ||
- string_is_equal(val, "armv7b")
- )
- return FRONTEND_ARCH_ARMV7;
- else if (string_starts_with_size(val, "arm", STRLEN_CONST("arm")))
- return FRONTEND_ARCH_ARM;
- else if (string_is_equal(val, "x86_64"))
- return FRONTEND_ARCH_X86_64;
- else if (string_is_equal(val, "x86"))
- return FRONTEND_ARCH_X86;
- else if (string_is_equal(val, "ppc64"))
- return FRONTEND_ARCH_PPC;
- else if (string_is_equal(val, "mips"))
- return FRONTEND_ARCH_MIPS;
- else if (string_is_equal(val, "tile"))
- return FRONTEND_ARCH_TILE;
- return FRONTEND_ARCH_NONE;
- }
- static void frontend_unix_get_os(char *s,
- size_t len, int *major, int *minor)
- {
- #ifdef ANDROID
- int rel;
- frontend_android_get_version(major, minor, &rel);
- strlcpy(s, "Android", len);
- #else
- char *ptr;
- struct utsname buffer;
- if (uname(&buffer) != 0)
- return;
- *major = (int)strtol(buffer.release, &ptr, 10);
- *minor = (int)strtol(++ptr, NULL, 10);
- #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);
- #elif defined(__HAIKU__)
- strlcpy(s, "Haiku", len);
- #else
- strlcpy(s, "Linux", len);
- #endif
- #endif
- }
- #ifdef HAVE_LAKKA
- static void frontend_unix_get_lakka_version(char *s,
- size_t len)
- {
- char version[128];
- size_t version_len;
- FILE *command_file = popen("cat /etc/release", "r");
- fgets(version, sizeof(version), command_file);
- version_len = strlen(version);
- if (version_len > 0 && version[version_len-1] == '\n')
- version[--version_len] = '\0';
- strlcpy(s, version, len);
- pclose(command_file);
- }
- static void frontend_unix_set_screen_brightness(int value)
- {
- char *buffer = NULL;
- char svalue[16] = {0};
- unsigned int max_brightness = 100;
- /* Device tree should have 'label = "backlight";' if control is desirable */
- filestream_read_file("/sys/class/backlight/backlight/max_brightness",
- &buffer, NULL);
- if (buffer)
- {
- sscanf(buffer, "%u", &max_brightness);
- free(buffer);
- }
- /* Calculate the brightness */
- value = (value * max_brightness) / 100;
- snprintf(svalue, sizeof(svalue), "%d\n", value);
- filestream_write_file("/sys/class/backlight/backlight/brightness",
- svalue, strlen(svalue));
- }
- #endif
- static void frontend_unix_get_env(int *argc,
- char *argv[], void *data, void *params_data)
- {
- unsigned i;
- const char* libretro_directory = getenv("LIBRETRO_DIRECTORY");
- #ifdef ANDROID
- int32_t major, minor, rel;
- char device_model[PROP_VALUE_MAX] = {0};
- struct rarch_main_wrap *args = NULL;
- JNIEnv *env = NULL;
- jobject obj = NULL;
- jstring jstr = NULL;
- struct android_app *android_app = (struct android_app*)data;
- char parent_path[PATH_MAX_LENGTH];
- if (!android_app)
- return;
- if (!(env = jni_thread_getenv()))
- return;
- if ((args = (struct rarch_main_wrap*)params_data))
- {
- args->flags &= ~(RARCH_MAIN_WRAP_FLAG_VERBOSE
- | RARCH_MAIN_WRAP_FLAG_NO_CONTENT);
- args->flags |= RARCH_MAIN_WRAP_FLAG_TOUCHED;
- args->sram_path = NULL;
- args->state_path = NULL;
- }
- frontend_android_get_version(&major, &minor, &rel);
- __android_log_print(ANDROID_LOG_INFO,
- "RetroArch", "[ENV] Android version (major : %d, minor : %d, rel : %d)\n",
- major, minor, rel);
- CALL_OBJ_METHOD(env, obj, android_app->activity->clazz,
- android_app->getIntent);
- __android_log_print(ANDROID_LOG_INFO,
- "RetroArch", "[ENV] Checking arguments passed from intent ...\n");
- /* 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);
- __android_log_print(ANDROID_LOG_INFO,
- "RetroArch", "[ENV]: config file: [%s]\n", config_path);
- 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);
- __android_log_print(ANDROID_LOG_INFO,
- "RetroArch", "[ENV]: current IME: [%s]\n", android_app->current_ime);
- }
- 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);
- bool used = string_is_equal(argv, "false") ? false : true;
- (*env)->ReleaseStringUTFChars(env, jstr, argv);
- __android_log_print(ANDROID_LOG_INFO,
- "RetroArch", "[ENV]: used: [%s].\n", used ? "true" : "false");
- }
- /* LIBRETRO. */
- CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra,
- (*env)->NewStringUTF(env, "LIBRETRO"));
- if (android_app->getStringExtra && jstr)
- {
- 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);
- __android_log_print(ANDROID_LOG_INFO,
- "RetroArch", "[ENV]: libretro path: [%s]\n", core_path);
- if (args && *core_path)
- args->libretro_path = core_path;
- }
- /* 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);
- if (!string_is_empty(path))
- {
- __android_log_print(ANDROID_LOG_INFO,
- "RetroArch", "[ENV]: auto-start game [%s]\n", path);
- if (args && *path)
- args->content_path = path;
- }
- }
- /* Internal Storage */
- 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);
- internal_storage_path[0] = '\0';
- if (argv && *argv)
- strlcpy(internal_storage_path, argv,
- sizeof(internal_storage_path));
- (*env)->ReleaseStringUTFChars(env, jstr, argv);
- if (!string_is_empty(internal_storage_path))
- {
- __android_log_print(ANDROID_LOG_INFO,
- "RetroArch", "[ENV]: android internal storage location: [%s]\n",
- internal_storage_path);
- }
- }
- CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra,
- (*env)->NewStringUTF(env, "APK"));
- if (android_app->getStringExtra && jstr)
- {
- static char apk_dir[PATH_MAX_LENGTH];
- const char *argv = (*env)->GetStringUTFChars(env, jstr, 0);
- *apk_dir = '\0';
- if (argv && *argv)
- strlcpy(apk_dir, argv, sizeof(apk_dir));
- (*env)->ReleaseStringUTFChars(env, jstr, argv);
- if (!string_is_empty(apk_dir))
- {
- __android_log_print(ANDROID_LOG_INFO,
- "RetroArch", "[ENV]: APK location [%s]\n", apk_dir);
- }
- }
- 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);
- *internal_storage_app_path = '\0';
- if (argv && *argv)
- strlcpy(internal_storage_app_path, argv,
- sizeof(internal_storage_app_path));
- (*env)->ReleaseStringUTFChars(env, jstr, argv);
- if (!string_is_empty(internal_storage_app_path))
- {
- __android_log_print(ANDROID_LOG_INFO,
- "RetroArch", "[ENV]: android external files location [%s]\n",
- internal_storage_app_path);
- }
- }
- /* Content. */
- CALL_OBJ_METHOD_PARAM(env, jstr, obj, android_app->getStringExtra,
- (*env)->NewStringUTF(env, "DATADIR"));
- if (android_app->getStringExtra && jstr)
- {
- 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);
- __android_log_print(ANDROID_LOG_INFO,
- "RetroArch", "[ENV]: app dir: [%s]\n", app_dir);
- /* set paths depending on the ability to write
- * to internal_storage_path */
- if (!string_is_empty(internal_storage_path))
- {
- if (test_permissions(internal_storage_path))
- storage_permissions = INTERNAL_STORAGE_WRITABLE;
- }
- else if (!string_is_empty(internal_storage_app_path))
- {
- if (test_permissions(internal_storage_app_path))
- storage_permissions = INTERNAL_STORAGE_APPDIR_WRITABLE;
- }
- else
- storage_permissions = INTERNAL_STORAGE_NOT_WRITABLE;
- /* code to populate default paths*/
- if (!string_is_empty(app_dir))
- {
- __android_log_print(ANDROID_LOG_INFO,
- "RetroArch", "[ENV]: application location: [%s]\n", app_dir);
- if (args && *app_dir)
- {
- /* this section populates the paths for the assets that are bundled
- with the APK.
- TODO/FIXME: change the extraction method so it honors the user defined paths instead
- */
- 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_SHADER], app_dir,
- "shaders", sizeof(g_defaults.dirs[DEFAULT_DIR_SHADER]));
- #ifdef HAVE_OVERLAY
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_OVERLAY], app_dir,
- "overlays", sizeof(g_defaults.dirs[DEFAULT_DIR_OVERLAY]));
- #endif
- 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],
- app_dir, "info",
- sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_INFO]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_AUTOCONFIG],
- app_dir, "autoconfig",
- sizeof(g_defaults.dirs[DEFAULT_DIR_AUTOCONFIG]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER],
- app_dir, "filters/audio",
- sizeof(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER],
- app_dir, "filters/video",
- sizeof(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER]));
- strlcpy(g_defaults.dirs[DEFAULT_DIR_CONTENT_HISTORY],
- app_dir, sizeof(g_defaults.dirs[DEFAULT_DIR_CONTENT_HISTORY]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_DATABASE],
- app_dir, "database/rdb",
- sizeof(g_defaults.dirs[DEFAULT_DIR_DATABASE]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_WALLPAPERS],
- app_dir, "assets/wallpapers",
- sizeof(g_defaults.dirs[DEFAULT_DIR_WALLPAPERS]));
- /* This switch tries to handle the different locations for devices with
- weird write permissions. Should be largelly unnecesary nowadays. Most
- devices I have tested are INTERNAL_STORAGE_WRITABLE but better safe than sorry */
- switch (storage_permissions)
- {
- /* only /sdcard/Android/data/com.retroarch is writable */
- case INTERNAL_STORAGE_APPDIR_WRITABLE:
- strlcpy(parent_path, internal_storage_app_path, sizeof(parent_path));
- break;
- /* only the internal app dir is writable, this should never happen but it did
- a few years ago in some devices */
- case INTERNAL_STORAGE_NOT_WRITABLE:
- strlcpy(parent_path, app_dir, sizeof(parent_path));
- break;
- /* sdcard is writable, this should be the case most of the time*/
- case INTERNAL_STORAGE_WRITABLE:
- fill_pathname_join(parent_path,
- internal_storage_path, "arcade",
- sizeof(parent_path));
- break;
- }
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SRAM],
- parent_path, "saves",
- sizeof(g_defaults.dirs[DEFAULT_DIR_SRAM]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SAVESTATE],
- parent_path, "states",
- sizeof(g_defaults.dirs[DEFAULT_DIR_SAVESTATE]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SYSTEM],
- parent_path, "system",
- sizeof(g_defaults.dirs[DEFAULT_DIR_SYSTEM]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT],
- parent_path, "screenshots",
- sizeof(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS],
- parent_path, "downloads",
- sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_LOGS],
- parent_path, "logs",
- sizeof(g_defaults.dirs[DEFAULT_DIR_LOGS]));
- /* remaps is nested in config */
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG],
- parent_path, "config",
- sizeof(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_REMAP],
- g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG], "remaps",
- sizeof(g_defaults.dirs[DEFAULT_DIR_REMAP]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_THUMBNAILS],
- parent_path, "thumbnails",
- sizeof(g_defaults.dirs[DEFAULT_DIR_THUMBNAILS]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_PLAYLIST],
- parent_path, "playlists",
- sizeof(g_defaults.dirs[DEFAULT_DIR_PLAYLIST]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CHEATS],
- parent_path, "cheats",
- sizeof(g_defaults.dirs[DEFAULT_DIR_CHEATS]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CACHE],
- parent_path, "temp",
- sizeof(g_defaults.dirs[DEFAULT_DIR_CACHE]));
- __android_log_print(ANDROID_LOG_INFO,
- "RetroArch", "[ENV]: default savefile folder: [%s]",
- g_defaults.dirs[DEFAULT_DIR_SRAM]);
- __android_log_print(ANDROID_LOG_INFO,
- "RetroArch", "[ENV]: default savestate folder: [%s]",
- g_defaults.dirs[DEFAULT_DIR_SAVESTATE]);
- __android_log_print(ANDROID_LOG_INFO,
- "RetroArch", "[ENV]: default system folder: [%s]",
- g_defaults.dirs[DEFAULT_DIR_SYSTEM]);
- __android_log_print(ANDROID_LOG_INFO,
- "RetroArch", "[ENV]: default screenshot folder: [%s]",
- g_defaults.dirs[DEFAULT_DIR_SCREENSHOT]);
- }
- }
- }
- system_property_get("getprop", "ro.product.model", device_model);
- /* Set automatic default values per device */
- if (g_platform_android_flags & PLAT_ANDROID_FLAG_XPERIA_PLAY_DEVICE)
- g_defaults.settings_out_latency = 128;
- else if (strstr(device_model, "GAMEMID_BT"))
- g_defaults.settings_out_latency = 160;
- else if (strstr(device_model, "SHIELD"))
- {
- g_defaults.settings_video_refresh_rate = 60.0;
- #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
- #if 0
- /* Set the OK/cancel menu buttons to the default
- * 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;
- #endif
- }
- else if (strstr(device_model, "JSS15J"))
- g_defaults.settings_video_refresh_rate = 59.65;
- /* For gamepad-like/console devices:
- *
- * - Explicitly disable input overlay by default
- * - Use Ozone menu driver by default
- *
- * */
- if ( (g_platform_android_flags & PLAT_ANDROID_FLAG_GAME_CONSOLE_DEVICE)
- || (g_platform_android_flags & PLAT_ANDROID_FLAG_ANDROID_TV_DEVICE))
- {
- g_defaults.overlay_set = true;
- g_defaults.overlay_enable = false;
- strlcpy(g_defaults.settings_menu, "ozone", sizeof(g_defaults.settings_menu));
- }
- #else
- char base_path[PATH_MAX] = {0};
- #if defined(RARCH_UNIX_CWD_ENV)
- /* The entire path is zero initialized. */
- getcwd(base_path, sizeof(base_path));
- #elif defined(DINGUX)
- dingux_get_base_path(base_path, sizeof(base_path));
- #else
- const char *xdg = getenv("XDG_CONFIG_HOME");
- const char *home = getenv("HOME");
- if (xdg)
- {
- strlcpy(base_path, xdg, sizeof(base_path));
- strlcat(base_path, "/retroarch", sizeof(base_path));
- }
- else if (home)
- {
- strlcpy(base_path, home, sizeof(base_path));
- strlcat(base_path, "/.config/retroarch", sizeof(base_path));
- }
- else
- strlcpy(base_path, "retroarch", sizeof(base_path));
- #endif
- if (!string_is_empty(libretro_directory))
- strlcpy(g_defaults.dirs[DEFAULT_DIR_CORE], libretro_directory,
- sizeof(g_defaults.dirs[DEFAULT_DIR_CORE]));
- else
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE], base_path,
- "cores", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE]));
- #if defined(DINGUX)
- /* On platforms that require manual core installation/
- * removal, placing core info files in the same directory
- * as the cores themselves makes file management highly
- * inconvenient. Use a dedicated core info directory instead */
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_INFO], base_path,
- "core_info", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_INFO]));
- #else
- #ifdef CORE_INFO_DIR
- if (path_is_directory(CORE_INFO_DIR "/cores"))
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_INFO], CORE_INFO_DIR,
- "cores", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_INFO]));
- else
- #endif
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_INFO], base_path,
- "cores", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_INFO]));
- #endif
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_AUTOCONFIG], base_path,
- "autoconfig", sizeof(g_defaults.dirs[DEFAULT_DIR_AUTOCONFIG]));
- #ifdef ASSETS_DIR
- if (path_is_directory(ASSETS_DIR "/assets"))
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_ASSETS],
- ASSETS_DIR,
- "assets", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS]));
- else
- #endif
- if (path_is_directory("/usr/local/share/retroarch/assets"))
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_ASSETS],
- "/usr/local/share/retroarch",
- "assets", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS]));
- else if (path_is_directory("/usr/share/retroarch/assets"))
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_ASSETS],
- "/usr/share/retroarch",
- "assets", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS]));
- else if (path_is_directory("/usr/local/share/games/retroarch/assets"))
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_ASSETS],
- "/usr/local/share/games/retroarch",
- "assets", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS]));
- else if (path_is_directory("/usr/share/games/retroarch/assets"))
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_ASSETS],
- "/usr/share/games/retroarch",
- "assets", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS]));
- else
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_ASSETS], base_path,
- "assets", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS]));
- #if defined(DINGUX)
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER], base_path,
- "filters/audio", sizeof(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER], base_path,
- "filters/video", sizeof(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER]));
- #else
- #ifdef FILTERS_DIR
- if (path_is_directory(FILTERS_DIR "/filters/audio"))
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER],
- FILTERS_DIR,
- "filters/audio", sizeof(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER]));
- else
- #endif
- if (path_is_directory("/usr/local/share/retroarch/filters/audio"))
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER],
- "/usr/local/share/retroarch",
- "filters/audio", sizeof(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER]));
- else if (path_is_directory("/usr/share/retroarch/filters/audio"))
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER],
- "/usr/share/retroarch",
- "filters/audio", sizeof(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER]));
- else if (path_is_directory("/usr/local/share/games/retroarch/filters/audio"))
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER],
- "/usr/local/share/games/retroarch",
- "filters/audio", sizeof(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER]));
- else if (path_is_directory("/usr/share/games/retroarch/filters/audio"))
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER],
- "/usr/share/games/retroarch",
- "filters/audio", sizeof(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER]));
- else
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER], base_path,
- "filters/audio", sizeof(g_defaults.dirs[DEFAULT_DIR_AUDIO_FILTER]));
- #ifdef FILTERS_DIR
- if (path_is_directory(FILTERS_DIR "/filters/video"))
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER],
- FILTERS_DIR,
- "filters/video", sizeof(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER]));
- else
- #endif
- if (path_is_directory("/usr/local/share/retroarch/filters/video"))
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER],
- "/usr/local/share/retroarch",
- "filters/video", sizeof(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER]));
- else if (path_is_directory("/usr/share/retroarch/filters/video"))
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER],
- "/usr/share/retroarch",
- "filters/video", sizeof(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER]));
- else if (path_is_directory("/usr/local/share/games/retroarch/filters/video"))
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER],
- "/usr/local/share/games/retroarch",
- "filters/video", sizeof(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER]));
- else if (path_is_directory("/usr/share/games/retroarch/filters/video"))
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER],
- "/usr/share/games/retroarch",
- "filters/video", sizeof(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER]));
- else
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER], base_path,
- "filters/video", sizeof(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER]));
- #endif
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG], base_path,
- "config", sizeof(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_REMAP],
- g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG],
- "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]));
- 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]));
- 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]));
- #ifdef HAVE_OVERLAY
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_OVERLAY], base_path,
- "overlay", sizeof(g_defaults.dirs[DEFAULT_DIR_OVERLAY]));
- #endif
- 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]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_LOGS], base_path,
- "logs", sizeof(g_defaults.dirs[DEFAULT_DIR_LOGS]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SRAM], base_path,
- "saves", sizeof(g_defaults.dirs[DEFAULT_DIR_SRAM]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SAVESTATE], base_path,
- "states", sizeof(g_defaults.dirs[DEFAULT_DIR_SAVESTATE]));
- fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SYSTEM], base_path,
- "system", sizeof(g_defaults.dirs[DEFAULT_DIR_SYSTEM]));
- #endif
- #ifndef IS_SALAMANDER
- #if defined(ANDROID)
- dir_check_defaults("host0:app/custom.ini");
- #else
- dir_check_defaults("custom.ini");
- #endif
- #endif
- }
- #ifdef ANDROID
- static void free_saved_state(struct android_app* android_app)
- {
- slock_lock(android_app->mutex);
- if (android_app->savedState)
- {
- 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)
- {
- JNIEnv *env = NULL;
- int result = system("sh -c \"sh /sdcard/reset\"");
- free_saved_state(android_app);
- slock_lock(android_app->mutex);
- 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);
- 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
- static bool frontend_unix_set_gamemode(bool on)
- {
- #ifdef FERAL_GAMEMODE
- int gamemode_status = gamemode_query_status();
- bool gamemode_active = (gamemode_status == 2);
- if (gamemode_status < 0)
- {
- if (on)
- RARCH_WARN("[GameMode]: GameMode cannot be enabled on this system (\"%s.\") "
- "https://github.com/FeralInteractive/gamemode needs to be installed.\n",
- gamemode_error_string());
- return false;
- }
- if (gamemode_active == on)
- return true;
- if (on)
- {
- if (gamemode_request_start() != 0)
- {
- RARCH_WARN("[GameMode]: Failed to enter GameMode: %s.\n", gamemode_error_string());
- return false;
- }
- }
- else
- {
- if (gamemode_request_end() != 0)
- {
- RARCH_WARN("[GameMode]: Failed to exit GameMode: %s.\n", gamemode_error_string());
- return false;
- }
- }
- return true;
- #else
- return false;
- #endif
- }
- static void frontend_unix_deinit(void *data)
- {
- settings_t *settings = config_get_ptr();
- #ifdef ANDROID
- struct android_app *android_app = (struct android_app*)data;
- if (!android_app)
- return;
- android_app_destroy(android_app);
- #endif
- #ifdef HAVE_LAKKA
- /* Reset brightness to maximum */
- if (settings->uints.screen_brightness != DEFAULT_SCREEN_BRIGHTNESS)
- frontend_unix_set_screen_brightness(DEFAULT_SCREEN_BRIGHTNESS);
- #endif
- frontend_unix_set_gamemode(false);
- }
- static void frontend_unix_init(void *data)
- {
- #ifdef ANDROID
- int i;
- char device_model[PROP_VALUE_MAX] = {0};
- JNIEnv *env = NULL;
- ALooper *looper = NULL;
- jboolean jbool = JNI_FALSE;
- jclass class = NULL;
- jobject obj = NULL;
- struct android_app* android_app = (struct android_app*)data;
- if (!android_app)
- return;
- android_app->config = AConfiguration_new();
- AConfiguration_fromAssetManager(android_app->config,
- android_app->activity->assetManager);
- 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;
- while (!android_app->window)
- {
- if (!android_run_events(android_app))
- {
- frontend_unix_deinit(android_app);
- frontend_android_shutdown(android_app);
- return;
- }
- }
- if (!(env = jni_thread_getenv()))
- return;
- for (i = 0; i < MAX_USERS; ++i) {
- android_app->id[i] = -1;
- }
- 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");
- GET_METHOD_ID(env, android_app->isAndroidTV, class,
- "isAndroidTV", "()Z");
- GET_METHOD_ID(env, android_app->getPowerstate, class,
- "getPowerstate", "()I");
- GET_METHOD_ID(env, android_app->getBatteryLevel, class,
- "getBatteryLevel", "()I");
- GET_METHOD_ID(env, android_app->setSustainedPerformanceMode, class,
- "setSustainedPerformanceMode", "(Z)V");
- GET_METHOD_ID(env, android_app->setScreenOrientation, class,
- "setScreenOrientation", "(I)V");
- GET_METHOD_ID(env, android_app->doVibrate, class,
- "doVibrate", "(IIII)V");
- GET_METHOD_ID(env, android_app->doHapticFeedback, class,
- "doHapticFeedback", "(I)V");
- GET_METHOD_ID(env, android_app->getUserLanguageString, class,
- "getUserLanguageString", "()Ljava/lang/String;");
- GET_METHOD_ID(env, android_app->isPlayStoreBuild, class,
- "isPlayStoreBuild", "()Z");
- GET_METHOD_ID(env, android_app->getAvailableCores, class,
- "getAvailableCores", "()[Ljava/lang/String;");
- GET_METHOD_ID(env, android_app->getInstalledCores, class,
- "getInstalledCores", "()[Ljava/lang/String;");
- GET_METHOD_ID(env, android_app->downloadCore, class,
- "downloadCore", "(Ljava/lang/String;)V");
- GET_METHOD_ID(env, android_app->deleteCore, class,
- "deleteCore", "(Ljava/lang/String;)V");
- CALL_OBJ_METHOD(env, obj, android_app->activity->clazz,
- android_app->getIntent);
- GET_METHOD_ID(env, android_app->getVolumeCount, class,
- "getVolumeCount", "()I");
- GET_METHOD_ID(env, android_app->getVolumePath, class,
- "getVolumePath", "(Ljava/lang/String;)Ljava/lang/String;");
- GET_METHOD_ID(env, android_app->openGameDialog, class,
- "openGameDialog", "()V");
- GET_METHOD_ID(env, android_app->environmentCallback, class,
- "environmentCallback", "(ILjava/lang/Object;)V");
- GET_METHOD_ID(env, android_app->contentLoaded, class,
- "contentLoaded", "()V");
- GET_OBJECT_CLASS(env, class, obj);
- GET_METHOD_ID(env, android_app->getStringExtra, class,
- "getStringExtra", "(Ljava/lang/String;)Ljava/lang/String;");
- /* Check if we are an Android TV device */
- if (env && android_app->isAndroidTV)
- {
- CALL_BOOLEAN_METHOD(env, jbool,
- android_app->activity->clazz, android_app->isAndroidTV);
- if (jbool != JNI_FALSE)
- g_platform_android_flags |= PLAT_ANDROID_FLAG_ANDROID_TV_DEVICE;
- }
- system_property_get("getprop", "ro.product.model", device_model);
- /* Check if we are a game console device */
- if (device_is_game_console(device_model))
- g_platform_android_flags |= PLAT_ANDROID_FLAG_GAME_CONSOLE_DEVICE;
- /* Set automatic default values per device */
- if (device_is_xperia_play(device_model))
- g_platform_android_flags |= PLAT_ANDROID_FLAG_XPERIA_PLAY_DEVICE;
- #endif
- }
- static int frontend_unix_parse_drive_list(void *data, bool load_content)
- {
- #ifdef HAVE_MENU
- file_list_t *list = (file_list_t*)data;
- enum msg_hash_enums enum_idx = load_content ?
- MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR :
- MENU_ENUM_LABEL_FILE_BROWSER_DIRECTORY;
- #ifdef ANDROID
- JNIEnv *env = jni_thread_getenv();
- jint output = 0;
- jobject obj = NULL;
- jstring jstr = NULL;
- int volume_count = 0;
- if (!env || !g_android)
- return 0;
- CALL_OBJ_METHOD(env, obj, g_android->activity->clazz,
- g_android->getIntent);
- if (g_android->getVolumeCount)
- {
- CALL_INT_METHOD(env, output,
- g_android->activity->clazz, g_android->getVolumeCount);
- volume_count = output;
- }
- if (!string_is_empty(internal_storage_path))
- {
- if (storage_permissions == INTERNAL_STORAGE_WRITABLE)
- {
- char user_data_path[PATH_MAX_LENGTH];
- fill_pathname_join_special(user_data_path,
- internal_storage_path, "RetroArch",
- sizeof(user_data_path));
- menu_entries_append(list,
- user_data_path,
- msg_hash_to_str(MSG_INTERNAL_STORAGE),
- enum_idx,
- FILE_TYPE_DIRECTORY, 0, 0, NULL);
- }
- menu_entries_append(list,
- internal_storage_path,
- msg_hash_to_str(MSG_INTERNAL_STORAGE),
- enum_idx,
- FILE_TYPE_DIRECTORY, 0, 0, NULL);
- }
- else
- menu_entries_append(list,
- "/storage/emulated/0",
- msg_hash_to_str(MSG_REMOVABLE_STORAGE),
- enum_idx,
- FILE_TYPE_DIRECTORY, 0, 0, NULL);
- menu_entries_append(list,
- "/storage",
- msg_hash_to_str(MSG_REMOVABLE_STORAGE),
- enum_idx,
- FILE_TYPE_DIRECTORY, 0, 0, NULL);
- if (!string_is_empty(internal_storage_app_path))
- menu_entries_append(list,
- internal_storage_app_path,
- msg_hash_to_str(MSG_EXTERNAL_APPLICATION_DIR),
- enum_idx,
- FILE_TYPE_DIRECTORY, 0, 0, NULL);
- if (!string_is_empty(app_dir))
- menu_entries_append(list,
- app_dir,
- msg_hash_to_str(MSG_APPLICATION_DIR),
- enum_idx,
- FILE_TYPE_DIRECTORY, 0, 0, NULL);
- for (unsigned i=0; i < volume_count; i++)
- {
- static char aux_path[PATH_MAX_LENGTH];
- char index[2];
- index[0] = '\0';
- snprintf(index, sizeof(index), "%d", i);
- CALL_OBJ_METHOD_PARAM(env, jstr, g_android->activity->clazz, g_android->getVolumePath,
- (*env)->NewStringUTF(env, index));
- if (jstr)
- {
- const char *str = (*env)->GetStringUTFChars(env, jstr, 0);
- aux_path[0] = '\0';
- if (str && *str)
- strlcpy(aux_path, str,
- sizeof(aux_path));
- (*env)->ReleaseStringUTFChars(env, jstr, str);
- if (!string_is_empty(aux_path))
- menu_entries_append(list,
- aux_path,
- msg_hash_to_str(MSG_APPLICATION_DIR),
- enum_idx,
- FILE_TYPE_DIRECTORY, 0, 0, NULL);
- }
- }
- #elif defined(WEBOS)
- if (path_is_directory("/media/internal"))
- menu_entries_append(list, "/media/internal",
- msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
- enum_idx,
- FILE_TYPE_DIRECTORY, 0, 0, NULL);
- if (path_is_directory("/tmp/usb"))
- menu_entries_append(list, "/tmp/usb",
- msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
- enum_idx,
- FILE_TYPE_DIRECTORY, 0, 0, NULL);
- #else
- char base_path[PATH_MAX] = {0};
- char udisks_media_path[PATH_MAX] = {0};
- const char *home = getenv("HOME");
- const char *user = getenv("USER");
- #if defined(DINGUX)
- dingux_get_base_path(base_path, sizeof(base_path));
- #else
- const char *xdg = getenv("XDG_CONFIG_HOME");
- if (xdg)
- {
- strlcpy(base_path, xdg, sizeof(base_path));
- strlcat(base_path, "/retroarch", sizeof(base_path));
- }
- else if (home)
- {
- strlcpy(base_path, home, sizeof(base_path));
- strlcat(base_path, "/.config/retroarch", sizeof(base_path));
- }
- #endif
- strlcpy(udisks_media_path, "/run/media", sizeof(udisks_media_path));
- if (user)
- {
- strlcat(udisks_media_path, "/", sizeof(udisks_media_path));
- strlcat(udisks_media_path, user, sizeof(udisks_media_path));
- }
- if (!string_is_empty(base_path))
- {
- menu_entries_append(list, base_path,
- msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
- enum_idx,
- FILE_TYPE_DIRECTORY, 0, 0, NULL);
- }
- if (!string_is_empty(home))
- {
- menu_entries_append(list, home,
- msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
- enum_idx,
- FILE_TYPE_DIRECTORY, 0, 0, NULL);
- }
- if (path_is_directory(udisks_media_path))
- {
- menu_entries_append(list, udisks_media_path,
- msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
- enum_idx,
- FILE_TYPE_DIRECTORY, 0, 0, NULL);
- }
- if (path_is_directory("/media"))
- {
- menu_entries_append(list, "/media",
- msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
- enum_idx,
- FILE_TYPE_DIRECTORY, 0, 0, NULL);
- }
- if (path_is_directory("/mnt"))
- {
- menu_entries_append(list, "/mnt",
- msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
- enum_idx,
- FILE_TYPE_DIRECTORY, 0, 0, NULL);
- }
- #endif
- menu_entries_append(list, "/",
- msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
- enum_idx,
- FILE_TYPE_DIRECTORY, 0, 0, NULL);
- #endif
- return 0;
- }
- #ifndef ANDROID
- static bool frontend_unix_set_fork(enum frontend_fork fork_mode)
- {
- switch (fork_mode)
- {
- case FRONTEND_FORK_CORE:
- unix_fork_mode = fork_mode;
- break;
- case FRONTEND_FORK_CORE_WITH_ARGS:
- unix_fork_mode = fork_mode;
- break;
- case FRONTEND_FORK_RESTART:
- unix_fork_mode = FRONTEND_FORK_CORE;
- {
- char executable_path[PATH_MAX_LENGTH] = {0};
- fill_pathname_application_path(executable_path,
- sizeof(executable_path));
- path_set(RARCH_PATH_CORE, executable_path);
- }
- command_event(CMD_EVENT_QUIT, NULL);
- break;
- case FRONTEND_FORK_NONE:
- default:
- return false;
- }
- return true;
- }
- static void frontend_unix_exec(const char *path, bool should_load_content)
- {
- char *newargv[] = { NULL, NULL };
- size_t len = strlen(path);
- newargv[0] = (char*)malloc(len);
- strlcpy(newargv[0], path, len);
- execv(path, newargv);
- }
- static void frontend_unix_exitspawn(char *s, size_t len, char *args)
- {
- bool should_load_content = false;
- if (unix_fork_mode == FRONTEND_FORK_NONE)
- return;
- switch (unix_fork_mode)
- {
- case FRONTEND_FORK_CORE_WITH_ARGS:
- should_load_content = true;
- break;
- case FRONTEND_FORK_NONE:
- default:
- break;
- }
- frontend_unix_exec(s, should_load_content);
- }
- #endif
- static uint64_t frontend_unix_get_total_mem(void)
- {
- #if defined(DINGUX)
- char line[256];
- unsigned long mem_total = 0;
- FILE* meminfo_file = NULL;
- line[0] = '\0';
- /* Open /proc/meminfo */
- if (!(meminfo_file = fopen(PROC_MEMINFO_PATH, "r")))
- return 0;
- /* Parse lines
- * (Note: virtual filesystem, so don't have to
- * worry about buffering file reads) */
- while (fgets(line, sizeof(line), meminfo_file))
- {
- if (string_starts_with_size(line, PROC_MEMINFO_MEM_TOTAL_TAG,
- STRLEN_CONST(PROC_MEMINFO_MEM_TOTAL_TAG)))
- {
- sscanf(line, PROC_MEMINFO_MEM_TOTAL_TAG " %lu kB", &mem_total);
- break;
- }
- }
- /* Close /proc/meminfo */
- fclose(meminfo_file);
- meminfo_file = NULL;
- return (uint64_t)mem_total * 1024;
- #else
- uint64_t pages = sysconf(_SC_PHYS_PAGES);
- uint64_t page_size = sysconf(_SC_PAGE_SIZE);
- return pages * page_size;
- #endif
- }
- static uint64_t frontend_unix_get_free_mem(void)
- {
- char line[256];
- unsigned long mem_available = 0;
- unsigned long mem_free = 0;
- unsigned long buffers = 0;
- unsigned long cached = 0;
- unsigned long shmem = 0;
- bool mem_available_found = false;
- bool mem_free_found = false;
- bool buffers_found = false;
- bool cached_found = false;
- bool shmem_found = false;
- FILE* meminfo_file = NULL;
- line[0] = '\0';
- /* Open /proc/meminfo */
- if (!(meminfo_file = fopen(PROC_MEMINFO_PATH, "r")))
- return 0;
- /* Parse lines
- * (Note: virtual filesystem, so don't have to
- * worry about buffering file reads) */
- while (fgets(line, sizeof(line), meminfo_file))
- {
- /* If 'MemAvailable' is found, we can return immediately */
- if (!mem_available_found)
- if (string_starts_with_size(line, PROC_MEMINFO_MEM_AVAILABLE_TAG,
- STRLEN_CONST(PROC_MEMINFO_MEM_AVAILABLE_TAG)))
- {
- mem_available_found = true;
- sscanf(line, PROC_MEMINFO_MEM_AVAILABLE_TAG " %lu kB", &mem_available);
- break;
- }
- if (!mem_free_found)
- if (string_starts_with_size(line, PROC_MEMINFO_MEM_FREE_TAG,
- STRLEN_CONST(PROC_MEMINFO_MEM_FREE_TAG)))
- {
- mem_free_found = true;
- sscanf(line, PROC_MEMINFO_MEM_FREE_TAG " %lu kB", &mem_free);
- }
- if (!buffers_found)
- if (string_starts_with_size(line, PROC_MEMINFO_BUFFERS_TAG,
- STRLEN_CONST(PROC_MEMINFO_BUFFERS_TAG)))
- {
- buffers_found = true;
- sscanf(line, PROC_MEMINFO_BUFFERS_TAG " %lu kB", &buffers);
- }
- if (!cached_found)
- if (string_starts_with_size(line, PROC_MEMINFO_CACHED_TAG,
- STRLEN_CONST(PROC_MEMINFO_CACHED_TAG)))
- {
- cached_found = true;
- sscanf(line, PROC_MEMINFO_CACHED_TAG " %lu kB", &cached);
- }
- if (!shmem_found)
- if (string_starts_with_size(line, PROC_MEMINFO_SHMEM_TAG,
- STRLEN_CONST(PROC_MEMINFO_SHMEM_TAG)))
- {
- shmem_found = true;
- sscanf(line, PROC_MEMINFO_SHMEM_TAG " %lu kB", &shmem);
- }
- }
- /* Close /proc/meminfo */
- fclose(meminfo_file);
- meminfo_file = NULL;
- /* Use 'accurate' free memory value, if available */
- if (mem_available_found)
- return (uint64_t)mem_available * 1024;
- /* ...Otherwise, use estimate */
- return (uint64_t)((mem_free + buffers + cached) - shmem) * 1024;
- }
- /*#include <valgrind/valgrind.h>*/
- static void frontend_unix_sighandler(int sig)
- {
- #ifdef VALGRIND_PRINTF_BACKTRACE
- VALGRIND_PRINTF_BACKTRACE("SIGINT");
- #endif
- (void)sig;
- unix_sighandler_quit++;
- if (unix_sighandler_quit == 1) {}
- if (unix_sighandler_quit == 2) exit(1);
- /* in case there's a second deadlock in a C++ destructor or something */
- if (unix_sighandler_quit >= 3) abort();
- }
- static void frontend_unix_install_signal_handlers(void)
- {
- struct sigaction sa;
- sa.sa_sigaction = NULL;
- sa.sa_handler = frontend_unix_sighandler;
- sa.sa_flags = SA_RESTART;
- sigemptyset(&sa.sa_mask);
- sigaction(SIGINT, &sa, NULL);
- sigaction(SIGTERM, &sa, NULL);
- }
- static int frontend_unix_get_signal_handler_state(void)
- {
- return (int)unix_sighandler_quit;
- }
- static void frontend_unix_set_signal_handler_state(int value)
- {
- unix_sighandler_quit = value;
- }
- static void frontend_unix_destroy_signal_handler_state(void)
- {
- unix_sighandler_quit = 0;
- }
- /* 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;
- }
- else
- return;
- }
- 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;
- }
- if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK))
- {
- RARCH_WARN("watch_path_for_changes: Could not set socket to non-blocking.\n");
- return;
- }
- 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;
- if (flags & PATH_CHANGE_TYPE_FILE_MOVED)
- inotify_mask |= IN_MOVE_SELF;
- if (flags & PATH_CHANGE_TYPE_FILE_DELETED)
- inotify_mask |= IN_DELETE_SELF;
- 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};
- 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;
- while (i < length && i < sizeof(buffer))
- {
- struct inotify_event *event = (struct inotify_event *)&buffer[i];
- if (event->mask & inotify_data->flags)
- {
- int 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 = (FILE*)fopen_utf8(path, "rb");
- if (fp)
- {
- fsync(fileno(fp));
- fclose(fp);
- }
- }
- }
- return true;
- }
- i += sizeof(struct inotify_event) + event->len;
- }
- }
- #endif
- return false;
- }
- static void frontend_unix_set_sustained_performance_mode(bool on)
- {
- #ifdef ANDROID
- JNIEnv *env = jni_thread_getenv();
- if (!env || !g_android)
- return;
- if (g_android->setSustainedPerformanceMode)
- CALL_VOID_METHOD_PARAM(env, g_android->activity->clazz,
- g_android->setSustainedPerformanceMode, on);
- #endif
- }
- static const char* frontend_unix_get_cpu_model_name(void)
- {
- #ifdef ANDROID
- return NULL;
- #else
- cpu_features_get_model_name(unix_cpu_model_name,
- sizeof(unix_cpu_model_name));
- return unix_cpu_model_name;
- #endif
- }
- enum retro_language frontend_unix_get_user_language(void)
- {
- enum retro_language lang = RETRO_LANGUAGE_ENGLISH;
- #ifdef HAVE_LANGEXTRA
- #ifdef ANDROID
- jstring jstr = NULL;
- JNIEnv *env = jni_thread_getenv();
- if (!env || !g_android)
- return lang;
- if (g_android->getUserLanguageString)
- {
- CALL_OBJ_METHOD(env, jstr,
- g_android->activity->clazz, g_android->getUserLanguageString);
- if (jstr)
- {
- const char *lang_str = (*env)->GetStringUTFChars(env, jstr, 0);
- lang = retroarch_get_language_from_iso(lang_str);
- (*env)->ReleaseStringUTFChars(env, jstr, lang_str);
- }
- }
- #else
- char *envvar = getenv("LANG");
- if (envvar)
- return retroarch_get_language_from_iso(envvar);
- #endif
- #endif
- return lang;
- }
- #if (defined(__linux__) || defined(__unix__)) && !defined(ANDROID)
- static bool is_narrator_running_unix(void)
- {
- return (kill(speak_pid, 0) == 0);
- }
- static bool accessibility_speak_unix(int speed,
- const char* speak_text, int priority)
- {
- int pid;
- const char *language = get_user_language_iso639_1(true);
- char* voice_out = (char*)malloc(3+strlen(language));
- char* speed_out = (char*)malloc(3+3);
- const char* speeds[10] = {"80", "100", "125", "150", "170", "210", "260", "310", "380", "450"};
- if (speed < 1)
- speed = 1;
- else if (speed > 10)
- speed = 10;
- voice_out[0] = '-';
- voice_out[1] = 'v';
- voice_out[2] = '\0';
- strlcat(voice_out, language, 5);
- speed_out[0] = '-';
- speed_out[1] = 's';
- speed_out[2] = '\0';
- strlcat(speed_out, speeds[speed-1], 6);
- if (priority < 10 && speak_pid > 0)
- {
- /* check if old pid is running */
- if (is_narrator_running_unix())
- goto end;
- }
- if (speak_pid > 0)
- {
- /* Kill the running espeak */
- kill(speak_pid, SIGTERM);
- speak_pid = 0;
- }
- pid = fork();
- if (pid < 0)
- {
- /* error */
- RARCH_LOG("ERROR: could not fork for espeak.\n");
- }
- else if (pid > 0)
- {
- /* parent process */
- speak_pid = pid;
- /* Tell the system that we'll ignore the exit status of the child
- * process. This prevents zombie processes. */
- signal(SIGCHLD,SIG_IGN);
- }
- else
- {
- /* child process: replace process with the espeak command */
- char* cmd[] = { (char*) "espeak", NULL, NULL, NULL, NULL};
- cmd[1] = voice_out;
- cmd[2] = speed_out;
- cmd[3] = (char*)speak_text;
- execvp("espeak", cmd);
- }
- end:
- if (voice_out)
- free(voice_out);
- if (speed_out)
- free(speed_out);
- return true;
- }
- #endif
- frontend_ctx_driver_t frontend_ctx_unix = {
- frontend_unix_get_env, /* get_env */
- frontend_unix_init, /* init */
- frontend_unix_deinit, /* deinit */
- #ifdef ANDROID
- NULL, /* exitspawn */
- #else
- frontend_unix_exitspawn, /* exitspawn */
- #endif
- NULL, /* process_args */
- #ifdef ANDROID
- NULL, /* exec */
- NULL, /* set_fork */
- #else
- frontend_unix_exec, /* exec */
- frontend_unix_set_fork, /* set_fork */
- #endif
- #ifdef ANDROID
- frontend_android_shutdown, /* shutdown */
- frontend_android_get_name, /* get_name */
- #else
- NULL, /* shutdown */
- NULL, /* get_name */
- #endif
- frontend_unix_get_os,
- frontend_unix_get_rating, /* get_rating */
- frontend_unix_content_loaded, /* content_loaded */
- frontend_unix_get_arch, /* get_architecture */
- frontend_unix_get_powerstate,
- frontend_unix_parse_drive_list,
- frontend_unix_get_total_mem,
- frontend_unix_get_free_mem,
- frontend_unix_install_signal_handlers,
- frontend_unix_get_signal_handler_state,
- frontend_unix_set_signal_handler_state,
- frontend_unix_destroy_signal_handler_state,
- NULL, /* attach_console */
- NULL, /* detach_console */
- #ifdef HAVE_LAKKA
- frontend_unix_get_lakka_version, /* get_lakka_version */
- #else
- NULL, /* get_lakka_version */
- #endif
- #if defined(HAVE_LAKKA_SWITCH) || (defined(HAVE_LAKKA) && defined(HAVE_ODROIDGO2))
- frontend_unix_set_screen_brightness,/* set_screen_brightness */
- #else
- NULL, /* set_screen_brightness */
- #endif
- frontend_unix_watch_path_for_changes,
- frontend_unix_check_for_path_changes,
- frontend_unix_set_sustained_performance_mode,
- frontend_unix_get_cpu_model_name,
- frontend_unix_get_user_language,
- #if (defined(__linux__) || defined(__unix__)) && !defined(ANDROID)
- is_narrator_running_unix, /* is_narrator_running */
- accessibility_speak_unix, /* accessibility_speak */
- #else
- NULL, /* is_narrator_running */
- NULL, /* accessibility_speak */
- #endif
- #ifdef FERAL_GAMEMODE
- frontend_unix_set_gamemode,
- #else
- NULL,
- #endif
- #ifdef ANDROID
- "android", /* ident */
- #else
- "unix", /* ident */
- #endif
- NULL /* get_video_driver */
- };
|