2014-02-10 01:10:30 +00:00
/*************************************************************************/
/* os_windows.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
2017-08-27 12:16:55 +00:00
/* https://godotengine.org */
2014-02-10 01:10:30 +00:00
/*************************************************************************/
2021-01-01 19:13:46 +00:00
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
2014-02-10 01:10:30 +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. */
/*************************************************************************/
2015-01-10 20:35:26 +00:00
2014-02-10 01:10:30 +00:00
# include "os_windows.h"
2016-12-21 05:29:58 +00:00
2020-02-27 02:30:20 +00:00
# include "core/debugger/engine_debugger.h"
# include "core/debugger/script_debugger.h"
2018-09-11 16:13:45 +00:00
# include "core/io/marshalls.h"
# include "core/version_generated.gen.h"
2021-09-23 06:56:12 +00:00
# include "drivers/unix/net_socket_posix.h"
2017-03-05 15:44:50 +00:00
# include "drivers/windows/dir_access_windows.h"
# include "drivers/windows/file_access_windows.h"
2019-02-12 14:43:54 +00:00
# include "joypad_windows.h"
2017-03-05 15:44:50 +00:00
# include "lang_table.h"
# include "main/main.h"
2020-03-09 15:56:48 +00:00
# include "platform/windows/display_server_windows.h"
2017-06-10 13:15:33 +00:00
# include "servers/audio_server.h"
2020-12-03 21:09:47 +00:00
# include "servers/rendering/rendering_server_default.h"
2017-09-22 05:56:02 +00:00
# include "windows_terminal_logger.h"
2014-12-02 17:02:41 +00:00
2019-02-12 14:43:54 +00:00
# include <avrt.h>
2019-02-20 12:00:19 +00:00
# include <direct.h>
2019-04-22 16:42:11 +00:00
# include <knownfolders.h>
2016-04-29 16:57:57 +00:00
# include <process.h>
2017-03-05 15:44:50 +00:00
# include <regstr.h>
# include <shlobj.h>
2015-02-12 03:17:29 +00:00
2014-02-10 01:10:30 +00:00
static const WORD MAX_CONSOLE_LINES = 1500 ;
2015-01-17 01:48:35 +00:00
extern " C " {
2018-11-02 22:10:44 +00:00
__declspec ( dllexport ) DWORD NvOptimusEnablement = 1 ;
__declspec ( dllexport ) int AmdPowerXpressRequestHighPerformance = 1 ;
2015-01-17 01:48:35 +00:00
}
2014-12-02 17:02:41 +00:00
2017-08-18 18:46:13 +00:00
// Workaround mingw-w64 < 4.0 bug
# ifndef WM_TOUCH
# define WM_TOUCH 576
2016-02-04 16:16:22 +00:00
# endif
2018-12-13 20:32:11 +00:00
# ifndef WM_POINTERUPDATE
# define WM_POINTERUPDATE 0x0245
# endif
2020-01-16 11:07:58 +00:00
# if defined(__GNUC__)
// Workaround GCC warning from -Wcast-function-type.
# define GetProcAddress (void *)GetProcAddress
# endif
2017-12-01 11:42:57 +00:00
static String format_error_message ( DWORD id ) {
2020-04-01 23:20:12 +00:00
LPWSTR messageBuffer = nullptr ;
2017-12-01 11:42:57 +00:00
size_t size = FormatMessageW ( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS ,
2020-04-01 23:20:12 +00:00
nullptr , id , MAKELANGID ( LANG_NEUTRAL , SUBLANG_DEFAULT ) , ( LPWSTR ) & messageBuffer , 0 , nullptr ) ;
2017-12-01 11:42:57 +00:00
2020-07-27 10:43:20 +00:00
String msg = " Error " + itos ( id ) + " : " + String : : utf16 ( ( const char16_t * ) messageBuffer , size ) ;
2017-12-01 11:42:57 +00:00
LocalFree ( messageBuffer ) ;
return msg ;
}
2014-02-10 01:10:30 +00: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 10:43:20 +00:00
GetConsoleScreenBufferInfo ( GetStdHandle ( STD_OUTPUT_HANDLE ) , & coninfo ) ;
2014-02-10 01:10:30 +00:00
coninfo . dwSize . Y = MAX_CONSOLE_LINES ;
2020-07-27 10:43:20 +00:00
SetConsoleScreenBufferSize ( GetStdHandle ( STD_OUTPUT_HANDLE ) , coninfo . dwSize ) ;
2014-02-10 01:10:30 +00:00
// redirect unbuffered STDOUT to the console
lStdHandle = ( intptr_t ) GetStdHandle ( STD_OUTPUT_HANDLE ) ;
hConHandle = _open_osfhandle ( lStdHandle , _O_TEXT ) ;
2017-03-05 15:44:50 +00:00
fp = _fdopen ( hConHandle , " w " ) ;
2014-02-10 01:10:30 +00:00
* stdout = * fp ;
2020-04-01 23:20:12 +00:00
setvbuf ( stdout , nullptr , _IONBF , 0 ) ;
2014-02-10 01:10:30 +00:00
// redirect unbuffered STDIN to the console
lStdHandle = ( intptr_t ) GetStdHandle ( STD_INPUT_HANDLE ) ;
hConHandle = _open_osfhandle ( lStdHandle , _O_TEXT ) ;
2017-03-05 15:44:50 +00:00
fp = _fdopen ( hConHandle , " r " ) ;
2014-02-10 01:10:30 +00:00
* stdin = * fp ;
2020-04-01 23:20:12 +00:00
setvbuf ( stdin , nullptr , _IONBF , 0 ) ;
2014-02-10 01:10:30 +00:00
2020-03-09 15:56:48 +00:00
// redirect unbuffered STDERR to the console
2015-03-22 22:00:50 +00:00
2020-03-09 15:56:48 +00:00
lStdHandle = ( intptr_t ) GetStdHandle ( STD_ERROR_HANDLE ) ;
2015-03-22 22:00:50 +00:00
2020-03-09 15:56:48 +00:00
hConHandle = _open_osfhandle ( lStdHandle , _O_TEXT ) ;
2017-12-27 19:51:19 +00:00
2020-03-09 15:56:48 +00:00
fp = _fdopen ( hConHandle , " w " ) ;
2017-12-27 19:51:19 +00:00
2020-03-09 15:56:48 +00:00
* stderr = * fp ;
2017-12-27 19:51:19 +00:00
2020-04-01 23:20:12 +00:00
setvbuf ( stderr , nullptr , _IONBF , 0 ) ;
2017-12-27 19:51:19 +00:00
2020-03-09 15:56:48 +00:00
// make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog
2019-11-28 12:41:07 +00:00
2020-03-09 15:56:48 +00:00
// point to console as well
2019-11-28 12:41:07 +00:00
}
2020-03-09 15:56:48 +00:00
BOOL WINAPI HandlerRoutine ( _In_ DWORD dwCtrlType ) {
if ( ! EngineDebugger : : is_active ( ) )
return FALSE ;
2018-12-18 13:17:43 +00:00
2020-03-09 15:56:48 +00: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 13:17:43 +00:00
}
2021-07-22 16:23:48 +00: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 15:56:48 +00:00
void OS_Windows : : initialize_debugging ( ) {
SetConsoleCtrlHandler ( HandlerRoutine , TRUE ) ;
2017-12-10 18:38:26 +00:00
}
2020-03-09 15:56:48 +00:00
void OS_Windows : : initialize ( ) {
crash_handler . initialize ( ) ;
2017-12-10 18:38:26 +00:00
2020-03-09 15:56:48 +00:00
//RedirectIOToConsole();
2017-12-10 18:38:26 +00:00
2020-03-09 15:56:48 +00: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 18:38:26 +00:00
2020-03-09 15:56:48 +00:00
NetSocketPosix : : make_default ( ) ;
2017-12-10 18:38:26 +00:00
2020-03-09 15:56:48 +00: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 18:38:26 +00:00
2020-03-09 15:56:48 +00: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 18:38:26 +00:00
2020-03-09 15:56:48 +00:00
process_map = memnew ( ( Map < ProcessID , ProcessInfo > ) ) ;
2017-12-10 18:38:26 +00:00
2020-05-11 14:26:10 +00: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 00:48:18 +00:00
IPUnix : : make_default ( ) ;
2020-04-01 23:20:12 +00:00
main_loop = nullptr ;
2017-12-10 18:38:26 +00:00
}
2020-03-09 15:56:48 +00:00
void OS_Windows : : delete_main_loop ( ) {
if ( main_loop )
memdelete ( main_loop ) ;
2020-04-01 23:20:12 +00:00
main_loop = nullptr ;
2017-12-10 18:38:26 +00:00
}
2020-03-09 15:56:48 +00:00
void OS_Windows : : set_main_loop ( MainLoop * p_main_loop ) {
main_loop = p_main_loop ;
2017-12-10 18:38:26 +00:00
}
2020-03-09 15:56:48 +00:00
void OS_Windows : : finalize ( ) {
# ifdef WINMIDI_ENABLED
driver_midi . close ( ) ;
# endif
2017-07-10 00:48:22 +00:00
2020-03-09 15:56:48 +00:00
if ( main_loop )
memdelete ( main_loop ) ;
2016-01-03 04:18:28 +00:00
2020-04-01 23:20:12 +00:00
main_loop = nullptr ;
2016-01-03 04:18:28 +00:00
}
2020-03-09 15:56:48 +00:00
void OS_Windows : : finalize_core ( ) {
timeEndPeriod ( 1 ) ;
2017-12-27 19:51:19 +00:00
2020-03-09 15:56:48 +00:00
memdelete ( process_map ) ;
NetSocketPosix : : cleanup ( ) ;
2017-07-10 00:48:22 +00:00
}
2017-11-30 13:00:10 +00:00
Error OS_Windows : : open_dynamic_library ( const String p_path , void * & p_library_handle , bool p_also_set_library_path ) {
2020-10-22 10:17:21 +00:00
String path = p_path . replace ( " / " , " \\ " ) ;
2018-01-04 18:42:29 +00: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 12:29:01 +00: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-01 23:20:12 +00:00
bool has_dll_directory_api = ( ( add_dll_directory ! = nullptr ) & & ( remove_dll_directory ! = nullptr ) ) ;
DLL_DIRECTORY_COOKIE cookie = nullptr ;
2017-11-30 13:00:10 +00:00
2017-12-06 12:29:01 +00:00
if ( p_also_set_library_path & & has_dll_directory_api ) {
2020-07-27 10:43:20 +00:00
cookie = add_dll_directory ( ( LPCWSTR ) ( path . get_base_dir ( ) . utf16 ( ) . get_data ( ) ) ) ;
2017-11-30 13:00:10 +00:00
}
2020-07-27 10:43:20 +00: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 04:49:33 +00: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 13:00:10 +00:00
2018-01-26 10:48:20 +00:00
if ( cookie ) {
2017-12-06 12:29:01 +00:00
remove_dll_directory ( cookie ) ;
2017-11-30 13:00:10 +00:00
}
2017-03-08 01:50:13 +00:00
return OK ;
}
2017-04-03 14:11:38 +00:00
Error OS_Windows : : close_dynamic_library ( void * p_library_handle ) {
if ( ! FreeLibrary ( ( HMODULE ) p_library_handle ) ) {
2017-03-08 01:50:13 +00:00
return FAILED ;
}
return OK ;
}
2017-07-27 07:23:21 +00: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 14:11:38 +00:00
p_symbol_handle = ( void * ) GetProcAddress ( ( HMODULE ) p_library_handle , p_name . utf8 ( ) . get_data ( ) ) ;
2017-03-08 01:50:13 +00:00
if ( ! p_symbol_handle ) {
2017-07-27 07:23:21 +00:00
if ( ! p_optional ) {
2019-08-09 04:49:33 +00:00
ERR_FAIL_V_MSG ( ERR_CANT_RESOLVE , " Can't resolve symbol " + p_name + " , error: " + String : : num ( GetLastError ( ) ) + " . " ) ;
2017-07-27 07:23:21 +00:00
} else {
return ERR_CANT_RESOLVE ;
}
2017-03-08 01:50:13 +00:00
}
return OK ;
}
2019-05-20 17:36:24 +00:00
String OS_Windows : : get_name ( ) const {
2014-02-10 01:10:30 +00:00
return " Windows " ;
}
2021-10-28 15:16:47 +00:00
OS : : Date OS_Windows : : get_date ( bool p_utc ) const {
2014-02-10 01:10:30 +00:00
SYSTEMTIME systemtime ;
2021-10-28 15:16:47 +00:00
if ( p_utc ) {
2015-06-06 01:40:56 +00:00
GetSystemTime ( & systemtime ) ;
2021-10-28 15:16:47 +00:00
} else {
2015-06-06 01:40:56 +00:00
GetLocalTime ( & systemtime ) ;
2021-10-28 15:16:47 +00:00
}
2015-06-07 13:06:13 +00:00
2014-02-10 01:10:30 +00:00
Date date ;
2017-03-05 15:44:50 +00: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 01:10:30 +00:00
return date ;
}
2020-05-14 12:29:06 +00:00
2021-10-28 15:16:47 +00:00
OS : : Time OS_Windows : : get_time ( bool p_utc ) const {
2014-02-10 01:10:30 +00:00
SYSTEMTIME systemtime ;
2021-10-28 15:16:47 +00:00
if ( p_utc ) {
2015-06-06 01:40:56 +00:00
GetSystemTime ( & systemtime ) ;
2021-10-28 15:16:47 +00:00
} else {
2015-06-06 01:40:56 +00:00
GetLocalTime ( & systemtime ) ;
2021-10-28 15:16:47 +00:00
}
2014-02-10 01:10:30 +00:00
Time time ;
2017-03-05 15:44:50 +00:00
time . hour = systemtime . wHour ;
2021-05-24 11:54:05 +00:00
time . minute = systemtime . wMinute ;
time . second = systemtime . wSecond ;
2014-02-10 01:10:30 +00:00
return time ;
}
2015-06-06 03:35:38 +00:00
OS : : TimeZoneInfo OS_Windows : : get_time_zone_info ( ) const {
TIME_ZONE_INFORMATION info ;
bool daylight = false ;
2015-06-07 14:10:33 +00:00
if ( GetTimeZoneInformation ( & info ) = = TIME_ZONE_ID_DAYLIGHT )
2015-06-06 03:35:38 +00:00
daylight = true ;
2015-06-07 14:10:33 +00:00
TimeZoneInfo ret ;
2015-06-06 03:35:38 +00:00
if ( daylight ) {
ret . name = info . DaylightName ;
} else {
ret . name = info . StandardName ;
}
2019-02-13 00:41:19 +00:00
// Bias value returned by GetTimeZoneInformation is inverted of what we expect
2021-03-12 13:35:16 +00:00
// For example, on GMT-3 GetTimeZoneInformation return a Bias of 180, so invert the value to get -180
2019-02-13 00:41:19 +00:00
ret . bias = - info . Bias ;
2015-06-06 03:35:38 +00:00
return ret ;
}
2014-02-10 01:10:30 +00:00
2020-05-31 12:19:31 +00: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 17:09:21 +00:00
2015-08-06 17:29:33 +00:00
SYSTEMTIME st ;
GetSystemTime ( & st ) ;
2016-01-10 21:24:55 +00:00
FILETIME ft ;
2017-03-05 15:44:50 +00:00
SystemTimeToFileTime ( & st , & ft ) ;
2020-05-31 12:19:31 +00:00
uint64_t ticks_time ;
ticks_time = ft . dwHighDateTime ;
ticks_time < < = 32 ;
ticks_time | = ft . dwLowDateTime ;
2016-06-11 17:09:21 +00:00
2020-05-31 12:19:31 +00:00
return ( double ) ( ticks_time - TICKS_TO_UNIX_EPOCH ) / WINDOWS_TICKS_PER_SECOND ;
2015-08-06 17:29:33 +00:00
}
2014-02-10 01:10:30 +00:00
void OS_Windows : : delay_usec ( uint32_t p_usec ) const {
2017-03-05 15:44:50 +00:00
if ( p_usec < 1000 )
Sleep ( 1 ) ;
else
Sleep ( p_usec / 1000 ) ;
2014-02-10 01:10:30 +00:00
}
2020-05-14 12:29:06 +00:00
2014-02-10 01:10:30 +00:00
uint64_t OS_Windows : : get_ticks_usec ( ) const {
2017-03-05 15:44:50 +00:00
uint64_t ticks ;
2020-05-22 11:20:19 +00:00
2017-03-05 15:44:50 +00:00
// This is the number of clock ticks since start
if ( ! QueryPerformanceCounter ( ( LARGE_INTEGER * ) & ticks ) )
ticks = ( UINT64 ) timeGetTime ( ) ;
2020-05-22 11:20:19 +00:00
2017-03-05 15:44:50 +00:00
// Divide by frequency to get the time in seconds
2020-05-22 11:20:19 +00: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 15:44:50 +00:00
// Subtract the time at game start to get
// the time since the game started
time - = ticks_start ;
return time ;
2014-02-10 01:10:30 +00:00
}
2020-05-19 13:34:15 +00: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 10:43:20 +00:00
char32_t c = p_text [ i ] ;
2020-05-19 13:34:15 +00: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 18:49:13 +00: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 10:17:21 +00:00
String path = p_path . replace ( " / " , " \\ " ) ;
2020-12-18 18:49:13 +00:00
String command = _quote_command_line_argument ( path ) ;
2021-07-16 03:45:57 +00:00
for ( const String & E : p_arguments ) {
command + = " " + _quote_command_line_argument ( E ) ;
2020-12-18 18:49:13 +00:00
}
2020-10-22 10:17:21 +00:00
2020-12-18 18:49:13 +00:00
if ( r_pipe ) {
2019-03-01 22:51:53 +00:00
if ( read_stderr ) {
2020-12-18 18:49:13 +00:00
command + = " 2>&1 " ; // Include stderr
2014-02-10 01:10:30 +00:00
}
2020-12-18 18:49:13 +00: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 01:10:30 +00:00
2020-12-18 18:49:13 +00: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 01:10:30 +00:00
char buf [ 65535 ] ;
2017-03-05 15:44:50 +00:00
while ( fgets ( buf , 65535 , f ) ) {
2019-04-07 18:46:52 +00:00
if ( p_pipe_mutex ) {
p_pipe_mutex - > lock ( ) ;
}
2020-02-19 18:59:37 +00:00
( * r_pipe ) + = String : : utf8 ( buf ) ;
2019-04-07 18:46:52 +00:00
if ( p_pipe_mutex ) {
2019-04-24 18:52:15 +00:00
p_pipe_mutex - > unlock ( ) ;
2019-04-07 18:46:52 +00:00
}
2014-02-10 01:10:30 +00:00
}
int rv = _pclose ( f ) ;
2020-12-18 18:49:13 +00:00
2020-05-19 13:34:15 +00:00
if ( r_exitcode ) {
2017-03-05 15:44:50 +00:00
* r_exitcode = rv ;
2020-05-19 13:34:15 +00:00
}
2014-02-10 01:10:30 +00:00
return OK ;
}
2020-12-18 18:49:13 +00: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 ;
2021-11-04 12:50:45 +00:00
int ret = CreateProcessW ( nullptr , ( LPWSTR ) ( command . utf16 ( ) . ptrw ( ) ) , nullptr , nullptr , false , NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW , nullptr , nullptr , si_w , & pi . pi ) ;
2020-12-18 18:49:13 +00:00
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 03:45:57 +00:00
for ( const String & E : p_arguments ) {
command + = " " + _quote_command_line_argument ( E ) ;
2020-05-19 13:34:15 +00:00
}
2014-02-10 01:10:30 +00:00
ProcessInfo pi ;
2017-03-05 15:44:50 +00:00
ZeroMemory ( & pi . si , sizeof ( pi . si ) ) ;
2014-02-10 01:10:30 +00:00
pi . si . cb = sizeof ( pi . si ) ;
2017-03-05 15:44:50 +00:00
ZeroMemory ( & pi . pi , sizeof ( pi . pi ) ) ;
LPSTARTUPINFOW si_w = ( LPSTARTUPINFOW ) & pi . si ;
2014-02-10 01:10:30 +00:00
2021-11-04 12:50:45 +00:00
int ret = CreateProcessW ( nullptr , ( LPWSTR ) ( command . utf16 ( ) . ptrw ( ) ) , nullptr , nullptr , false , NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW , nullptr , nullptr , si_w , & pi . pi ) ;
2020-12-18 18:49:13 +00:00
ERR_FAIL_COND_V_MSG ( ret = = 0 , ERR_CANT_FORK , " Could not create child process: " + command ) ;
2014-02-10 01:10:30 +00:00
2020-12-18 18:49:13 +00:00
ProcessID pid = pi . pi . dwProcessId ;
if ( r_child_id ) {
* r_child_id = pid ;
2020-05-19 13:34:15 +00:00
}
2020-12-18 18:49:13 +00:00
process_map - > insert ( pid , pi ) ;
2014-02-10 01:10:30 +00:00
return OK ;
} ;
2018-08-27 15:32:43 +00:00
Error OS_Windows : : kill ( const ProcessID & p_pid ) {
2018-07-30 07:55:33 +00:00
ERR_FAIL_COND_V ( ! process_map - > has ( p_pid ) , FAILED ) ;
2014-02-10 01:10:30 +00:00
2018-07-30 07:55:33 +00:00
const PROCESS_INFORMATION pi = ( * process_map ) [ p_pid ] . pi ;
process_map - > erase ( p_pid ) ;
2014-02-10 01:10:30 +00:00
2018-08-27 15:32:43 +00:00
const int ret = TerminateProcess ( pi . hProcess , 0 ) ;
2014-02-10 01:10:30 +00:00
2018-07-30 07:55:33 +00:00
CloseHandle ( pi . hProcess ) ;
CloseHandle ( pi . hThread ) ;
2014-02-10 01:10:30 +00:00
2018-08-27 15:32:43 +00:00
return ret ! = 0 ? OK : FAILED ;
} ;
2014-02-10 01:10:30 +00:00
2017-08-07 10:17:31 +00:00
int OS_Windows : : get_process_id ( ) const {
2016-04-29 16:57:57 +00:00
return _getpid ( ) ;
}
2017-03-05 15:44:50 +00:00
Error OS_Windows : : set_cwd ( const String & p_cwd ) {
2020-07-27 10:43:20 +00:00
if ( _wchdir ( ( LPCWSTR ) ( p_cwd . utf16 ( ) . get_data ( ) ) ) ! = 0 )
2014-02-10 01:10:30 +00:00
return ERR_CANT_OPEN ;
return OK ;
}
2014-02-15 05:01:39 +00:00
String OS_Windows : : get_executable_path ( ) const {
2020-07-27 10:43:20 +00:00
WCHAR bufname [ 4096 ] ;
2020-04-01 23:20:12 +00:00
GetModuleFileNameW ( nullptr , bufname , 4096 ) ;
2020-10-22 10:17:21 +00:00
String s = String : : utf16 ( ( const char16_t * ) bufname ) . replace ( " \\ " , " / " ) ;
2014-02-15 05:01:39 +00:00
return s ;
}
2017-03-05 15:44:50 +00:00
bool OS_Windows : : has_environment ( const String & p_var ) const {
2018-10-04 13:38:52 +00:00
# ifdef MINGW_ENABLED
2020-07-27 10:43:20 +00:00
return _wgetenv ( ( LPCWSTR ) ( p_var . utf16 ( ) . get_data ( ) ) ) ! = nullptr ;
2018-10-04 13:38:52 +00:00
# else
2020-07-27 10:43:20 +00:00
WCHAR * env ;
2018-10-04 13:38:52 +00:00
size_t len ;
2020-07-27 10:43:20 +00:00
_wdupenv_s ( & env , & len , ( LPCWSTR ) ( p_var . utf16 ( ) . get_data ( ) ) ) ;
2020-04-01 23:20:12 +00:00
const bool has_env = env ! = nullptr ;
2018-10-04 13:38:52 +00:00
free ( env ) ;
return has_env ;
# endif
2014-02-10 01:10:30 +00:00
} ;
2017-03-05 15:44:50 +00:00
String OS_Windows : : get_environment ( const String & p_var ) const {
2020-07-27 10:43:20 +00: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 15:44:50 +00:00
if ( wlen > 0 ) {
2020-07-27 10:43:20 +00:00
return String : : utf16 ( ( const char16_t * ) wval ) ;
2015-05-04 16:12:05 +00:00
}
2014-02-13 21:03:28 +00:00
return " " ;
2015-05-04 16:12:05 +00:00
}
2014-02-10 01:10:30 +00:00
2019-01-29 21:59:38 +00:00
bool OS_Windows : : set_environment ( const String & p_var , const String & p_value ) const {
2020-07-27 10:43:20 +00:00
return ( bool ) SetEnvironmentVariableW ( ( LPCWSTR ) ( p_var . utf16 ( ) . get_data ( ) ) , ( LPCWSTR ) ( p_value . utf16 ( ) . get_data ( ) ) ) ;
2019-01-29 21:59:38 +00:00
}
2014-02-10 01:10:30 +00:00
String OS_Windows : : get_stdin_string ( bool p_block ) {
if ( p_block ) {
char buff [ 1024 ] ;
2017-03-05 15:44:50 +00:00
return fgets ( buff , 1024 , stdin ) ;
2014-02-10 01:10:30 +00:00
} ;
return String ( ) ;
}
2014-04-18 14:43:54 +00:00
Error OS_Windows : : shell_open ( String p_uri ) {
2021-09-19 10:29:56 +00:00
INT_PTR ret = ( INT_PTR ) ShellExecuteW ( nullptr , nullptr , ( LPCWSTR ) ( p_uri . utf16 ( ) . get_data ( ) ) , nullptr , nullptr , SW_SHOWNORMAL ) ;
if ( ret > 32 ) {
return OK ;
} else {
switch ( ret ) {
case ERROR_FILE_NOT_FOUND :
case SE_ERR_DLLNOTFOUND :
return ERR_FILE_NOT_FOUND ;
case ERROR_PATH_NOT_FOUND :
return ERR_FILE_BAD_PATH ;
case ERROR_BAD_FORMAT :
return ERR_FILE_CORRUPT ;
case SE_ERR_ACCESSDENIED :
return ERR_UNAUTHORIZED ;
case 0 :
case SE_ERR_OOM :
return ERR_OUT_OF_MEMORY ;
default :
return FAILED ;
}
}
2014-04-18 14:43:54 +00:00
}
2014-02-10 01:10:30 +00:00
String OS_Windows : : get_locale ( ) const {
const _WinLocale * wl = & _win_locales [ 0 ] ;
LANGID langid = GetUserDefaultUILanguage ( ) ;
String neutral ;
2020-07-25 20:42:11 +00:00
int lang = PRIMARYLANGID ( langid ) ;
int sublang = SUBLANGID ( langid ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
while ( wl - > locale ) {
if ( wl - > main_lang = = lang & & wl - > sublang = = SUBLANG_NEUTRAL )
neutral = wl - > locale ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( lang = = wl - > main_lang & & sublang = = wl - > sublang )
2020-07-25 20:42:11 +00:00
return String ( wl - > locale ) . replace ( " - " , " _ " ) ;
2014-02-10 01:10:30 +00:00
wl + + ;
}
2017-03-05 15:44:50 +00:00
if ( neutral ! = " " )
2020-07-25 20:42:11 +00:00
return String ( neutral ) . replace ( " - " , " _ " ) ;
2014-02-10 01:10:30 +00:00
return " en " ;
}
2018-01-29 15:46:30 +00: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 01:10:30 +00:00
void OS_Windows : : run ( ) {
if ( ! main_loop )
return ;
2016-03-08 23:00:52 +00:00
2020-12-22 09:50:29 +00:00
main_loop - > initialize ( ) ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
while ( ! force_quit ) {
2020-03-09 15:56:48 +00:00
DisplayServer : : get_singleton ( ) - > process_events ( ) ; // get rid of pending events
2018-10-03 17:40:37 +00:00
if ( Main : : iteration ( ) )
2014-02-10 01:10:30 +00:00
break ;
} ;
2016-03-08 23:00:52 +00:00
2020-12-22 09:50:29 +00:00
main_loop - > finalize ( ) ;
2014-02-10 01:10:30 +00: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 16:11:41 +00:00
String OS_Windows : : get_config_path ( ) const {
2021-05-07 17:02:35 +00: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 13:41:22 +00:00
if ( get_environment ( " XDG_CONFIG_HOME " ) . is_absolute_path ( ) ) {
2021-07-03 20:41:17 +00:00
return get_environment ( " XDG_CONFIG_HOME " ) . replace ( " \\ " , " / " ) ;
2021-05-07 17:02:35 +00: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 10:48:12 +00:00
}
if ( has_environment ( " APPDATA " ) ) {
2021-07-03 20:41:17 +00: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 16:11:41 +00:00
}
2021-05-21 10:48:12 +00: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 16:11:41 +00:00
}
String OS_Windows : : get_data_path ( ) const {
2021-05-07 17:02:35 +00: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 16:11:41 +00:00
if ( has_environment ( " XDG_DATA_HOME " ) ) {
2021-06-03 13:41:22 +00:00
if ( get_environment ( " XDG_DATA_HOME " ) . is_absolute_path ( ) ) {
2021-07-03 20:41:17 +00:00
return get_environment ( " XDG_DATA_HOME " ) . replace ( " \\ " , " / " ) ;
2021-05-07 17:02:35 +00: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 16:11:41 +00:00
}
2021-05-21 10:48:12 +00: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 16:11:41 +00:00
}
String OS_Windows : : get_cache_path ( ) const {
2021-02-22 21:54:12 +00:00
static String cache_path_cache ;
if ( cache_path_cache . is_empty ( ) ) {
// 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_CACHE_HOME " ) ) {
if ( get_environment ( " XDG_CACHE_HOME " ) . is_absolute_path ( ) ) {
cache_path_cache = get_environment ( " XDG_CACHE_HOME " ) . replace ( " \\ " , " / " ) ;
} else {
WARN_PRINT_ONCE ( " `XDG_CACHE_HOME` is a relative path. Ignoring its value and falling back to `%LOCALAPPDATA% \\ cache`, `%TEMP%` or `get_config_path()` per the XDG Base Directory specification. " ) ;
}
}
if ( cache_path_cache . is_empty ( ) & & has_environment ( " LOCALAPPDATA " ) ) {
cache_path_cache = get_environment ( " LOCALAPPDATA " ) . replace ( " \\ " , " / " ) ;
}
if ( cache_path_cache . is_empty ( ) & & has_environment ( " TEMP " ) ) {
cache_path_cache = get_environment ( " TEMP " ) . replace ( " \\ " , " / " ) ;
}
if ( cache_path_cache . is_empty ( ) ) {
cache_path_cache = get_config_path ( ) ;
2021-05-07 17:02:35 +00:00
}
2021-05-21 10:48:12 +00:00
}
2021-02-22 21:54:12 +00:00
return cache_path_cache ;
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 16:11:41 +00:00
}
// Get properly capitalized engine name for system paths
String OS_Windows : : get_godot_dir_name ( ) const {
2017-11-19 20:18:01 +00: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 16:11:41 +00:00
}
2021-07-11 01:39:31 +00:00
String OS_Windows : : get_system_dir ( SystemDir p_dir , bool p_shared_storage ) const {
2019-04-18 02:43:33 +00:00
KNOWNFOLDERID id ;
2014-12-02 17:02:41 +00:00
2017-03-05 15:44:50 +00:00
switch ( p_dir ) {
2014-12-02 17:02:41 +00:00
case SYSTEM_DIR_DESKTOP : {
2019-04-18 02:43:33 +00:00
id = FOLDERID_Desktop ;
2014-12-02 17:02:41 +00:00
} break ;
case SYSTEM_DIR_DCIM : {
2019-04-18 02:43:33 +00:00
id = FOLDERID_Pictures ;
2014-12-02 17:02:41 +00:00
} break ;
case SYSTEM_DIR_DOCUMENTS : {
2019-04-18 02:43:33 +00:00
id = FOLDERID_Documents ;
2014-12-02 17:02:41 +00:00
} break ;
case SYSTEM_DIR_DOWNLOADS : {
2019-04-18 02:43:33 +00:00
id = FOLDERID_Downloads ;
2014-12-02 17:02:41 +00:00
} break ;
case SYSTEM_DIR_MOVIES : {
2019-04-18 02:43:33 +00:00
id = FOLDERID_Videos ;
2014-12-02 17:02:41 +00:00
} break ;
case SYSTEM_DIR_MUSIC : {
2019-04-18 02:43:33 +00:00
id = FOLDERID_Music ;
2014-12-02 17:02:41 +00:00
} break ;
case SYSTEM_DIR_PICTURES : {
2019-04-18 02:43:33 +00:00
id = FOLDERID_Pictures ;
2014-12-02 17:02:41 +00:00
} break ;
case SYSTEM_DIR_RINGTONES : {
2019-04-18 02:43:33 +00:00
id = FOLDERID_Music ;
2014-12-02 17:02:41 +00:00
} break ;
}
2019-04-18 02:43:33 +00:00
PWSTR szPath ;
2020-04-01 23:20:12 +00:00
HRESULT res = SHGetKnownFolderPath ( id , 0 , nullptr , & szPath ) ;
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND_V ( res ! = S_OK , String ( ) ) ;
2021-07-03 20:41:17 +00:00
String path = String : : utf16 ( ( const char16_t * ) szPath ) . replace ( " \\ " , " / " ) ;
2019-04-18 02:43:33 +00:00
CoTaskMemFree ( szPath ) ;
return path ;
2014-12-02 17:02:41 +00:00
}
2014-02-10 01:10:30 +00: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 16:11:41 +00:00
String OS_Windows : : get_user_data_dir ( ) const {
2017-11-26 18:00:53 +00: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 16:11:41 +00:00
if ( appname ! = " " ) {
2017-11-26 18:00:53 +00: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 16:11:41 +00:00
} else {
2017-11-26 18:00:53 +00:00
return get_data_path ( ) . plus_file ( get_godot_dir_name ( ) ) . plus_file ( " app_userdata " ) . plus_file ( appname ) . replace ( " \\ " , " / " ) ;
2014-02-10 01:10:30 +00:00
}
}
2021-11-18 00:36:13 +00:00
return get_data_path ( ) . plus_file ( get_godot_dir_name ( ) ) . plus_file ( " app_userdata " ) . plus_file ( " [unnamed project] " ) ;
2014-02-10 01:10:30 +00:00
}
2018-01-20 13:40:52 +00:00
String OS_Windows : : get_unique_id ( ) const {
HW_PROFILE_INFO HwProfInfo ;
ERR_FAIL_COND_V ( ! GetCurrentHwProfile ( & HwProfInfo ) , " " ) ;
2020-07-27 10:43:20 +00:00
return String : : utf16 ( ( const char16_t * ) ( HwProfInfo . szHwProfileGuid ) , HW_PROFILE_GUIDLEN ) ;
2018-01-20 13:40:52 +00:00
}
2017-07-19 20:00:46 +00:00
bool OS_Windows : : _check_internal_feature_support ( const String & p_feature ) {
2019-02-26 14:58:47 +00:00
return p_feature = = " pc " ;
2017-02-08 23:07:35 +00:00
}
2016-06-05 22:14:33 +00:00
2017-09-08 01:01:49 +00: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 13:15:11 +00:00
Error OS_Windows : : move_to_trash ( const String & p_path ) {
2018-08-14 08:49:16 +00:00
SHFILEOPSTRUCTW sf ;
2020-07-27 10:43:20 +00: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-17 22:30:22 +00:00
2020-03-09 15:56:48 +00:00
sf . hwnd = main_window ;
2017-09-25 13:15:11 +00:00
sf . wFunc = FO_DELETE ;
2018-08-17 22:30:22 +00:00
sf . pFrom = from ;
2020-04-01 23:20:12 +00:00
sf . pTo = nullptr ;
2017-09-25 13:15:11 +00:00
sf . fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION ;
sf . fAnyOperationsAborted = FALSE ;
2020-04-01 23:20:12 +00:00
sf . hNameMappings = nullptr ;
sf . lpszProgressTitle = nullptr ;
2017-09-25 13:15:11 +00:00
2018-08-14 08:49:16 +00:00
int ret = SHFileOperationW ( & sf ) ;
2018-08-17 22:30:22 +00:00
delete [ ] from ;
2017-09-25 13:15:11 +00:00
if ( ret ) {
2019-11-06 16:03:04 +00:00
ERR_PRINT ( " SHFileOperation error: " + itos ( ret ) ) ;
2017-09-25 13:15:11 +00:00
return FAILED ;
}
return OK ;
}
2014-02-10 01:10:30 +00:00
OS_Windows : : OS_Windows ( HINSTANCE _hInstance ) {
2020-11-24 09:12:55 +00:00
ticks_per_second = 0 ;
ticks_start = 0 ;
main_loop = nullptr ;
process_map = nullptr ;
2017-03-05 15:44:50 +00:00
force_quit = false ;
2018-12-13 20:32:11 +00:00
2017-03-05 15:44:50 +00:00
hInstance = _hInstance ;
2014-02-10 01:10:30 +00:00
# ifdef STDOUT_FILE
2017-03-05 15:44:50 +00:00
stdo = fopen ( " stdout.txt " , " wb " ) ;
2014-02-10 01:10:30 +00:00
# endif
2017-08-27 17:01:34 +00:00
# ifdef WASAPI_ENABLED
AudioDriverManager : : add_driver ( & driver_wasapi ) ;
# endif
2016-10-17 15:40:45 +00:00
# ifdef XAUDIO2_ENABLED
2017-01-16 18:19:45 +00:00
AudioDriverManager : : add_driver ( & driver_xaudio2 ) ;
2016-10-17 15:40:45 +00:00
# endif
2017-09-22 05:56:02 +00:00
2020-03-09 15:56:48 +00:00
DisplayServerWindows : : register_windows_driver ( ) ;
2017-11-21 09:35:01 +00:00
Vector < Logger * > loggers ;
loggers . push_back ( memnew ( WindowsTerminalLogger ) ) ;
_set_logger ( memnew ( CompositeLogger ( loggers ) ) ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
OS_Windows : : ~ OS_Windows ( ) {
2014-02-10 01:10:30 +00:00
# ifdef STDOUT_FILE
fclose ( stdo ) ;
# endif
}