2020-03-03 13:36:29 +00:00
/*************************************************************************/
/* os_linuxbsd.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
2022-01-03 20:27:34 +00:00
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
2020-03-03 13:36:29 +00:00
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
# include "os_linuxbsd.h"
2021-06-11 12:51:48 +00:00
# include "core/io/dir_access.h"
2020-06-29 11:29:31 +00:00
# include "main/main.h"
2022-03-09 08:58:20 +00:00
# include "servers/display_server.h"
2020-06-29 11:29:31 +00:00
# ifdef X11_ENABLED
# include "display_server_x11.h"
# endif
2020-03-03 13:36:29 +00:00
# ifdef HAVE_MNTENT
# include <mntent.h>
# endif
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <dlfcn.h>
# include <fcntl.h>
# include <sys/stat.h>
# include <sys/types.h>
# include <unistd.h>
2021-07-22 16:23:48 +00:00
void OS_LinuxBSD : : alert ( const String & p_alert , const String & p_title ) {
const char * message_programs [ ] = { " zenity " , " kdialog " , " Xdialog " , " xmessage " } ;
String path = get_environment ( " PATH " ) ;
Vector < String > path_elems = path . split ( " : " , false ) ;
String program ;
for ( int i = 0 ; i < path_elems . size ( ) ; i + + ) {
for ( uint64_t k = 0 ; k < sizeof ( message_programs ) / sizeof ( char * ) ; k + + ) {
String tested_path = path_elems [ i ] . plus_file ( message_programs [ k ] ) ;
if ( FileAccess : : exists ( tested_path ) ) {
program = tested_path ;
break ;
}
}
if ( program . length ( ) ) {
break ;
}
}
List < String > args ;
if ( program . ends_with ( " zenity " ) ) {
args . push_back ( " --error " ) ;
args . push_back ( " --width " ) ;
args . push_back ( " 500 " ) ;
args . push_back ( " --title " ) ;
args . push_back ( p_title ) ;
args . push_back ( " --text " ) ;
args . push_back ( p_alert ) ;
}
if ( program . ends_with ( " kdialog " ) ) {
args . push_back ( " --error " ) ;
args . push_back ( p_alert ) ;
args . push_back ( " --title " ) ;
args . push_back ( p_title ) ;
}
if ( program . ends_with ( " Xdialog " ) ) {
args . push_back ( " --title " ) ;
args . push_back ( p_title ) ;
args . push_back ( " --msgbox " ) ;
args . push_back ( p_alert ) ;
args . push_back ( " 0 " ) ;
args . push_back ( " 0 " ) ;
}
if ( program . ends_with ( " xmessage " ) ) {
args . push_back ( " -center " ) ;
args . push_back ( " -title " ) ;
args . push_back ( p_title ) ;
args . push_back ( p_alert ) ;
}
if ( program . length ( ) ) {
execute ( program , args ) ;
} else {
print_line ( p_alert ) ;
}
}
2020-03-03 13:36:29 +00:00
void OS_LinuxBSD : : initialize ( ) {
crash_handler . initialize ( ) ;
OS_Unix : : initialize_core ( ) ;
}
void OS_LinuxBSD : : initialize_joypads ( ) {
# ifdef JOYDEV_ENABLED
2020-04-28 13:19:37 +00:00
joypad = memnew ( JoypadLinux ( Input : : get_singleton ( ) ) ) ;
2020-03-03 13:36:29 +00:00
# endif
}
String OS_LinuxBSD : : get_unique_id ( ) const {
static String machine_id ;
2020-12-15 12:04:21 +00:00
if ( machine_id . is_empty ( ) ) {
2022-03-23 09:08:58 +00:00
Ref < FileAccess > f = FileAccess : : open ( " /etc/machine-id " , FileAccess : : READ ) ;
if ( f . is_valid ( ) ) {
2020-12-15 12:04:21 +00:00
while ( machine_id . is_empty ( ) & & ! f - > eof_reached ( ) ) {
2020-03-03 13:36:29 +00:00
machine_id = f - > get_line ( ) . strip_edges ( ) ;
}
}
}
return machine_id ;
}
2020-12-27 00:50:21 +00:00
String OS_LinuxBSD : : get_processor_name ( ) const {
2022-03-23 09:08:58 +00:00
Ref < FileAccess > f = FileAccess : : open ( " /proc/cpuinfo " , FileAccess : : READ ) ;
ERR_FAIL_COND_V_MSG ( f . is_null ( ) , " " , String ( " Couldn't open `/proc/cpuinfo` to get the CPU model name. Returning an empty string. " ) ) ;
2020-12-27 00:50:21 +00:00
while ( ! f - > eof_reached ( ) ) {
const String line = f - > get_line ( ) ;
if ( line . find ( " model name " ) ! = - 1 ) {
return line . split ( " : " ) [ 1 ] . strip_edges ( ) ;
}
}
ERR_FAIL_V_MSG ( " " , String ( " Couldn't get the CPU model name from `/proc/cpuinfo`. Returning an empty string. " ) ) ;
}
2020-03-03 13:36:29 +00:00
void OS_LinuxBSD : : finalize ( ) {
2020-05-14 14:41:43 +00:00
if ( main_loop ) {
2020-03-03 13:36:29 +00:00
memdelete ( main_loop ) ;
2020-05-14 14:41:43 +00:00
}
2020-04-01 23:20:12 +00:00
main_loop = nullptr ;
2020-03-03 13:36:29 +00:00
# ifdef ALSAMIDI_ENABLED
driver_alsamidi . close ( ) ;
# endif
# ifdef JOYDEV_ENABLED
2020-08-02 18:30:56 +00:00
if ( joypad ) {
memdelete ( joypad ) ;
}
2020-03-03 13:36:29 +00:00
# endif
}
MainLoop * OS_LinuxBSD : : get_main_loop ( ) const {
return main_loop ;
}
void OS_LinuxBSD : : delete_main_loop ( ) {
2020-05-14 14:41:43 +00:00
if ( main_loop ) {
2020-03-03 13:36:29 +00:00
memdelete ( main_loop ) ;
2020-05-14 14:41:43 +00:00
}
2020-04-01 23:20:12 +00:00
main_loop = nullptr ;
2020-03-03 13:36:29 +00:00
}
void OS_LinuxBSD : : set_main_loop ( MainLoop * p_main_loop ) {
main_loop = p_main_loop ;
}
String OS_LinuxBSD : : get_name ( ) const {
# ifdef __linux__
return " Linux " ;
# elif defined(__FreeBSD__)
return " FreeBSD " ;
# elif defined(__NetBSD__)
return " NetBSD " ;
2021-05-21 19:35:31 +00:00
# elif defined(__OpenBSD__)
return " OpenBSD " ;
2020-03-03 13:36:29 +00:00
# else
return " BSD " ;
# endif
}
Error OS_LinuxBSD : : shell_open ( String p_uri ) {
Error ok ;
2020-10-24 15:54:24 +00:00
int err_code ;
2020-03-03 13:36:29 +00:00
List < String > args ;
args . push_back ( p_uri ) ;
2020-10-24 15:54:24 +00:00
// Agnostic
2020-12-18 18:49:13 +00:00
ok = execute ( " xdg-open " , args , nullptr , & err_code ) ;
2020-10-24 15:54:24 +00:00
if ( ok = = OK & & ! err_code ) {
return OK ;
} else if ( err_code = = 2 ) {
return ERR_FILE_NOT_FOUND ;
}
// GNOME
args . push_front ( " open " ) ; // The command is `gio open`, so we need to add it to args
2020-12-18 18:49:13 +00:00
ok = execute ( " gio " , args , nullptr , & err_code ) ;
2020-10-24 15:54:24 +00:00
if ( ok = = OK & & ! err_code ) {
return OK ;
} else if ( err_code = = 2 ) {
return ERR_FILE_NOT_FOUND ;
}
args . pop_front ( ) ;
2020-12-18 18:49:13 +00:00
ok = execute ( " gvfs-open " , args , nullptr , & err_code ) ;
2020-10-24 15:54:24 +00:00
if ( ok = = OK & & ! err_code ) {
2020-03-03 13:36:29 +00:00
return OK ;
2020-10-24 15:54:24 +00:00
} else if ( err_code = = 2 ) {
return ERR_FILE_NOT_FOUND ;
2020-05-14 14:41:43 +00:00
}
2020-10-24 15:54:24 +00:00
// KDE
2020-12-18 18:49:13 +00:00
ok = execute ( " kde-open5 " , args , nullptr , & err_code ) ;
2020-10-24 15:54:24 +00:00
if ( ok = = OK & & ! err_code ) {
2020-03-03 13:36:29 +00:00
return OK ;
2020-05-14 14:41:43 +00:00
}
2020-12-18 18:49:13 +00:00
ok = execute ( " kde-open " , args , nullptr , & err_code ) ;
2020-10-24 15:54:24 +00:00
return ! err_code ? ok : FAILED ;
2020-03-03 13:36:29 +00:00
}
bool OS_LinuxBSD : : _check_internal_feature_support ( const String & p_feature ) {
return p_feature = = " pc " ;
}
String OS_LinuxBSD : : get_config_path ( ) const {
if ( has_environment ( " XDG_CONFIG_HOME " ) ) {
2021-06-03 13:41:22 +00:00
if ( get_environment ( " XDG_CONFIG_HOME " ) . is_absolute_path ( ) ) {
2021-05-07 17:02:35 +00:00
return get_environment ( " XDG_CONFIG_HOME " ) ;
} else {
WARN_PRINT_ONCE ( " `XDG_CONFIG_HOME` is a relative path. Ignoring its value and falling back to `$HOME/.config` or `.` per the XDG Base Directory specification. " ) ;
return has_environment ( " HOME " ) ? get_environment ( " HOME " ) . plus_file ( " .config " ) : " . " ;
}
2020-03-03 13:36:29 +00:00
} else if ( has_environment ( " HOME " ) ) {
return get_environment ( " HOME " ) . plus_file ( " .config " ) ;
} else {
return " . " ;
}
}
String OS_LinuxBSD : : get_data_path ( ) const {
if ( has_environment ( " XDG_DATA_HOME " ) ) {
2021-06-03 13:41:22 +00:00
if ( get_environment ( " XDG_DATA_HOME " ) . is_absolute_path ( ) ) {
2021-05-07 17:02:35 +00:00
return get_environment ( " XDG_DATA_HOME " ) ;
} else {
WARN_PRINT_ONCE ( " `XDG_DATA_HOME` is a relative path. Ignoring its value and falling back to `$HOME/.local/share` or `get_config_path()` per the XDG Base Directory specification. " ) ;
return has_environment ( " HOME " ) ? get_environment ( " HOME " ) . plus_file ( " .local/share " ) : get_config_path ( ) ;
}
2020-03-03 13:36:29 +00:00
} else if ( has_environment ( " HOME " ) ) {
return get_environment ( " HOME " ) . plus_file ( " .local/share " ) ;
} else {
return get_config_path ( ) ;
}
}
String OS_LinuxBSD : : get_cache_path ( ) const {
if ( has_environment ( " XDG_CACHE_HOME " ) ) {
2021-06-03 13:41:22 +00:00
if ( get_environment ( " XDG_CACHE_HOME " ) . is_absolute_path ( ) ) {
2021-05-07 17:02:35 +00:00
return get_environment ( " XDG_CACHE_HOME " ) ;
} else {
WARN_PRINT_ONCE ( " `XDG_CACHE_HOME` is a relative path. Ignoring its value and falling back to `$HOME/.cache` or `get_config_path()` per the XDG Base Directory specification. " ) ;
return has_environment ( " HOME " ) ? get_environment ( " HOME " ) . plus_file ( " .cache " ) : get_config_path ( ) ;
}
2020-03-03 13:36:29 +00:00
} else if ( has_environment ( " HOME " ) ) {
return get_environment ( " HOME " ) . plus_file ( " .cache " ) ;
} else {
return get_config_path ( ) ;
}
}
2021-07-11 01:39:31 +00:00
String OS_LinuxBSD : : get_system_dir ( SystemDir p_dir , bool p_shared_storage ) const {
2020-03-03 13:36:29 +00:00
String xdgparam ;
switch ( p_dir ) {
case SYSTEM_DIR_DESKTOP : {
xdgparam = " DESKTOP " ;
} break ;
case SYSTEM_DIR_DCIM : {
xdgparam = " PICTURES " ;
} break ;
case SYSTEM_DIR_DOCUMENTS : {
xdgparam = " DOCUMENTS " ;
} break ;
case SYSTEM_DIR_DOWNLOADS : {
xdgparam = " DOWNLOAD " ;
} break ;
case SYSTEM_DIR_MOVIES : {
xdgparam = " VIDEOS " ;
} break ;
case SYSTEM_DIR_MUSIC : {
xdgparam = " MUSIC " ;
} break ;
case SYSTEM_DIR_PICTURES : {
xdgparam = " PICTURES " ;
} break ;
case SYSTEM_DIR_RINGTONES : {
xdgparam = " MUSIC " ;
} break ;
}
String pipe ;
List < String > arg ;
arg . push_back ( xdgparam ) ;
2020-12-18 18:49:13 +00:00
Error err = const_cast < OS_LinuxBSD * > ( this ) - > execute ( " xdg-user-dir " , arg , & pipe ) ;
2020-05-14 14:41:43 +00:00
if ( err ! = OK ) {
2020-03-03 13:36:29 +00:00
return " . " ;
2020-05-14 14:41:43 +00:00
}
2020-03-03 13:36:29 +00:00
return pipe . strip_edges ( ) ;
}
void OS_LinuxBSD : : run ( ) {
force_quit = false ;
2020-05-14 14:41:43 +00:00
if ( ! main_loop ) {
2020-03-03 13:36:29 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2020-03-03 13:36:29 +00:00
2020-12-22 09:50:29 +00:00
main_loop - > initialize ( ) ;
2020-03-03 13:36:29 +00:00
//uint64_t last_ticks=get_ticks_usec();
//int frames=0;
//uint64_t frame=0;
while ( ! force_quit ) {
DisplayServer : : get_singleton ( ) - > process_events ( ) ; // get rid of pending events
# ifdef JOYDEV_ENABLED
joypad - > process_joypads ( ) ;
# endif
2020-05-14 14:41:43 +00:00
if ( Main : : iteration ( ) ) {
2020-03-03 13:36:29 +00:00
break ;
2020-05-14 14:41:43 +00:00
}
2022-02-16 12:56:32 +00:00
}
2020-03-03 13:36:29 +00:00
2020-12-22 09:50:29 +00:00
main_loop - > finalize ( ) ;
2020-03-03 13:36:29 +00:00
}
void OS_LinuxBSD : : disable_crash_handler ( ) {
crash_handler . disable ( ) ;
}
bool OS_LinuxBSD : : is_disable_crash_handler ( ) const {
return crash_handler . is_disabled ( ) ;
}
static String get_mountpoint ( const String & p_path ) {
struct stat s ;
if ( stat ( p_path . utf8 ( ) . get_data ( ) , & s ) ) {
return " " ;
}
# ifdef HAVE_MNTENT
dev_t dev = s . st_dev ;
FILE * fd = setmntent ( " /proc/mounts " , " r " ) ;
if ( ! fd ) {
return " " ;
}
struct mntent mnt ;
char buf [ 1024 ] ;
size_t buflen = 1024 ;
while ( getmntent_r ( fd , & mnt , buf , buflen ) ) {
if ( ! stat ( mnt . mnt_dir , & s ) & & s . st_dev = = dev ) {
endmntent ( fd ) ;
return String ( mnt . mnt_dir ) ;
}
}
endmntent ( fd ) ;
# endif
return " " ;
}
Error OS_LinuxBSD : : move_to_trash ( const String & p_path ) {
2022-02-20 00:58:38 +00:00
String path = p_path . rstrip ( " / " ) ; // Strip trailing slash when path points to a directory
2020-11-30 20:19:52 +00:00
int err_code ;
List < String > args ;
2022-02-20 00:58:38 +00:00
args . push_back ( path ) ;
2020-11-30 20:19:52 +00:00
args . push_front ( " trash " ) ; // The command is `gio trash <file_name>` so we need to add it to args.
2020-12-18 18:49:13 +00:00
Error result = execute ( " gio " , args , nullptr , & err_code ) ; // For GNOME based machines.
2020-11-30 20:19:52 +00:00
if ( result = = OK & & ! err_code ) {
return OK ;
} else if ( err_code = = 2 ) {
return ERR_FILE_NOT_FOUND ;
}
args . pop_front ( ) ;
args . push_front ( " move " ) ;
args . push_back ( " trash:/ " ) ; // The command is `kioclient5 move <file_name> trash:/`.
2020-12-18 18:49:13 +00:00
result = execute ( " kioclient5 " , args , nullptr , & err_code ) ; // For KDE based machines.
2020-11-30 20:19:52 +00:00
if ( result = = OK & & ! err_code ) {
return OK ;
} else if ( err_code = = 2 ) {
return ERR_FILE_NOT_FOUND ;
}
args . pop_front ( ) ;
args . pop_back ( ) ;
2020-12-18 18:49:13 +00:00
result = execute ( " gvfs-trash " , args , nullptr , & err_code ) ; // For older Linux machines.
2020-11-30 20:19:52 +00:00
if ( result = = OK & & ! err_code ) {
return OK ;
} else if ( err_code = = 2 ) {
return ERR_FILE_NOT_FOUND ;
}
// If the commands `kioclient5`, `gio` or `gvfs-trash` don't exist on the system we do it manually.
String trash_path = " " ;
2022-02-20 00:58:38 +00:00
String mnt = get_mountpoint ( path ) ;
2020-03-03 13:36:29 +00:00
2020-11-30 20:19:52 +00:00
// If there is a directory "[Mountpoint]/.Trash-[UID], use it as the trash can.
2021-12-09 09:42:46 +00:00
if ( ! mnt . is_empty ( ) ) {
2022-02-20 00:58:38 +00:00
String mountpoint_trash_path ( mnt + " /.Trash- " + itos ( getuid ( ) ) ) ;
2020-03-03 13:36:29 +00:00
struct stat s ;
2022-02-20 00:58:38 +00:00
if ( ! stat ( mountpoint_trash_path . utf8 ( ) . get_data ( ) , & s ) ) {
trash_path = mountpoint_trash_path ;
2020-03-03 13:36:29 +00:00
}
}
2020-11-30 20:19:52 +00:00
// Otherwise, if ${XDG_DATA_HOME} is defined, use "${XDG_DATA_HOME}/Trash" as the trash can.
2021-12-09 09:42:46 +00:00
if ( trash_path . is_empty ( ) ) {
2020-03-03 13:36:29 +00:00
char * dhome = getenv ( " XDG_DATA_HOME " ) ;
if ( dhome ) {
2022-01-06 09:34:10 +00:00
trash_path = String : : utf8 ( dhome ) + " /Trash " ;
2020-03-03 13:36:29 +00:00
}
}
2020-11-30 20:19:52 +00:00
// Otherwise, if ${HOME} is defined, use "${HOME}/.local/share/Trash" as the trash can.
2021-12-09 09:42:46 +00:00
if ( trash_path . is_empty ( ) ) {
2020-03-03 13:36:29 +00:00
char * home = getenv ( " HOME " ) ;
if ( home ) {
2022-01-06 09:34:10 +00:00
trash_path = String : : utf8 ( home ) + " /.local/share/Trash " ;
2020-03-03 13:36:29 +00:00
}
}
// Issue an error if none of the previous locations is appropriate for the trash can.
2021-12-09 09:42:46 +00:00
ERR_FAIL_COND_V_MSG ( trash_path . is_empty ( ) , FAILED , " Could not determine the trash can location " ) ;
2020-03-03 13:36:29 +00:00
// Create needed directories for decided trash can location.
2020-11-30 20:19:52 +00:00
{
2022-03-23 09:08:58 +00:00
Ref < DirAccess > dir_access = DirAccess : : create ( DirAccess : : ACCESS_FILESYSTEM ) ;
2020-11-30 20:19:52 +00:00
Error err = dir_access - > make_dir_recursive ( trash_path ) ;
Fix various typos with codespell
Found via `codespell -q 3 -S ./thirdparty,*.po,./DONORS.md -L ackward,ang,ans,ba,beng,cas,childs,childrens,dof,doubleclick,fave,findn,hist,inout,leapyear,lod,nd,numer,ois,ony,paket,seeked,sinc,switchs,te,uint`
2021-07-07 15:17:32 +00:00
// Issue an error if trash can is not created properly.
2020-11-30 20:19:52 +00:00
ERR_FAIL_COND_V_MSG ( err ! = OK , err , " Could not create the trash path \" " + trash_path + " \" " ) ;
err = dir_access - > make_dir_recursive ( trash_path + " /files " ) ;
2022-02-20 00:58:38 +00:00
ERR_FAIL_COND_V_MSG ( err ! = OK , err , " Could not create the trash path \" " + trash_path + " /files \" " ) ;
2020-11-30 20:19:52 +00:00
err = dir_access - > make_dir_recursive ( trash_path + " /info " ) ;
2022-02-20 00:58:38 +00:00
ERR_FAIL_COND_V_MSG ( err ! = OK , err , " Could not create the trash path \" " + trash_path + " /info \" " ) ;
2020-11-30 20:19:52 +00:00
}
2020-03-03 13:36:29 +00:00
2020-11-30 20:19:52 +00:00
// The trash can is successfully created, now we check that we don't exceed our file name length limit.
// If the file name is too long trim it so we can add the identifying number and ".trashinfo".
// Assumes that the file name length limit is 255 characters.
2022-02-20 00:58:38 +00:00
String file_name = path . get_file ( ) ;
2020-11-30 20:19:52 +00:00
if ( file_name . length ( ) > 240 ) {
file_name = file_name . substr ( 0 , file_name . length ( ) - 15 ) ;
}
String dest_path = trash_path + " /files/ " + file_name ;
struct stat buff ;
int id_number = 0 ;
String fn = file_name ;
// Checks if a resource with the same name already exist in the trash can,
// if there is, add an identifying number to our resource's name.
while ( stat ( dest_path . utf8 ( ) . get_data ( ) , & buff ) = = 0 ) {
id_number + + ;
// Added a limit to check for identically named files already on the trash can
// if there are too many it could make the editor unresponsive.
ERR_FAIL_COND_V_MSG ( id_number > 99 , FAILED , " Too many identically named resources already in the trash can. " ) ;
fn = file_name + " . " + itos ( id_number ) ;
dest_path = trash_path + " /files/ " + fn ;
}
file_name = fn ;
2022-02-20 00:58:38 +00:00
String renamed_path = path . get_base_dir ( ) + " / " + file_name ;
2020-11-30 20:19:52 +00:00
// Generates the .trashinfo file
OS : : Date date = OS : : get_singleton ( ) - > get_date ( false ) ;
OS : : Time time = OS : : get_singleton ( ) - > get_time ( false ) ;
2021-07-13 02:44:03 +00:00
String timestamp = vformat ( " %04d-%02d-%02dT%02d:%02d: " , date . year , ( int ) date . month , date . day , time . hour , time . minute ) ;
2021-05-24 11:54:05 +00:00
timestamp = vformat ( " %s%02d " , timestamp , time . second ) ; // vformat only supports up to 6 arguments.
2022-02-20 00:58:38 +00:00
String trash_info = " [Trash Info] \n Path= " + path . uri_encode ( ) + " \n DeletionDate= " + timestamp + " \n " ;
2020-11-30 20:19:52 +00:00
{
Error err ;
2022-04-12 07:12:40 +00:00
{
Ref < FileAccess > file = FileAccess : : open ( trash_path + " /info/ " + file_name + " .trashinfo " , FileAccess : : WRITE , & err ) ;
ERR_FAIL_COND_V_MSG ( err ! = OK , err , " Can't create trashinfo file: \" " + trash_path + " /info/ " + file_name + " .trashinfo \" " ) ;
file - > store_string ( trash_info ) ;
}
2020-11-30 20:19:52 +00:00
// Rename our resource before moving it to the trash can.
2022-03-23 09:08:58 +00:00
Ref < DirAccess > dir_access = DirAccess : : create ( DirAccess : : ACCESS_FILESYSTEM ) ;
2022-02-20 00:58:38 +00:00
err = dir_access - > rename ( path , renamed_path ) ;
ERR_FAIL_COND_V_MSG ( err ! = OK , err , " Can't rename file \" " + path + " \" to \" " + renamed_path + " \" " ) ;
2020-03-03 13:36:29 +00:00
}
2020-11-30 20:19:52 +00:00
// Move the given resource to the trash can.
2020-03-03 13:36:29 +00:00
// Do not use DirAccess:rename() because it can't move files across multiple mountpoints.
List < String > mv_args ;
2022-02-20 00:58:38 +00:00
mv_args . push_back ( renamed_path ) ;
2020-11-30 20:19:52 +00:00
mv_args . push_back ( trash_path + " /files " ) ;
{
int retval ;
2020-12-18 18:49:13 +00:00
Error err = execute ( " mv " , mv_args , nullptr , & retval ) ;
2020-11-30 20:19:52 +00:00
// Issue an error if "mv" failed to move the given resource to the trash can.
if ( err ! = OK | | retval ! = 0 ) {
2022-02-20 00:58:38 +00:00
ERR_PRINT ( " move_to_trash: Could not move the resource \" " + path + " \" to the trash can \" " + trash_path + " /files \" " ) ;
2022-03-23 09:08:58 +00:00
Ref < DirAccess > dir_access = DirAccess : : create ( DirAccess : : ACCESS_FILESYSTEM ) ;
2022-02-20 00:58:38 +00:00
err = dir_access - > rename ( renamed_path , path ) ;
ERR_FAIL_COND_V_MSG ( err ! = OK , err , " Could not rename \" " + renamed_path + " \" back to its original name: \" " + path + " \" " ) ;
2020-11-30 20:19:52 +00:00
return FAILED ;
}
2020-03-03 13:36:29 +00:00
}
return OK ;
}
OS_LinuxBSD : : OS_LinuxBSD ( ) {
2020-04-01 23:20:12 +00:00
main_loop = nullptr ;
2020-03-03 13:36:29 +00:00
force_quit = false ;
# ifdef PULSEAUDIO_ENABLED
AudioDriverManager : : add_driver ( & driver_pulseaudio ) ;
# endif
# ifdef ALSA_ENABLED
AudioDriverManager : : add_driver ( & driver_alsa ) ;
# endif
# ifdef X11_ENABLED
DisplayServerX11 : : register_x11_driver ( ) ;
# endif
}