2014-02-10 02:10:30 +01:00
/*************************************************************************/
/* os_windows.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
2017-08-27 14:16:55 +02:00
/* https://godotengine.org */
2014-02-10 02:10:30 +01:00
/*************************************************************************/
2021-01-01 20:13:46 +01:00
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
2014-02-10 02:10:30 +01: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. */
/*************************************************************************/
2015-01-10 21:35:26 +01:00
2018-09-02 05:32:12 +02:00
// Must include Winsock before windows.h (included by os_windows.h)
# include "drivers/unix/net_socket_posix.h"
2014-02-10 02:10:30 +01:00
# include "os_windows.h"
2016-12-21 06:29:58 +01:00
2020-02-27 03:30:20 +01:00
# include "core/debugger/engine_debugger.h"
# include "core/debugger/script_debugger.h"
2018-09-11 18:13:45 +02:00
# include "core/io/marshalls.h"
# include "core/version_generated.gen.h"
2017-03-05 16:44:50 +01:00
# include "drivers/windows/dir_access_windows.h"
# include "drivers/windows/file_access_windows.h"
2019-02-12 15:43:54 +01:00
# include "joypad_windows.h"
2017-03-05 16:44:50 +01:00
# include "lang_table.h"
# include "main/main.h"
2020-03-09 16:56:48 +01:00
# include "platform/windows/display_server_windows.h"
2017-06-10 15:15:33 +02:00
# include "servers/audio_server.h"
2020-12-03 22:09:47 +01:00
# include "servers/rendering/rendering_server_default.h"
2017-09-22 07:56:02 +02:00
# include "windows_terminal_logger.h"
2014-12-02 18:02:41 +01:00
2019-02-12 15:43:54 +01:00
# include <avrt.h>
2019-02-20 13:00:19 +01:00
# include <direct.h>
2019-04-22 18:42:11 +02:00
# include <knownfolders.h>
2016-04-29 18:57:57 +02:00
# include <process.h>
2017-03-05 16:44:50 +01:00
# include <regstr.h>
# include <shlobj.h>
2015-02-12 04:17:29 +01:00
2014-02-10 02:10:30 +01:00
static const WORD MAX_CONSOLE_LINES = 1500 ;
2015-01-17 02:48:35 +01:00
extern " C " {
2018-11-02 23:10:44 +01:00
__declspec ( dllexport ) DWORD NvOptimusEnablement = 1 ;
__declspec ( dllexport ) int AmdPowerXpressRequestHighPerformance = 1 ;
2015-01-17 02:48:35 +01:00
}
2014-12-02 18:02:41 +01:00
2017-08-18 20:46:13 +02:00
// Workaround mingw-w64 < 4.0 bug
# ifndef WM_TOUCH
# define WM_TOUCH 576
2016-02-04 17:16:22 +01:00
# endif
2018-12-13 21:32:11 +01:00
# ifndef WM_POINTERUPDATE
# define WM_POINTERUPDATE 0x0245
# endif
2020-01-16 12:07:58 +01:00
# if defined(__GNUC__)
// Workaround GCC warning from -Wcast-function-type.
# define GetProcAddress (void *)GetProcAddress
# endif
2019-06-15 12:11:30 +02:00
# ifdef DEBUG_ENABLED
2017-12-01 12:42:57 +01:00
static String format_error_message ( DWORD id ) {
2020-04-02 01:20:12 +02:00
LPWSTR messageBuffer = nullptr ;
2017-12-01 12:42:57 +01:00
size_t size = FormatMessageW ( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS ,
2020-04-02 01:20:12 +02:00
nullptr , id , MAKELANGID ( LANG_NEUTRAL , SUBLANG_DEFAULT ) , ( LPWSTR ) & messageBuffer , 0 , nullptr ) ;
2017-12-01 12:42:57 +01:00
2020-07-27 12:43:20 +02:00
String msg = " Error " + itos ( id ) + " : " + String : : utf16 ( ( const char16_t * ) messageBuffer , size ) ;
2017-12-01 12:42:57 +01:00
LocalFree ( messageBuffer ) ;
return msg ;
}
2019-06-15 12:11:30 +02:00
# endif // DEBUG_ENABLED
2017-12-01 12:42:57 +01:00
2014-02-10 02:10:30 +01:00
void RedirectIOToConsole ( ) {
int hConHandle ;
intptr_t lStdHandle ;
CONSOLE_SCREEN_BUFFER_INFO coninfo ;
FILE * fp ;
// allocate a console for this app
AllocConsole ( ) ;
// set the screen buffer to be big enough to let us scroll text
2020-07-27 12:43:20 +02:00
GetConsoleScreenBufferInfo ( GetStdHandle ( STD_OUTPUT_HANDLE ) , & coninfo ) ;
2014-02-10 02:10:30 +01:00
coninfo . dwSize . Y = MAX_CONSOLE_LINES ;
2020-07-27 12:43:20 +02:00
SetConsoleScreenBufferSize ( GetStdHandle ( STD_OUTPUT_HANDLE ) , coninfo . dwSize ) ;
2014-02-10 02:10:30 +01:00
// redirect unbuffered STDOUT to the console
lStdHandle = ( intptr_t ) GetStdHandle ( STD_OUTPUT_HANDLE ) ;
hConHandle = _open_osfhandle ( lStdHandle , _O_TEXT ) ;
2017-03-05 16:44:50 +01:00
fp = _fdopen ( hConHandle , " w " ) ;
2014-02-10 02:10:30 +01:00
* stdout = * fp ;
2020-04-02 01:20:12 +02:00
setvbuf ( stdout , nullptr , _IONBF , 0 ) ;
2014-02-10 02:10:30 +01:00
// redirect unbuffered STDIN to the console
lStdHandle = ( intptr_t ) GetStdHandle ( STD_INPUT_HANDLE ) ;
hConHandle = _open_osfhandle ( lStdHandle , _O_TEXT ) ;
2017-03-05 16:44:50 +01:00
fp = _fdopen ( hConHandle , " r " ) ;
2014-02-10 02:10:30 +01:00
* stdin = * fp ;
2020-04-02 01:20:12 +02:00
setvbuf ( stdin , nullptr , _IONBF , 0 ) ;
2014-02-10 02:10:30 +01:00
2020-03-09 16:56:48 +01:00
// redirect unbuffered STDERR to the console
2015-03-22 23:00:50 +01:00
2020-03-09 16:56:48 +01:00
lStdHandle = ( intptr_t ) GetStdHandle ( STD_ERROR_HANDLE ) ;
2015-03-22 23:00:50 +01:00
2020-03-09 16:56:48 +01:00
hConHandle = _open_osfhandle ( lStdHandle , _O_TEXT ) ;
2017-12-27 20:51:19 +01:00
2020-03-09 16:56:48 +01:00
fp = _fdopen ( hConHandle , " w " ) ;
2017-12-27 20:51:19 +01:00
2020-03-09 16:56:48 +01:00
* stderr = * fp ;
2017-12-27 20:51:19 +01:00
2020-04-02 01:20:12 +02:00
setvbuf ( stderr , nullptr , _IONBF , 0 ) ;
2017-12-27 20:51:19 +01:00
2020-03-09 16:56:48 +01:00
// make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog
2019-11-28 13:41:07 +01:00
2020-03-09 16:56:48 +01:00
// point to console as well
2019-11-28 13:41:07 +01:00
}
2020-03-09 16:56:48 +01:00
BOOL WINAPI HandlerRoutine ( _In_ DWORD dwCtrlType ) {
if ( ! EngineDebugger : : is_active ( ) )
return FALSE ;
2018-12-18 14:17:43 +01:00
2020-03-09 16:56:48 +01:00
switch ( dwCtrlType ) {
case CTRL_C_EVENT :
EngineDebugger : : get_script_debugger ( ) - > set_depth ( - 1 ) ;
EngineDebugger : : get_script_debugger ( ) - > set_lines_left ( 1 ) ;
return TRUE ;
default :
return FALSE ;
}
2018-12-18 14:17:43 +01:00
}
2021-07-22 18:23:48 +02:00
void OS_Windows : : alert ( const String & p_alert , const String & p_title ) {
MessageBoxW ( nullptr , ( LPCWSTR ) ( p_alert . utf16 ( ) . get_data ( ) ) , ( LPCWSTR ) ( p_title . utf16 ( ) . get_data ( ) ) , MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL ) ;
}
2020-03-09 16:56:48 +01:00
void OS_Windows : : initialize_debugging ( ) {
SetConsoleCtrlHandler ( HandlerRoutine , TRUE ) ;
2017-12-10 19:38:26 +01:00
}
2020-03-09 16:56:48 +01:00
void OS_Windows : : initialize ( ) {
crash_handler . initialize ( ) ;
2017-12-10 19:38:26 +01:00
2020-03-09 16:56:48 +01:00
//RedirectIOToConsole();
2017-12-10 19:38:26 +01:00
2020-03-09 16:56:48 +01:00
FileAccess : : make_default < FileAccessWindows > ( FileAccess : : ACCESS_RESOURCES ) ;
FileAccess : : make_default < FileAccessWindows > ( FileAccess : : ACCESS_USERDATA ) ;
FileAccess : : make_default < FileAccessWindows > ( FileAccess : : ACCESS_FILESYSTEM ) ;
DirAccess : : make_default < DirAccessWindows > ( DirAccess : : ACCESS_RESOURCES ) ;
DirAccess : : make_default < DirAccessWindows > ( DirAccess : : ACCESS_USERDATA ) ;
DirAccess : : make_default < DirAccessWindows > ( DirAccess : : ACCESS_FILESYSTEM ) ;
2017-12-10 19:38:26 +01:00
2020-03-09 16:56:48 +01:00
NetSocketPosix : : make_default ( ) ;
2017-12-10 19:38:26 +01:00
2020-03-09 16:56:48 +01:00
// We need to know how often the clock is updated
if ( ! QueryPerformanceFrequency ( ( LARGE_INTEGER * ) & ticks_per_second ) )
ticks_per_second = 1000 ;
// If timeAtGameStart is 0 then we get the time since
// the start of the computer when we call GetGameTime()
ticks_start = 0 ;
ticks_start = get_ticks_usec ( ) ;
2017-12-10 19:38:26 +01:00
2020-03-09 16:56:48 +01:00
// set minimum resolution for periodic timers, otherwise Sleep(n) may wait at least as
// long as the windows scheduler resolution (~16-30ms) even for calls like Sleep(1)
timeBeginPeriod ( 1 ) ;
2017-12-10 19:38:26 +01:00
2020-03-09 16:56:48 +01:00
process_map = memnew ( ( Map < ProcessID , ProcessInfo > ) ) ;
2017-12-10 19:38:26 +01:00
2020-05-11 16:26:10 +02:00
// Add current Godot PID to the list of known PIDs
ProcessInfo current_pi = { } ;
PROCESS_INFORMATION current_pi_pi = { } ;
current_pi . pi = current_pi_pi ;
current_pi . pi . hProcess = GetCurrentProcess ( ) ;
process_map - > insert ( GetCurrentProcessId ( ) , current_pi ) ;
2021-05-06 02:48:18 +02:00
IPUnix : : make_default ( ) ;
2020-04-02 01:20:12 +02:00
main_loop = nullptr ;
2017-12-10 19:38:26 +01:00
}
2020-03-09 16:56:48 +01:00
void OS_Windows : : delete_main_loop ( ) {
if ( main_loop )
memdelete ( main_loop ) ;
2020-04-02 01:20:12 +02:00
main_loop = nullptr ;
2017-12-10 19:38:26 +01:00
}
2020-03-09 16:56:48 +01:00
void OS_Windows : : set_main_loop ( MainLoop * p_main_loop ) {
main_loop = p_main_loop ;
2017-12-10 19:38:26 +01:00
}
2020-03-09 16:56:48 +01:00
void OS_Windows : : finalize ( ) {
# ifdef WINMIDI_ENABLED
driver_midi . close ( ) ;
# endif
2017-07-10 02:48:22 +02:00
2020-03-09 16:56:48 +01:00
if ( main_loop )
memdelete ( main_loop ) ;
2016-01-03 05:18:28 +01:00
2020-04-02 01:20:12 +02:00
main_loop = nullptr ;
2016-01-03 05:18:28 +01:00
}
2020-03-09 16:56:48 +01:00
void OS_Windows : : finalize_core ( ) {
timeEndPeriod ( 1 ) ;
2017-12-27 20:51:19 +01:00
2020-03-09 16:56:48 +01:00
memdelete ( process_map ) ;
NetSocketPosix : : cleanup ( ) ;
2017-07-10 02:48:22 +02:00
}
2017-11-30 14:00:10 +01:00
Error OS_Windows : : open_dynamic_library ( const String p_path , void * & p_library_handle , bool p_also_set_library_path ) {
2020-10-22 12:17:21 +02:00
String path = p_path . replace ( " / " , " \\ " ) ;
2018-01-04 19:42:29 +01:00
if ( ! FileAccess : : exists ( path ) ) {
//this code exists so gdnative can load .dll files from within the executable path
path = get_executable_path ( ) . get_base_dir ( ) . plus_file ( p_path . get_file ( ) ) ;
}
2017-12-06 13:29:01 +01:00
typedef DLL_DIRECTORY_COOKIE ( WINAPI * PAddDllDirectory ) ( PCWSTR ) ;
typedef BOOL ( WINAPI * PRemoveDllDirectory ) ( DLL_DIRECTORY_COOKIE ) ;
PAddDllDirectory add_dll_directory = ( PAddDllDirectory ) GetProcAddress ( GetModuleHandle ( " kernel32.dll " ) , " AddDllDirectory " ) ;
PRemoveDllDirectory remove_dll_directory = ( PRemoveDllDirectory ) GetProcAddress ( GetModuleHandle ( " kernel32.dll " ) , " RemoveDllDirectory " ) ;
2020-04-02 01:20:12 +02:00
bool has_dll_directory_api = ( ( add_dll_directory ! = nullptr ) & & ( remove_dll_directory ! = nullptr ) ) ;
DLL_DIRECTORY_COOKIE cookie = nullptr ;
2017-11-30 14:00:10 +01:00
2017-12-06 13:29:01 +01:00
if ( p_also_set_library_path & & has_dll_directory_api ) {
2020-07-27 12:43:20 +02:00
cookie = add_dll_directory ( ( LPCWSTR ) ( path . get_base_dir ( ) . utf16 ( ) . get_data ( ) ) ) ;
2017-11-30 14:00:10 +01:00
}
2020-07-27 12:43:20 +02:00
p_library_handle = ( void * ) LoadLibraryExW ( ( LPCWSTR ) ( path . utf16 ( ) . get_data ( ) ) , nullptr , ( p_also_set_library_path & & has_dll_directory_api ) ? LOAD_LIBRARY_SEARCH_DEFAULT_DIRS : 0 ) ;
2019-08-09 06:49:33 +02:00
ERR_FAIL_COND_V_MSG ( ! p_library_handle , ERR_CANT_OPEN , " Can't open dynamic library: " + p_path + " , error: " + format_error_message ( GetLastError ( ) ) + " . " ) ;
2017-11-30 14:00:10 +01:00
2018-01-26 11:48:20 +01:00
if ( cookie ) {
2017-12-06 13:29:01 +01:00
remove_dll_directory ( cookie ) ;
2017-11-30 14:00:10 +01:00
}
2017-03-08 02:50:13 +01:00
return OK ;
}
2017-04-03 16:11:38 +02:00
Error OS_Windows : : close_dynamic_library ( void * p_library_handle ) {
if ( ! FreeLibrary ( ( HMODULE ) p_library_handle ) ) {
2017-03-08 02:50:13 +01:00
return FAILED ;
}
return OK ;
}
2017-07-27 09:23:21 +02:00
Error OS_Windows : : get_dynamic_library_symbol_handle ( void * p_library_handle , const String p_name , void * & p_symbol_handle , bool p_optional ) {
2017-04-03 16:11:38 +02:00
p_symbol_handle = ( void * ) GetProcAddress ( ( HMODULE ) p_library_handle , p_name . utf8 ( ) . get_data ( ) ) ;
2017-03-08 02:50:13 +01:00
if ( ! p_symbol_handle ) {
2017-07-27 09:23:21 +02:00
if ( ! p_optional ) {
2019-08-09 06:49:33 +02:00
ERR_FAIL_V_MSG ( ERR_CANT_RESOLVE , " Can't resolve symbol " + p_name + " , error: " + String : : num ( GetLastError ( ) ) + " . " ) ;
2017-07-27 09:23:21 +02:00
} else {
return ERR_CANT_RESOLVE ;
}
2017-03-08 02:50:13 +01:00
}
return OK ;
}
2019-05-20 19:36:24 +02:00
String OS_Windows : : get_name ( ) const {
2014-02-10 02:10:30 +01:00
return " Windows " ;
}
2015-06-07 15:06:13 +02:00
OS : : Date OS_Windows : : get_date ( bool utc ) const {
2014-02-10 02:10:30 +01:00
SYSTEMTIME systemtime ;
2015-06-07 15:06:13 +02:00
if ( utc )
2015-06-06 03:40:56 +02:00
GetSystemTime ( & systemtime ) ;
else
GetLocalTime ( & systemtime ) ;
2015-06-07 15:06:13 +02:00
2014-02-10 02:10:30 +01:00
Date date ;
2017-03-05 16:44:50 +01:00
date . day = systemtime . wDay ;
date . month = Month ( systemtime . wMonth ) ;
date . weekday = Weekday ( systemtime . wDayOfWeek ) ;
date . year = systemtime . wYear ;
date . dst = false ;
2014-02-10 02:10:30 +01:00
return date ;
}
2020-05-14 14:29:06 +02:00
2015-06-06 03:40:56 +02:00
OS : : Time OS_Windows : : get_time ( bool utc ) const {
2014-02-10 02:10:30 +01:00
SYSTEMTIME systemtime ;
2015-06-06 03:40:56 +02:00
if ( utc )
GetSystemTime ( & systemtime ) ;
else
GetLocalTime ( & systemtime ) ;
2014-02-10 02:10:30 +01:00
Time time ;
2017-03-05 16:44:50 +01:00
time . hour = systemtime . wHour ;
2021-05-24 13:54:05 +02:00
time . minute = systemtime . wMinute ;
time . second = systemtime . wSecond ;
2014-02-10 02:10:30 +01:00
return time ;
}
2015-06-06 05:35:38 +02:00
OS : : TimeZoneInfo OS_Windows : : get_time_zone_info ( ) const {
TIME_ZONE_INFORMATION info ;
bool daylight = false ;
2015-06-07 16:10:33 +02:00
if ( GetTimeZoneInformation ( & info ) = = TIME_ZONE_ID_DAYLIGHT )
2015-06-06 05:35:38 +02:00
daylight = true ;
2015-06-07 16:10:33 +02:00
TimeZoneInfo ret ;
2015-06-06 05:35:38 +02:00
if ( daylight ) {
ret . name = info . DaylightName ;
} else {
ret . name = info . StandardName ;
}
2019-02-13 01:41:19 +01:00
// Bias value returned by GetTimeZoneInformation is inverted of what we expect
2021-03-12 14:35:16 +01:00
// For example, on GMT-3 GetTimeZoneInformation return a Bias of 180, so invert the value to get -180
2019-02-13 01:41:19 +01:00
ret . bias = - info . Bias ;
2015-06-06 05:35:38 +02:00
return ret ;
}
2014-02-10 02:10:30 +01:00
2020-05-31 14:19:31 +02:00
double OS_Windows : : get_unix_time ( ) const {
// 1 Windows tick is 100ns
const uint64_t WINDOWS_TICKS_PER_SECOND = 10000000 ;
const uint64_t TICKS_TO_UNIX_EPOCH = 116444736000000000LL ;
2016-06-11 19:09:21 +02:00
2015-08-06 19:29:33 +02:00
SYSTEMTIME st ;
GetSystemTime ( & st ) ;
2016-01-10 22:24:55 +01:00
FILETIME ft ;
2017-03-05 16:44:50 +01:00
SystemTimeToFileTime ( & st , & ft ) ;
2020-05-31 14:19:31 +02:00
uint64_t ticks_time ;
ticks_time = ft . dwHighDateTime ;
ticks_time < < = 32 ;
ticks_time | = ft . dwLowDateTime ;
2016-06-11 19:09:21 +02:00
2020-05-31 14:19:31 +02:00
return ( double ) ( ticks_time - TICKS_TO_UNIX_EPOCH ) / WINDOWS_TICKS_PER_SECOND ;
2015-08-06 19:29:33 +02:00
}
2014-02-10 02:10:30 +01:00
void OS_Windows : : delay_usec ( uint32_t p_usec ) const {
2017-03-05 16:44:50 +01:00
if ( p_usec < 1000 )
Sleep ( 1 ) ;
else
Sleep ( p_usec / 1000 ) ;
2014-02-10 02:10:30 +01:00
}
2020-05-14 14:29:06 +02:00
2014-02-10 02:10:30 +01:00
uint64_t OS_Windows : : get_ticks_usec ( ) const {
2017-03-05 16:44:50 +01:00
uint64_t ticks ;
2020-05-22 13:20:19 +02:00
2017-03-05 16:44:50 +01:00
// This is the number of clock ticks since start
if ( ! QueryPerformanceCounter ( ( LARGE_INTEGER * ) & ticks ) )
ticks = ( UINT64 ) timeGetTime ( ) ;
2020-05-22 13:20:19 +02:00
2017-03-05 16:44:50 +01:00
// Divide by frequency to get the time in seconds
2020-05-22 13:20:19 +02:00
// original calculation shown below is subject to overflow
// with high ticks_per_second and a number of days since the last reboot.
// time = ticks * 1000000L / ticks_per_second;
// we can prevent this by either using 128 bit math
// or separating into a calculation for seconds, and the fraction
uint64_t seconds = ticks / ticks_per_second ;
// compiler will optimize these two into one divide
uint64_t leftover = ticks % ticks_per_second ;
// remainder
uint64_t time = ( leftover * 1000000L ) / ticks_per_second ;
// seconds
time + = seconds * 1000000L ;
2017-03-05 16:44:50 +01:00
// Subtract the time at game start to get
// the time since the game started
time - = ticks_start ;
return time ;
2014-02-10 02:10:30 +01:00
}
2020-05-19 15:34:15 +02:00
String OS_Windows : : _quote_command_line_argument ( const String & p_text ) const {
for ( int i = 0 ; i < p_text . size ( ) ; i + + ) {
2020-07-27 12:43:20 +02:00
char32_t c = p_text [ i ] ;
2020-05-19 15:34:15 +02:00
if ( c = = ' ' | | c = = ' & ' | | c = = ' ( ' | | c = = ' ) ' | | c = = ' [ ' | | c = = ' ] ' | | c = = ' { ' | | c = = ' } ' | | c = = ' ^ ' | | c = = ' = ' | | c = = ' ; ' | | c = = ' ! ' | | c = = ' \' ' | | c = = ' + ' | | c = = ' , ' | | c = = ' ` ' | | c = = ' ~ ' ) {
return " \" " + p_text + " \" " ;
}
}
return p_text ;
}
2020-12-18 19:49:13 +01:00
Error OS_Windows : : execute ( const String & p_path , const List < String > & p_arguments , String * r_pipe , int * r_exitcode , bool read_stderr , Mutex * p_pipe_mutex ) {
2020-10-22 12:17:21 +02:00
String path = p_path . replace ( " / " , " \\ " ) ;
2020-12-18 19:49:13 +01:00
String command = _quote_command_line_argument ( path ) ;
2021-07-16 05:45:57 +02:00
for ( const String & E : p_arguments ) {
command + = " " + _quote_command_line_argument ( E ) ;
2020-12-18 19:49:13 +01:00
}
2020-10-22 12:17:21 +02:00
2020-12-18 19:49:13 +01:00
if ( r_pipe ) {
2019-03-01 23:51:53 +01:00
if ( read_stderr ) {
2020-12-18 19:49:13 +01:00
command + = " 2>&1 " ; // Include stderr
2014-02-10 02:10:30 +01:00
}
2020-12-18 19:49:13 +01:00
// Add extra quotes around the full command, to prevent it from stripping quotes in the command,
// because _wpopen calls command as "cmd.exe /c command", instead of executing it directly
command = _quote_command_line_argument ( command ) ;
2014-02-10 02:10:30 +01:00
2020-12-18 19:49:13 +01:00
FILE * f = _wpopen ( ( LPCWSTR ) ( command . utf16 ( ) . get_data ( ) ) , L " r " ) ;
ERR_FAIL_COND_V_MSG ( ! f , ERR_CANT_OPEN , " Cannot create pipe from command: " + command ) ;
2014-02-10 02:10:30 +01:00
char buf [ 65535 ] ;
2017-03-05 16:44:50 +01:00
while ( fgets ( buf , 65535 , f ) ) {
2019-04-07 20:46:52 +02:00
if ( p_pipe_mutex ) {
p_pipe_mutex - > lock ( ) ;
}
2020-02-19 19:59:37 +01:00
( * r_pipe ) + = String : : utf8 ( buf ) ;
2019-04-07 20:46:52 +02:00
if ( p_pipe_mutex ) {
2019-04-24 20:52:15 +02:00
p_pipe_mutex - > unlock ( ) ;
2019-04-07 20:46:52 +02:00
}
2014-02-10 02:10:30 +01:00
}
int rv = _pclose ( f ) ;
2020-12-18 19:49:13 +01:00
2020-05-19 15:34:15 +02:00
if ( r_exitcode ) {
2017-03-05 16:44:50 +01:00
* r_exitcode = rv ;
2020-05-19 15:34:15 +02:00
}
2014-02-10 02:10:30 +01:00
return OK ;
}
2020-12-18 19:49:13 +01:00
ProcessInfo pi ;
ZeroMemory ( & pi . si , sizeof ( pi . si ) ) ;
pi . si . cb = sizeof ( pi . si ) ;
ZeroMemory ( & pi . pi , sizeof ( pi . pi ) ) ;
LPSTARTUPINFOW si_w = ( LPSTARTUPINFOW ) & pi . si ;
int ret = CreateProcessW ( nullptr , ( LPWSTR ) ( command . utf16 ( ) . ptrw ( ) ) , nullptr , nullptr , false , NORMAL_PRIORITY_CLASS & CREATE_NO_WINDOW , nullptr , nullptr , si_w , & pi . pi ) ;
ERR_FAIL_COND_V_MSG ( ret = = 0 , ERR_CANT_FORK , " Could not create child process: " + command ) ;
WaitForSingleObject ( pi . pi . hProcess , INFINITE ) ;
if ( r_exitcode ) {
DWORD ret2 ;
GetExitCodeProcess ( pi . pi . hProcess , & ret2 ) ;
* r_exitcode = ret2 ;
}
CloseHandle ( pi . pi . hProcess ) ;
CloseHandle ( pi . pi . hThread ) ;
return OK ;
} ;
Error OS_Windows : : create_process ( const String & p_path , const List < String > & p_arguments , ProcessID * r_child_id ) {
String path = p_path . replace ( " / " , " \\ " ) ;
String command = _quote_command_line_argument ( path ) ;
2021-07-16 05:45:57 +02:00
for ( const String & E : p_arguments ) {
command + = " " + _quote_command_line_argument ( E ) ;
2020-05-19 15:34:15 +02:00
}
2014-02-10 02:10:30 +01:00
ProcessInfo pi ;
2017-03-05 16:44:50 +01:00
ZeroMemory ( & pi . si , sizeof ( pi . si ) ) ;
2014-02-10 02:10:30 +01:00
pi . si . cb = sizeof ( pi . si ) ;
2017-03-05 16:44:50 +01:00
ZeroMemory ( & pi . pi , sizeof ( pi . pi ) ) ;
LPSTARTUPINFOW si_w = ( LPSTARTUPINFOW ) & pi . si ;
2014-02-10 02:10:30 +01:00
2020-12-18 19:49:13 +01:00
int ret = CreateProcessW ( nullptr , ( LPWSTR ) ( command . utf16 ( ) . ptrw ( ) ) , nullptr , nullptr , false , NORMAL_PRIORITY_CLASS & CREATE_NO_WINDOW , nullptr , nullptr , si_w , & pi . pi ) ;
ERR_FAIL_COND_V_MSG ( ret = = 0 , ERR_CANT_FORK , " Could not create child process: " + command ) ;
2014-02-10 02:10:30 +01:00
2020-12-18 19:49:13 +01:00
ProcessID pid = pi . pi . dwProcessId ;
if ( r_child_id ) {
* r_child_id = pid ;
2020-05-19 15:34:15 +02:00
}
2020-12-18 19:49:13 +01:00
process_map - > insert ( pid , pi ) ;
2014-02-10 02:10:30 +01:00
return OK ;
} ;
2018-08-27 17:32:43 +02:00
Error OS_Windows : : kill ( const ProcessID & p_pid ) {
2018-07-30 09:55:33 +02:00
ERR_FAIL_COND_V ( ! process_map - > has ( p_pid ) , FAILED ) ;
2014-02-10 02:10:30 +01:00
2018-07-30 09:55:33 +02:00
const PROCESS_INFORMATION pi = ( * process_map ) [ p_pid ] . pi ;
process_map - > erase ( p_pid ) ;
2014-02-10 02:10:30 +01:00
2018-08-27 17:32:43 +02:00
const int ret = TerminateProcess ( pi . hProcess , 0 ) ;
2014-02-10 02:10:30 +01:00
2018-07-30 09:55:33 +02:00
CloseHandle ( pi . hProcess ) ;
CloseHandle ( pi . hThread ) ;
2014-02-10 02:10:30 +01:00
2018-08-27 17:32:43 +02:00
return ret ! = 0 ? OK : FAILED ;
} ;
2014-02-10 02:10:30 +01:00
2017-08-07 12:17:31 +02:00
int OS_Windows : : get_process_id ( ) const {
2016-04-29 18:57:57 +02:00
return _getpid ( ) ;
}
2017-03-05 16:44:50 +01:00
Error OS_Windows : : set_cwd ( const String & p_cwd ) {
2020-07-27 12:43:20 +02:00
if ( _wchdir ( ( LPCWSTR ) ( p_cwd . utf16 ( ) . get_data ( ) ) ) ! = 0 )
2014-02-10 02:10:30 +01:00
return ERR_CANT_OPEN ;
return OK ;
}
2014-02-15 06:01:39 +01:00
String OS_Windows : : get_executable_path ( ) const {
2020-07-27 12:43:20 +02:00
WCHAR bufname [ 4096 ] ;
2020-04-02 01:20:12 +02:00
GetModuleFileNameW ( nullptr , bufname , 4096 ) ;
2020-10-22 12:17:21 +02:00
String s = String : : utf16 ( ( const char16_t * ) bufname ) . replace ( " \\ " , " / " ) ;
2014-02-15 06:01:39 +01:00
return s ;
}
2017-03-05 16:44:50 +01:00
bool OS_Windows : : has_environment ( const String & p_var ) const {
2018-10-04 15:38:52 +02:00
# ifdef MINGW_ENABLED
2020-07-27 12:43:20 +02:00
return _wgetenv ( ( LPCWSTR ) ( p_var . utf16 ( ) . get_data ( ) ) ) ! = nullptr ;
2018-10-04 15:38:52 +02:00
# else
2020-07-27 12:43:20 +02:00
WCHAR * env ;
2018-10-04 15:38:52 +02:00
size_t len ;
2020-07-27 12:43:20 +02:00
_wdupenv_s ( & env , & len , ( LPCWSTR ) ( p_var . utf16 ( ) . get_data ( ) ) ) ;
2020-04-02 01:20:12 +02:00
const bool has_env = env ! = nullptr ;
2018-10-04 15:38:52 +02:00
free ( env ) ;
return has_env ;
# endif
2014-02-10 02:10:30 +01:00
} ;
2017-03-05 16:44:50 +01:00
String OS_Windows : : get_environment ( const String & p_var ) const {
2020-07-27 12:43:20 +02:00
WCHAR wval [ 0x7fff ] ; // MSDN says 32767 char is the maximum
int wlen = GetEnvironmentVariableW ( ( LPCWSTR ) ( p_var . utf16 ( ) . get_data ( ) ) , wval , 0x7fff ) ;
2017-03-05 16:44:50 +01:00
if ( wlen > 0 ) {
2020-07-27 12:43:20 +02:00
return String : : utf16 ( ( const char16_t * ) wval ) ;
2015-05-04 18:12:05 +02:00
}
2014-02-13 22:03:28 +01:00
return " " ;
2015-05-04 18:12:05 +02:00
}
2014-02-10 02:10:30 +01:00
2019-01-29 22:59:38 +01:00
bool OS_Windows : : set_environment ( const String & p_var , const String & p_value ) const {
2020-07-27 12:43:20 +02:00
return ( bool ) SetEnvironmentVariableW ( ( LPCWSTR ) ( p_var . utf16 ( ) . get_data ( ) ) , ( LPCWSTR ) ( p_value . utf16 ( ) . get_data ( ) ) ) ;
2019-01-29 22:59:38 +01:00
}
2014-02-10 02:10:30 +01:00
String OS_Windows : : get_stdin_string ( bool p_block ) {
if ( p_block ) {
char buff [ 1024 ] ;
2017-03-05 16:44:50 +01:00
return fgets ( buff , 1024 , stdin ) ;
2014-02-10 02:10:30 +01:00
} ;
return String ( ) ;
}
2014-04-18 16:43:54 +02:00
Error OS_Windows : : shell_open ( String p_uri ) {
2020-07-27 12:43:20 +02:00
ShellExecuteW ( nullptr , nullptr , ( LPCWSTR ) ( p_uri . utf16 ( ) . get_data ( ) ) , nullptr , nullptr , SW_SHOWNORMAL ) ;
2014-04-18 16:43:54 +02:00
return OK ;
}
2014-02-10 02:10:30 +01:00
String OS_Windows : : get_locale ( ) const {
const _WinLocale * wl = & _win_locales [ 0 ] ;
LANGID langid = GetUserDefaultUILanguage ( ) ;
String neutral ;
2020-07-25 22:42:11 +02:00
int lang = PRIMARYLANGID ( langid ) ;
int sublang = SUBLANGID ( langid ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
while ( wl - > locale ) {
if ( wl - > main_lang = = lang & & wl - > sublang = = SUBLANG_NEUTRAL )
neutral = wl - > locale ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( lang = = wl - > main_lang & & sublang = = wl - > sublang )
2020-07-25 22:42:11 +02:00
return String ( wl - > locale ) . replace ( " - " , " _ " ) ;
2014-02-10 02:10:30 +01:00
wl + + ;
}
2017-03-05 16:44:50 +01:00
if ( neutral ! = " " )
2020-07-25 22:42:11 +02:00
return String ( neutral ) . replace ( " - " , " _ " ) ;
2014-02-10 02:10:30 +01:00
return " en " ;
}
2018-01-29 16:46:30 +01:00
// We need this because GetSystemInfo() is unreliable on WOW64
// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms724381(v=vs.85).aspx
// Taken from MSDN
typedef BOOL ( WINAPI * LPFN_ISWOW64PROCESS ) ( HANDLE , PBOOL ) ;
LPFN_ISWOW64PROCESS fnIsWow64Process ;
BOOL is_wow64 ( ) {
BOOL wow64 = FALSE ;
fnIsWow64Process = ( LPFN_ISWOW64PROCESS ) GetProcAddress ( GetModuleHandle ( TEXT ( " kernel32 " ) ) , " IsWow64Process " ) ;
if ( fnIsWow64Process ) {
if ( ! fnIsWow64Process ( GetCurrentProcess ( ) , & wow64 ) ) {
wow64 = FALSE ;
}
}
return wow64 ;
}
int OS_Windows : : get_processor_count ( ) const {
SYSTEM_INFO sysinfo ;
if ( is_wow64 ( ) )
GetNativeSystemInfo ( & sysinfo ) ;
else
GetSystemInfo ( & sysinfo ) ;
return sysinfo . dwNumberOfProcessors ;
}
2014-02-10 02:10:30 +01:00
void OS_Windows : : run ( ) {
if ( ! main_loop )
return ;
2016-03-09 00:00:52 +01:00
2020-12-22 10:50:29 +01:00
main_loop - > initialize ( ) ;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
while ( ! force_quit ) {
2020-03-09 16:56:48 +01:00
DisplayServer : : get_singleton ( ) - > process_events ( ) ; // get rid of pending events
2018-10-03 19:40:37 +02:00
if ( Main : : iteration ( ) )
2014-02-10 02:10:30 +01:00
break ;
} ;
2016-03-09 00:00:52 +01:00
2020-12-22 10:50:29 +01:00
main_loop - > finalize ( ) ;
2014-02-10 02:10:30 +01:00
}
MainLoop * OS_Windows : : get_main_loop ( ) const {
return main_loop ;
}
Add initial support for the XDG Base Directory spec
Spec version 0.7 from https://standards.freedesktop.org/basedir-spec/basedir-spec-0.7.html
(latest as of this commit).
Three virtual methods are added to OS for the various XDG paths we will use:
- OS::get_data_path gives XDG_DATA_HOME, or if missing:
~/.local/share on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_config_path gives XDG_CONFIG_HOME, or if missing:
~/.config on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_cache_path gives XDG_CACHE_HOME, or if missing:
~/.cache on X11, ~/Library/Caches on macOS and %APPDATA% on Windows
So for Windows there are no changes, for Linux we follow the full split spec
and for macOS stuff will move from ~/.godot to ~/Library/Application Support/Godot.
Support for system-wide installation of templates on Unix was removed for now,
as it's a bit hackish and I don't think anyone uses it.
user:// will still be OS::get_data_path() + "/godot/app_userdata/$name" by
default, but when using the application/config/use_shared_user_dir option
it will now use XDG_DATA_HOME/$name, e.g. ~/.local/share/MyGame.
For now everything still goes in EditorSettings::get_settings_dir(), but
this will be changed in a later commit to make use of the new splitting
where relevant.
Part of #3513.
2017-11-17 17:11:41 +01:00
String OS_Windows : : get_config_path ( ) const {
2021-05-07 19:02:35 +02:00
// The XDG Base Directory specification technically only applies on Linux/*BSD, but it doesn't hurt to support it on Windows as well.
if ( has_environment ( " XDG_CONFIG_HOME " ) ) {
2021-06-03 15:41:22 +02:00
if ( get_environment ( " XDG_CONFIG_HOME " ) . is_absolute_path ( ) ) {
2021-07-03 22:41:17 +02:00
return get_environment ( " XDG_CONFIG_HOME " ) . replace ( " \\ " , " / " ) ;
2021-05-07 19:02:35 +02:00
} else {
WARN_PRINT_ONCE ( " `XDG_CONFIG_HOME` is a relative path. Ignoring its value and falling back to `%APPDATA%` or `.` per the XDG Base Directory specification. " ) ;
}
2021-05-21 12:48:12 +02:00
}
if ( has_environment ( " APPDATA " ) ) {
2021-07-03 22:41:17 +02:00
return get_environment ( " APPDATA " ) . replace ( " \\ " , " / " ) ;
Add initial support for the XDG Base Directory spec
Spec version 0.7 from https://standards.freedesktop.org/basedir-spec/basedir-spec-0.7.html
(latest as of this commit).
Three virtual methods are added to OS for the various XDG paths we will use:
- OS::get_data_path gives XDG_DATA_HOME, or if missing:
~/.local/share on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_config_path gives XDG_CONFIG_HOME, or if missing:
~/.config on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_cache_path gives XDG_CACHE_HOME, or if missing:
~/.cache on X11, ~/Library/Caches on macOS and %APPDATA% on Windows
So for Windows there are no changes, for Linux we follow the full split spec
and for macOS stuff will move from ~/.godot to ~/Library/Application Support/Godot.
Support for system-wide installation of templates on Unix was removed for now,
as it's a bit hackish and I don't think anyone uses it.
user:// will still be OS::get_data_path() + "/godot/app_userdata/$name" by
default, but when using the application/config/use_shared_user_dir option
it will now use XDG_DATA_HOME/$name, e.g. ~/.local/share/MyGame.
For now everything still goes in EditorSettings::get_settings_dir(), but
this will be changed in a later commit to make use of the new splitting
where relevant.
Part of #3513.
2017-11-17 17:11:41 +01:00
}
2021-05-21 12:48:12 +02:00
return " . " ;
Add initial support for the XDG Base Directory spec
Spec version 0.7 from https://standards.freedesktop.org/basedir-spec/basedir-spec-0.7.html
(latest as of this commit).
Three virtual methods are added to OS for the various XDG paths we will use:
- OS::get_data_path gives XDG_DATA_HOME, or if missing:
~/.local/share on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_config_path gives XDG_CONFIG_HOME, or if missing:
~/.config on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_cache_path gives XDG_CACHE_HOME, or if missing:
~/.cache on X11, ~/Library/Caches on macOS and %APPDATA% on Windows
So for Windows there are no changes, for Linux we follow the full split spec
and for macOS stuff will move from ~/.godot to ~/Library/Application Support/Godot.
Support for system-wide installation of templates on Unix was removed for now,
as it's a bit hackish and I don't think anyone uses it.
user:// will still be OS::get_data_path() + "/godot/app_userdata/$name" by
default, but when using the application/config/use_shared_user_dir option
it will now use XDG_DATA_HOME/$name, e.g. ~/.local/share/MyGame.
For now everything still goes in EditorSettings::get_settings_dir(), but
this will be changed in a later commit to make use of the new splitting
where relevant.
Part of #3513.
2017-11-17 17:11:41 +01:00
}
String OS_Windows : : get_data_path ( ) const {
2021-05-07 19:02:35 +02:00
// The XDG Base Directory specification technically only applies on Linux/*BSD, but it doesn't hurt to support it on Windows as well.
Add initial support for the XDG Base Directory spec
Spec version 0.7 from https://standards.freedesktop.org/basedir-spec/basedir-spec-0.7.html
(latest as of this commit).
Three virtual methods are added to OS for the various XDG paths we will use:
- OS::get_data_path gives XDG_DATA_HOME, or if missing:
~/.local/share on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_config_path gives XDG_CONFIG_HOME, or if missing:
~/.config on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_cache_path gives XDG_CACHE_HOME, or if missing:
~/.cache on X11, ~/Library/Caches on macOS and %APPDATA% on Windows
So for Windows there are no changes, for Linux we follow the full split spec
and for macOS stuff will move from ~/.godot to ~/Library/Application Support/Godot.
Support for system-wide installation of templates on Unix was removed for now,
as it's a bit hackish and I don't think anyone uses it.
user:// will still be OS::get_data_path() + "/godot/app_userdata/$name" by
default, but when using the application/config/use_shared_user_dir option
it will now use XDG_DATA_HOME/$name, e.g. ~/.local/share/MyGame.
For now everything still goes in EditorSettings::get_settings_dir(), but
this will be changed in a later commit to make use of the new splitting
where relevant.
Part of #3513.
2017-11-17 17:11:41 +01:00
if ( has_environment ( " XDG_DATA_HOME " ) ) {
2021-06-03 15:41:22 +02:00
if ( get_environment ( " XDG_DATA_HOME " ) . is_absolute_path ( ) ) {
2021-07-03 22:41:17 +02:00
return get_environment ( " XDG_DATA_HOME " ) . replace ( " \\ " , " / " ) ;
2021-05-07 19:02:35 +02:00
} else {
WARN_PRINT_ONCE ( " `XDG_DATA_HOME` is a relative path. Ignoring its value and falling back to `get_config_path()` per the XDG Base Directory specification. " ) ;
}
Add initial support for the XDG Base Directory spec
Spec version 0.7 from https://standards.freedesktop.org/basedir-spec/basedir-spec-0.7.html
(latest as of this commit).
Three virtual methods are added to OS for the various XDG paths we will use:
- OS::get_data_path gives XDG_DATA_HOME, or if missing:
~/.local/share on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_config_path gives XDG_CONFIG_HOME, or if missing:
~/.config on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_cache_path gives XDG_CACHE_HOME, or if missing:
~/.cache on X11, ~/Library/Caches on macOS and %APPDATA% on Windows
So for Windows there are no changes, for Linux we follow the full split spec
and for macOS stuff will move from ~/.godot to ~/Library/Application Support/Godot.
Support for system-wide installation of templates on Unix was removed for now,
as it's a bit hackish and I don't think anyone uses it.
user:// will still be OS::get_data_path() + "/godot/app_userdata/$name" by
default, but when using the application/config/use_shared_user_dir option
it will now use XDG_DATA_HOME/$name, e.g. ~/.local/share/MyGame.
For now everything still goes in EditorSettings::get_settings_dir(), but
this will be changed in a later commit to make use of the new splitting
where relevant.
Part of #3513.
2017-11-17 17:11:41 +01:00
}
2021-05-21 12:48:12 +02:00
return get_config_path ( ) ;
Add initial support for the XDG Base Directory spec
Spec version 0.7 from https://standards.freedesktop.org/basedir-spec/basedir-spec-0.7.html
(latest as of this commit).
Three virtual methods are added to OS for the various XDG paths we will use:
- OS::get_data_path gives XDG_DATA_HOME, or if missing:
~/.local/share on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_config_path gives XDG_CONFIG_HOME, or if missing:
~/.config on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_cache_path gives XDG_CACHE_HOME, or if missing:
~/.cache on X11, ~/Library/Caches on macOS and %APPDATA% on Windows
So for Windows there are no changes, for Linux we follow the full split spec
and for macOS stuff will move from ~/.godot to ~/Library/Application Support/Godot.
Support for system-wide installation of templates on Unix was removed for now,
as it's a bit hackish and I don't think anyone uses it.
user:// will still be OS::get_data_path() + "/godot/app_userdata/$name" by
default, but when using the application/config/use_shared_user_dir option
it will now use XDG_DATA_HOME/$name, e.g. ~/.local/share/MyGame.
For now everything still goes in EditorSettings::get_settings_dir(), but
this will be changed in a later commit to make use of the new splitting
where relevant.
Part of #3513.
2017-11-17 17:11:41 +01:00
}
String OS_Windows : : get_cache_path ( ) const {
2021-05-07 19:02:35 +02:00
// The XDG Base Directory specification technically only applies on Linux/*BSD, but it doesn't hurt to support it on Windows as well.
Add initial support for the XDG Base Directory spec
Spec version 0.7 from https://standards.freedesktop.org/basedir-spec/basedir-spec-0.7.html
(latest as of this commit).
Three virtual methods are added to OS for the various XDG paths we will use:
- OS::get_data_path gives XDG_DATA_HOME, or if missing:
~/.local/share on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_config_path gives XDG_CONFIG_HOME, or if missing:
~/.config on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_cache_path gives XDG_CACHE_HOME, or if missing:
~/.cache on X11, ~/Library/Caches on macOS and %APPDATA% on Windows
So for Windows there are no changes, for Linux we follow the full split spec
and for macOS stuff will move from ~/.godot to ~/Library/Application Support/Godot.
Support for system-wide installation of templates on Unix was removed for now,
as it's a bit hackish and I don't think anyone uses it.
user:// will still be OS::get_data_path() + "/godot/app_userdata/$name" by
default, but when using the application/config/use_shared_user_dir option
it will now use XDG_DATA_HOME/$name, e.g. ~/.local/share/MyGame.
For now everything still goes in EditorSettings::get_settings_dir(), but
this will be changed in a later commit to make use of the new splitting
where relevant.
Part of #3513.
2017-11-17 17:11:41 +01:00
if ( has_environment ( " XDG_CACHE_HOME " ) ) {
2021-06-03 15:41:22 +02:00
if ( get_environment ( " XDG_CACHE_HOME " ) . is_absolute_path ( ) ) {
2021-07-03 22:41:17 +02:00
return get_environment ( " XDG_CACHE_HOME " ) . replace ( " \\ " , " / " ) ;
2021-05-07 19:02:35 +02:00
} else {
WARN_PRINT_ONCE ( " `XDG_CACHE_HOME` is a relative path. Ignoring its value and falling back to `%TEMP%` or `get_config_path()` per the XDG Base Directory specification. " ) ;
}
2021-05-21 12:48:12 +02:00
}
if ( has_environment ( " TEMP " ) ) {
2021-07-03 22:41:17 +02:00
return get_environment ( " TEMP " ) . replace ( " \\ " , " / " ) ;
Add initial support for the XDG Base Directory spec
Spec version 0.7 from https://standards.freedesktop.org/basedir-spec/basedir-spec-0.7.html
(latest as of this commit).
Three virtual methods are added to OS for the various XDG paths we will use:
- OS::get_data_path gives XDG_DATA_HOME, or if missing:
~/.local/share on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_config_path gives XDG_CONFIG_HOME, or if missing:
~/.config on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_cache_path gives XDG_CACHE_HOME, or if missing:
~/.cache on X11, ~/Library/Caches on macOS and %APPDATA% on Windows
So for Windows there are no changes, for Linux we follow the full split spec
and for macOS stuff will move from ~/.godot to ~/Library/Application Support/Godot.
Support for system-wide installation of templates on Unix was removed for now,
as it's a bit hackish and I don't think anyone uses it.
user:// will still be OS::get_data_path() + "/godot/app_userdata/$name" by
default, but when using the application/config/use_shared_user_dir option
it will now use XDG_DATA_HOME/$name, e.g. ~/.local/share/MyGame.
For now everything still goes in EditorSettings::get_settings_dir(), but
this will be changed in a later commit to make use of the new splitting
where relevant.
Part of #3513.
2017-11-17 17:11:41 +01:00
}
2021-05-21 12:48:12 +02:00
return get_config_path ( ) ;
Add initial support for the XDG Base Directory spec
Spec version 0.7 from https://standards.freedesktop.org/basedir-spec/basedir-spec-0.7.html
(latest as of this commit).
Three virtual methods are added to OS for the various XDG paths we will use:
- OS::get_data_path gives XDG_DATA_HOME, or if missing:
~/.local/share on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_config_path gives XDG_CONFIG_HOME, or if missing:
~/.config on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_cache_path gives XDG_CACHE_HOME, or if missing:
~/.cache on X11, ~/Library/Caches on macOS and %APPDATA% on Windows
So for Windows there are no changes, for Linux we follow the full split spec
and for macOS stuff will move from ~/.godot to ~/Library/Application Support/Godot.
Support for system-wide installation of templates on Unix was removed for now,
as it's a bit hackish and I don't think anyone uses it.
user:// will still be OS::get_data_path() + "/godot/app_userdata/$name" by
default, but when using the application/config/use_shared_user_dir option
it will now use XDG_DATA_HOME/$name, e.g. ~/.local/share/MyGame.
For now everything still goes in EditorSettings::get_settings_dir(), but
this will be changed in a later commit to make use of the new splitting
where relevant.
Part of #3513.
2017-11-17 17:11:41 +01:00
}
// Get properly capitalized engine name for system paths
String OS_Windows : : get_godot_dir_name ( ) const {
2017-11-19 21:18:01 +01:00
return String ( VERSION_SHORT_NAME ) . capitalize ( ) ;
Add initial support for the XDG Base Directory spec
Spec version 0.7 from https://standards.freedesktop.org/basedir-spec/basedir-spec-0.7.html
(latest as of this commit).
Three virtual methods are added to OS for the various XDG paths we will use:
- OS::get_data_path gives XDG_DATA_HOME, or if missing:
~/.local/share on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_config_path gives XDG_CONFIG_HOME, or if missing:
~/.config on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_cache_path gives XDG_CACHE_HOME, or if missing:
~/.cache on X11, ~/Library/Caches on macOS and %APPDATA% on Windows
So for Windows there are no changes, for Linux we follow the full split spec
and for macOS stuff will move from ~/.godot to ~/Library/Application Support/Godot.
Support for system-wide installation of templates on Unix was removed for now,
as it's a bit hackish and I don't think anyone uses it.
user:// will still be OS::get_data_path() + "/godot/app_userdata/$name" by
default, but when using the application/config/use_shared_user_dir option
it will now use XDG_DATA_HOME/$name, e.g. ~/.local/share/MyGame.
For now everything still goes in EditorSettings::get_settings_dir(), but
this will be changed in a later commit to make use of the new splitting
where relevant.
Part of #3513.
2017-11-17 17:11:41 +01:00
}
2021-07-11 03:39:31 +02:00
String OS_Windows : : get_system_dir ( SystemDir p_dir , bool p_shared_storage ) const {
2019-04-18 04:43:33 +02:00
KNOWNFOLDERID id ;
2014-12-02 18:02:41 +01:00
2017-03-05 16:44:50 +01:00
switch ( p_dir ) {
2014-12-02 18:02:41 +01:00
case SYSTEM_DIR_DESKTOP : {
2019-04-18 04:43:33 +02:00
id = FOLDERID_Desktop ;
2014-12-02 18:02:41 +01:00
} break ;
case SYSTEM_DIR_DCIM : {
2019-04-18 04:43:33 +02:00
id = FOLDERID_Pictures ;
2014-12-02 18:02:41 +01:00
} break ;
case SYSTEM_DIR_DOCUMENTS : {
2019-04-18 04:43:33 +02:00
id = FOLDERID_Documents ;
2014-12-02 18:02:41 +01:00
} break ;
case SYSTEM_DIR_DOWNLOADS : {
2019-04-18 04:43:33 +02:00
id = FOLDERID_Downloads ;
2014-12-02 18:02:41 +01:00
} break ;
case SYSTEM_DIR_MOVIES : {
2019-04-18 04:43:33 +02:00
id = FOLDERID_Videos ;
2014-12-02 18:02:41 +01:00
} break ;
case SYSTEM_DIR_MUSIC : {
2019-04-18 04:43:33 +02:00
id = FOLDERID_Music ;
2014-12-02 18:02:41 +01:00
} break ;
case SYSTEM_DIR_PICTURES : {
2019-04-18 04:43:33 +02:00
id = FOLDERID_Pictures ;
2014-12-02 18:02:41 +01:00
} break ;
case SYSTEM_DIR_RINGTONES : {
2019-04-18 04:43:33 +02:00
id = FOLDERID_Music ;
2014-12-02 18:02:41 +01:00
} break ;
}
2019-04-18 04:43:33 +02:00
PWSTR szPath ;
2020-04-02 01:20:12 +02:00
HRESULT res = SHGetKnownFolderPath ( id , 0 , nullptr , & szPath ) ;
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( res ! = S_OK , String ( ) ) ;
2021-07-03 22:41:17 +02:00
String path = String : : utf16 ( ( const char16_t * ) szPath ) . replace ( " \\ " , " / " ) ;
2019-04-18 04:43:33 +02:00
CoTaskMemFree ( szPath ) ;
return path ;
2014-12-02 18:02:41 +01:00
}
2014-02-10 02:10:30 +01:00
Add initial support for the XDG Base Directory spec
Spec version 0.7 from https://standards.freedesktop.org/basedir-spec/basedir-spec-0.7.html
(latest as of this commit).
Three virtual methods are added to OS for the various XDG paths we will use:
- OS::get_data_path gives XDG_DATA_HOME, or if missing:
~/.local/share on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_config_path gives XDG_CONFIG_HOME, or if missing:
~/.config on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_cache_path gives XDG_CACHE_HOME, or if missing:
~/.cache on X11, ~/Library/Caches on macOS and %APPDATA% on Windows
So for Windows there are no changes, for Linux we follow the full split spec
and for macOS stuff will move from ~/.godot to ~/Library/Application Support/Godot.
Support for system-wide installation of templates on Unix was removed for now,
as it's a bit hackish and I don't think anyone uses it.
user:// will still be OS::get_data_path() + "/godot/app_userdata/$name" by
default, but when using the application/config/use_shared_user_dir option
it will now use XDG_DATA_HOME/$name, e.g. ~/.local/share/MyGame.
For now everything still goes in EditorSettings::get_settings_dir(), but
this will be changed in a later commit to make use of the new splitting
where relevant.
Part of #3513.
2017-11-17 17:11:41 +01:00
String OS_Windows : : get_user_data_dir ( ) const {
2017-11-26 19:00:53 +01:00
String appname = get_safe_dir_name ( ProjectSettings : : get_singleton ( ) - > get ( " application/config/name " ) ) ;
Add initial support for the XDG Base Directory spec
Spec version 0.7 from https://standards.freedesktop.org/basedir-spec/basedir-spec-0.7.html
(latest as of this commit).
Three virtual methods are added to OS for the various XDG paths we will use:
- OS::get_data_path gives XDG_DATA_HOME, or if missing:
~/.local/share on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_config_path gives XDG_CONFIG_HOME, or if missing:
~/.config on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_cache_path gives XDG_CACHE_HOME, or if missing:
~/.cache on X11, ~/Library/Caches on macOS and %APPDATA% on Windows
So for Windows there are no changes, for Linux we follow the full split spec
and for macOS stuff will move from ~/.godot to ~/Library/Application Support/Godot.
Support for system-wide installation of templates on Unix was removed for now,
as it's a bit hackish and I don't think anyone uses it.
user:// will still be OS::get_data_path() + "/godot/app_userdata/$name" by
default, but when using the application/config/use_shared_user_dir option
it will now use XDG_DATA_HOME/$name, e.g. ~/.local/share/MyGame.
For now everything still goes in EditorSettings::get_settings_dir(), but
this will be changed in a later commit to make use of the new splitting
where relevant.
Part of #3513.
2017-11-17 17:11:41 +01:00
if ( appname ! = " " ) {
2017-11-26 19:00:53 +01:00
bool use_custom_dir = ProjectSettings : : get_singleton ( ) - > get ( " application/config/use_custom_user_dir " ) ;
if ( use_custom_dir ) {
String custom_dir = get_safe_dir_name ( ProjectSettings : : get_singleton ( ) - > get ( " application/config/custom_user_dir_name " ) , true ) ;
if ( custom_dir = = " " ) {
custom_dir = appname ;
}
return get_data_path ( ) . plus_file ( custom_dir ) . replace ( " \\ " , " / " ) ;
Add initial support for the XDG Base Directory spec
Spec version 0.7 from https://standards.freedesktop.org/basedir-spec/basedir-spec-0.7.html
(latest as of this commit).
Three virtual methods are added to OS for the various XDG paths we will use:
- OS::get_data_path gives XDG_DATA_HOME, or if missing:
~/.local/share on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_config_path gives XDG_CONFIG_HOME, or if missing:
~/.config on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_cache_path gives XDG_CACHE_HOME, or if missing:
~/.cache on X11, ~/Library/Caches on macOS and %APPDATA% on Windows
So for Windows there are no changes, for Linux we follow the full split spec
and for macOS stuff will move from ~/.godot to ~/Library/Application Support/Godot.
Support for system-wide installation of templates on Unix was removed for now,
as it's a bit hackish and I don't think anyone uses it.
user:// will still be OS::get_data_path() + "/godot/app_userdata/$name" by
default, but when using the application/config/use_shared_user_dir option
it will now use XDG_DATA_HOME/$name, e.g. ~/.local/share/MyGame.
For now everything still goes in EditorSettings::get_settings_dir(), but
this will be changed in a later commit to make use of the new splitting
where relevant.
Part of #3513.
2017-11-17 17:11:41 +01:00
} else {
2017-11-26 19:00:53 +01:00
return get_data_path ( ) . plus_file ( get_godot_dir_name ( ) ) . plus_file ( " app_userdata " ) . plus_file ( appname ) . replace ( " \\ " , " / " ) ;
2014-02-10 02:10:30 +01:00
}
}
2017-07-19 22:00:46 +02:00
return ProjectSettings : : get_singleton ( ) - > get_resource_path ( ) ;
2014-02-10 02:10:30 +01:00
}
2018-01-20 14:40:52 +01:00
String OS_Windows : : get_unique_id ( ) const {
HW_PROFILE_INFO HwProfInfo ;
ERR_FAIL_COND_V ( ! GetCurrentHwProfile ( & HwProfInfo ) , " " ) ;
2020-07-27 12:43:20 +02:00
return String : : utf16 ( ( const char16_t * ) ( HwProfInfo . szHwProfileGuid ) , HW_PROFILE_GUIDLEN ) ;
2018-01-20 14:40:52 +01:00
}
2017-07-19 22:00:46 +02:00
bool OS_Windows : : _check_internal_feature_support ( const String & p_feature ) {
2019-02-26 15:58:47 +01:00
return p_feature = = " pc " ;
2017-02-09 00:07:35 +01:00
}
2016-06-06 00:14:33 +02:00
2017-09-08 03:01:49 +02:00
void OS_Windows : : disable_crash_handler ( ) {
crash_handler . disable ( ) ;
}
bool OS_Windows : : is_disable_crash_handler ( ) const {
return crash_handler . is_disabled ( ) ;
}
2017-09-25 15:15:11 +02:00
Error OS_Windows : : move_to_trash ( const String & p_path ) {
2018-08-14 10:49:16 +02:00
SHFILEOPSTRUCTW sf ;
2020-07-27 12:43:20 +02:00
Char16String utf16 = p_path . utf16 ( ) ;
WCHAR * from = new WCHAR [ utf16 . length ( ) + 2 ] ;
wcscpy_s ( from , utf16 . length ( ) + 1 , ( LPCWSTR ) ( utf16 . get_data ( ) ) ) ;
from [ utf16 . length ( ) + 1 ] = 0 ;
2018-08-18 00:30:22 +02:00
2020-03-09 16:56:48 +01:00
sf . hwnd = main_window ;
2017-09-25 15:15:11 +02:00
sf . wFunc = FO_DELETE ;
2018-08-18 00:30:22 +02:00
sf . pFrom = from ;
2020-04-02 01:20:12 +02:00
sf . pTo = nullptr ;
2017-09-25 15:15:11 +02:00
sf . fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION ;
sf . fAnyOperationsAborted = FALSE ;
2020-04-02 01:20:12 +02:00
sf . hNameMappings = nullptr ;
sf . lpszProgressTitle = nullptr ;
2017-09-25 15:15:11 +02:00
2018-08-14 10:49:16 +02:00
int ret = SHFileOperationW ( & sf ) ;
2018-08-18 00:30:22 +02:00
delete [ ] from ;
2017-09-25 15:15:11 +02:00
if ( ret ) {
2019-11-06 17:03:04 +01:00
ERR_PRINT ( " SHFileOperation error: " + itos ( ret ) ) ;
2017-09-25 15:15:11 +02:00
return FAILED ;
}
return OK ;
}
2014-02-10 02:10:30 +01:00
OS_Windows : : OS_Windows ( HINSTANCE _hInstance ) {
2020-11-24 10:12:55 +01:00
ticks_per_second = 0 ;
ticks_start = 0 ;
main_loop = nullptr ;
process_map = nullptr ;
2017-03-05 16:44:50 +01:00
force_quit = false ;
2018-12-13 21:32:11 +01:00
2017-03-05 16:44:50 +01:00
hInstance = _hInstance ;
2014-02-10 02:10:30 +01:00
# ifdef STDOUT_FILE
2017-03-05 16:44:50 +01:00
stdo = fopen ( " stdout.txt " , " wb " ) ;
2014-02-10 02:10:30 +01:00
# endif
2017-08-27 19:01:34 +02:00
# ifdef WASAPI_ENABLED
AudioDriverManager : : add_driver ( & driver_wasapi ) ;
# endif
2016-10-17 17:40:45 +02:00
# ifdef XAUDIO2_ENABLED
2017-01-16 19:19:45 +01:00
AudioDriverManager : : add_driver ( & driver_xaudio2 ) ;
2016-10-17 17:40:45 +02:00
# endif
2017-09-22 07:56:02 +02:00
2020-03-09 16:56:48 +01:00
DisplayServerWindows : : register_windows_driver ( ) ;
2017-11-21 10:35:01 +01:00
Vector < Logger * > loggers ;
loggers . push_back ( memnew ( WindowsTerminalLogger ) ) ;
_set_logger ( memnew ( CompositeLogger ( loggers ) ) ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
OS_Windows : : ~ OS_Windows ( ) {
2014-02-10 02:10:30 +01:00
# ifdef STDOUT_FILE
fclose ( stdo ) ;
# endif
}