Browse Source

Refactored Input, create DisplayServer and DisplayServerX11

Juan Linietsky 5 years ago
parent
commit
4396e98834
95 changed files with 4820 additions and 693 deletions
  1. 1 0
      core/SCsub
  2. 1 1
      core/debugger/remote_debugger.cpp
  3. 1 1
      core/global_constants.cpp
  4. 20 0
      core/input/SCsub
  5. 0 0
      core/input/default_controller_mappings.h
  6. 0 0
      core/input/gamecontrollerdb.txt
  7. 0 0
      core/input/gamecontrollerdb_204.txt
  8. 0 0
      core/input/gamecontrollerdb_205.txt
  9. 0 0
      core/input/godotcontrollerdb.txt
  10. 257 128
      core/input/input.cpp
  11. 128 79
      core/input/input.h
  12. 73 0
      core/input/input_builders.py
  13. 32 2
      core/input/input_event.cpp
  14. 22 6
      core/input/input_event.h
  15. 0 0
      core/input/input_map.cpp
  16. 1 1
      core/input/input_map.h
  17. 3 0
      core/method_ptrcall.h
  18. 0 157
      core/os/input.cpp
  19. 0 146
      core/os/input.h
  20. 1 1
      core/os/main_loop.h
  21. 2 2
      core/os/midi_driver.cpp
  22. 1 1
      core/os/os.cpp
  23. 2 2
      core/register_core_types.cpp
  24. 3 0
      core/type_info.h
  25. 1 1
      core/variant_parser.cpp
  26. 1 1
      editor/animation_track_editor.cpp
  27. 1 1
      editor/code_editor.cpp
  28. 1 1
      editor/editor_audio_buses.cpp
  29. 1 1
      editor/editor_help.cpp
  30. 2 3
      editor/editor_node.cpp
  31. 1 1
      editor/editor_spin_slider.cpp
  32. 1 1
      editor/export_template_manager.cpp
  33. 1 1
      editor/plugins/animation_blend_space_2d_editor.cpp
  34. 1 1
      editor/plugins/animation_blend_tree_editor_plugin.cpp
  35. 1 1
      editor/plugins/animation_player_editor_plugin.cpp
  36. 1 1
      editor/plugins/animation_state_machine_editor.cpp
  37. 1 1
      editor/plugins/animation_tree_editor_plugin.cpp
  38. 1 1
      editor/plugins/asset_library_editor_plugin.cpp
  39. 1 1
      editor/plugins/canvas_item_editor_plugin.cpp
  40. 1 1
      editor/plugins/collision_polygon_editor_plugin.cpp
  41. 1 1
      editor/plugins/curve_editor_plugin.cpp
  42. 1 1
      editor/plugins/polygon_2d_editor_plugin.cpp
  43. 1 1
      editor/plugins/script_editor_plugin.cpp
  44. 1 1
      editor/plugins/spatial_editor_plugin.cpp
  45. 1 1
      editor/plugins/texture_region_editor_plugin.cpp
  46. 1 1
      editor/plugins/tile_map_editor_plugin.cpp
  47. 1 1
      editor/plugins/tile_set_editor_plugin.cpp
  48. 1 1
      editor/plugins/visual_shader_editor_plugin.cpp
  49. 1 1
      editor/project_settings_editor.cpp
  50. 1 1
      editor/property_editor.cpp
  51. 1 1
      editor/scene_tree_dock.cpp
  52. 0 9
      main/SCsub
  53. 3 3
      main/main.cpp
  54. 0 62
      main/main_builders.py
  55. 1 1
      modules/arkit/arkit_interface.mm
  56. 6 6
      modules/gdnative/arvr/arvr_interface_gdnative.cpp
  57. 1 1
      modules/gridmap/grid_map_editor_plugin.cpp
  58. 1 1
      modules/mobile_vr/mobile_vr_interface.cpp
  59. 1 1
      modules/visual_script/visual_script_editor.cpp
  60. 1 1
      modules/visual_script/visual_script_nodes.cpp
  61. 1 1
      platform/android/java_godot_lib_jni.cpp
  62. 1 2
      platform/android/os_android.h
  63. 1 1
      platform/haiku/haiku_direct_window.h
  64. 1 1
      platform/haiku/os_haiku.h
  65. 2 2
      platform/iphone/os_iphone.h
  66. 1 1
      platform/javascript/os_javascript.h
  67. 1 1
      platform/osx/joypad_osx.h
  68. 1 2
      platform/osx/os_osx.h
  69. 1 1
      platform/server/os_server.h
  70. 1 1
      platform/uwp/joypad_uwp.h
  71. 1 2
      platform/uwp/os_uwp.h
  72. 1 2
      platform/windows/os_windows.h
  73. 1 0
      platform/x11/SCsub
  74. 3216 0
      platform/x11/display_server_x11.cpp
  75. 315 0
      platform/x11/display_server_x11.h
  76. 11 11
      platform/x11/joypad_linux.cpp
  77. 5 5
      platform/x11/joypad_linux.h
  78. 1 1
      platform/x11/os_x11.cpp
  79. 2 3
      platform/x11/os_x11.h
  80. 2 1
      scene/2d/canvas_item.cpp
  81. 2 2
      scene/2d/touch_screen_button.cpp
  82. 1 1
      scene/3d/arvr_nodes.cpp
  83. 1 1
      scene/gui/color_picker.cpp
  84. 1 1
      scene/gui/graph_edit.cpp
  85. 1 1
      scene/gui/popup_menu.cpp
  86. 1 1
      scene/gui/shortcut.h
  87. 1 1
      scene/gui/spin_box.cpp
  88. 1 1
      scene/gui/text_edit.cpp
  89. 1 1
      scene/gui/tree.cpp
  90. 2 2
      scene/main/scene_tree.cpp
  91. 1 1
      scene/main/viewport.cpp
  92. 1 1
      servers/arvr/arvr_positional_tracker.cpp
  93. 374 0
      servers/display_server.cpp
  94. 273 0
      servers/display_server.h
  95. 3 0
      servers/register_server_types.cpp

+ 1 - 0
core/SCsub

@@ -166,6 +166,7 @@ SConscript('math/SCsub')
 SConscript('crypto/SCsub')
 SConscript('crypto/SCsub')
 SConscript('io/SCsub')
 SConscript('io/SCsub')
 SConscript('debugger/SCsub')
 SConscript('debugger/SCsub')
+SConscript('input/SCsub')
 SConscript('bind/SCsub')
 SConscript('bind/SCsub')
 
 
 
 

+ 1 - 1
core/debugger/remote_debugger.cpp

@@ -33,7 +33,7 @@
 #include "core/debugger/debugger_marshalls.h"
 #include "core/debugger/debugger_marshalls.h"
 #include "core/debugger/engine_debugger.h"
 #include "core/debugger/engine_debugger.h"
 #include "core/debugger/script_debugger.h"
 #include "core/debugger/script_debugger.h"
-#include "core/os/input.h"
+#include "core/input/input.h"
 #include "core/os/os.h"
 #include "core/os/os.h"
 #include "core/project_settings.h"
 #include "core/project_settings.h"
 #include "core/script_language.h"
 #include "core/script_language.h"

+ 1 - 1
core/global_constants.cpp

@@ -30,8 +30,8 @@
 
 
 #include "global_constants.h"
 #include "global_constants.h"
 
 
+#include "core/input/input_event.h"
 #include "core/object.h"
 #include "core/object.h"
-#include "core/os/input_event.h"
 #include "core/os/keyboard.h"
 #include "core/os/keyboard.h"
 #include "core/variant.h"
 #include "core/variant.h"
 
 

+ 20 - 0
core/input/SCsub

@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+
+Import('env')
+
+from platform_methods import run_in_subprocess
+import input_builders
+
+
+# Order matters here. Higher index controller database files write on top of lower index database files.
+controller_databases = ["#core/input/gamecontrollerdb_204.txt", "#core/input/gamecontrollerdb_205.txt", "#core/input/gamecontrollerdb.txt", "#core/input/godotcontrollerdb.txt"]
+
+env.Depends("#core/input/default_controller_mappings.gen.cpp", controller_databases)
+env.CommandNoCache("#core/input/default_controller_mappings.gen.cpp", controller_databases, run_in_subprocess(input_builders.make_default_controller_mappings))
+
+env.add_source_files(env.core_sources, "*.cpp")
+
+# Don't warn about duplicate entry here, we need it registered manually for first build,
+# even if later builds will pick it up twice due to above *.cpp globbing.
+env.add_source_files(env.core_sources, "#core/input/default_controller_mappings.gen.cpp", warn_duplicates=False)
+

+ 0 - 0
main/default_controller_mappings.h → core/input/default_controller_mappings.h


+ 0 - 0
main/gamecontrollerdb.txt → core/input/gamecontrollerdb.txt


+ 0 - 0
main/gamecontrollerdb_204.txt → core/input/gamecontrollerdb_204.txt


+ 0 - 0
main/gamecontrollerdb_205.txt → core/input/gamecontrollerdb_205.txt


+ 0 - 0
main/godotcontrollerdb.txt → core/input/godotcontrollerdb.txt


+ 257 - 128
main/input_default.cpp → core/input/input.cpp

@@ -1,5 +1,5 @@
 /*************************************************************************/
 /*************************************************************************/
-/*  input_default.cpp                                                    */
+/*  input.cpp                                                            */
 /*************************************************************************/
 /*************************************************************************/
 /*                       This file is part of:                           */
 /*                       This file is part of:                           */
 /*                           GODOT ENGINE                                */
 /*                           GODOT ENGINE                                */
@@ -28,15 +28,129 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
 /*************************************************************************/
 
 
-#include "input_default.h"
+#include "input.h"
 
 
-#include "core/input_map.h"
+#include "core/input/default_controller_mappings.h"
+#include "core/input/input_map.h"
 #include "core/os/os.h"
 #include "core/os/os.h"
-#include "main/default_controller_mappings.h"
-#include "scene/resources/texture.h"
-#include "servers/visual_server.h"
+#include "core/project_settings.h"
+
+#ifdef TOOLS_ENABLED
+#include "editor/editor_settings.h"
+#endif
+
+Input *Input::singleton = NULL;
+
+Input *Input::get_singleton() {
+
+	return singleton;
+}
+
+void Input::set_mouse_mode(MouseMode p_mode) {
+	ERR_FAIL_INDEX((int)p_mode, 4);
+	OS::get_singleton()->set_mouse_mode((OS::MouseMode)p_mode);
+}
+
+Input::MouseMode Input::get_mouse_mode() const {
+
+	return (MouseMode)OS::get_singleton()->get_mouse_mode();
+}
+
+void Input::_bind_methods() {
+
+	ClassDB::bind_method(D_METHOD("is_key_pressed", "keycode"), &Input::is_key_pressed);
+	ClassDB::bind_method(D_METHOD("is_mouse_button_pressed", "button"), &Input::is_mouse_button_pressed);
+	ClassDB::bind_method(D_METHOD("is_joy_button_pressed", "device", "button"), &Input::is_joy_button_pressed);
+	ClassDB::bind_method(D_METHOD("is_action_pressed", "action"), &Input::is_action_pressed);
+	ClassDB::bind_method(D_METHOD("is_action_just_pressed", "action"), &Input::is_action_just_pressed);
+	ClassDB::bind_method(D_METHOD("is_action_just_released", "action"), &Input::is_action_just_released);
+	ClassDB::bind_method(D_METHOD("get_action_strength", "action"), &Input::get_action_strength);
+	ClassDB::bind_method(D_METHOD("add_joy_mapping", "mapping", "update_existing"), &Input::add_joy_mapping, DEFVAL(false));
+	ClassDB::bind_method(D_METHOD("remove_joy_mapping", "guid"), &Input::remove_joy_mapping);
+	ClassDB::bind_method(D_METHOD("joy_connection_changed", "device", "connected", "name", "guid"), &Input::joy_connection_changed);
+	ClassDB::bind_method(D_METHOD("is_joy_known", "device"), &Input::is_joy_known);
+	ClassDB::bind_method(D_METHOD("get_joy_axis", "device", "axis"), &Input::get_joy_axis);
+	ClassDB::bind_method(D_METHOD("get_joy_name", "device"), &Input::get_joy_name);
+	ClassDB::bind_method(D_METHOD("get_joy_guid", "device"), &Input::get_joy_guid);
+	ClassDB::bind_method(D_METHOD("get_connected_joypads"), &Input::get_connected_joypads);
+	ClassDB::bind_method(D_METHOD("get_joy_vibration_strength", "device"), &Input::get_joy_vibration_strength);
+	ClassDB::bind_method(D_METHOD("get_joy_vibration_duration", "device"), &Input::get_joy_vibration_duration);
+	ClassDB::bind_method(D_METHOD("get_joy_button_string", "button_index"), &Input::get_joy_button_string);
+	ClassDB::bind_method(D_METHOD("get_joy_button_index_from_string", "button"), &Input::get_joy_button_index_from_string);
+	ClassDB::bind_method(D_METHOD("get_joy_axis_string", "axis_index"), &Input::get_joy_axis_string);
+	ClassDB::bind_method(D_METHOD("get_joy_axis_index_from_string", "axis"), &Input::get_joy_axis_index_from_string);
+	ClassDB::bind_method(D_METHOD("start_joy_vibration", "device", "weak_magnitude", "strong_magnitude", "duration"), &Input::start_joy_vibration, DEFVAL(0));
+	ClassDB::bind_method(D_METHOD("stop_joy_vibration", "device"), &Input::stop_joy_vibration);
+	ClassDB::bind_method(D_METHOD("vibrate_handheld", "duration_ms"), &Input::vibrate_handheld, DEFVAL(500));
+	ClassDB::bind_method(D_METHOD("get_gravity"), &Input::get_gravity);
+	ClassDB::bind_method(D_METHOD("get_accelerometer"), &Input::get_accelerometer);
+	ClassDB::bind_method(D_METHOD("get_magnetometer"), &Input::get_magnetometer);
+	ClassDB::bind_method(D_METHOD("get_gyroscope"), &Input::get_gyroscope);
+	//ClassDB::bind_method(D_METHOD("get_mouse_position"),&Input::get_mouse_position); - this is not the function you want
+	ClassDB::bind_method(D_METHOD("get_last_mouse_speed"), &Input::get_last_mouse_speed);
+	ClassDB::bind_method(D_METHOD("get_mouse_button_mask"), &Input::get_mouse_button_mask);
+	ClassDB::bind_method(D_METHOD("set_mouse_mode", "mode"), &Input::set_mouse_mode);
+	ClassDB::bind_method(D_METHOD("get_mouse_mode"), &Input::get_mouse_mode);
+	ClassDB::bind_method(D_METHOD("warp_mouse_position", "to"), &Input::warp_mouse_position);
+	ClassDB::bind_method(D_METHOD("action_press", "action", "strength"), &Input::action_press, DEFVAL(1.f));
+	ClassDB::bind_method(D_METHOD("action_release", "action"), &Input::action_release);
+	ClassDB::bind_method(D_METHOD("set_default_cursor_shape", "shape"), &Input::set_default_cursor_shape, DEFVAL(CURSOR_ARROW));
+	ClassDB::bind_method(D_METHOD("get_current_cursor_shape"), &Input::get_current_cursor_shape);
+	ClassDB::bind_method(D_METHOD("set_custom_mouse_cursor", "image", "shape", "hotspot"), &Input::set_custom_mouse_cursor, DEFVAL(CURSOR_ARROW), DEFVAL(Vector2()));
+	ClassDB::bind_method(D_METHOD("parse_input_event", "event"), &Input::parse_input_event);
+	ClassDB::bind_method(D_METHOD("set_use_accumulated_input", "enable"), &Input::set_use_accumulated_input);
+
+	BIND_ENUM_CONSTANT(MOUSE_MODE_VISIBLE);
+	BIND_ENUM_CONSTANT(MOUSE_MODE_HIDDEN);
+	BIND_ENUM_CONSTANT(MOUSE_MODE_CAPTURED);
+	BIND_ENUM_CONSTANT(MOUSE_MODE_CONFINED);
+
+	BIND_ENUM_CONSTANT(CURSOR_ARROW);
+	BIND_ENUM_CONSTANT(CURSOR_IBEAM);
+	BIND_ENUM_CONSTANT(CURSOR_POINTING_HAND);
+	BIND_ENUM_CONSTANT(CURSOR_CROSS);
+	BIND_ENUM_CONSTANT(CURSOR_WAIT);
+	BIND_ENUM_CONSTANT(CURSOR_BUSY);
+	BIND_ENUM_CONSTANT(CURSOR_DRAG);
+	BIND_ENUM_CONSTANT(CURSOR_CAN_DROP);
+	BIND_ENUM_CONSTANT(CURSOR_FORBIDDEN);
+	BIND_ENUM_CONSTANT(CURSOR_VSIZE);
+	BIND_ENUM_CONSTANT(CURSOR_HSIZE);
+	BIND_ENUM_CONSTANT(CURSOR_BDIAGSIZE);
+	BIND_ENUM_CONSTANT(CURSOR_FDIAGSIZE);
+	BIND_ENUM_CONSTANT(CURSOR_MOVE);
+	BIND_ENUM_CONSTANT(CURSOR_VSPLIT);
+	BIND_ENUM_CONSTANT(CURSOR_HSPLIT);
+	BIND_ENUM_CONSTANT(CURSOR_HELP);
+
+	ADD_SIGNAL(MethodInfo("joy_connection_changed", PropertyInfo(Variant::INT, "device"), PropertyInfo(Variant::BOOL, "connected")));
+}
+
+void Input::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
+#ifdef TOOLS_ENABLED
+
+	const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", 0) ? "'" : "\"";
+
+	String pf = p_function;
+	if (p_idx == 0 && (pf == "is_action_pressed" || pf == "action_press" || pf == "action_release" || pf == "is_action_just_pressed" || pf == "is_action_just_released" || pf == "get_action_strength")) {
+
+		List<PropertyInfo> pinfo;
+		ProjectSettings::get_singleton()->get_property_list(&pinfo);
+
+		for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) {
+			const PropertyInfo &pi = E->get();
+
+			if (!pi.name.begins_with("input/"))
+				continue;
 
 
-void InputDefault::SpeedTrack::update(const Vector2 &p_delta_p) {
+			String name = pi.name.substr(pi.name.find("/") + 1, pi.name.length());
+			r_options->push_back(quote_style + name + quote_style);
+		}
+	}
+#endif
+}
+
+void Input::SpeedTrack::update(const Vector2 &p_delta_p) {
 
 
 	uint64_t tick = OS::get_singleton()->get_ticks_usec();
 	uint64_t tick = OS::get_singleton()->get_ticks_usec();
 	uint32_t tdiff = tick - last_tick;
 	uint32_t tdiff = tick - last_tick;
@@ -60,26 +174,26 @@ void InputDefault::SpeedTrack::update(const Vector2 &p_delta_p) {
 	}
 	}
 }
 }
 
 
-void InputDefault::SpeedTrack::reset() {
+void Input::SpeedTrack::reset() {
 	last_tick = OS::get_singleton()->get_ticks_usec();
 	last_tick = OS::get_singleton()->get_ticks_usec();
 	speed = Vector2();
 	speed = Vector2();
 	accum_t = 0;
 	accum_t = 0;
 }
 }
 
 
-InputDefault::SpeedTrack::SpeedTrack() {
+Input::SpeedTrack::SpeedTrack() {
 
 
 	min_ref_frame = 0.1;
 	min_ref_frame = 0.1;
 	max_ref_frame = 0.3;
 	max_ref_frame = 0.3;
 	reset();
 	reset();
 }
 }
 
 
-bool InputDefault::is_key_pressed(int p_keycode) const {
+bool Input::is_key_pressed(int p_keycode) const {
 
 
 	_THREAD_SAFE_METHOD_
 	_THREAD_SAFE_METHOD_
 	return keys_pressed.has(p_keycode);
 	return keys_pressed.has(p_keycode);
 }
 }
 
 
-bool InputDefault::is_mouse_button_pressed(int p_button) const {
+bool Input::is_mouse_button_pressed(int p_button) const {
 
 
 	_THREAD_SAFE_METHOD_
 	_THREAD_SAFE_METHOD_
 	return (mouse_button_mask & (1 << (p_button - 1))) != 0;
 	return (mouse_button_mask & (1 << (p_button - 1))) != 0;
@@ -90,18 +204,18 @@ static int _combine_device(int p_value, int p_device) {
 	return p_value | (p_device << 20);
 	return p_value | (p_device << 20);
 }
 }
 
 
-bool InputDefault::is_joy_button_pressed(int p_device, int p_button) const {
+bool Input::is_joy_button_pressed(int p_device, int p_button) const {
 
 
 	_THREAD_SAFE_METHOD_
 	_THREAD_SAFE_METHOD_
 	return joy_buttons_pressed.has(_combine_device(p_button, p_device));
 	return joy_buttons_pressed.has(_combine_device(p_button, p_device));
 }
 }
 
 
-bool InputDefault::is_action_pressed(const StringName &p_action) const {
+bool Input::is_action_pressed(const StringName &p_action) const {
 
 
 	return action_state.has(p_action) && action_state[p_action].pressed;
 	return action_state.has(p_action) && action_state[p_action].pressed;
 }
 }
 
 
-bool InputDefault::is_action_just_pressed(const StringName &p_action) const {
+bool Input::is_action_just_pressed(const StringName &p_action) const {
 
 
 	const Map<StringName, Action>::Element *E = action_state.find(p_action);
 	const Map<StringName, Action>::Element *E = action_state.find(p_action);
 	if (!E)
 	if (!E)
@@ -114,7 +228,7 @@ bool InputDefault::is_action_just_pressed(const StringName &p_action) const {
 	}
 	}
 }
 }
 
 
-bool InputDefault::is_action_just_released(const StringName &p_action) const {
+bool Input::is_action_just_released(const StringName &p_action) const {
 
 
 	const Map<StringName, Action>::Element *E = action_state.find(p_action);
 	const Map<StringName, Action>::Element *E = action_state.find(p_action);
 	if (!E)
 	if (!E)
@@ -127,7 +241,7 @@ bool InputDefault::is_action_just_released(const StringName &p_action) const {
 	}
 	}
 }
 }
 
 
-float InputDefault::get_action_strength(const StringName &p_action) const {
+float Input::get_action_strength(const StringName &p_action) const {
 	const Map<StringName, Action>::Element *E = action_state.find(p_action);
 	const Map<StringName, Action>::Element *E = action_state.find(p_action);
 	if (!E)
 	if (!E)
 		return 0.0f;
 		return 0.0f;
@@ -135,7 +249,7 @@ float InputDefault::get_action_strength(const StringName &p_action) const {
 	return E->get().strength;
 	return E->get().strength;
 }
 }
 
 
-float InputDefault::get_joy_axis(int p_device, int p_axis) const {
+float Input::get_joy_axis(int p_device, int p_axis) const {
 
 
 	_THREAD_SAFE_METHOD_
 	_THREAD_SAFE_METHOD_
 	int c = _combine_device(p_axis, p_device);
 	int c = _combine_device(p_axis, p_device);
@@ -146,13 +260,13 @@ float InputDefault::get_joy_axis(int p_device, int p_axis) const {
 	}
 	}
 }
 }
 
 
-String InputDefault::get_joy_name(int p_idx) {
+String Input::get_joy_name(int p_idx) {
 
 
 	_THREAD_SAFE_METHOD_
 	_THREAD_SAFE_METHOD_
 	return joy_names[p_idx].name;
 	return joy_names[p_idx].name;
 };
 };
 
 
-Vector2 InputDefault::get_joy_vibration_strength(int p_device) {
+Vector2 Input::get_joy_vibration_strength(int p_device) {
 	if (joy_vibration.has(p_device)) {
 	if (joy_vibration.has(p_device)) {
 		return Vector2(joy_vibration[p_device].weak_magnitude, joy_vibration[p_device].strong_magnitude);
 		return Vector2(joy_vibration[p_device].weak_magnitude, joy_vibration[p_device].strong_magnitude);
 	} else {
 	} else {
@@ -160,7 +274,7 @@ Vector2 InputDefault::get_joy_vibration_strength(int p_device) {
 	}
 	}
 }
 }
 
 
-uint64_t InputDefault::get_joy_vibration_timestamp(int p_device) {
+uint64_t Input::get_joy_vibration_timestamp(int p_device) {
 	if (joy_vibration.has(p_device)) {
 	if (joy_vibration.has(p_device)) {
 		return joy_vibration[p_device].timestamp;
 		return joy_vibration[p_device].timestamp;
 	} else {
 	} else {
@@ -168,7 +282,7 @@ uint64_t InputDefault::get_joy_vibration_timestamp(int p_device) {
 	}
 	}
 }
 }
 
 
-float InputDefault::get_joy_vibration_duration(int p_device) {
+float Input::get_joy_vibration_duration(int p_device) {
 	if (joy_vibration.has(p_device)) {
 	if (joy_vibration.has(p_device)) {
 		return joy_vibration[p_device].duration;
 		return joy_vibration[p_device].duration;
 	} else {
 	} else {
@@ -188,7 +302,7 @@ static String _hex_str(uint8_t p_byte) {
 	return ret;
 	return ret;
 };
 };
 
 
-void InputDefault::joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid) {
+void Input::joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid) {
 
 
 	_THREAD_SAFE_METHOD_
 	_THREAD_SAFE_METHOD_
 	Joypad js;
 	Joypad js;
@@ -230,36 +344,47 @@ void InputDefault::joy_connection_changed(int p_idx, bool p_connected, String p_
 	emit_signal("joy_connection_changed", p_idx, p_connected);
 	emit_signal("joy_connection_changed", p_idx, p_connected);
 };
 };
 
 
-Vector3 InputDefault::get_gravity() const {
+Vector3 Input::get_gravity() const {
 
 
 	_THREAD_SAFE_METHOD_
 	_THREAD_SAFE_METHOD_
 	return gravity;
 	return gravity;
 }
 }
 
 
-Vector3 InputDefault::get_accelerometer() const {
+Vector3 Input::get_accelerometer() const {
 
 
 	_THREAD_SAFE_METHOD_
 	_THREAD_SAFE_METHOD_
 	return accelerometer;
 	return accelerometer;
 }
 }
 
 
-Vector3 InputDefault::get_magnetometer() const {
+Vector3 Input::get_magnetometer() const {
 
 
 	_THREAD_SAFE_METHOD_
 	_THREAD_SAFE_METHOD_
 	return magnetometer;
 	return magnetometer;
 }
 }
 
 
-Vector3 InputDefault::get_gyroscope() const {
+Vector3 Input::get_gyroscope() const {
 
 
 	_THREAD_SAFE_METHOD_
 	_THREAD_SAFE_METHOD_
 	return gyroscope;
 	return gyroscope;
 }
 }
 
 
-void InputDefault::parse_input_event(const Ref<InputEvent> &p_event) {
+void Input::parse_drop_files(const Vector<String> &p_files) {
+	if (main_loop) {
+		main_loop->drop_files(p_files);
+	}
+}
+void Input::parse_notification(int p_notification) {
+	if (main_loop) {
+		main_loop->notification(p_notification);
+	}
+}
+
+void Input::parse_input_event(const Ref<InputEvent> &p_event) {
 
 
 	_parse_input_event_impl(p_event, false);
 	_parse_input_event_impl(p_event, false);
 }
 }
 
 
-void InputDefault::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_emulated) {
+void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_emulated) {
 
 
 	// Notes on mouse-touch emulation:
 	// Notes on mouse-touch emulation:
 	// - Emulated mouse events are parsed, that is, re-routed to this method, so they make the same effects
 	// - Emulated mouse events are parsed, that is, re-routed to this method, so they make the same effects
@@ -442,14 +567,14 @@ void InputDefault::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool
 		main_loop->input_event(p_event);
 		main_loop->input_event(p_event);
 }
 }
 
 
-void InputDefault::set_joy_axis(int p_device, int p_axis, float p_value) {
+void Input::set_joy_axis(int p_device, int p_axis, float p_value) {
 
 
 	_THREAD_SAFE_METHOD_
 	_THREAD_SAFE_METHOD_
 	int c = _combine_device(p_axis, p_device);
 	int c = _combine_device(p_axis, p_device);
 	_joy_axis[c] = p_value;
 	_joy_axis[c] = p_value;
 }
 }
 
 
-void InputDefault::start_joy_vibration(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration) {
+void Input::start_joy_vibration(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration) {
 	_THREAD_SAFE_METHOD_
 	_THREAD_SAFE_METHOD_
 	if (p_weak_magnitude < 0.f || p_weak_magnitude > 1.f || p_strong_magnitude < 0.f || p_strong_magnitude > 1.f) {
 	if (p_weak_magnitude < 0.f || p_weak_magnitude > 1.f || p_strong_magnitude < 0.f || p_strong_magnitude > 1.f) {
 		return;
 		return;
@@ -462,7 +587,7 @@ void InputDefault::start_joy_vibration(int p_device, float p_weak_magnitude, flo
 	joy_vibration[p_device] = vibration;
 	joy_vibration[p_device] = vibration;
 }
 }
 
 
-void InputDefault::stop_joy_vibration(int p_device) {
+void Input::stop_joy_vibration(int p_device) {
 	_THREAD_SAFE_METHOD_
 	_THREAD_SAFE_METHOD_
 	VibrationInfo vibration;
 	VibrationInfo vibration;
 	vibration.weak_magnitude = 0;
 	vibration.weak_magnitude = 0;
@@ -472,68 +597,68 @@ void InputDefault::stop_joy_vibration(int p_device) {
 	joy_vibration[p_device] = vibration;
 	joy_vibration[p_device] = vibration;
 }
 }
 
 
-void InputDefault::vibrate_handheld(int p_duration_ms) {
+void Input::vibrate_handheld(int p_duration_ms) {
 	OS::get_singleton()->vibrate_handheld(p_duration_ms);
 	OS::get_singleton()->vibrate_handheld(p_duration_ms);
 }
 }
 
 
-void InputDefault::set_gravity(const Vector3 &p_gravity) {
+void Input::set_gravity(const Vector3 &p_gravity) {
 
 
 	_THREAD_SAFE_METHOD_
 	_THREAD_SAFE_METHOD_
 
 
 	gravity = p_gravity;
 	gravity = p_gravity;
 }
 }
 
 
-void InputDefault::set_accelerometer(const Vector3 &p_accel) {
+void Input::set_accelerometer(const Vector3 &p_accel) {
 
 
 	_THREAD_SAFE_METHOD_
 	_THREAD_SAFE_METHOD_
 
 
 	accelerometer = p_accel;
 	accelerometer = p_accel;
 }
 }
 
 
-void InputDefault::set_magnetometer(const Vector3 &p_magnetometer) {
+void Input::set_magnetometer(const Vector3 &p_magnetometer) {
 
 
 	_THREAD_SAFE_METHOD_
 	_THREAD_SAFE_METHOD_
 
 
 	magnetometer = p_magnetometer;
 	magnetometer = p_magnetometer;
 }
 }
 
 
-void InputDefault::set_gyroscope(const Vector3 &p_gyroscope) {
+void Input::set_gyroscope(const Vector3 &p_gyroscope) {
 
 
 	_THREAD_SAFE_METHOD_
 	_THREAD_SAFE_METHOD_
 
 
 	gyroscope = p_gyroscope;
 	gyroscope = p_gyroscope;
 }
 }
 
 
-void InputDefault::set_main_loop(MainLoop *p_main_loop) {
+void Input::set_main_loop(MainLoop *p_main_loop) {
 	main_loop = p_main_loop;
 	main_loop = p_main_loop;
 }
 }
 
 
-void InputDefault::set_mouse_position(const Point2 &p_posf) {
+void Input::set_mouse_position(const Point2 &p_posf) {
 
 
 	mouse_speed_track.update(p_posf - mouse_pos);
 	mouse_speed_track.update(p_posf - mouse_pos);
 	mouse_pos = p_posf;
 	mouse_pos = p_posf;
 }
 }
 
 
-Point2 InputDefault::get_mouse_position() const {
+Point2 Input::get_mouse_position() const {
 
 
 	return mouse_pos;
 	return mouse_pos;
 }
 }
-Point2 InputDefault::get_last_mouse_speed() const {
+Point2 Input::get_last_mouse_speed() const {
 
 
 	return mouse_speed_track.speed;
 	return mouse_speed_track.speed;
 }
 }
 
 
-int InputDefault::get_mouse_button_mask() const {
+int Input::get_mouse_button_mask() const {
 
 
 	return mouse_button_mask; // do not trust OS implementation, should remove it - OS::get_singleton()->get_mouse_button_state();
 	return mouse_button_mask; // do not trust OS implementation, should remove it - OS::get_singleton()->get_mouse_button_state();
 }
 }
 
 
-void InputDefault::warp_mouse_position(const Vector2 &p_to) {
+void Input::warp_mouse_position(const Vector2 &p_to) {
 
 
 	OS::get_singleton()->warp_mouse_position(p_to);
 	OS::get_singleton()->warp_mouse_position(p_to);
 }
 }
 
 
-Point2i InputDefault::warp_mouse_motion(const Ref<InputEventMouseMotion> &p_motion, const Rect2 &p_rect) {
+Point2i Input::warp_mouse_motion(const Ref<InputEventMouseMotion> &p_motion, const Rect2 &p_rect) {
 
 
 	// The relative distance reported for the next event after a warp is in the boundaries of the
 	// The relative distance reported for the next event after a warp is in the boundaries of the
 	// size of the rect on that axis, but it may be greater, in which case there's not problem as fmod()
 	// size of the rect on that axis, but it may be greater, in which case there's not problem as fmod()
@@ -559,10 +684,10 @@ Point2i InputDefault::warp_mouse_motion(const Ref<InputEventMouseMotion> &p_moti
 	return rel_warped;
 	return rel_warped;
 }
 }
 
 
-void InputDefault::iteration(float p_step) {
+void Input::iteration(float p_step) {
 }
 }
 
 
-void InputDefault::action_press(const StringName &p_action, float p_strength) {
+void Input::action_press(const StringName &p_action, float p_strength) {
 
 
 	Action action;
 	Action action;
 
 
@@ -574,7 +699,7 @@ void InputDefault::action_press(const StringName &p_action, float p_strength) {
 	action_state[p_action] = action;
 	action_state[p_action] = action;
 }
 }
 
 
-void InputDefault::action_release(const StringName &p_action) {
+void Input::action_release(const StringName &p_action) {
 
 
 	Action action;
 	Action action;
 
 
@@ -586,19 +711,19 @@ void InputDefault::action_release(const StringName &p_action) {
 	action_state[p_action] = action;
 	action_state[p_action] = action;
 }
 }
 
 
-void InputDefault::set_emulate_touch_from_mouse(bool p_emulate) {
+void Input::set_emulate_touch_from_mouse(bool p_emulate) {
 
 
 	emulate_touch_from_mouse = p_emulate;
 	emulate_touch_from_mouse = p_emulate;
 }
 }
 
 
-bool InputDefault::is_emulating_touch_from_mouse() const {
+bool Input::is_emulating_touch_from_mouse() const {
 
 
 	return emulate_touch_from_mouse;
 	return emulate_touch_from_mouse;
 }
 }
 
 
 // Calling this whenever the game window is focused helps unstucking the "touch mouse"
 // Calling this whenever the game window is focused helps unstucking the "touch mouse"
 // if the OS or its abstraction class hasn't properly reported that touch pointers raised
 // if the OS or its abstraction class hasn't properly reported that touch pointers raised
-void InputDefault::ensure_touch_mouse_raised() {
+void Input::ensure_touch_mouse_raised() {
 
 
 	if (mouse_from_touch_index != -1) {
 	if (mouse_from_touch_index != -1) {
 		mouse_from_touch_index = -1;
 		mouse_from_touch_index = -1;
@@ -617,22 +742,22 @@ void InputDefault::ensure_touch_mouse_raised() {
 	}
 	}
 }
 }
 
 
-void InputDefault::set_emulate_mouse_from_touch(bool p_emulate) {
+void Input::set_emulate_mouse_from_touch(bool p_emulate) {
 
 
 	emulate_mouse_from_touch = p_emulate;
 	emulate_mouse_from_touch = p_emulate;
 }
 }
 
 
-bool InputDefault::is_emulating_mouse_from_touch() const {
+bool Input::is_emulating_mouse_from_touch() const {
 
 
 	return emulate_mouse_from_touch;
 	return emulate_mouse_from_touch;
 }
 }
 
 
-Input::CursorShape InputDefault::get_default_cursor_shape() const {
+Input::CursorShape Input::get_default_cursor_shape() const {
 
 
 	return default_shape;
 	return default_shape;
 }
 }
 
 
-void InputDefault::set_default_cursor_shape(CursorShape p_shape) {
+void Input::set_default_cursor_shape(CursorShape p_shape) {
 
 
 	if (default_shape == p_shape)
 	if (default_shape == p_shape)
 		return;
 		return;
@@ -647,19 +772,19 @@ void InputDefault::set_default_cursor_shape(CursorShape p_shape) {
 	parse_input_event(mm);
 	parse_input_event(mm);
 }
 }
 
 
-Input::CursorShape InputDefault::get_current_cursor_shape() const {
+Input::CursorShape Input::get_current_cursor_shape() const {
 
 
 	return (Input::CursorShape)OS::get_singleton()->get_cursor_shape();
 	return (Input::CursorShape)OS::get_singleton()->get_cursor_shape();
 }
 }
 
 
-void InputDefault::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
+void Input::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
 	if (Engine::get_singleton()->is_editor_hint())
 	if (Engine::get_singleton()->is_editor_hint())
 		return;
 		return;
 
 
 	OS::get_singleton()->set_custom_mouse_cursor(p_cursor, (OS::CursorShape)p_shape, p_hotspot);
 	OS::get_singleton()->set_custom_mouse_cursor(p_cursor, (OS::CursorShape)p_shape, p_hotspot);
 }
 }
 
 
-void InputDefault::accumulate_input_event(const Ref<InputEvent> &p_event) {
+void Input::accumulate_input_event(const Ref<InputEvent> &p_event) {
 	ERR_FAIL_COND(p_event.is_null());
 	ERR_FAIL_COND(p_event.is_null());
 
 
 	if (!use_accumulated_input) {
 	if (!use_accumulated_input) {
@@ -672,7 +797,7 @@ void InputDefault::accumulate_input_event(const Ref<InputEvent> &p_event) {
 
 
 	accumulated_events.push_back(p_event);
 	accumulated_events.push_back(p_event);
 }
 }
-void InputDefault::flush_accumulated_events() {
+void Input::flush_accumulated_events() {
 
 
 	while (accumulated_events.front()) {
 	while (accumulated_events.front()) {
 		parse_input_event(accumulated_events.front()->get());
 		parse_input_event(accumulated_events.front()->get());
@@ -680,12 +805,12 @@ void InputDefault::flush_accumulated_events() {
 	}
 	}
 }
 }
 
 
-void InputDefault::set_use_accumulated_input(bool p_enable) {
+void Input::set_use_accumulated_input(bool p_enable) {
 
 
 	use_accumulated_input = p_enable;
 	use_accumulated_input = p_enable;
 }
 }
 
 
-void InputDefault::release_pressed_events() {
+void Input::release_pressed_events() {
 
 
 	flush_accumulated_events(); // this is needed to release actions strengths
 	flush_accumulated_events(); // this is needed to release actions strengths
 
 
@@ -693,61 +818,13 @@ void InputDefault::release_pressed_events() {
 	joy_buttons_pressed.clear();
 	joy_buttons_pressed.clear();
 	_joy_axis.clear();
 	_joy_axis.clear();
 
 
-	for (Map<StringName, InputDefault::Action>::Element *E = action_state.front(); E; E = E->next()) {
+	for (Map<StringName, Input::Action>::Element *E = action_state.front(); E; E = E->next()) {
 		if (E->get().pressed)
 		if (E->get().pressed)
 			action_release(E->key());
 			action_release(E->key());
 	}
 	}
 }
 }
 
 
-InputDefault::InputDefault() {
-
-	use_accumulated_input = true;
-	mouse_button_mask = 0;
-	emulate_touch_from_mouse = false;
-	emulate_mouse_from_touch = false;
-	mouse_from_touch_index = -1;
-	main_loop = NULL;
-	default_shape = CURSOR_ARROW;
-
-	hat_map_default[HAT_UP].type = TYPE_BUTTON;
-	hat_map_default[HAT_UP].index = JOY_DPAD_UP;
-	hat_map_default[HAT_UP].value = 0;
-
-	hat_map_default[HAT_RIGHT].type = TYPE_BUTTON;
-	hat_map_default[HAT_RIGHT].index = JOY_DPAD_RIGHT;
-	hat_map_default[HAT_RIGHT].value = 0;
-
-	hat_map_default[HAT_DOWN].type = TYPE_BUTTON;
-	hat_map_default[HAT_DOWN].index = JOY_DPAD_DOWN;
-	hat_map_default[HAT_DOWN].value = 0;
-
-	hat_map_default[HAT_LEFT].type = TYPE_BUTTON;
-	hat_map_default[HAT_LEFT].index = JOY_DPAD_LEFT;
-	hat_map_default[HAT_LEFT].value = 0;
-
-	fallback_mapping = -1;
-
-	// Parse default mappings.
-	{
-		int i = 0;
-		while (DefaultControllerMappings::mappings[i]) {
-			parse_mapping(DefaultControllerMappings::mappings[i++]);
-		}
-	}
-
-	// If defined, parse SDL_GAMECONTROLLERCONFIG for possible new mappings/overrides.
-	String env_mapping = OS::get_singleton()->get_environment("SDL_GAMECONTROLLERCONFIG");
-	if (env_mapping != "") {
-		Vector<String> entries = env_mapping.split("\n");
-		for (int i = 0; i < entries.size(); i++) {
-			if (entries[i] == "")
-				continue;
-			parse_mapping(entries[i]);
-		}
-	}
-}
-
-void InputDefault::joy_button(int p_device, int p_button, bool p_pressed) {
+void Input::joy_button(int p_device, int p_button, bool p_pressed) {
 
 
 	_THREAD_SAFE_METHOD_;
 	_THREAD_SAFE_METHOD_;
 	Joypad &joy = joy_names[p_device];
 	Joypad &joy = joy_names[p_device];
@@ -786,7 +863,7 @@ void InputDefault::joy_button(int p_device, int p_button, bool p_pressed) {
 	// no event?
 	// no event?
 }
 }
 
 
-void InputDefault::joy_axis(int p_device, int p_axis, const JoyAxis &p_value) {
+void Input::joy_axis(int p_device, int p_axis, const JoyAxis &p_value) {
 
 
 	_THREAD_SAFE_METHOD_;
 	_THREAD_SAFE_METHOD_;
 
 
@@ -901,7 +978,7 @@ void InputDefault::joy_axis(int p_device, int p_axis, const JoyAxis &p_value) {
 	//printf("invalid mapping\n");
 	//printf("invalid mapping\n");
 }
 }
 
 
-void InputDefault::joy_hat(int p_device, int p_val) {
+void Input::joy_hat(int p_device, int p_val) {
 
 
 	_THREAD_SAFE_METHOD_;
 	_THREAD_SAFE_METHOD_;
 	const Joypad &joy = joy_names[p_device];
 	const Joypad &joy = joy_names[p_device];
@@ -933,7 +1010,7 @@ void InputDefault::joy_hat(int p_device, int p_val) {
 	joy_names[p_device].hat_current = p_val;
 	joy_names[p_device].hat_current = p_val;
 }
 }
 
 
-void InputDefault::_button_event(int p_device, int p_index, bool p_pressed) {
+void Input::_button_event(int p_device, int p_index, bool p_pressed) {
 
 
 	Ref<InputEventJoypadButton> ievent;
 	Ref<InputEventJoypadButton> ievent;
 	ievent.instance();
 	ievent.instance();
@@ -944,7 +1021,7 @@ void InputDefault::_button_event(int p_device, int p_index, bool p_pressed) {
 	parse_input_event(ievent);
 	parse_input_event(ievent);
 }
 }
 
 
-void InputDefault::_axis_event(int p_device, int p_axis, float p_value) {
+void Input::_axis_event(int p_device, int p_axis, float p_value) {
 
 
 	Ref<InputEventJoypadMotion> ievent;
 	Ref<InputEventJoypadMotion> ievent;
 	ievent.instance();
 	ievent.instance();
@@ -955,7 +1032,7 @@ void InputDefault::_axis_event(int p_device, int p_axis, float p_value) {
 	parse_input_event(ievent);
 	parse_input_event(ievent);
 };
 };
 
 
-InputDefault::JoyEvent InputDefault::_find_to_event(String p_to) {
+Input::JoyEvent Input::_find_to_event(String p_to) {
 
 
 	// string names of the SDL buttons in the same order as input_event.h godot buttons
 	// string names of the SDL buttons in the same order as input_event.h godot buttons
 	static const char *buttons[] = { "a", "b", "x", "y", "leftshoulder", "rightshoulder", "lefttrigger", "righttrigger", "leftstick", "rightstick", "back", "start", "dpup", "dpdown", "dpleft", "dpright", "guide", NULL };
 	static const char *buttons[] = { "a", "b", "x", "y", "leftshoulder", "rightshoulder", "lefttrigger", "righttrigger", "leftstick", "rightstick", "back", "start", "dpup", "dpdown", "dpleft", "dpright", "guide", NULL };
@@ -993,7 +1070,7 @@ InputDefault::JoyEvent InputDefault::_find_to_event(String p_to) {
 	return ret;
 	return ret;
 };
 };
 
 
-void InputDefault::parse_mapping(String p_mapping) {
+void Input::parse_mapping(String p_mapping) {
 
 
 	_THREAD_SAFE_METHOD_;
 	_THREAD_SAFE_METHOD_;
 	JoyDeviceMapping mapping;
 	JoyDeviceMapping mapping;
@@ -1058,7 +1135,7 @@ void InputDefault::parse_mapping(String p_mapping) {
 	//printf("added mapping with uuid %ls\n", mapping.uid.c_str());
 	//printf("added mapping with uuid %ls\n", mapping.uid.c_str());
 };
 };
 
 
-void InputDefault::add_joy_mapping(String p_mapping, bool p_update_existing) {
+void Input::add_joy_mapping(String p_mapping, bool p_update_existing) {
 	parse_mapping(p_mapping);
 	parse_mapping(p_mapping);
 	if (p_update_existing) {
 	if (p_update_existing) {
 		Vector<String> entry = p_mapping.split(",");
 		Vector<String> entry = p_mapping.split(",");
@@ -1071,7 +1148,7 @@ void InputDefault::add_joy_mapping(String p_mapping, bool p_update_existing) {
 	}
 	}
 }
 }
 
 
-void InputDefault::remove_joy_mapping(String p_guid) {
+void Input::remove_joy_mapping(String p_guid) {
 	for (int i = map_db.size() - 1; i >= 0; i--) {
 	for (int i = map_db.size() - 1; i >= 0; i--) {
 		if (p_guid == map_db[i].uid) {
 		if (p_guid == map_db[i].uid) {
 			map_db.remove(i);
 			map_db.remove(i);
@@ -1084,7 +1161,7 @@ void InputDefault::remove_joy_mapping(String p_guid) {
 	}
 	}
 }
 }
 
 
-void InputDefault::set_fallback_mapping(String p_guid) {
+void Input::set_fallback_mapping(String p_guid) {
 
 
 	for (int i = 0; i < map_db.size(); i++) {
 	for (int i = 0; i < map_db.size(); i++) {
 		if (map_db[i].uid == p_guid) {
 		if (map_db[i].uid == p_guid) {
@@ -1095,27 +1172,27 @@ void InputDefault::set_fallback_mapping(String p_guid) {
 }
 }
 
 
 //Defaults to simple implementation for platforms with a fixed gamepad layout, like consoles.
 //Defaults to simple implementation for platforms with a fixed gamepad layout, like consoles.
-bool InputDefault::is_joy_known(int p_device) {
+bool Input::is_joy_known(int p_device) {
 
 
 	return OS::get_singleton()->is_joy_known(p_device);
 	return OS::get_singleton()->is_joy_known(p_device);
 }
 }
 
 
-String InputDefault::get_joy_guid(int p_device) const {
+String Input::get_joy_guid(int p_device) const {
 	return OS::get_singleton()->get_joy_guid(p_device);
 	return OS::get_singleton()->get_joy_guid(p_device);
 }
 }
 
 
 //platforms that use the remapping system can override and call to these ones
 //platforms that use the remapping system can override and call to these ones
-bool InputDefault::is_joy_mapped(int p_device) {
+bool Input::is_joy_mapped(int p_device) {
 	int mapping = joy_names[p_device].mapping;
 	int mapping = joy_names[p_device].mapping;
 	return mapping != -1 ? (mapping != fallback_mapping) : false;
 	return mapping != -1 ? (mapping != fallback_mapping) : false;
 }
 }
 
 
-String InputDefault::get_joy_guid_remapped(int p_device) const {
+String Input::get_joy_guid_remapped(int p_device) const {
 	ERR_FAIL_COND_V(!joy_names.has(p_device), "");
 	ERR_FAIL_COND_V(!joy_names.has(p_device), "");
 	return joy_names[p_device].uid;
 	return joy_names[p_device].uid;
 }
 }
 
 
-Array InputDefault::get_connected_joypads() {
+Array Input::get_connected_joypads() {
 	Array ret;
 	Array ret;
 	Map<int, Joypad>::Element *elem = joy_names.front();
 	Map<int, Joypad>::Element *elem = joy_names.front();
 	while (elem) {
 	while (elem) {
@@ -1159,12 +1236,12 @@ static const char *_axes[JOY_AXIS_MAX] = {
 	""
 	""
 };
 };
 
 
-String InputDefault::get_joy_button_string(int p_button) {
+String Input::get_joy_button_string(int p_button) {
 	ERR_FAIL_INDEX_V(p_button, JOY_BUTTON_MAX, "");
 	ERR_FAIL_INDEX_V(p_button, JOY_BUTTON_MAX, "");
 	return _buttons[p_button];
 	return _buttons[p_button];
 }
 }
 
 
-int InputDefault::get_joy_button_index_from_string(String p_button) {
+int Input::get_joy_button_index_from_string(String p_button) {
 	for (int i = 0; i < JOY_BUTTON_MAX; i++) {
 	for (int i = 0; i < JOY_BUTTON_MAX; i++) {
 		if (p_button == _buttons[i]) {
 		if (p_button == _buttons[i]) {
 			return i;
 			return i;
@@ -1173,7 +1250,7 @@ int InputDefault::get_joy_button_index_from_string(String p_button) {
 	ERR_FAIL_V(-1);
 	ERR_FAIL_V(-1);
 }
 }
 
 
-int InputDefault::get_unused_joy_id() {
+int Input::get_unused_joy_id() {
 	for (int i = 0; i < JOYPADS_MAX; i++) {
 	for (int i = 0; i < JOYPADS_MAX; i++) {
 		if (!joy_names.has(i) || !joy_names[i].connected) {
 		if (!joy_names.has(i) || !joy_names[i].connected) {
 			return i;
 			return i;
@@ -1182,12 +1259,12 @@ int InputDefault::get_unused_joy_id() {
 	return -1;
 	return -1;
 }
 }
 
 
-String InputDefault::get_joy_axis_string(int p_axis) {
+String Input::get_joy_axis_string(int p_axis) {
 	ERR_FAIL_INDEX_V(p_axis, JOY_AXIS_MAX, "");
 	ERR_FAIL_INDEX_V(p_axis, JOY_AXIS_MAX, "");
 	return _axes[p_axis];
 	return _axes[p_axis];
 }
 }
 
 
-int InputDefault::get_joy_axis_index_from_string(String p_axis) {
+int Input::get_joy_axis_index_from_string(String p_axis) {
 	for (int i = 0; i < JOY_AXIS_MAX; i++) {
 	for (int i = 0; i < JOY_AXIS_MAX; i++) {
 		if (p_axis == _axes[i]) {
 		if (p_axis == _axes[i]) {
 			return i;
 			return i;
@@ -1195,3 +1272,55 @@ int InputDefault::get_joy_axis_index_from_string(String p_axis) {
 	}
 	}
 	ERR_FAIL_V(-1);
 	ERR_FAIL_V(-1);
 }
 }
+
+Input::Input() {
+
+	singleton = this;
+	use_accumulated_input = true;
+	mouse_button_mask = 0;
+	mouse_window = 0;
+	emulate_touch_from_mouse = false;
+	emulate_mouse_from_touch = false;
+	mouse_from_touch_index = -1;
+	main_loop = NULL;
+	default_shape = CURSOR_ARROW;
+
+	hat_map_default[HAT_UP].type = TYPE_BUTTON;
+	hat_map_default[HAT_UP].index = JOY_DPAD_UP;
+	hat_map_default[HAT_UP].value = 0;
+
+	hat_map_default[HAT_RIGHT].type = TYPE_BUTTON;
+	hat_map_default[HAT_RIGHT].index = JOY_DPAD_RIGHT;
+	hat_map_default[HAT_RIGHT].value = 0;
+
+	hat_map_default[HAT_DOWN].type = TYPE_BUTTON;
+	hat_map_default[HAT_DOWN].index = JOY_DPAD_DOWN;
+	hat_map_default[HAT_DOWN].value = 0;
+
+	hat_map_default[HAT_LEFT].type = TYPE_BUTTON;
+	hat_map_default[HAT_LEFT].index = JOY_DPAD_LEFT;
+	hat_map_default[HAT_LEFT].value = 0;
+
+	fallback_mapping = -1;
+
+	// Parse default mappings.
+	{
+		int i = 0;
+		while (DefaultControllerMappings::mappings[i]) {
+			parse_mapping(DefaultControllerMappings::mappings[i++]);
+		}
+	}
+
+	// If defined, parse SDL_GAMECONTROLLERCONFIG for possible new mappings/overrides.
+	String env_mapping = OS::get_singleton()->get_environment("SDL_GAMECONTROLLERCONFIG");
+	if (env_mapping != "") {
+		Vector<String> entries = env_mapping.split("\n");
+		for (int i = 0; i < entries.size(); i++) {
+			if (entries[i] == "")
+				continue;
+			parse_mapping(entries[i]);
+		}
+	}
+}
+
+//////////////////////////////////////////////////////////

+ 128 - 79
main/input_default.h → core/input/input.h

@@ -1,5 +1,5 @@
 /*************************************************************************/
 /*************************************************************************/
-/*  input_default.h                                                      */
+/*  input.h                                                              */
 /*************************************************************************/
 /*************************************************************************/
 /*                       This file is part of:                           */
 /*                       This file is part of:                           */
 /*                           GODOT ENGINE                                */
 /*                           GODOT ENGINE                                */
@@ -28,16 +28,76 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
 /*************************************************************************/
 
 
-#ifndef INPUT_DEFAULT_H
-#define INPUT_DEFAULT_H
+#ifndef INPUT_H
+#define INPUT_H
 
 
-#include "core/os/input.h"
+#include "core/object.h"
+#include "core/os/main_loop.h"
+#include "core/os/thread_safe.h"
 
 
-class InputDefault : public Input {
+class Input : public Object {
 
 
-	GDCLASS(InputDefault, Input);
+	GDCLASS(Input, Object);
 	_THREAD_SAFE_CLASS_
 	_THREAD_SAFE_CLASS_
 
 
+	static Input *singleton;
+
+public:
+	enum MouseMode {
+		MOUSE_MODE_VISIBLE,
+		MOUSE_MODE_HIDDEN,
+		MOUSE_MODE_CAPTURED,
+		MOUSE_MODE_CONFINED
+	};
+
+#undef CursorShape
+	enum CursorShape {
+		CURSOR_ARROW,
+		CURSOR_IBEAM,
+		CURSOR_POINTING_HAND,
+		CURSOR_CROSS,
+		CURSOR_WAIT,
+		CURSOR_BUSY,
+		CURSOR_DRAG,
+		CURSOR_CAN_DROP,
+		CURSOR_FORBIDDEN,
+		CURSOR_VSIZE,
+		CURSOR_HSIZE,
+		CURSOR_BDIAGSIZE,
+		CURSOR_FDIAGSIZE,
+		CURSOR_MOVE,
+		CURSOR_VSPLIT,
+		CURSOR_HSPLIT,
+		CURSOR_HELP,
+		CURSOR_MAX
+	};
+
+	enum HatMask {
+		HAT_MASK_CENTER = 0,
+		HAT_MASK_UP = 1,
+		HAT_MASK_RIGHT = 2,
+		HAT_MASK_DOWN = 4,
+		HAT_MASK_LEFT = 8,
+	};
+
+	enum HatDir {
+		HAT_UP,
+		HAT_RIGHT,
+		HAT_DOWN,
+		HAT_LEFT,
+		HAT_MAX,
+	};
+
+	enum {
+		JOYPADS_MAX = 16,
+	};
+
+	struct JoyAxis {
+		int min;
+		float value;
+	};
+
+private:
 	int mouse_button_mask;
 	int mouse_button_mask;
 
 
 	Set<int> keys_pressed;
 	Set<int> keys_pressed;
@@ -49,6 +109,7 @@ class InputDefault : public Input {
 	Vector3 magnetometer;
 	Vector3 magnetometer;
 	Vector3 gyroscope;
 	Vector3 gyroscope;
 	Vector2 mouse_pos;
 	Vector2 mouse_pos;
+	int64_t mouse_window;
 	MainLoop *main_loop;
 	MainLoop *main_loop;
 
 
 	struct Action {
 	struct Action {
@@ -123,33 +184,6 @@ class InputDefault : public Input {
 
 
 	CursorShape default_shape;
 	CursorShape default_shape;
 
 
-public:
-	enum HatMask {
-		HAT_MASK_CENTER = 0,
-		HAT_MASK_UP = 1,
-		HAT_MASK_RIGHT = 2,
-		HAT_MASK_DOWN = 4,
-		HAT_MASK_LEFT = 8,
-	};
-
-	enum HatDir {
-		HAT_UP,
-		HAT_RIGHT,
-		HAT_DOWN,
-		HAT_LEFT,
-		HAT_MAX,
-	};
-
-	enum {
-		JOYPADS_MAX = 16,
-	};
-
-	struct JoyAxis {
-		int min;
-		float value;
-	};
-
-private:
 	enum JoyType {
 	enum JoyType {
 		TYPE_BUTTON,
 		TYPE_BUTTON,
 		TYPE_AXIS,
 		TYPE_AXIS,
@@ -186,37 +220,48 @@ private:
 	List<Ref<InputEvent>> accumulated_events;
 	List<Ref<InputEvent>> accumulated_events;
 	bool use_accumulated_input;
 	bool use_accumulated_input;
 
 
+protected:
+	static void _bind_methods();
+
 public:
 public:
-	virtual bool is_key_pressed(int p_keycode) const;
-	virtual bool is_mouse_button_pressed(int p_button) const;
-	virtual bool is_joy_button_pressed(int p_device, int p_button) const;
-	virtual bool is_action_pressed(const StringName &p_action) const;
-	virtual bool is_action_just_pressed(const StringName &p_action) const;
-	virtual bool is_action_just_released(const StringName &p_action) const;
-	virtual float get_action_strength(const StringName &p_action) const;
-
-	virtual float get_joy_axis(int p_device, int p_axis) const;
+	void set_mouse_mode(MouseMode p_mode);
+	MouseMode get_mouse_mode() const;
+	void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const;
+
+	static Input *get_singleton();
+
+	bool is_key_pressed(int p_keycode) const;
+	bool is_mouse_button_pressed(int p_button) const;
+	bool is_joy_button_pressed(int p_device, int p_button) const;
+	bool is_action_pressed(const StringName &p_action) const;
+	bool is_action_just_pressed(const StringName &p_action) const;
+	bool is_action_just_released(const StringName &p_action) const;
+	float get_action_strength(const StringName &p_action) const;
+
+	float get_joy_axis(int p_device, int p_axis) const;
 	String get_joy_name(int p_idx);
 	String get_joy_name(int p_idx);
-	virtual Array get_connected_joypads();
-	virtual Vector2 get_joy_vibration_strength(int p_device);
-	virtual float get_joy_vibration_duration(int p_device);
-	virtual uint64_t get_joy_vibration_timestamp(int p_device);
+	Array get_connected_joypads();
+	Vector2 get_joy_vibration_strength(int p_device);
+	float get_joy_vibration_duration(int p_device);
+	uint64_t get_joy_vibration_timestamp(int p_device);
 	void joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid = "");
 	void joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid = "");
 	void parse_joypad_mapping(String p_mapping, bool p_update_existing);
 	void parse_joypad_mapping(String p_mapping, bool p_update_existing);
 
 
-	virtual Vector3 get_gravity() const;
-	virtual Vector3 get_accelerometer() const;
-	virtual Vector3 get_magnetometer() const;
-	virtual Vector3 get_gyroscope() const;
+	Vector3 get_gravity() const;
+	Vector3 get_accelerometer() const;
+	Vector3 get_magnetometer() const;
+	Vector3 get_gyroscope() const;
 
 
-	virtual Point2 get_mouse_position() const;
-	virtual Point2 get_last_mouse_speed() const;
-	virtual int get_mouse_button_mask() const;
+	Point2 get_mouse_position() const;
+	Point2 get_last_mouse_speed() const;
+	int get_mouse_button_mask() const;
 
 
-	virtual void warp_mouse_position(const Vector2 &p_to);
-	virtual Point2i warp_mouse_motion(const Ref<InputEventMouseMotion> &p_motion, const Rect2 &p_rect);
+	void warp_mouse_position(const Vector2 &p_to);
+	Point2i warp_mouse_motion(const Ref<InputEventMouseMotion> &p_motion, const Rect2 &p_rect);
 
 
-	virtual void parse_input_event(const Ref<InputEvent> &p_event);
+	void parse_drop_files(const Vector<String> &p_files);
+	void parse_notification(int p_notification);
+	void parse_input_event(const Ref<InputEvent> &p_event);
 
 
 	void set_gravity(const Vector3 &p_gravity);
 	void set_gravity(const Vector3 &p_gravity);
 	void set_accelerometer(const Vector3 &p_accel);
 	void set_accelerometer(const Vector3 &p_accel);
@@ -224,9 +269,9 @@ public:
 	void set_gyroscope(const Vector3 &p_gyroscope);
 	void set_gyroscope(const Vector3 &p_gyroscope);
 	void set_joy_axis(int p_device, int p_axis, float p_value);
 	void set_joy_axis(int p_device, int p_axis, float p_value);
 
 
-	virtual void start_joy_vibration(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration = 0);
-	virtual void stop_joy_vibration(int p_device);
-	virtual void vibrate_handheld(int p_duration_ms = 500);
+	void start_joy_vibration(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration = 0);
+	void stop_joy_vibration(int p_device);
+	void vibrate_handheld(int p_duration_ms = 500);
 
 
 	void set_main_loop(MainLoop *p_main_loop);
 	void set_main_loop(MainLoop *p_main_loop);
 	void set_mouse_position(const Point2 &p_posf);
 	void set_mouse_position(const Point2 &p_posf);
@@ -237,31 +282,31 @@ public:
 	void iteration(float p_step);
 	void iteration(float p_step);
 
 
 	void set_emulate_touch_from_mouse(bool p_emulate);
 	void set_emulate_touch_from_mouse(bool p_emulate);
-	virtual bool is_emulating_touch_from_mouse() const;
+	bool is_emulating_touch_from_mouse() const;
 	void ensure_touch_mouse_raised();
 	void ensure_touch_mouse_raised();
 
 
 	void set_emulate_mouse_from_touch(bool p_emulate);
 	void set_emulate_mouse_from_touch(bool p_emulate);
-	virtual bool is_emulating_mouse_from_touch() const;
+	bool is_emulating_mouse_from_touch() const;
 
 
-	virtual CursorShape get_default_cursor_shape() const;
-	virtual void set_default_cursor_shape(CursorShape p_shape);
-	virtual CursorShape get_current_cursor_shape() const;
-	virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape = Input::CURSOR_ARROW, const Vector2 &p_hotspot = Vector2());
+	CursorShape get_default_cursor_shape() const;
+	void set_default_cursor_shape(CursorShape p_shape);
+	CursorShape get_current_cursor_shape() const;
+	void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape = Input::CURSOR_ARROW, const Vector2 &p_hotspot = Vector2());
 
 
 	void parse_mapping(String p_mapping);
 	void parse_mapping(String p_mapping);
 	void joy_button(int p_device, int p_button, bool p_pressed);
 	void joy_button(int p_device, int p_button, bool p_pressed);
 	void joy_axis(int p_device, int p_axis, const JoyAxis &p_value);
 	void joy_axis(int p_device, int p_axis, const JoyAxis &p_value);
 	void joy_hat(int p_device, int p_val);
 	void joy_hat(int p_device, int p_val);
 
 
-	virtual void add_joy_mapping(String p_mapping, bool p_update_existing = false);
-	virtual void remove_joy_mapping(String p_guid);
-	virtual bool is_joy_known(int p_device);
-	virtual String get_joy_guid(int p_device) const;
+	void add_joy_mapping(String p_mapping, bool p_update_existing = false);
+	void remove_joy_mapping(String p_guid);
+	bool is_joy_known(int p_device);
+	String get_joy_guid(int p_device) const;
 
 
-	virtual String get_joy_button_string(int p_button);
-	virtual String get_joy_axis_string(int p_axis);
-	virtual int get_joy_axis_index_from_string(String p_axis);
-	virtual int get_joy_button_index_from_string(String p_button);
+	String get_joy_button_string(int p_button);
+	String get_joy_axis_string(int p_axis);
+	int get_joy_axis_index_from_string(String p_axis);
+	int get_joy_button_index_from_string(String p_button);
 
 
 	int get_unused_joy_id();
 	int get_unused_joy_id();
 
 
@@ -269,12 +314,16 @@ public:
 	String get_joy_guid_remapped(int p_device) const;
 	String get_joy_guid_remapped(int p_device) const;
 	void set_fallback_mapping(String p_guid);
 	void set_fallback_mapping(String p_guid);
 
 
-	virtual void accumulate_input_event(const Ref<InputEvent> &p_event);
-	virtual void flush_accumulated_events();
-	virtual void set_use_accumulated_input(bool p_enable);
+	void accumulate_input_event(const Ref<InputEvent> &p_event);
+	void flush_accumulated_events();
+	void set_use_accumulated_input(bool p_enable);
 
 
-	virtual void release_pressed_events();
-	InputDefault();
+	void release_pressed_events();
+
+	Input();
 };
 };
 
 
-#endif // INPUT_DEFAULT_H
+VARIANT_ENUM_CAST(Input::MouseMode);
+VARIANT_ENUM_CAST(Input::CursorShape);
+
+#endif // INPUT_H

+ 73 - 0
core/input/input_builders.py

@@ -0,0 +1,73 @@
+"""Functions used to generate source files during build time
+
+All such functions are invoked in a subprocess on Windows to prevent build flakiness.
+"""
+
+from platform_methods import subprocess_main
+from collections import OrderedDict
+
+
+def make_default_controller_mappings(target, source, env):
+    dst = target[0]
+    g = open(dst, "w")
+
+    g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
+    g.write("#include \"core/typedefs.h\"\n")
+    g.write("#include \"core/input/default_controller_mappings.h\"\n")
+
+    # ensure mappings have a consistent order
+    platform_mappings = OrderedDict()
+    for src_path in source:
+        with open(src_path, "r") as f:
+            # read mapping file and skip header
+            mapping_file_lines = f.readlines()[2:]
+
+        current_platform = None
+        for line in mapping_file_lines:
+            if not line:
+                continue
+            line = line.strip()
+            if len(line) == 0:
+                continue
+            if line[0] == "#":
+                current_platform = line[1:].strip()
+                if current_platform not in platform_mappings:
+                    platform_mappings[current_platform] = {}
+            elif current_platform:
+                line_parts = line.split(",")
+                guid = line_parts[0]
+                if guid in platform_mappings[current_platform]:
+                    g.write("// WARNING - DATABASE {} OVERWROTE PRIOR MAPPING: {} {}\n".format(src_path, current_platform, platform_mappings[current_platform][guid]))
+                valid_mapping = True
+                for input_map in line_parts[2:]:
+                    if "+" in input_map or "-" in input_map or "~" in input_map:
+                        g.write("// WARNING - DISCARDED UNSUPPORTED MAPPING TYPE FROM DATABASE {}: {} {}\n".format(src_path, current_platform, line))
+                        valid_mapping = False
+                        break
+                if valid_mapping:
+                    platform_mappings[current_platform][guid] = line
+
+    platform_variables = {
+        "Linux": "#if X11_ENABLED",
+        "Windows": "#ifdef WINDOWS_ENABLED",
+        "Mac OS X": "#ifdef OSX_ENABLED",
+        "Android": "#if defined(__ANDROID__)",
+        "iOS": "#ifdef IPHONE_ENABLED",
+        "Javascript": "#ifdef JAVASCRIPT_ENABLED",
+        "UWP": "#ifdef UWP_ENABLED",
+    }
+
+    g.write("const char* DefaultControllerMappings::mappings[] = {\n")
+    for platform, mappings in platform_mappings.items():
+        variable = platform_variables[platform]
+        g.write("{}\n".format(variable))
+        for mapping in mappings.values():
+            g.write("\t\"{}\",\n".format(mapping))
+        g.write("#endif\n")
+
+    g.write("\tNULL\n};\n")
+    g.close()
+
+
+if __name__ == '__main__':
+    subprocess_main(globals())

+ 32 - 2
core/os/input_event.cpp → core/input/input_event.cpp

@@ -30,7 +30,7 @@
 
 
 #include "input_event.h"
 #include "input_event.h"
 
 
-#include "core/input_map.h"
+#include "core/input/input_map.h"
 #include "core/os/keyboard.h"
 #include "core/os/keyboard.h"
 
 
 const int InputEvent::DEVICE_ID_TOUCH_MOUSE = -1;
 const int InputEvent::DEVICE_ID_TOUCH_MOUSE = -1;
@@ -136,6 +136,25 @@ InputEvent::InputEvent() {
 
 
 	device = 0;
 	device = 0;
 }
 }
+////////////////
+
+void InputEventFromWindow::_bind_methods() {
+
+	ClassDB::bind_method(D_METHOD("set_window_id", "id"), &InputEventFromWindow::set_window_id);
+	ClassDB::bind_method(D_METHOD("get_window_id"), &InputEventFromWindow::get_window_id);
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "window_id"), "set_window_id", "get_window_id");
+}
+
+void InputEventFromWindow::set_window_id(int64_t p_id) {
+	window_id = p_id;
+}
+int64_t InputEventFromWindow::get_window_id() const {
+	return window_id;
+}
+
+InputEventFromWindow::InputEventFromWindow() {
+	window_id = 0;
+}
 
 
 //////////////////
 //////////////////
 
 
@@ -499,7 +518,7 @@ Ref<InputEvent> InputEventMouseButton::xformed_by(const Transform2D &p_xform, co
 	mb.instance();
 	mb.instance();
 
 
 	mb->set_device(get_device());
 	mb->set_device(get_device());
-
+	mb->set_window_id(get_window_id());
 	mb->set_modifiers_from_event(this);
 	mb->set_modifiers_from_event(this);
 
 
 	mb->set_position(l);
 	mb->set_position(l);
@@ -650,6 +669,7 @@ Ref<InputEvent> InputEventMouseMotion::xformed_by(const Transform2D &p_xform, co
 	mm.instance();
 	mm.instance();
 
 
 	mm->set_device(get_device());
 	mm->set_device(get_device());
+	mm->set_window_id(get_window_id());
 
 
 	mm->set_modifiers_from_event(this);
 	mm->set_modifiers_from_event(this);
 
 
@@ -697,6 +717,10 @@ bool InputEventMouseMotion::accumulate(const Ref<InputEvent> &p_event) {
 	if (motion.is_null())
 	if (motion.is_null())
 		return false;
 		return false;
 
 
+	if (get_window_id() != motion->get_window_id()) {
+		return false;
+	}
+
 	if (is_pressed() != motion->is_pressed()) {
 	if (is_pressed() != motion->is_pressed()) {
 		return false;
 		return false;
 	}
 	}
@@ -948,6 +972,7 @@ Ref<InputEvent> InputEventScreenTouch::xformed_by(const Transform2D &p_xform, co
 	Ref<InputEventScreenTouch> st;
 	Ref<InputEventScreenTouch> st;
 	st.instance();
 	st.instance();
 	st->set_device(get_device());
 	st->set_device(get_device());
+	st->set_window_id(get_window_id());
 	st->set_index(index);
 	st->set_index(index);
 	st->set_position(p_xform.xform(pos + p_local_ofs));
 	st->set_position(p_xform.xform(pos + p_local_ofs));
 	st->set_pressed(pressed);
 	st->set_pressed(pressed);
@@ -1028,6 +1053,7 @@ Ref<InputEvent> InputEventScreenDrag::xformed_by(const Transform2D &p_xform, con
 	sd.instance();
 	sd.instance();
 
 
 	sd->set_device(get_device());
 	sd->set_device(get_device());
+	sd->set_window_id(get_window_id());
 
 
 	sd->set_index(index);
 	sd->set_index(index);
 	sd->set_position(p_xform.xform(pos + p_local_ofs));
 	sd->set_position(p_xform.xform(pos + p_local_ofs));
@@ -1186,6 +1212,8 @@ Ref<InputEvent> InputEventMagnifyGesture::xformed_by(const Transform2D &p_xform,
 	ev.instance();
 	ev.instance();
 
 
 	ev->set_device(get_device());
 	ev->set_device(get_device());
+	ev->set_window_id(get_window_id());
+
 	ev->set_modifiers_from_event(this);
 	ev->set_modifiers_from_event(this);
 
 
 	ev->set_position(p_xform.xform(get_position() + p_local_ofs));
 	ev->set_position(p_xform.xform(get_position() + p_local_ofs));
@@ -1228,6 +1256,8 @@ Ref<InputEvent> InputEventPanGesture::xformed_by(const Transform2D &p_xform, con
 	ev.instance();
 	ev.instance();
 
 
 	ev->set_device(get_device());
 	ev->set_device(get_device());
+	ev->set_window_id(get_window_id());
+
 	ev->set_modifiers_from_event(this);
 	ev->set_modifiers_from_event(this);
 
 
 	ev->set_position(p_xform.xform(get_position() + p_local_ofs));
 	ev->set_position(p_xform.xform(get_position() + p_local_ofs));

+ 22 - 6
core/os/input_event.h → core/input/input_event.h

@@ -205,8 +205,24 @@ public:
 	InputEvent();
 	InputEvent();
 };
 };
 
 
-class InputEventWithModifiers : public InputEvent {
-	GDCLASS(InputEventWithModifiers, InputEvent);
+class InputEventFromWindow : public InputEvent {
+
+	GDCLASS(InputEventFromWindow, InputEvent);
+
+	int64_t window_id;
+
+protected:
+	static void _bind_methods();
+
+public:
+	void set_window_id(int64_t p_id);
+	int64_t get_window_id() const;
+
+	InputEventFromWindow();
+};
+
+class InputEventWithModifiers : public InputEventFromWindow {
+	GDCLASS(InputEventWithModifiers, InputEventFromWindow);
 
 
 	bool shift;
 	bool shift;
 	bool alt;
 	bool alt;
@@ -440,8 +456,8 @@ public:
 	InputEventJoypadButton();
 	InputEventJoypadButton();
 };
 };
 
 
-class InputEventScreenTouch : public InputEvent {
-	GDCLASS(InputEventScreenTouch, InputEvent);
+class InputEventScreenTouch : public InputEventFromWindow {
+	GDCLASS(InputEventScreenTouch, InputEventFromWindow);
 	int index;
 	int index;
 	Vector2 pos;
 	Vector2 pos;
 	bool pressed;
 	bool pressed;
@@ -465,9 +481,9 @@ public:
 	InputEventScreenTouch();
 	InputEventScreenTouch();
 };
 };
 
 
-class InputEventScreenDrag : public InputEvent {
+class InputEventScreenDrag : public InputEventFromWindow {
 
 
-	GDCLASS(InputEventScreenDrag, InputEvent);
+	GDCLASS(InputEventScreenDrag, InputEventFromWindow);
 	int index;
 	int index;
 	Vector2 pos;
 	Vector2 pos;
 	Vector2 relative;
 	Vector2 relative;

+ 0 - 0
core/input_map.cpp → core/input/input_map.cpp


+ 1 - 1
core/input_map.h → core/input/input_map.h

@@ -31,8 +31,8 @@
 #ifndef INPUT_MAP_H
 #ifndef INPUT_MAP_H
 #define INPUT_MAP_H
 #define INPUT_MAP_H
 
 
+#include "core/input/input_event.h"
 #include "core/object.h"
 #include "core/object.h"
-#include "core/os/input_event.h"
 
 
 class InputMap : public Object {
 class InputMap : public Object {
 
 

+ 3 - 0
core/method_ptrcall.h

@@ -118,6 +118,9 @@ MAKE_PTRARG(String);
 MAKE_PTRARG(Vector2);
 MAKE_PTRARG(Vector2);
 MAKE_PTRARG(Rect2);
 MAKE_PTRARG(Rect2);
 MAKE_PTRARG_BY_REFERENCE(Vector3);
 MAKE_PTRARG_BY_REFERENCE(Vector3);
+MAKE_PTRARG(Vector2i);
+MAKE_PTRARG(Rect2i);
+MAKE_PTRARG_BY_REFERENCE(Vector3i);
 MAKE_PTRARG(Transform2D);
 MAKE_PTRARG(Transform2D);
 MAKE_PTRARG_BY_REFERENCE(Plane);
 MAKE_PTRARG_BY_REFERENCE(Plane);
 MAKE_PTRARG(Quat);
 MAKE_PTRARG(Quat);

+ 0 - 157
core/os/input.cpp

@@ -1,157 +0,0 @@
-/*************************************************************************/
-/*  input.cpp                                                            */
-/*************************************************************************/
-/*                       This file is part of:                           */
-/*                           GODOT ENGINE                                */
-/*                      https://godotengine.org                          */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
-/*                                                                       */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the       */
-/* "Software"), to deal in the Software without restriction, including   */
-/* without limitation the rights to use, copy, modify, merge, publish,   */
-/* distribute, sublicense, and/or sell copies of the Software, and to    */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions:                                             */
-/*                                                                       */
-/* The above copyright notice and this permission notice shall be        */
-/* included in all copies or substantial portions of the Software.       */
-/*                                                                       */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
-/*************************************************************************/
-
-#include "input.h"
-
-#include "core/input_map.h"
-#include "core/os/os.h"
-#include "core/project_settings.h"
-
-#ifdef TOOLS_ENABLED
-#include "editor/editor_settings.h"
-#endif
-
-Input *Input::singleton = NULL;
-
-Input *Input::get_singleton() {
-
-	return singleton;
-}
-
-void Input::set_mouse_mode(MouseMode p_mode) {
-	ERR_FAIL_INDEX((int)p_mode, 4);
-	OS::get_singleton()->set_mouse_mode((OS::MouseMode)p_mode);
-}
-
-Input::MouseMode Input::get_mouse_mode() const {
-
-	return (MouseMode)OS::get_singleton()->get_mouse_mode();
-}
-
-void Input::_bind_methods() {
-
-	ClassDB::bind_method(D_METHOD("is_key_pressed", "keycode"), &Input::is_key_pressed);
-	ClassDB::bind_method(D_METHOD("is_mouse_button_pressed", "button"), &Input::is_mouse_button_pressed);
-	ClassDB::bind_method(D_METHOD("is_joy_button_pressed", "device", "button"), &Input::is_joy_button_pressed);
-	ClassDB::bind_method(D_METHOD("is_action_pressed", "action"), &Input::is_action_pressed);
-	ClassDB::bind_method(D_METHOD("is_action_just_pressed", "action"), &Input::is_action_just_pressed);
-	ClassDB::bind_method(D_METHOD("is_action_just_released", "action"), &Input::is_action_just_released);
-	ClassDB::bind_method(D_METHOD("get_action_strength", "action"), &Input::get_action_strength);
-	ClassDB::bind_method(D_METHOD("add_joy_mapping", "mapping", "update_existing"), &Input::add_joy_mapping, DEFVAL(false));
-	ClassDB::bind_method(D_METHOD("remove_joy_mapping", "guid"), &Input::remove_joy_mapping);
-	ClassDB::bind_method(D_METHOD("joy_connection_changed", "device", "connected", "name", "guid"), &Input::joy_connection_changed);
-	ClassDB::bind_method(D_METHOD("is_joy_known", "device"), &Input::is_joy_known);
-	ClassDB::bind_method(D_METHOD("get_joy_axis", "device", "axis"), &Input::get_joy_axis);
-	ClassDB::bind_method(D_METHOD("get_joy_name", "device"), &Input::get_joy_name);
-	ClassDB::bind_method(D_METHOD("get_joy_guid", "device"), &Input::get_joy_guid);
-	ClassDB::bind_method(D_METHOD("get_connected_joypads"), &Input::get_connected_joypads);
-	ClassDB::bind_method(D_METHOD("get_joy_vibration_strength", "device"), &Input::get_joy_vibration_strength);
-	ClassDB::bind_method(D_METHOD("get_joy_vibration_duration", "device"), &Input::get_joy_vibration_duration);
-	ClassDB::bind_method(D_METHOD("get_joy_button_string", "button_index"), &Input::get_joy_button_string);
-	ClassDB::bind_method(D_METHOD("get_joy_button_index_from_string", "button"), &Input::get_joy_button_index_from_string);
-	ClassDB::bind_method(D_METHOD("get_joy_axis_string", "axis_index"), &Input::get_joy_axis_string);
-	ClassDB::bind_method(D_METHOD("get_joy_axis_index_from_string", "axis"), &Input::get_joy_axis_index_from_string);
-	ClassDB::bind_method(D_METHOD("start_joy_vibration", "device", "weak_magnitude", "strong_magnitude", "duration"), &Input::start_joy_vibration, DEFVAL(0));
-	ClassDB::bind_method(D_METHOD("stop_joy_vibration", "device"), &Input::stop_joy_vibration);
-	ClassDB::bind_method(D_METHOD("vibrate_handheld", "duration_ms"), &Input::vibrate_handheld, DEFVAL(500));
-	ClassDB::bind_method(D_METHOD("get_gravity"), &Input::get_gravity);
-	ClassDB::bind_method(D_METHOD("get_accelerometer"), &Input::get_accelerometer);
-	ClassDB::bind_method(D_METHOD("get_magnetometer"), &Input::get_magnetometer);
-	ClassDB::bind_method(D_METHOD("get_gyroscope"), &Input::get_gyroscope);
-	//ClassDB::bind_method(D_METHOD("get_mouse_position"),&Input::get_mouse_position); - this is not the function you want
-	ClassDB::bind_method(D_METHOD("get_last_mouse_speed"), &Input::get_last_mouse_speed);
-	ClassDB::bind_method(D_METHOD("get_mouse_button_mask"), &Input::get_mouse_button_mask);
-	ClassDB::bind_method(D_METHOD("set_mouse_mode", "mode"), &Input::set_mouse_mode);
-	ClassDB::bind_method(D_METHOD("get_mouse_mode"), &Input::get_mouse_mode);
-	ClassDB::bind_method(D_METHOD("warp_mouse_position", "to"), &Input::warp_mouse_position);
-	ClassDB::bind_method(D_METHOD("action_press", "action", "strength"), &Input::action_press, DEFVAL(1.f));
-	ClassDB::bind_method(D_METHOD("action_release", "action"), &Input::action_release);
-	ClassDB::bind_method(D_METHOD("set_default_cursor_shape", "shape"), &Input::set_default_cursor_shape, DEFVAL(CURSOR_ARROW));
-	ClassDB::bind_method(D_METHOD("get_current_cursor_shape"), &Input::get_current_cursor_shape);
-	ClassDB::bind_method(D_METHOD("set_custom_mouse_cursor", "image", "shape", "hotspot"), &Input::set_custom_mouse_cursor, DEFVAL(CURSOR_ARROW), DEFVAL(Vector2()));
-	ClassDB::bind_method(D_METHOD("parse_input_event", "event"), &Input::parse_input_event);
-	ClassDB::bind_method(D_METHOD("set_use_accumulated_input", "enable"), &Input::set_use_accumulated_input);
-
-	BIND_ENUM_CONSTANT(MOUSE_MODE_VISIBLE);
-	BIND_ENUM_CONSTANT(MOUSE_MODE_HIDDEN);
-	BIND_ENUM_CONSTANT(MOUSE_MODE_CAPTURED);
-	BIND_ENUM_CONSTANT(MOUSE_MODE_CONFINED);
-
-	BIND_ENUM_CONSTANT(CURSOR_ARROW);
-	BIND_ENUM_CONSTANT(CURSOR_IBEAM);
-	BIND_ENUM_CONSTANT(CURSOR_POINTING_HAND);
-	BIND_ENUM_CONSTANT(CURSOR_CROSS);
-	BIND_ENUM_CONSTANT(CURSOR_WAIT);
-	BIND_ENUM_CONSTANT(CURSOR_BUSY);
-	BIND_ENUM_CONSTANT(CURSOR_DRAG);
-	BIND_ENUM_CONSTANT(CURSOR_CAN_DROP);
-	BIND_ENUM_CONSTANT(CURSOR_FORBIDDEN);
-	BIND_ENUM_CONSTANT(CURSOR_VSIZE);
-	BIND_ENUM_CONSTANT(CURSOR_HSIZE);
-	BIND_ENUM_CONSTANT(CURSOR_BDIAGSIZE);
-	BIND_ENUM_CONSTANT(CURSOR_FDIAGSIZE);
-	BIND_ENUM_CONSTANT(CURSOR_MOVE);
-	BIND_ENUM_CONSTANT(CURSOR_VSPLIT);
-	BIND_ENUM_CONSTANT(CURSOR_HSPLIT);
-	BIND_ENUM_CONSTANT(CURSOR_HELP);
-
-	ADD_SIGNAL(MethodInfo("joy_connection_changed", PropertyInfo(Variant::INT, "device"), PropertyInfo(Variant::BOOL, "connected")));
-}
-
-void Input::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
-#ifdef TOOLS_ENABLED
-
-	const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", 0) ? "'" : "\"";
-
-	String pf = p_function;
-	if (p_idx == 0 && (pf == "is_action_pressed" || pf == "action_press" || pf == "action_release" || pf == "is_action_just_pressed" || pf == "is_action_just_released" || pf == "get_action_strength")) {
-
-		List<PropertyInfo> pinfo;
-		ProjectSettings::get_singleton()->get_property_list(&pinfo);
-
-		for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) {
-			const PropertyInfo &pi = E->get();
-
-			if (!pi.name.begins_with("input/"))
-				continue;
-
-			String name = pi.name.substr(pi.name.find("/") + 1, pi.name.length());
-			r_options->push_back(quote_style + name + quote_style);
-		}
-	}
-#endif
-}
-
-Input::Input() {
-
-	singleton = this;
-}
-
-//////////////////////////////////////////////////////////

+ 0 - 146
core/os/input.h

@@ -1,146 +0,0 @@
-/*************************************************************************/
-/*  input.h                                                              */
-/*************************************************************************/
-/*                       This file is part of:                           */
-/*                           GODOT ENGINE                                */
-/*                      https://godotengine.org                          */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
-/*                                                                       */
-/* 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.                */
-/*************************************************************************/
-
-#ifndef INPUT_H
-#define INPUT_H
-
-#include "core/object.h"
-#include "core/os/main_loop.h"
-#include "core/os/thread_safe.h"
-
-class Input : public Object {
-
-	GDCLASS(Input, Object);
-
-	static Input *singleton;
-
-protected:
-	static void _bind_methods();
-
-public:
-	enum MouseMode {
-		MOUSE_MODE_VISIBLE,
-		MOUSE_MODE_HIDDEN,
-		MOUSE_MODE_CAPTURED,
-		MOUSE_MODE_CONFINED
-	};
-
-#undef CursorShape
-	enum CursorShape {
-		CURSOR_ARROW,
-		CURSOR_IBEAM,
-		CURSOR_POINTING_HAND,
-		CURSOR_CROSS,
-		CURSOR_WAIT,
-		CURSOR_BUSY,
-		CURSOR_DRAG,
-		CURSOR_CAN_DROP,
-		CURSOR_FORBIDDEN,
-		CURSOR_VSIZE,
-		CURSOR_HSIZE,
-		CURSOR_BDIAGSIZE,
-		CURSOR_FDIAGSIZE,
-		CURSOR_MOVE,
-		CURSOR_VSPLIT,
-		CURSOR_HSPLIT,
-		CURSOR_HELP,
-		CURSOR_MAX
-	};
-
-	void set_mouse_mode(MouseMode p_mode);
-	MouseMode get_mouse_mode() const;
-
-	static Input *get_singleton();
-
-	virtual bool is_key_pressed(int p_keycode) const = 0;
-	virtual bool is_mouse_button_pressed(int p_button) const = 0;
-	virtual bool is_joy_button_pressed(int p_device, int p_button) const = 0;
-	virtual bool is_action_pressed(const StringName &p_action) const = 0;
-	virtual bool is_action_just_pressed(const StringName &p_action) const = 0;
-	virtual bool is_action_just_released(const StringName &p_action) const = 0;
-	virtual float get_action_strength(const StringName &p_action) const = 0;
-
-	virtual float get_joy_axis(int p_device, int p_axis) const = 0;
-	virtual String get_joy_name(int p_idx) = 0;
-	virtual Array get_connected_joypads() = 0;
-	virtual void joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid) = 0;
-	virtual void add_joy_mapping(String p_mapping, bool p_update_existing = false) = 0;
-	virtual void remove_joy_mapping(String p_guid) = 0;
-	virtual bool is_joy_known(int p_device) = 0;
-	virtual String get_joy_guid(int p_device) const = 0;
-	virtual Vector2 get_joy_vibration_strength(int p_device) = 0;
-	virtual float get_joy_vibration_duration(int p_device) = 0;
-	virtual uint64_t get_joy_vibration_timestamp(int p_device) = 0;
-	virtual void start_joy_vibration(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration = 0) = 0;
-	virtual void stop_joy_vibration(int p_device) = 0;
-	virtual void vibrate_handheld(int p_duration_ms = 500) = 0;
-
-	virtual Point2 get_mouse_position() const = 0;
-	virtual Point2 get_last_mouse_speed() const = 0;
-	virtual int get_mouse_button_mask() const = 0;
-
-	virtual void warp_mouse_position(const Vector2 &p_to) = 0;
-	virtual Point2i warp_mouse_motion(const Ref<InputEventMouseMotion> &p_motion, const Rect2 &p_rect) = 0;
-
-	virtual Vector3 get_gravity() const = 0;
-	virtual Vector3 get_accelerometer() const = 0;
-	virtual Vector3 get_magnetometer() const = 0;
-	virtual Vector3 get_gyroscope() const = 0;
-
-	virtual void action_press(const StringName &p_action, float p_strength = 1.f) = 0;
-	virtual void action_release(const StringName &p_action) = 0;
-
-	void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const;
-
-	virtual bool is_emulating_touch_from_mouse() const = 0;
-	virtual bool is_emulating_mouse_from_touch() const = 0;
-
-	virtual CursorShape get_default_cursor_shape() const = 0;
-	virtual void set_default_cursor_shape(CursorShape p_shape) = 0;
-	virtual CursorShape get_current_cursor_shape() const = 0;
-	virtual void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2()) = 0;
-
-	virtual String get_joy_button_string(int p_button) = 0;
-	virtual String get_joy_axis_string(int p_axis) = 0;
-	virtual int get_joy_button_index_from_string(String p_button) = 0;
-	virtual int get_joy_axis_index_from_string(String p_axis) = 0;
-
-	virtual void parse_input_event(const Ref<InputEvent> &p_event) = 0;
-	virtual void accumulate_input_event(const Ref<InputEvent> &p_event) = 0;
-	virtual void flush_accumulated_events() = 0;
-	virtual void set_use_accumulated_input(bool p_enable) = 0;
-
-	Input();
-};
-
-VARIANT_ENUM_CAST(Input::MouseMode);
-VARIANT_ENUM_CAST(Input::CursorShape);
-
-#endif // INPUT_H

+ 1 - 1
core/os/main_loop.h

@@ -31,7 +31,7 @@
 #ifndef MAIN_LOOP_H
 #ifndef MAIN_LOOP_H
 #define MAIN_LOOP_H
 #define MAIN_LOOP_H
 
 
-#include "core/os/input_event.h"
+#include "core/input/input_event.h"
 #include "core/reference.h"
 #include "core/reference.h"
 #include "core/script_language.h"
 #include "core/script_language.h"
 
 

+ 2 - 2
core/os/midi_driver.cpp

@@ -30,8 +30,8 @@
 
 
 #include "midi_driver.h"
 #include "midi_driver.h"
 
 
+#include "core/input/input.h"
 #include "core/os/os.h"
 #include "core/os/os.h"
-#include "main/input_default.h"
 
 
 uint8_t MIDIDriver::last_received_message = 0x00;
 uint8_t MIDIDriver::last_received_message = 0x00;
 MIDIDriver *MIDIDriver::singleton = NULL;
 MIDIDriver *MIDIDriver::singleton = NULL;
@@ -117,7 +117,7 @@ void MIDIDriver::receive_input_packet(uint64_t timestamp, uint8_t *data, uint32_
 			break;
 			break;
 	}
 	}
 
 
-	InputDefault *id = Object::cast_to<InputDefault>(Input::get_singleton());
+	Input *id = Input::get_singleton();
 	id->parse_input_event(event);
 	id->parse_input_event(event);
 }
 }
 
 

+ 1 - 1
core/os/os.cpp

@@ -30,9 +30,9 @@
 
 
 #include "os.h"
 #include "os.h"
 
 
+#include "core/input/input.h"
 #include "core/os/dir_access.h"
 #include "core/os/dir_access.h"
 #include "core/os/file_access.h"
 #include "core/os/file_access.h"
-#include "core/os/input.h"
 #include "core/os/midi_driver.h"
 #include "core/os/midi_driver.h"
 #include "core/project_settings.h"
 #include "core/project_settings.h"
 #include "core/version_generated.gen.h"
 #include "core/version_generated.gen.h"

+ 2 - 2
core/register_core_types.cpp

@@ -38,7 +38,8 @@
 #include "core/crypto/hashing_context.h"
 #include "core/crypto/hashing_context.h"
 #include "core/engine.h"
 #include "core/engine.h"
 #include "core/func_ref.h"
 #include "core/func_ref.h"
-#include "core/input_map.h"
+#include "core/input/input.h"
+#include "core/input/input_map.h"
 #include "core/io/config_file.h"
 #include "core/io/config_file.h"
 #include "core/io/dtls_server.h"
 #include "core/io/dtls_server.h"
 #include "core/io/http_client.h"
 #include "core/io/http_client.h"
@@ -62,7 +63,6 @@
 #include "core/math/geometry.h"
 #include "core/math/geometry.h"
 #include "core/math/random_number_generator.h"
 #include "core/math/random_number_generator.h"
 #include "core/math/triangle_mesh.h"
 #include "core/math/triangle_mesh.h"
-#include "core/os/input.h"
 #include "core/os/main_loop.h"
 #include "core/os/main_loop.h"
 #include "core/packed_data_container.h"
 #include "core/packed_data_container.h"
 #include "core/path_remap.h"
 #include "core/path_remap.h"

+ 3 - 0
core/type_info.h

@@ -144,6 +144,9 @@ MAKE_TYPE_INFO(String, Variant::STRING)
 MAKE_TYPE_INFO(Vector2, Variant::VECTOR2)
 MAKE_TYPE_INFO(Vector2, Variant::VECTOR2)
 MAKE_TYPE_INFO(Rect2, Variant::RECT2)
 MAKE_TYPE_INFO(Rect2, Variant::RECT2)
 MAKE_TYPE_INFO(Vector3, Variant::VECTOR3)
 MAKE_TYPE_INFO(Vector3, Variant::VECTOR3)
+MAKE_TYPE_INFO(Vector2i, Variant::VECTOR2I)
+MAKE_TYPE_INFO(Rect2i, Variant::RECT2I)
+MAKE_TYPE_INFO(Vector3i, Variant::VECTOR3I)
 MAKE_TYPE_INFO(Transform2D, Variant::TRANSFORM2D)
 MAKE_TYPE_INFO(Transform2D, Variant::TRANSFORM2D)
 MAKE_TYPE_INFO(Plane, Variant::PLANE)
 MAKE_TYPE_INFO(Plane, Variant::PLANE)
 MAKE_TYPE_INFO(Quat, Variant::QUAT)
 MAKE_TYPE_INFO(Quat, Variant::QUAT)

+ 1 - 1
core/variant_parser.cpp

@@ -30,8 +30,8 @@
 
 
 #include "variant_parser.h"
 #include "variant_parser.h"
 
 
+#include "core/input/input_event.h"
 #include "core/io/resource_loader.h"
 #include "core/io/resource_loader.h"
-#include "core/os/input_event.h"
 #include "core/os/keyboard.h"
 #include "core/os/keyboard.h"
 #include "core/string_buffer.h"
 #include "core/string_buffer.h"
 
 

+ 1 - 1
editor/animation_track_editor.cpp

@@ -31,7 +31,7 @@
 #include "animation_track_editor.h"
 #include "animation_track_editor.h"
 
 
 #include "animation_track_editor_plugins.h"
 #include "animation_track_editor_plugins.h"
-#include "core/os/input.h"
+#include "core/input/input.h"
 #include "core/os/keyboard.h"
 #include "core/os/keyboard.h"
 #include "editor/animation_bezier_editor.h"
 #include "editor/animation_bezier_editor.h"
 #include "editor/plugins/animation_player_editor_plugin.h"
 #include "editor/plugins/animation_player_editor_plugin.h"

+ 1 - 1
editor/code_editor.cpp

@@ -30,7 +30,7 @@
 
 
 #include "code_editor.h"
 #include "code_editor.h"
 
 
-#include "core/os/input.h"
+#include "core/input/input.h"
 #include "core/os/keyboard.h"
 #include "core/os/keyboard.h"
 #include "core/string_builder.h"
 #include "core/string_builder.h"
 #include "editor/editor_scale.h"
 #include "editor/editor_scale.h"

+ 1 - 1
editor/editor_audio_buses.cpp

@@ -30,8 +30,8 @@
 
 
 #include "editor_audio_buses.h"
 #include "editor_audio_buses.h"
 
 
+#include "core/input/input.h"
 #include "core/io/resource_saver.h"
 #include "core/io/resource_saver.h"
-#include "core/os/input.h"
 #include "core/os/keyboard.h"
 #include "core/os/keyboard.h"
 #include "editor_node.h"
 #include "editor_node.h"
 #include "editor_scale.h"
 #include "editor_scale.h"

+ 1 - 1
editor/editor_help.cpp

@@ -30,7 +30,7 @@
 
 
 #include "editor_help.h"
 #include "editor_help.h"
 
 
-#include "core/os/input.h"
+#include "core/input/input.h"
 #include "core/os/keyboard.h"
 #include "core/os/keyboard.h"
 #include "doc_data_compressed.gen.h"
 #include "doc_data_compressed.gen.h"
 #include "editor/plugins/script_editor_plugin.h"
 #include "editor/plugins/script_editor_plugin.h"

+ 2 - 3
editor/editor_node.cpp

@@ -32,6 +32,7 @@
 
 
 #include "core/bind/core_bind.h"
 #include "core/bind/core_bind.h"
 #include "core/class_db.h"
 #include "core/class_db.h"
+#include "core/input/input.h"
 #include "core/io/config_file.h"
 #include "core/io/config_file.h"
 #include "core/io/image_loader.h"
 #include "core/io/image_loader.h"
 #include "core/io/resource_loader.h"
 #include "core/io/resource_loader.h"
@@ -39,7 +40,6 @@
 #include "core/io/stream_peer_ssl.h"
 #include "core/io/stream_peer_ssl.h"
 #include "core/message_queue.h"
 #include "core/message_queue.h"
 #include "core/os/file_access.h"
 #include "core/os/file_access.h"
-#include "core/os/input.h"
 #include "core/os/keyboard.h"
 #include "core/os/keyboard.h"
 #include "core/os/os.h"
 #include "core/os/os.h"
 #include "core/path_remap.h"
 #include "core/path_remap.h"
@@ -47,7 +47,6 @@
 #include "core/project_settings.h"
 #include "core/project_settings.h"
 #include "core/translation.h"
 #include "core/translation.h"
 #include "core/version.h"
 #include "core/version.h"
-#include "main/input_default.h"
 #include "main/main.h"
 #include "main/main.h"
 #include "scene/gui/center_container.h"
 #include "scene/gui/center_container.h"
 #include "scene/gui/control.h"
 #include "scene/gui/control.h"
@@ -5482,7 +5481,7 @@ EditorNode::EditorNode() {
 	ResourceLoader::clear_translation_remaps(); //no remaps using during editor
 	ResourceLoader::clear_translation_remaps(); //no remaps using during editor
 	ResourceLoader::clear_path_remaps();
 	ResourceLoader::clear_path_remaps();
 
 
-	InputDefault *id = Object::cast_to<InputDefault>(Input::get_singleton());
+	Input *id = Input::get_singleton();
 
 
 	if (id) {
 	if (id) {
 
 

+ 1 - 1
editor/editor_spin_slider.cpp

@@ -29,8 +29,8 @@
 /*************************************************************************/
 /*************************************************************************/
 
 
 #include "editor_spin_slider.h"
 #include "editor_spin_slider.h"
+#include "core/input/input.h"
 #include "core/math/expression.h"
 #include "core/math/expression.h"
-#include "core/os/input.h"
 #include "editor_node.h"
 #include "editor_node.h"
 #include "editor_scale.h"
 #include "editor_scale.h"
 
 

+ 1 - 1
editor/export_template_manager.cpp

@@ -30,10 +30,10 @@
 
 
 #include "export_template_manager.h"
 #include "export_template_manager.h"
 
 
+#include "core/input/input.h"
 #include "core/io/json.h"
 #include "core/io/json.h"
 #include "core/io/zip_io.h"
 #include "core/io/zip_io.h"
 #include "core/os/dir_access.h"
 #include "core/os/dir_access.h"
-#include "core/os/input.h"
 #include "core/os/keyboard.h"
 #include "core/os/keyboard.h"
 #include "core/version.h"
 #include "core/version.h"
 #include "editor_node.h"
 #include "editor_node.h"

+ 1 - 1
editor/plugins/animation_blend_space_2d_editor.cpp

@@ -30,9 +30,9 @@
 
 
 #include "animation_blend_space_2d_editor.h"
 #include "animation_blend_space_2d_editor.h"
 
 
+#include "core/input/input.h"
 #include "core/io/resource_loader.h"
 #include "core/io/resource_loader.h"
 #include "core/math/delaunay.h"
 #include "core/math/delaunay.h"
-#include "core/os/input.h"
 #include "core/os/keyboard.h"
 #include "core/os/keyboard.h"
 #include "core/project_settings.h"
 #include "core/project_settings.h"
 #include "editor/editor_scale.h"
 #include "editor/editor_scale.h"

+ 1 - 1
editor/plugins/animation_blend_tree_editor_plugin.cpp

@@ -30,8 +30,8 @@
 
 
 #include "animation_blend_tree_editor_plugin.h"
 #include "animation_blend_tree_editor_plugin.h"
 
 
+#include "core/input/input.h"
 #include "core/io/resource_loader.h"
 #include "core/io/resource_loader.h"
-#include "core/os/input.h"
 #include "core/os/keyboard.h"
 #include "core/os/keyboard.h"
 #include "core/project_settings.h"
 #include "core/project_settings.h"
 #include "editor/editor_inspector.h"
 #include "editor/editor_inspector.h"

+ 1 - 1
editor/plugins/animation_player_editor_plugin.cpp

@@ -30,9 +30,9 @@
 
 
 #include "animation_player_editor_plugin.h"
 #include "animation_player_editor_plugin.h"
 
 
+#include "core/input/input.h"
 #include "core/io/resource_loader.h"
 #include "core/io/resource_loader.h"
 #include "core/io/resource_saver.h"
 #include "core/io/resource_saver.h"
-#include "core/os/input.h"
 #include "core/os/keyboard.h"
 #include "core/os/keyboard.h"
 #include "core/project_settings.h"
 #include "core/project_settings.h"
 #include "editor/animation_track_editor.h"
 #include "editor/animation_track_editor.h"

+ 1 - 1
editor/plugins/animation_state_machine_editor.cpp

@@ -30,9 +30,9 @@
 
 
 #include "animation_state_machine_editor.h"
 #include "animation_state_machine_editor.h"
 
 
+#include "core/input/input.h"
 #include "core/io/resource_loader.h"
 #include "core/io/resource_loader.h"
 #include "core/math/delaunay.h"
 #include "core/math/delaunay.h"
-#include "core/os/input.h"
 #include "core/os/keyboard.h"
 #include "core/os/keyboard.h"
 #include "core/project_settings.h"
 #include "core/project_settings.h"
 #include "editor/editor_scale.h"
 #include "editor/editor_scale.h"

+ 1 - 1
editor/plugins/animation_tree_editor_plugin.cpp

@@ -34,9 +34,9 @@
 #include "animation_blend_space_2d_editor.h"
 #include "animation_blend_space_2d_editor.h"
 #include "animation_blend_tree_editor_plugin.h"
 #include "animation_blend_tree_editor_plugin.h"
 #include "animation_state_machine_editor.h"
 #include "animation_state_machine_editor.h"
+#include "core/input/input.h"
 #include "core/io/resource_loader.h"
 #include "core/io/resource_loader.h"
 #include "core/math/delaunay.h"
 #include "core/math/delaunay.h"
-#include "core/os/input.h"
 #include "core/os/keyboard.h"
 #include "core/os/keyboard.h"
 #include "core/project_settings.h"
 #include "core/project_settings.h"
 #include "editor/editor_scale.h"
 #include "editor/editor_scale.h"

+ 1 - 1
editor/plugins/asset_library_editor_plugin.cpp

@@ -30,8 +30,8 @@
 
 
 #include "asset_library_editor_plugin.h"
 #include "asset_library_editor_plugin.h"
 
 
+#include "core/input/input.h"
 #include "core/io/json.h"
 #include "core/io/json.h"
-#include "core/os/input.h"
 #include "core/os/keyboard.h"
 #include "core/os/keyboard.h"
 #include "core/version.h"
 #include "core/version.h"
 #include "editor/editor_node.h"
 #include "editor/editor_node.h"

+ 1 - 1
editor/plugins/canvas_item_editor_plugin.cpp

@@ -30,7 +30,7 @@
 
 
 #include "canvas_item_editor_plugin.h"
 #include "canvas_item_editor_plugin.h"
 
 
-#include "core/os/input.h"
+#include "core/input/input.h"
 #include "core/os/keyboard.h"
 #include "core/os/keyboard.h"
 #include "core/print_string.h"
 #include "core/print_string.h"
 #include "core/project_settings.h"
 #include "core/project_settings.h"

+ 1 - 1
editor/plugins/collision_polygon_editor_plugin.cpp

@@ -31,8 +31,8 @@
 #include "collision_polygon_editor_plugin.h"
 #include "collision_polygon_editor_plugin.h"
 
 
 #include "canvas_item_editor_plugin.h"
 #include "canvas_item_editor_plugin.h"
+#include "core/input/input.h"
 #include "core/os/file_access.h"
 #include "core/os/file_access.h"
-#include "core/os/input.h"
 #include "core/os/keyboard.h"
 #include "core/os/keyboard.h"
 #include "editor/editor_settings.h"
 #include "editor/editor_settings.h"
 #include "scene/3d/camera.h"
 #include "scene/3d/camera.h"

+ 1 - 1
editor/plugins/curve_editor_plugin.cpp

@@ -32,7 +32,7 @@
 
 
 #include "canvas_item_editor_plugin.h"
 #include "canvas_item_editor_plugin.h"
 #include "core/core_string_names.h"
 #include "core/core_string_names.h"
-#include "core/os/input.h"
+#include "core/input/input.h"
 #include "core/os/keyboard.h"
 #include "core/os/keyboard.h"
 #include "editor/editor_scale.h"
 #include "editor/editor_scale.h"
 
 

+ 1 - 1
editor/plugins/polygon_2d_editor_plugin.cpp

@@ -31,8 +31,8 @@
 #include "polygon_2d_editor_plugin.h"
 #include "polygon_2d_editor_plugin.h"
 
 
 #include "canvas_item_editor_plugin.h"
 #include "canvas_item_editor_plugin.h"
+#include "core/input/input.h"
 #include "core/os/file_access.h"
 #include "core/os/file_access.h"
-#include "core/os/input.h"
 #include "core/os/keyboard.h"
 #include "core/os/keyboard.h"
 #include "editor/editor_scale.h"
 #include "editor/editor_scale.h"
 #include "editor/editor_settings.h"
 #include "editor/editor_settings.h"

+ 1 - 1
editor/plugins/script_editor_plugin.cpp

@@ -30,9 +30,9 @@
 
 
 #include "script_editor_plugin.h"
 #include "script_editor_plugin.h"
 
 
+#include "core/input/input.h"
 #include "core/io/resource_loader.h"
 #include "core/io/resource_loader.h"
 #include "core/os/file_access.h"
 #include "core/os/file_access.h"
-#include "core/os/input.h"
 #include "core/os/keyboard.h"
 #include "core/os/keyboard.h"
 #include "core/os/os.h"
 #include "core/os/os.h"
 #include "core/project_settings.h"
 #include "core/project_settings.h"

+ 1 - 1
editor/plugins/spatial_editor_plugin.cpp

@@ -30,8 +30,8 @@
 
 
 #include "spatial_editor_plugin.h"
 #include "spatial_editor_plugin.h"
 
 
+#include "core/input/input.h"
 #include "core/math/camera_matrix.h"
 #include "core/math/camera_matrix.h"
-#include "core/os/input.h"
 #include "core/os/keyboard.h"
 #include "core/os/keyboard.h"
 #include "core/print_string.h"
 #include "core/print_string.h"
 #include "core/project_settings.h"
 #include "core/project_settings.h"

+ 1 - 1
editor/plugins/texture_region_editor_plugin.cpp

@@ -31,7 +31,7 @@
 #include "texture_region_editor_plugin.h"
 #include "texture_region_editor_plugin.h"
 
 
 #include "core/core_string_names.h"
 #include "core/core_string_names.h"
-#include "core/os/input.h"
+#include "core/input/input.h"
 #include "core/os/keyboard.h"
 #include "core/os/keyboard.h"
 #include "editor/editor_scale.h"
 #include "editor/editor_scale.h"
 #include "scene/gui/check_box.h"
 #include "scene/gui/check_box.h"

+ 1 - 1
editor/plugins/tile_map_editor_plugin.cpp

@@ -31,8 +31,8 @@
 #include "tile_map_editor_plugin.h"
 #include "tile_map_editor_plugin.h"
 
 
 #include "canvas_item_editor_plugin.h"
 #include "canvas_item_editor_plugin.h"
+#include "core/input/input.h"
 #include "core/math/math_funcs.h"
 #include "core/math/math_funcs.h"
-#include "core/os/input.h"
 #include "core/os/keyboard.h"
 #include "core/os/keyboard.h"
 #include "editor/editor_scale.h"
 #include "editor/editor_scale.h"
 #include "editor/editor_settings.h"
 #include "editor/editor_settings.h"

+ 1 - 1
editor/plugins/tile_set_editor_plugin.cpp

@@ -30,7 +30,7 @@
 
 
 #include "tile_set_editor_plugin.h"
 #include "tile_set_editor_plugin.h"
 
 
-#include "core/os/input.h"
+#include "core/input/input.h"
 #include "core/os/keyboard.h"
 #include "core/os/keyboard.h"
 #include "editor/editor_scale.h"
 #include "editor/editor_scale.h"
 #include "editor/plugins/canvas_item_editor_plugin.h"
 #include "editor/plugins/canvas_item_editor_plugin.h"

+ 1 - 1
editor/plugins/visual_shader_editor_plugin.cpp

@@ -30,9 +30,9 @@
 
 
 #include "visual_shader_editor_plugin.h"
 #include "visual_shader_editor_plugin.h"
 
 
+#include "core/input/input.h"
 #include "core/io/resource_loader.h"
 #include "core/io/resource_loader.h"
 #include "core/math/math_defs.h"
 #include "core/math/math_defs.h"
-#include "core/os/input.h"
 #include "core/os/keyboard.h"
 #include "core/os/keyboard.h"
 #include "core/project_settings.h"
 #include "core/project_settings.h"
 #include "core/version.h"
 #include "core/version.h"

+ 1 - 1
editor/project_settings_editor.cpp

@@ -31,7 +31,7 @@
 #include "project_settings_editor.h"
 #include "project_settings_editor.h"
 
 
 #include "core/global_constants.h"
 #include "core/global_constants.h"
-#include "core/input_map.h"
+#include "core/input/input_map.h"
 #include "core/os/keyboard.h"
 #include "core/os/keyboard.h"
 #include "core/project_settings.h"
 #include "core/project_settings.h"
 #include "core/translation.h"
 #include "core/translation.h"

+ 1 - 1
editor/property_editor.cpp

@@ -31,11 +31,11 @@
 #include "property_editor.h"
 #include "property_editor.h"
 
 
 #include "core/class_db.h"
 #include "core/class_db.h"
+#include "core/input/input.h"
 #include "core/io/image_loader.h"
 #include "core/io/image_loader.h"
 #include "core/io/marshalls.h"
 #include "core/io/marshalls.h"
 #include "core/io/resource_loader.h"
 #include "core/io/resource_loader.h"
 #include "core/math/expression.h"
 #include "core/math/expression.h"
-#include "core/os/input.h"
 #include "core/os/keyboard.h"
 #include "core/os/keyboard.h"
 #include "core/pair.h"
 #include "core/pair.h"
 #include "core/print_string.h"
 #include "core/print_string.h"

+ 1 - 1
editor/scene_tree_dock.cpp

@@ -30,8 +30,8 @@
 
 
 #include "scene_tree_dock.h"
 #include "scene_tree_dock.h"
 
 
+#include "core/input/input.h"
 #include "core/io/resource_saver.h"
 #include "core/io/resource_saver.h"
-#include "core/os/input.h"
 #include "core/os/keyboard.h"
 #include "core/os/keyboard.h"
 #include "core/project_settings.h"
 #include "core/project_settings.h"
 #include "editor/debugger/editor_debugger_node.h"
 #include "editor/debugger/editor_debugger_node.h"

+ 0 - 9
main/SCsub

@@ -9,15 +9,6 @@ env.main_sources = []
 
 
 env.add_source_files(env.main_sources, "*.cpp")
 env.add_source_files(env.main_sources, "*.cpp")
 
 
-# Order matters here. Higher index controller database files write on top of lower index database files.
-controller_databases = ["#main/gamecontrollerdb_204.txt", "#main/gamecontrollerdb_205.txt", "#main/gamecontrollerdb.txt", "#main/godotcontrollerdb.txt"]
-
-env.Depends("#main/default_controller_mappings.gen.cpp", controller_databases)
-env.CommandNoCache("#main/default_controller_mappings.gen.cpp", controller_databases, run_in_subprocess(main_builders.make_default_controller_mappings))
-
-# Don't warn about duplicate entry here, we need it registered manually for first build,
-# even if later builds will pick it up twice due to above *.cpp globbing.
-env.add_source_files(env.main_sources, "#main/default_controller_mappings.gen.cpp", warn_duplicates=False)
 
 
 env.Depends("#main/splash.gen.h", "#main/splash.png")
 env.Depends("#main/splash.gen.h", "#main/splash.png")
 env.CommandNoCache("#main/splash.gen.h", "#main/splash.png", run_in_subprocess(main_builders.make_splash))
 env.CommandNoCache("#main/splash.gen.h", "#main/splash.png", run_in_subprocess(main_builders.make_splash))

+ 3 - 3
main/main.cpp

@@ -32,7 +32,8 @@
 
 
 #include "core/crypto/crypto.h"
 #include "core/crypto/crypto.h"
 #include "core/debugger/engine_debugger.h"
 #include "core/debugger/engine_debugger.h"
-#include "core/input_map.h"
+#include "core/input/input.h"
+#include "core/input/input_map.h"
 #include "core/io/file_access_network.h"
 #include "core/io/file_access_network.h"
 #include "core/io/file_access_pack.h"
 #include "core/io/file_access_pack.h"
 #include "core/io/file_access_zip.h"
 #include "core/io/file_access_zip.h"
@@ -49,7 +50,6 @@
 #include "core/version_hash.gen.h"
 #include "core/version_hash.gen.h"
 #include "drivers/register_driver_types.h"
 #include "drivers/register_driver_types.h"
 #include "main/app_icon.gen.h"
 #include "main/app_icon.gen.h"
-#include "main/input_default.h"
 #include "main/main_timer_sync.h"
 #include "main/main_timer_sync.h"
 #include "main/performance.h"
 #include "main/performance.h"
 #include "main/splash.gen.h"
 #include "main/splash.gen.h"
@@ -1294,7 +1294,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
 	GLOBAL_DEF("application/config/windows_native_icon", String());
 	GLOBAL_DEF("application/config/windows_native_icon", String());
 	ProjectSettings::get_singleton()->set_custom_property_info("application/config/windows_native_icon", PropertyInfo(Variant::STRING, "application/config/windows_native_icon", PROPERTY_HINT_FILE, "*.ico"));
 	ProjectSettings::get_singleton()->set_custom_property_info("application/config/windows_native_icon", PropertyInfo(Variant::STRING, "application/config/windows_native_icon", PROPERTY_HINT_FILE, "*.ico"));
 
 
-	InputDefault *id = Object::cast_to<InputDefault>(Input::get_singleton());
+	Input *id = Input::get_singleton();
 	if (id) {
 	if (id) {
 		if (bool(GLOBAL_DEF("input_devices/pointing/emulate_touch_from_mouse", false)) && !(editor || project_manager)) {
 		if (bool(GLOBAL_DEF("input_devices/pointing/emulate_touch_from_mouse", false)) && !(editor || project_manager)) {
 			if (!OS::get_singleton()->has_touchscreen_ui_hint()) {
 			if (!OS::get_singleton()->has_touchscreen_ui_hint()) {

+ 0 - 62
main/main_builders.py

@@ -63,67 +63,5 @@ def make_app_icon(target, source, env):
         g.write("#endif")
         g.write("#endif")
 
 
 
 
-def make_default_controller_mappings(target, source, env):
-    dst = target[0]
-    g = open(dst, "w")
-
-    g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
-    g.write("#include \"core/typedefs.h\"\n")
-    g.write("#include \"main/default_controller_mappings.h\"\n")
-
-    # ensure mappings have a consistent order
-    platform_mappings = OrderedDict()
-    for src_path in source:
-        with open(src_path, "r") as f:
-            # read mapping file and skip header
-            mapping_file_lines = f.readlines()[2:]
-
-        current_platform = None
-        for line in mapping_file_lines:
-            if not line:
-                continue
-            line = line.strip()
-            if len(line) == 0:
-                continue
-            if line[0] == "#":
-                current_platform = line[1:].strip()
-                if current_platform not in platform_mappings:
-                    platform_mappings[current_platform] = {}
-            elif current_platform:
-                line_parts = line.split(",")
-                guid = line_parts[0]
-                if guid in platform_mappings[current_platform]:
-                    g.write("// WARNING - DATABASE {} OVERWROTE PRIOR MAPPING: {} {}\n".format(src_path, current_platform, platform_mappings[current_platform][guid]))
-                valid_mapping = True
-                for input_map in line_parts[2:]:
-                    if "+" in input_map or "-" in input_map or "~" in input_map:
-                        g.write("// WARNING - DISCARDED UNSUPPORTED MAPPING TYPE FROM DATABASE {}: {} {}\n".format(src_path, current_platform, line))
-                        valid_mapping = False
-                        break
-                if valid_mapping:
-                    platform_mappings[current_platform][guid] = line
-
-    platform_variables = {
-        "Linux": "#if X11_ENABLED",
-        "Windows": "#ifdef WINDOWS_ENABLED",
-        "Mac OS X": "#ifdef OSX_ENABLED",
-        "Android": "#if defined(__ANDROID__)",
-        "iOS": "#ifdef IPHONE_ENABLED",
-        "Javascript": "#ifdef JAVASCRIPT_ENABLED",
-        "UWP": "#ifdef UWP_ENABLED",
-    }
-
-    g.write("const char* DefaultControllerMappings::mappings[] = {\n")
-    for platform, mappings in platform_mappings.items():
-        variable = platform_variables[platform]
-        g.write("{}\n".format(variable))
-        for mapping in mappings.values():
-            g.write("\t\"{}\",\n".format(mapping))
-        g.write("#endif\n")
-
-    g.write("\tNULL\n};\n")
-    g.close()
-
-
 if __name__ == '__main__':
 if __name__ == '__main__':
     subprocess_main(globals())
     subprocess_main(globals())

+ 1 - 1
modules/arkit/arkit_interface.mm

@@ -28,7 +28,7 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
 /*************************************************************************/
 
 
-#include "core/os/input.h"
+#include "core/input/input.h"
 #include "core/os/os.h"
 #include "core/os/os.h"
 #include "scene/resources/surface_tool.h"
 #include "scene/resources/surface_tool.h"
 #include "servers/visual/visual_server_globals.h"
 #include "servers/visual/visual_server_globals.h"

+ 6 - 6
modules/gdnative/arvr/arvr_interface_gdnative.cpp

@@ -29,7 +29,7 @@
 /*************************************************************************/
 /*************************************************************************/
 
 
 #include "arvr_interface_gdnative.h"
 #include "arvr_interface_gdnative.h"
-#include "main/input_default.h"
+#include "core/input/input.h"
 #include "servers/arvr/arvr_positional_tracker.h"
 #include "servers/arvr/arvr_positional_tracker.h"
 #include "servers/visual/visual_server_globals.h"
 #include "servers/visual/visual_server_globals.h"
 
 
@@ -317,7 +317,7 @@ godot_int GDAPI godot_arvr_add_controller(char *p_device_name, godot_int p_hand,
 	ARVRServer *arvr_server = ARVRServer::get_singleton();
 	ARVRServer *arvr_server = ARVRServer::get_singleton();
 	ERR_FAIL_NULL_V(arvr_server, 0);
 	ERR_FAIL_NULL_V(arvr_server, 0);
 
 
-	InputDefault *input = (InputDefault *)Input::get_singleton();
+	Input *input = Input::get_singleton();
 	ERR_FAIL_NULL_V(input, 0);
 	ERR_FAIL_NULL_V(input, 0);
 
 
 	ARVRPositionalTracker *new_tracker = memnew(ARVRPositionalTracker);
 	ARVRPositionalTracker *new_tracker = memnew(ARVRPositionalTracker);
@@ -356,7 +356,7 @@ void GDAPI godot_arvr_remove_controller(godot_int p_controller_id) {
 	ARVRServer *arvr_server = ARVRServer::get_singleton();
 	ARVRServer *arvr_server = ARVRServer::get_singleton();
 	ERR_FAIL_NULL(arvr_server);
 	ERR_FAIL_NULL(arvr_server);
 
 
-	InputDefault *input = (InputDefault *)Input::get_singleton();
+	Input *input = Input::get_singleton();
 	ERR_FAIL_NULL(input);
 	ERR_FAIL_NULL(input);
 
 
 	ARVRPositionalTracker *remove_tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_CONTROLLER, p_controller_id);
 	ARVRPositionalTracker *remove_tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_CONTROLLER, p_controller_id);
@@ -394,7 +394,7 @@ void GDAPI godot_arvr_set_controller_button(godot_int p_controller_id, godot_int
 	ARVRServer *arvr_server = ARVRServer::get_singleton();
 	ARVRServer *arvr_server = ARVRServer::get_singleton();
 	ERR_FAIL_NULL(arvr_server);
 	ERR_FAIL_NULL(arvr_server);
 
 
-	InputDefault *input = (InputDefault *)Input::get_singleton();
+	Input *input = Input::get_singleton();
 	ERR_FAIL_NULL(input);
 	ERR_FAIL_NULL(input);
 
 
 	ARVRPositionalTracker *tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_CONTROLLER, p_controller_id);
 	ARVRPositionalTracker *tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_CONTROLLER, p_controller_id);
@@ -410,14 +410,14 @@ void GDAPI godot_arvr_set_controller_axis(godot_int p_controller_id, godot_int p
 	ARVRServer *arvr_server = ARVRServer::get_singleton();
 	ARVRServer *arvr_server = ARVRServer::get_singleton();
 	ERR_FAIL_NULL(arvr_server);
 	ERR_FAIL_NULL(arvr_server);
 
 
-	InputDefault *input = (InputDefault *)Input::get_singleton();
+	Input *input = Input::get_singleton();
 	ERR_FAIL_NULL(input);
 	ERR_FAIL_NULL(input);
 
 
 	ARVRPositionalTracker *tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_CONTROLLER, p_controller_id);
 	ARVRPositionalTracker *tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_CONTROLLER, p_controller_id);
 	if (tracker != NULL) {
 	if (tracker != NULL) {
 		int joyid = tracker->get_joy_id();
 		int joyid = tracker->get_joy_id();
 		if (joyid != -1) {
 		if (joyid != -1) {
-			InputDefault::JoyAxis jx;
+			Input::JoyAxis jx;
 			jx.min = p_can_be_negative ? -1 : 0;
 			jx.min = p_can_be_negative ? -1 : 0;
 			jx.value = p_value;
 			jx.value = p_value;
 			input->joy_axis(joyid, p_axis, jx);
 			input->joy_axis(joyid, p_axis, jx);

+ 1 - 1
modules/gridmap/grid_map_editor_plugin.cpp

@@ -29,7 +29,7 @@
 /*************************************************************************/
 /*************************************************************************/
 
 
 #include "grid_map_editor_plugin.h"
 #include "grid_map_editor_plugin.h"
-#include "core/os/input.h"
+#include "core/input/input.h"
 #include "editor/editor_scale.h"
 #include "editor/editor_scale.h"
 #include "editor/editor_settings.h"
 #include "editor/editor_settings.h"
 #include "editor/plugins/spatial_editor_plugin.h"
 #include "editor/plugins/spatial_editor_plugin.h"

+ 1 - 1
modules/mobile_vr/mobile_vr_interface.cpp

@@ -29,7 +29,7 @@
 /*************************************************************************/
 /*************************************************************************/
 
 
 #include "mobile_vr_interface.h"
 #include "mobile_vr_interface.h"
-#include "core/os/input.h"
+#include "core/input/input.h"
 #include "core/os/os.h"
 #include "core/os/os.h"
 #include "servers/visual/visual_server_globals.h"
 #include "servers/visual/visual_server_globals.h"
 
 

+ 1 - 1
modules/visual_script/visual_script_editor.cpp

@@ -30,8 +30,8 @@
 
 
 #include "visual_script_editor.h"
 #include "visual_script_editor.h"
 
 
+#include "core/input/input.h"
 #include "core/object.h"
 #include "core/object.h"
-#include "core/os/input.h"
 #include "core/os/keyboard.h"
 #include "core/os/keyboard.h"
 #include "core/script_language.h"
 #include "core/script_language.h"
 #include "core/variant.h"
 #include "core/variant.h"

+ 1 - 1
modules/visual_script/visual_script_nodes.cpp

@@ -32,7 +32,7 @@
 
 
 #include "core/engine.h"
 #include "core/engine.h"
 #include "core/global_constants.h"
 #include "core/global_constants.h"
-#include "core/os/input.h"
+#include "core/input/input.h"
 #include "core/os/os.h"
 #include "core/os/os.h"
 #include "core/project_settings.h"
 #include "core/project_settings.h"
 #include "scene/main/node.h"
 #include "scene/main/node.h"

+ 1 - 1
platform/android/java_godot_lib_jni.cpp

@@ -37,12 +37,12 @@
 #include "api/java_class_wrapper.h"
 #include "api/java_class_wrapper.h"
 #include "audio_driver_jandroid.h"
 #include "audio_driver_jandroid.h"
 #include "core/engine.h"
 #include "core/engine.h"
+#include "core/input/input.h"
 #include "core/project_settings.h"
 #include "core/project_settings.h"
 #include "dir_access_jandroid.h"
 #include "dir_access_jandroid.h"
 #include "file_access_android.h"
 #include "file_access_android.h"
 #include "file_access_jandroid.h"
 #include "file_access_jandroid.h"
 #include "jni_utils.h"
 #include "jni_utils.h"
-#include "main/input_default.h"
 #include "main/main.h"
 #include "main/main.h"
 #include "net_socket_android.h"
 #include "net_socket_android.h"
 #include "os_android.h"
 #include "os_android.h"

+ 1 - 2
platform/android/os_android.h

@@ -33,10 +33,9 @@
 
 
 #include "audio_driver_jandroid.h"
 #include "audio_driver_jandroid.h"
 #include "audio_driver_opensl.h"
 #include "audio_driver_opensl.h"
-#include "core/os/input.h"
+#include "core/input/input.h"
 #include "core/os/main_loop.h"
 #include "core/os/main_loop.h"
 #include "drivers/unix/os_unix.h"
 #include "drivers/unix/os_unix.h"
-#include "main/input_default.h"
 #include "servers/audio_server.h"
 #include "servers/audio_server.h"
 #include "servers/visual/rasterizer.h"
 #include "servers/visual/rasterizer.h"
 
 

+ 1 - 1
platform/haiku/haiku_direct_window.h

@@ -35,8 +35,8 @@
 
 
 #include <DirectWindow.h>
 #include <DirectWindow.h>
 
 
+#include "core/input/input.h"
 #include "core/os/os.h"
 #include "core/os/os.h"
-#include "main/input_default.h"
 
 
 #include "haiku_gl_view.h"
 #include "haiku_gl_view.h"
 
 

+ 1 - 1
platform/haiku/os_haiku.h

@@ -33,10 +33,10 @@
 
 
 #include "audio_driver_media_kit.h"
 #include "audio_driver_media_kit.h"
 #include "context_gl_haiku.h"
 #include "context_gl_haiku.h"
+#include "core/input/input.h"
 #include "drivers/unix/os_unix.h"
 #include "drivers/unix/os_unix.h"
 #include "haiku_application.h"
 #include "haiku_application.h"
 #include "haiku_direct_window.h"
 #include "haiku_direct_window.h"
-#include "main/input_default.h"
 #include "servers/audio_server.h"
 #include "servers/audio_server.h"
 #include "servers/visual_server.h"
 #include "servers/visual_server.h"
 
 

+ 2 - 2
platform/iphone/os_iphone.h

@@ -33,15 +33,15 @@
 #ifndef OS_IPHONE_H
 #ifndef OS_IPHONE_H
 #define OS_IPHONE_H
 #define OS_IPHONE_H
 
 
-#include "core/os/input.h"
+#include "core/input/input.h"
 #include "drivers/coreaudio/audio_driver_coreaudio.h"
 #include "drivers/coreaudio/audio_driver_coreaudio.h"
 #include "drivers/unix/os_unix.h"
 #include "drivers/unix/os_unix.h"
 
 
+#include "core/input/input.h"
 #include "game_center.h"
 #include "game_center.h"
 #include "icloud.h"
 #include "icloud.h"
 #include "in_app_store.h"
 #include "in_app_store.h"
 #include "ios.h"
 #include "ios.h"
-#include "main/input_default.h"
 #include "servers/audio_server.h"
 #include "servers/audio_server.h"
 #include "servers/visual/rasterizer.h"
 #include "servers/visual/rasterizer.h"
 #include "servers/visual_server.h"
 #include "servers/visual_server.h"

+ 1 - 1
platform/javascript/os_javascript.h

@@ -32,8 +32,8 @@
 #define OS_JAVASCRIPT_H
 #define OS_JAVASCRIPT_H
 
 
 #include "audio_driver_javascript.h"
 #include "audio_driver_javascript.h"
+#include "core/input/input.h"
 #include "drivers/unix/os_unix.h"
 #include "drivers/unix/os_unix.h"
-#include "main/input_default.h"
 #include "servers/audio_server.h"
 #include "servers/audio_server.h"
 #include "servers/visual/rasterizer.h"
 #include "servers/visual/rasterizer.h"
 
 

+ 1 - 1
platform/osx/joypad_osx.h

@@ -40,7 +40,7 @@
 #include <ForceFeedback/ForceFeedbackConstants.h>
 #include <ForceFeedback/ForceFeedbackConstants.h>
 #include <IOKit/hid/IOHIDLib.h>
 #include <IOKit/hid/IOHIDLib.h>
 
 
-#include "main/input_default.h"
+#include "core/input/input.h"
 
 
 struct rec_element {
 struct rec_element {
 	IOHIDElementRef ref;
 	IOHIDElementRef ref;

+ 1 - 2
platform/osx/os_osx.h

@@ -33,13 +33,12 @@
 
 
 #define BitMap _QDBitMap // Suppress deprecated QuickDraw definition.
 #define BitMap _QDBitMap // Suppress deprecated QuickDraw definition.
 
 
-#include "core/os/input.h"
+#include "core/input/input.h"
 #include "crash_handler_osx.h"
 #include "crash_handler_osx.h"
 #include "drivers/coreaudio/audio_driver_coreaudio.h"
 #include "drivers/coreaudio/audio_driver_coreaudio.h"
 #include "drivers/coremidi/midi_driver_coremidi.h"
 #include "drivers/coremidi/midi_driver_coremidi.h"
 #include "drivers/unix/os_unix.h"
 #include "drivers/unix/os_unix.h"
 #include "joypad_osx.h"
 #include "joypad_osx.h"
-#include "main/input_default.h"
 #include "servers/audio_server.h"
 #include "servers/audio_server.h"
 #include "servers/visual/rasterizer.h"
 #include "servers/visual/rasterizer.h"
 #include "servers/visual/visual_server_wrap_mt.h"
 #include "servers/visual/visual_server_wrap_mt.h"

+ 1 - 1
platform/server/os_server.h

@@ -31,9 +31,9 @@
 #ifndef OS_SERVER_H
 #ifndef OS_SERVER_H
 #define OS_SERVER_H
 #define OS_SERVER_H
 
 
+#include "core/input/input.h"
 #include "drivers/dummy/texture_loader_dummy.h"
 #include "drivers/dummy/texture_loader_dummy.h"
 #include "drivers/unix/os_unix.h"
 #include "drivers/unix/os_unix.h"
-#include "main/input_default.h"
 #ifdef __APPLE__
 #ifdef __APPLE__
 #include "platform/osx/crash_handler_osx.h"
 #include "platform/osx/crash_handler_osx.h"
 #include "platform/osx/semaphore_osx.h"
 #include "platform/osx/semaphore_osx.h"

+ 1 - 1
platform/uwp/joypad_uwp.h

@@ -31,7 +31,7 @@
 #ifndef JOYPAD_UWP_H
 #ifndef JOYPAD_UWP_H
 #define JOYPAD_UWP_H
 #define JOYPAD_UWP_H
 
 
-#include "main/input_default.h"
+#include "core/input/input.h"
 
 
 ref class JoypadUWP sealed {
 ref class JoypadUWP sealed {
 
 

+ 1 - 2
platform/uwp/os_uwp.h

@@ -32,13 +32,12 @@
 #define OS_UWP_H
 #define OS_UWP_H
 
 
 #include "context_egl_uwp.h"
 #include "context_egl_uwp.h"
+#include "core/input/input.h"
 #include "core/math/transform_2d.h"
 #include "core/math/transform_2d.h"
-#include "core/os/input.h"
 #include "core/os/os.h"
 #include "core/os/os.h"
 #include "core/ustring.h"
 #include "core/ustring.h"
 #include "drivers/xaudio2/audio_driver_xaudio2.h"
 #include "drivers/xaudio2/audio_driver_xaudio2.h"
 #include "joypad_uwp.h"
 #include "joypad_uwp.h"
-#include "main/input_default.h"
 #include "servers/audio_server.h"
 #include "servers/audio_server.h"
 #include "servers/visual/rasterizer.h"
 #include "servers/visual/rasterizer.h"
 #include "servers/visual_server.h"
 #include "servers/visual_server.h"

+ 1 - 2
platform/windows/os_windows.h

@@ -31,7 +31,7 @@
 #ifndef OS_WINDOWS_H
 #ifndef OS_WINDOWS_H
 #define OS_WINDOWS_H
 #define OS_WINDOWS_H
 
 
-#include "core/os/input.h"
+#include "core/input/input.h"
 #include "core/os/os.h"
 #include "core/os/os.h"
 #include "core/project_settings.h"
 #include "core/project_settings.h"
 #include "crash_handler_windows.h"
 #include "crash_handler_windows.h"
@@ -39,7 +39,6 @@
 #include "drivers/wasapi/audio_driver_wasapi.h"
 #include "drivers/wasapi/audio_driver_wasapi.h"
 #include "drivers/winmidi/midi_driver_winmidi.h"
 #include "drivers/winmidi/midi_driver_winmidi.h"
 #include "key_mapping_windows.h"
 #include "key_mapping_windows.h"
-#include "main/input_default.h"
 #include "servers/audio_server.h"
 #include "servers/audio_server.h"
 #include "servers/visual/rasterizer.h"
 #include "servers/visual/rasterizer.h"
 #include "servers/visual_server.h"
 #include "servers/visual_server.h"

+ 1 - 0
platform/x11/SCsub

@@ -11,6 +11,7 @@ common_x11 = [
     "crash_handler_x11.cpp",
     "crash_handler_x11.cpp",
     "os_x11.cpp",
     "os_x11.cpp",
     "key_mapping_x11.cpp",
     "key_mapping_x11.cpp",
+    "display_server_x11.cpp",
     "joypad_linux.cpp",
     "joypad_linux.cpp",
     "detect_prime.cpp"
     "detect_prime.cpp"
 ]
 ]

+ 3216 - 0
platform/x11/display_server_x11.cpp

@@ -0,0 +1,3216 @@
+/*************************************************************************/
+/*  display_server_x11.cpp                                               */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#include "display_server_x11.h"
+
+#ifdef X11_ENABLED
+
+#include "detect_prime.h"
+
+#include "core/os/dir_access.h"
+#include "core/print_string.h"
+#include "errno.h"
+#include "key_mapping_x11.h"
+
+#if defined(OPENGL_ENABLED)
+#include "drivers/gles2/rasterizer_gles2.h"
+#endif
+
+#if defined(VULKAN_ENABLED)
+#include "servers/visual/rasterizer_rd/rasterizer_rd.h"
+#endif
+
+#include "servers/visual/visual_server_raster.h"
+#include "servers/visual/visual_server_wrap_mt.h"
+
+#ifdef HAVE_MNTENT
+#include <mntent.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "X11/Xutil.h"
+
+#include "X11/Xatom.h"
+#include "X11/extensions/Xinerama.h"
+// ICCCM
+#define WM_NormalState 1L // window normal state
+#define WM_IconicState 3L // window minimized
+// EWMH
+#define _NET_WM_STATE_REMOVE 0L // remove/unset property
+#define _NET_WM_STATE_ADD 1L // add/set property
+#define _NET_WM_STATE_TOGGLE 2L // toggle property
+
+#include "main/main.h"
+
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+//stupid linux.h
+#ifdef KEY_TAB
+#undef KEY_TAB
+#endif
+
+#include <X11/Xatom.h>
+
+#undef CursorShape
+
+#include <X11/XKBlib.h>
+
+// 2.2 is the first release with multitouch
+#define XINPUT_CLIENT_VERSION_MAJOR 2
+#define XINPUT_CLIENT_VERSION_MINOR 2
+
+#define VALUATOR_ABSX 0
+#define VALUATOR_ABSY 1
+#define VALUATOR_PRESSURE 2
+#define VALUATOR_TILTX 3
+#define VALUATOR_TILTY 4
+
+static const double abs_resolution_mult = 10000.0;
+static const double abs_resolution_range_mult = 10.0;
+
+bool DisplayServerX11::has_feature(Feature p_feature) const {
+	switch (p_feature) {
+		case FEATURE_SUBWINDOWS:
+#ifdef TOUCH_ENABLED
+		case FEATURE_TOUCHSCREEN:
+#endif
+		case FEATURE_MOUSE:
+		case FEATURE_MOUSE_WARP:
+		case FEATURE_CLIPBOARD:
+		case FEATURE_CURSOR_SHAPE:
+		case FEATURE_CUSTOM_CURSOR_SHAPE:
+		case FEATURE_IME:
+		case FEATURE_WINDOW_TRANSPARENCY:
+		//case FEATURE_HIDPI:
+		case FEATURE_ICON:
+		case FEATURE_NATIVE_ICON:
+		case FEATURE_SWAP_BUFFERS:
+			return true;
+		default: {
+		}
+	}
+
+	return false;
+}
+String DisplayServerX11::get_name() const {
+	return "X11";
+}
+
+void DisplayServerX11::alert(const String &p_alert, const String &p_title) {
+	const char *message_programs[] = { "zenity", "kdialog", "Xdialog", "xmessage" };
+
+	String path = OS::get_singleton()->get_environment("PATH");
+	Vector<String> path_elems = path.split(":", false);
+	String program;
+
+	for (int i = 0; i < path_elems.size(); i++) {
+		for (uint64_t k = 0; k < sizeof(message_programs) / sizeof(char *); k++) {
+			String tested_path = path_elems[i].plus_file(message_programs[k]);
+
+			if (FileAccess::exists(tested_path)) {
+				program = tested_path;
+				break;
+			}
+		}
+
+		if (program.length())
+			break;
+	}
+
+	List<String> args;
+
+	if (program.ends_with("zenity")) {
+		args.push_back("--error");
+		args.push_back("--width");
+		args.push_back("500");
+		args.push_back("--title");
+		args.push_back(p_title);
+		args.push_back("--text");
+		args.push_back(p_alert);
+	}
+
+	if (program.ends_with("kdialog")) {
+		args.push_back("--error");
+		args.push_back(p_alert);
+		args.push_back("--title");
+		args.push_back(p_title);
+	}
+
+	if (program.ends_with("Xdialog")) {
+		args.push_back("--title");
+		args.push_back(p_title);
+		args.push_back("--msgbox");
+		args.push_back(p_alert);
+		args.push_back("0");
+		args.push_back("0");
+	}
+
+	if (program.ends_with("xmessage")) {
+		args.push_back("-center");
+		args.push_back("-title");
+		args.push_back(p_title);
+		args.push_back(p_alert);
+	}
+
+	if (program.length()) {
+		OS::get_singleton()->execute(program, args, true);
+	} else {
+		print_line(p_alert);
+	}
+}
+
+void DisplayServerX11::_update_real_mouse_position(const WindowData &wd) {
+	Window root_return, child_return;
+	int root_x, root_y, win_x, win_y;
+	unsigned int mask_return;
+
+	Bool xquerypointer_result = XQueryPointer(x11_display, wd.x11_window, &root_return, &child_return, &root_x, &root_y,
+			&win_x, &win_y, &mask_return);
+
+	if (xquerypointer_result) {
+		if (win_x > 0 && win_y > 0 && win_x <= wd.size.width && win_y <= wd.size.height) {
+
+			last_mouse_pos.x = win_x;
+			last_mouse_pos.y = win_y;
+			last_mouse_pos_valid = true;
+			Input::get_singleton()->set_mouse_position(last_mouse_pos);
+		}
+	}
+}
+
+bool DisplayServerX11::_refresh_device_info() {
+	int event_base, error_base;
+
+	print_verbose("XInput: Refreshing devices.");
+
+	if (!XQueryExtension(x11_display, "XInputExtension", &xi.opcode, &event_base, &error_base)) {
+		print_verbose("XInput extension not available. Please upgrade your distribution.");
+		return false;
+	}
+
+	int xi_major_query = XINPUT_CLIENT_VERSION_MAJOR;
+	int xi_minor_query = XINPUT_CLIENT_VERSION_MINOR;
+
+	if (XIQueryVersion(x11_display, &xi_major_query, &xi_minor_query) != Success) {
+		print_verbose(vformat("XInput 2 not available (server supports %d.%d).", xi_major_query, xi_minor_query));
+		xi.opcode = 0;
+		return false;
+	}
+
+	if (xi_major_query < XINPUT_CLIENT_VERSION_MAJOR || (xi_major_query == XINPUT_CLIENT_VERSION_MAJOR && xi_minor_query < XINPUT_CLIENT_VERSION_MINOR)) {
+		print_verbose(vformat("XInput %d.%d not available (server supports %d.%d). Touch input unavailable.",
+				XINPUT_CLIENT_VERSION_MAJOR, XINPUT_CLIENT_VERSION_MINOR, xi_major_query, xi_minor_query));
+	}
+
+	xi.absolute_devices.clear();
+	xi.touch_devices.clear();
+
+	int dev_count;
+	XIDeviceInfo *info = XIQueryDevice(x11_display, XIAllDevices, &dev_count);
+
+	for (int i = 0; i < dev_count; i++) {
+		XIDeviceInfo *dev = &info[i];
+		if (!dev->enabled)
+			continue;
+		if (!(dev->use == XIMasterPointer || dev->use == XIFloatingSlave))
+			continue;
+
+		bool direct_touch = false;
+		bool absolute_mode = false;
+		int resolution_x = 0;
+		int resolution_y = 0;
+		int range_min_x = 0;
+		int range_min_y = 0;
+		int range_max_x = 0;
+		int range_max_y = 0;
+		int pressure_resolution = 0;
+		int tilt_resolution_x = 0;
+		int tilt_resolution_y = 0;
+		for (int j = 0; j < dev->num_classes; j++) {
+#ifdef TOUCH_ENABLED
+			if (dev->classes[j]->type == XITouchClass && ((XITouchClassInfo *)dev->classes[j])->mode == XIDirectTouch) {
+				direct_touch = true;
+			}
+#endif
+			if (dev->classes[j]->type == XIValuatorClass) {
+				XIValuatorClassInfo *class_info = (XIValuatorClassInfo *)dev->classes[j];
+
+				if (class_info->number == VALUATOR_ABSX && class_info->mode == XIModeAbsolute) {
+					resolution_x = class_info->resolution;
+					range_min_x = class_info->min;
+					range_max_x = class_info->max;
+					absolute_mode = true;
+				} else if (class_info->number == VALUATOR_ABSY && class_info->mode == XIModeAbsolute) {
+					resolution_y = class_info->resolution;
+					range_min_y = class_info->min;
+					range_max_y = class_info->max;
+					absolute_mode = true;
+				} else if (class_info->number == VALUATOR_PRESSURE && class_info->mode == XIModeAbsolute) {
+					pressure_resolution = (class_info->max - class_info->min);
+					if (pressure_resolution == 0) pressure_resolution = 1;
+				} else if (class_info->number == VALUATOR_TILTX && class_info->mode == XIModeAbsolute) {
+					tilt_resolution_x = (class_info->max - class_info->min);
+					if (tilt_resolution_x == 0) tilt_resolution_x = 1;
+				} else if (class_info->number == VALUATOR_TILTY && class_info->mode == XIModeAbsolute) {
+					tilt_resolution_y = (class_info->max - class_info->min);
+					if (tilt_resolution_y == 0) tilt_resolution_y = 1;
+				}
+			}
+		}
+		if (direct_touch) {
+			xi.touch_devices.push_back(dev->deviceid);
+			print_verbose("XInput: Using touch device: " + String(dev->name));
+		}
+		if (absolute_mode) {
+			// If no resolution was reported, use the min/max ranges.
+			if (resolution_x <= 0) {
+				resolution_x = (range_max_x - range_min_x) * abs_resolution_range_mult;
+			}
+			if (resolution_y <= 0) {
+				resolution_y = (range_max_y - range_min_y) * abs_resolution_range_mult;
+			}
+
+			xi.absolute_devices[dev->deviceid] = Vector2(abs_resolution_mult / resolution_x, abs_resolution_mult / resolution_y);
+			print_verbose("XInput: Absolute pointing device: " + String(dev->name));
+		}
+
+		xi.pressure = 0;
+		xi.pen_devices[dev->deviceid] = Vector3(pressure_resolution, tilt_resolution_x, tilt_resolution_y);
+	}
+
+	XIFreeDeviceInfo(info);
+#ifdef TOUCH_ENABLED
+	if (!xi.touch_devices.size()) {
+		print_verbose("XInput: No touch devices found.");
+	}
+#endif
+
+	return true;
+}
+
+void DisplayServerX11::_flush_mouse_motion() {
+	while (true) {
+		if (XPending(x11_display) > 0) {
+			XEvent event;
+			XPeekEvent(x11_display, &event);
+
+			if (XGetEventData(x11_display, &event.xcookie) && event.xcookie.type == GenericEvent && event.xcookie.extension == xi.opcode) {
+				XIDeviceEvent *event_data = (XIDeviceEvent *)event.xcookie.data;
+
+				if (event_data->evtype == XI_RawMotion) {
+					XNextEvent(x11_display, &event);
+				} else {
+					break;
+				}
+			} else {
+				break;
+			}
+		} else {
+			break;
+		}
+	}
+
+	xi.relative_motion.x = 0;
+	xi.relative_motion.y = 0;
+}
+
+void DisplayServerX11::mouse_set_mode(MouseMode p_mode) {
+	if (p_mode == mouse_mode)
+		return;
+
+	if (mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED)
+		XUngrabPointer(x11_display, CurrentTime);
+
+	// The only modes that show a cursor are VISIBLE and CONFINED
+	bool showCursor = (p_mode == MOUSE_MODE_VISIBLE || p_mode == MOUSE_MODE_CONFINED);
+
+	for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+
+		if (showCursor) {
+			XDefineCursor(x11_display, E->get().x11_window, cursors[current_cursor]); // show cursor
+		} else {
+			XDefineCursor(x11_display, E->get().x11_window, null_cursor); // hide cursor
+		}
+	}
+	mouse_mode = p_mode;
+
+	if (mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED) {
+
+		//flush pending motion events
+		_flush_mouse_motion();
+		WindowData &main_window = windows[MAIN_WINDOW_ID];
+
+		if (XGrabPointer(
+					x11_display, main_window.x11_window, True,
+					ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
+					GrabModeAsync, GrabModeAsync, windows[MAIN_WINDOW_ID].x11_window, None, CurrentTime) != GrabSuccess) {
+			ERR_PRINT("NO GRAB");
+		}
+
+		if (mouse_mode == MOUSE_MODE_CAPTURED) {
+			center.x = main_window.size.width / 2;
+			center.y = main_window.size.height / 2;
+
+			XWarpPointer(x11_display, None, main_window.x11_window,
+					0, 0, 0, 0, (int)center.x, (int)center.y);
+
+			Input::get_singleton()->set_mouse_position(center);
+		}
+	} else {
+		do_mouse_warp = false;
+	}
+
+	XFlush(x11_display);
+}
+DisplayServerX11::MouseMode DisplayServerX11::mouse_get_mode() const {
+	return mouse_mode;
+}
+
+void DisplayServerX11::mouse_warp_to_position(const Point2i &p_to) {
+	if (mouse_mode == MOUSE_MODE_CAPTURED) {
+
+		last_mouse_pos = p_to;
+	} else {
+
+		/*XWindowAttributes xwa;
+		XGetWindowAttributes(x11_display, x11_window, &xwa);
+		printf("%d %d\n", xwa.x, xwa.y); needed? */
+
+		XWarpPointer(x11_display, None, windows[MAIN_WINDOW_ID].x11_window,
+				0, 0, 0, 0, (int)p_to.x, (int)p_to.y);
+	}
+}
+Point2i DisplayServerX11::mouse_get_position() const {
+	return last_mouse_pos;
+}
+int DisplayServerX11::mouse_get_button_state() const {
+	return last_button_state;
+}
+
+void DisplayServerX11::clipboard_set(const String &p_text) {
+
+	internal_clipboard = p_text;
+	XSetSelectionOwner(x11_display, XA_PRIMARY, windows[MAIN_WINDOW_ID].x11_window, CurrentTime);
+	XSetSelectionOwner(x11_display, XInternAtom(x11_display, "CLIPBOARD", 0), windows[MAIN_WINDOW_ID].x11_window, CurrentTime);
+}
+
+static String _clipboard_get_impl(Atom p_source, Window x11_window, ::Display *x11_display, String p_internal_clipboard, Atom target) {
+
+	String ret;
+
+	Atom type;
+	Atom selection = XA_PRIMARY;
+	int format, result;
+	unsigned long len, bytes_left, dummy;
+	unsigned char *data;
+	Window Sown = XGetSelectionOwner(x11_display, p_source);
+
+	if (Sown == x11_window) {
+
+		return p_internal_clipboard;
+	};
+
+	if (Sown != None) {
+		XConvertSelection(x11_display, p_source, target, selection,
+				x11_window, CurrentTime);
+		XFlush(x11_display);
+		while (true) {
+			XEvent event;
+			XNextEvent(x11_display, &event);
+			if (event.type == SelectionNotify && event.xselection.requestor == x11_window) {
+				break;
+			};
+		};
+
+		//
+		// Do not get any data, see how much data is there
+		//
+		XGetWindowProperty(x11_display, x11_window,
+				selection, // Tricky..
+				0, 0, // offset - len
+				0, // Delete 0==FALSE
+				AnyPropertyType, //flag
+				&type, // return type
+				&format, // return format
+				&len, &bytes_left, //that
+				&data);
+		// DATA is There
+		if (bytes_left > 0) {
+			result = XGetWindowProperty(x11_display, x11_window,
+					selection, 0, bytes_left, 0,
+					AnyPropertyType, &type, &format,
+					&len, &dummy, &data);
+			if (result == Success) {
+				ret.parse_utf8((const char *)data);
+			} else
+				printf("FAIL\n");
+			XFree(data);
+		}
+	}
+
+	return ret;
+}
+
+static String _clipboard_get(Atom p_source, Window x11_window, ::Display *x11_display, String p_internal_clipboard) {
+	String ret;
+	Atom utf8_atom = XInternAtom(x11_display, "UTF8_STRING", True);
+	if (utf8_atom != None) {
+		ret = _clipboard_get_impl(p_source, x11_window, x11_display, p_internal_clipboard, utf8_atom);
+	}
+	if (ret == "") {
+		ret = _clipboard_get_impl(p_source, x11_window, x11_display, p_internal_clipboard, XA_STRING);
+	}
+	return ret;
+}
+
+String DisplayServerX11::clipboard_get() const {
+
+	String ret;
+	ret = _clipboard_get(XInternAtom(x11_display, "CLIPBOARD", 0), windows[MAIN_WINDOW_ID].x11_window, x11_display, internal_clipboard);
+
+	if (ret == "") {
+		ret = _clipboard_get(XA_PRIMARY, windows[MAIN_WINDOW_ID].x11_window, x11_display, internal_clipboard);
+	};
+
+	return ret;
+}
+
+int DisplayServerX11::get_screen_count() const {
+	// Using Xinerama Extension
+	int event_base, error_base;
+	const Bool ext_okay = XineramaQueryExtension(x11_display, &event_base, &error_base);
+	if (!ext_okay) return 0;
+
+	int count;
+	XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &count);
+	XFree(xsi);
+	return count;
+}
+Point2i DisplayServerX11::screen_get_position(int p_screen) const {
+	if (p_screen == SCREEN_OF_MAIN_WINDOW) {
+		p_screen = window_get_current_screen();
+	}
+
+	// Using Xinerama Extension
+	int event_base, error_base;
+	const Bool ext_okay = XineramaQueryExtension(x11_display, &event_base, &error_base);
+	if (!ext_okay) {
+		return Point2i(0, 0);
+	}
+
+	int count;
+	XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &count);
+	if (p_screen >= count) {
+		return Point2i(0, 0);
+	}
+
+	Point2i position = Point2i(xsi[p_screen].x_org, xsi[p_screen].y_org);
+
+	XFree(xsi);
+
+	return position;
+}
+Size2i DisplayServerX11::screen_get_size(int p_screen) const {
+
+	if (p_screen == SCREEN_OF_MAIN_WINDOW) {
+		p_screen = window_get_current_screen();
+	}
+
+	// Using Xinerama Extension
+	int event_base, error_base;
+	const Bool ext_okay = XineramaQueryExtension(x11_display, &event_base, &error_base);
+	if (!ext_okay) return Size2i(0, 0);
+
+	int count;
+	XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &count);
+	if (p_screen >= count) return Size2i(0, 0);
+
+	Size2i size = Point2i(xsi[p_screen].width, xsi[p_screen].height);
+	XFree(xsi);
+	return size;
+}
+int DisplayServerX11::screen_get_dpi(int p_screen) const {
+	if (p_screen == SCREEN_OF_MAIN_WINDOW) {
+		p_screen = window_get_current_screen();
+	}
+
+	//invalid screen?
+	ERR_FAIL_INDEX_V(p_screen, get_screen_count(), 0);
+
+	//Get physical monitor Dimensions through XRandR and calculate dpi
+	Size2i sc = screen_get_size(p_screen);
+	if (xrandr_ext_ok) {
+		int count = 0;
+		if (xrr_get_monitors) {
+			xrr_monitor_info *monitors = xrr_get_monitors(x11_display, windows[MAIN_WINDOW_ID].x11_window, true, &count);
+			if (p_screen < count) {
+				double xdpi = sc.width / (double)monitors[p_screen].mwidth * 25.4;
+				double ydpi = sc.height / (double)monitors[p_screen].mheight * 25.4;
+				xrr_free_monitors(monitors);
+				return (xdpi + ydpi) / 2;
+			}
+			xrr_free_monitors(monitors);
+		} else if (p_screen == 0) {
+			XRRScreenSize *sizes = XRRSizes(x11_display, 0, &count);
+			if (sizes) {
+				double xdpi = sc.width / (double)sizes[0].mwidth * 25.4;
+				double ydpi = sc.height / (double)sizes[0].mheight * 25.4;
+				return (xdpi + ydpi) / 2;
+			}
+		}
+	}
+
+	int width_mm = DisplayWidthMM(x11_display, p_screen);
+	int height_mm = DisplayHeightMM(x11_display, p_screen);
+	double xdpi = (width_mm ? sc.width / (double)width_mm * 25.4 : 0);
+	double ydpi = (height_mm ? sc.height / (double)height_mm * 25.4 : 0);
+	if (xdpi || ydpi)
+		return (xdpi + ydpi) / (xdpi && ydpi ? 2 : 1);
+
+	//could not get dpi
+	return 96;
+}
+bool DisplayServerX11::screen_is_touchscreen(int p_screen) const {
+#ifndef _MSC_VER
+#warning Need to get from proper window
+#endif
+	return false; //?
+}
+
+Vector<DisplayServer::WindowID> DisplayServerX11::get_window_list() const {
+	Vector<int> ret;
+	for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+		ret.push_back(E->key());
+	}
+	return ret;
+}
+
+DisplayServer::WindowID DisplayServerX11::create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect) {
+
+	WindowID id = _create_window(p_mode, p_rect.size);
+	window_set_position(p_rect.position, id);
+	for (int i = 0; i < WINDOW_FLAG_MAX; i++) {
+		if (p_flags & (1 << i)) {
+			window_set_flag(WindowFlags(i), true, id);
+		}
+	}
+
+	return id;
+}
+
+void DisplayServerX11::delete_sub_window(WindowID p_id) {
+	ERR_FAIL_COND(windows.has(p_id));
+	ERR_FAIL_COND_MSG(p_id == MAIN_WINDOW_ID, "Main window can't be deleted"); //ma
+
+	WindowData &wd = windows[p_id];
+
+	XUnmapWindow(x11_display, wd.x11_window);
+	XDestroyWindow(x11_display, wd.x11_window);
+	if (wd.xic) {
+		XDestroyIC(wd.xic);
+	}
+
+	windows.erase(p_id);
+}
+
+void DisplayServerX11::window_set_title(const String &p_title, WindowID p_window) {
+
+	ERR_FAIL_COND(windows.has(p_window));
+	WindowData &wd = windows[p_window];
+
+	XStoreName(x11_display, wd.x11_window, p_title.utf8().get_data());
+
+	Atom _net_wm_name = XInternAtom(x11_display, "_NET_WM_NAME", false);
+	Atom utf8_string = XInternAtom(x11_display, "UTF8_STRING", false);
+	XChangeProperty(x11_display, wd.x11_window, _net_wm_name, utf8_string, 8, PropModeReplace, (unsigned char *)p_title.utf8().get_data(), p_title.utf8().length());
+}
+
+int DisplayServerX11::window_get_current_screen(WindowID p_window) const {
+	ERR_FAIL_COND_V(windows.has(p_window), -1);
+	const WindowData &wd = windows[p_window];
+
+	int x, y;
+	Window child;
+	XTranslateCoordinates(x11_display, wd.x11_window, DefaultRootWindow(x11_display), 0, 0, &x, &y, &child);
+
+	int count = get_screen_count();
+	for (int i = 0; i < count; i++) {
+		Point2i pos = screen_get_position(i);
+		Size2i size = screen_get_size(i);
+		if ((x >= pos.x && x < pos.x + size.width) && (y >= pos.y && y < pos.y + size.height))
+			return i;
+	}
+	return 0;
+}
+void DisplayServerX11::window_set_current_screen(int p_screen, WindowID p_window) {
+	ERR_FAIL_COND(windows.has(p_window));
+	WindowData &wd = windows[p_window];
+
+	int count = get_screen_count();
+	if (p_screen >= count) return;
+
+	if (window_get_mode(p_window) == WINDOW_MODE_FULLSCREEN) {
+		Point2i position = screen_get_position(p_screen);
+		Size2i size = screen_get_size(p_screen);
+
+		XMoveResizeWindow(x11_display, wd.x11_window, position.x, position.y, size.x, size.y);
+	} else {
+		if (p_screen != window_get_current_screen(p_window)) {
+			Point2i position = screen_get_position(p_screen);
+			XMoveWindow(x11_display, wd.x11_window, position.x, position.y);
+		}
+	}
+}
+
+Point2i DisplayServerX11::window_get_position(WindowID p_window) const {
+	ERR_FAIL_COND_V(windows.has(p_window), Point2i());
+	const WindowData &wd = windows[p_window];
+	int x, y;
+	Window child;
+	XTranslateCoordinates(x11_display, wd.x11_window, DefaultRootWindow(x11_display), 0, 0, &x, &y, &child);
+	return Point2i(x, y);
+}
+void DisplayServerX11::window_set_position(const Point2i &p_position, WindowID p_window) {
+	ERR_FAIL_COND(windows.has(p_window));
+	WindowData &wd = windows[p_window];
+
+	int x = 0;
+	int y = 0;
+	if (!window_get_flag(WINDOW_FLAG_BORDERLESS, p_window)) {
+		//exclude window decorations
+		XSync(x11_display, False);
+		Atom prop = XInternAtom(x11_display, "_NET_FRAME_EXTENTS", True);
+		if (prop != None) {
+			Atom type;
+			int format;
+			unsigned long len;
+			unsigned long remaining;
+			unsigned char *data = NULL;
+			if (XGetWindowProperty(x11_display, wd.x11_window, prop, 0, 4, False, AnyPropertyType, &type, &format, &len, &remaining, &data) == Success) {
+				if (format == 32 && len == 4) {
+					long *extents = (long *)data;
+					x = extents[0];
+					y = extents[2];
+				}
+				XFree(data);
+			}
+		}
+	}
+	XMoveWindow(x11_display, wd.x11_window, p_position.x - x, p_position.y - y);
+	_update_real_mouse_position(wd);
+}
+
+void DisplayServerX11::window_set_max_size(const Size2i p_size, WindowID p_window) {
+	ERR_FAIL_COND(windows.has(p_window));
+	WindowData &wd = windows[p_window];
+
+	if ((p_size != Size2i()) && ((p_size.x < wd.min_size.x) || (p_size.y < wd.min_size.y))) {
+		ERR_PRINT("Maximum window size can't be smaller than minimum window size!");
+		return;
+	}
+	wd.max_size = p_size;
+
+	if (!window_get_flag(WINDOW_FLAG_RESIZE_DISABLED, p_window)) {
+		XSizeHints *xsh;
+		xsh = XAllocSizeHints();
+		xsh->flags = 0L;
+		if (wd.min_size != Size2i()) {
+			xsh->flags |= PMinSize;
+			xsh->min_width = wd.min_size.x;
+			xsh->min_height = wd.min_size.y;
+		}
+		if (wd.max_size != Size2i()) {
+			xsh->flags |= PMaxSize;
+			xsh->max_width = wd.max_size.x;
+			xsh->max_height = wd.max_size.y;
+		}
+		XSetWMNormalHints(x11_display, wd.x11_window, xsh);
+		XFree(xsh);
+
+		XFlush(x11_display);
+	}
+}
+Size2i DisplayServerX11::window_get_max_size(WindowID p_window) const {
+	ERR_FAIL_COND_V(windows.has(p_window), Size2i());
+	const WindowData &wd = windows[p_window];
+
+	return wd.max_size;
+}
+
+void DisplayServerX11::window_set_min_size(const Size2i p_size, WindowID p_window) {
+	ERR_FAIL_COND(windows.has(p_window));
+	WindowData &wd = windows[p_window];
+
+	if ((p_size != Size2i()) && (wd.max_size != Size2i()) && ((p_size.x > wd.max_size.x) || (p_size.y > wd.max_size.y))) {
+		ERR_PRINT("Minimum window size can't be larger than maximum window size!");
+		return;
+	}
+	wd.min_size = p_size;
+
+	if (!window_get_flag(WINDOW_FLAG_RESIZE_DISABLED, p_window)) {
+		XSizeHints *xsh;
+		xsh = XAllocSizeHints();
+		xsh->flags = 0L;
+		if (wd.min_size != Size2i()) {
+			xsh->flags |= PMinSize;
+			xsh->min_width = wd.min_size.x;
+			xsh->min_height = wd.min_size.y;
+		}
+		if (wd.max_size != Size2i()) {
+			xsh->flags |= PMaxSize;
+			xsh->max_width = wd.max_size.x;
+			xsh->max_height = wd.max_size.y;
+		}
+		XSetWMNormalHints(x11_display, wd.x11_window, xsh);
+		XFree(xsh);
+
+		XFlush(x11_display);
+	}
+}
+Size2i DisplayServerX11::window_get_min_size(WindowID p_window) const {
+	ERR_FAIL_COND_V(windows.has(p_window), Size2i());
+	const WindowData &wd = windows[p_window];
+
+	return wd.min_size;
+}
+
+void DisplayServerX11::window_set_size(const Size2i p_size, WindowID p_window) {
+	ERR_FAIL_COND(windows.has(p_window));
+	WindowData &wd = windows[p_window];
+
+	if (wd.size.width == p_size.width && wd.size.height == p_size.height)
+		return;
+
+	XWindowAttributes xwa;
+	XSync(x11_display, False);
+	XGetWindowAttributes(x11_display, wd.x11_window, &xwa);
+	int old_w = xwa.width;
+	int old_h = xwa.height;
+
+	// If window resizable is disabled we need to update the attributes first
+	XSizeHints *xsh;
+	xsh = XAllocSizeHints();
+	if (!window_get_flag(WINDOW_FLAG_RESIZE_DISABLED, p_window)) {
+		xsh->flags = PMinSize | PMaxSize;
+		xsh->min_width = p_size.x;
+		xsh->max_width = p_size.x;
+		xsh->min_height = p_size.y;
+		xsh->max_height = p_size.y;
+	} else {
+		xsh->flags = 0L;
+		if (wd.min_size != Size2i()) {
+			xsh->flags |= PMinSize;
+			xsh->min_width = wd.min_size.x;
+			xsh->min_height = wd.min_size.y;
+		}
+		if (wd.max_size != Size2i()) {
+			xsh->flags |= PMaxSize;
+			xsh->max_width = wd.max_size.x;
+			xsh->max_height = wd.max_size.y;
+		}
+	}
+	XSetWMNormalHints(x11_display, wd.x11_window, xsh);
+	XFree(xsh);
+
+	// Resize the window
+	XResizeWindow(x11_display, wd.x11_window, p_size.x, p_size.y);
+
+	// Update our videomode width and height
+	wd.size = p_size;
+
+	for (int timeout = 0; timeout < 50; ++timeout) {
+		XSync(x11_display, False);
+		XGetWindowAttributes(x11_display, wd.x11_window, &xwa);
+
+		if (old_w != xwa.width || old_h != xwa.height)
+			break;
+
+		usleep(10000);
+	}
+}
+Size2i DisplayServerX11::window_get_size(WindowID p_window) const {
+	ERR_FAIL_COND_V(windows.has(p_window), Size2i());
+	const WindowData &wd = windows[p_window];
+	return wd.size;
+}
+Size2i DisplayServerX11::window_get_real_size(WindowID p_window) const {
+	ERR_FAIL_COND_V(windows.has(p_window), Size2i());
+	const WindowData &wd = windows[p_window];
+
+	XWindowAttributes xwa;
+	XSync(x11_display, False);
+	XGetWindowAttributes(x11_display, wd.x11_window, &xwa);
+	int w = xwa.width;
+	int h = xwa.height;
+	Atom prop = XInternAtom(x11_display, "_NET_FRAME_EXTENTS", True);
+	if (prop != None) {
+		Atom type;
+		int format;
+		unsigned long len;
+		unsigned long remaining;
+		unsigned char *data = NULL;
+		if (XGetWindowProperty(x11_display, wd.x11_window, prop, 0, 4, False, AnyPropertyType, &type, &format, &len, &remaining, &data) == Success) {
+			if (format == 32 && len == 4) {
+				long *extents = (long *)data;
+				w += extents[0] + extents[1]; // left, right
+				h += extents[2] + extents[3]; // top, bottom
+			}
+			XFree(data);
+		}
+	}
+	return Size2(w, h);
+}
+
+bool DisplayServerX11::window_is_maximize_allowed(WindowID p_window) const {
+
+	ERR_FAIL_COND_V(windows.has(p_window), false);
+	const WindowData &wd = windows[p_window];
+
+	Atom property = XInternAtom(x11_display, "_NET_WM_ALLOWED_ACTIONS", False);
+	Atom type;
+	int format;
+	unsigned long len;
+	unsigned long remaining;
+	unsigned char *data = NULL;
+
+	int result = XGetWindowProperty(
+			x11_display,
+			wd.x11_window,
+			property,
+			0,
+			1024,
+			False,
+			XA_ATOM,
+			&type,
+			&format,
+			&len,
+			&remaining,
+			&data);
+
+	if (result == Success) {
+		Atom *atoms = (Atom *)data;
+		Atom wm_act_max_horz = XInternAtom(x11_display, "_NET_WM_ACTION_MAXIMIZE_HORZ", False);
+		Atom wm_act_max_vert = XInternAtom(x11_display, "_NET_WM_ACTION_MAXIMIZE_VERT", False);
+		bool found_wm_act_max_horz = false;
+		bool found_wm_act_max_vert = false;
+
+		for (uint64_t i = 0; i < len; i++) {
+			if (atoms[i] == wm_act_max_horz)
+				found_wm_act_max_horz = true;
+			if (atoms[i] == wm_act_max_vert)
+				found_wm_act_max_vert = true;
+
+			if (found_wm_act_max_horz || found_wm_act_max_vert)
+				return true;
+		}
+		XFree(atoms);
+	}
+
+	return false;
+}
+
+void DisplayServerX11::_set_wm_maximized(WindowID p_window, bool p_enabled) {
+	ERR_FAIL_COND(windows.has(p_window));
+	WindowData &wd = windows[p_window];
+
+	// Using EWMH -- Extended Window Manager Hints
+	XEvent xev;
+	Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
+	Atom wm_max_horz = XInternAtom(x11_display, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
+	Atom wm_max_vert = XInternAtom(x11_display, "_NET_WM_STATE_MAXIMIZED_VERT", False);
+
+	memset(&xev, 0, sizeof(xev));
+	xev.type = ClientMessage;
+	xev.xclient.window = wd.x11_window;
+	xev.xclient.message_type = wm_state;
+	xev.xclient.format = 32;
+	xev.xclient.data.l[0] = p_enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
+	xev.xclient.data.l[1] = wm_max_horz;
+	xev.xclient.data.l[2] = wm_max_vert;
+
+	XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+
+	if (p_enabled && window_is_maximize_allowed(p_window)) {
+		// Wait for effective resizing (so the GLX context is too).
+		// Give up after 0.5s, it's not going to happen on this WM.
+		// https://github.com/godotengine/godot/issues/19978
+		for (int attempt = 0; window_get_mode(p_window) != WINDOW_MODE_MAXIMIZED && attempt < 50; attempt++) {
+			usleep(10000);
+		}
+	}
+}
+
+void DisplayServerX11::_set_wm_fullscreen(WindowID p_window, bool p_enabled) {
+
+	ERR_FAIL_COND(windows.has(p_window));
+	WindowData &wd = windows[p_window];
+
+	if (p_enabled && !window_get_flag(WINDOW_FLAG_BORDERLESS, p_window)) {
+		// remove decorations if the window is not already borderless
+		Hints hints;
+		Atom property;
+		hints.flags = 2;
+		hints.decorations = 0;
+		property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True);
+		XChangeProperty(x11_display, wd.x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5);
+	}
+
+	if (p_enabled && window_get_flag(WINDOW_FLAG_RESIZE_DISABLED, p_window)) {
+		// Set the window as resizable to prevent window managers to ignore the fullscreen state flag.
+		XSizeHints *xsh;
+
+		xsh = XAllocSizeHints();
+		xsh->flags = 0L;
+		XSetWMNormalHints(x11_display, wd.x11_window, xsh);
+		XFree(xsh);
+	}
+
+	// Using EWMH -- Extended Window Manager Hints
+	XEvent xev;
+	Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
+	Atom wm_fullscreen = XInternAtom(x11_display, "_NET_WM_STATE_FULLSCREEN", False);
+
+	memset(&xev, 0, sizeof(xev));
+	xev.type = ClientMessage;
+	xev.xclient.window = wd.x11_window;
+	xev.xclient.message_type = wm_state;
+	xev.xclient.format = 32;
+	xev.xclient.data.l[0] = p_enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
+	xev.xclient.data.l[1] = wm_fullscreen;
+	xev.xclient.data.l[2] = 0;
+
+	XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+
+	// set bypass compositor hint
+	Atom bypass_compositor = XInternAtom(x11_display, "_NET_WM_BYPASS_COMPOSITOR", False);
+	unsigned long compositing_disable_on = p_enabled ? 1 : 0;
+	XChangeProperty(x11_display, wd.x11_window, bypass_compositor, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&compositing_disable_on, 1);
+
+	XFlush(x11_display);
+
+	if (!p_enabled) {
+		// Reset the non-resizable flags if we un-set these before.
+		Size2 size = window_get_size(p_window);
+		XSizeHints *xsh;
+		xsh = XAllocSizeHints();
+		if (window_get_flag(WINDOW_FLAG_RESIZE_DISABLED, p_window)) {
+			xsh->flags = PMinSize | PMaxSize;
+			xsh->min_width = size.x;
+			xsh->max_width = size.x;
+			xsh->min_height = size.y;
+			xsh->max_height = size.y;
+		} else {
+			xsh->flags = 0L;
+			if (wd.min_size != Size2()) {
+				xsh->flags |= PMinSize;
+				xsh->min_width = wd.min_size.x;
+				xsh->min_height = wd.min_size.y;
+			}
+			if (wd.max_size != Size2()) {
+				xsh->flags |= PMaxSize;
+				xsh->max_width = wd.max_size.x;
+				xsh->max_height = wd.max_size.y;
+			}
+		}
+		XSetWMNormalHints(x11_display, wd.x11_window, xsh);
+		XFree(xsh);
+
+		// put back or remove decorations according to the last set borderless state
+		Hints hints;
+		Atom property;
+		hints.flags = 2;
+		hints.decorations = window_get_flag(WINDOW_FLAG_BORDERLESS, p_window) ? 0 : 1;
+		property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True);
+		XChangeProperty(x11_display, wd.x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5);
+	}
+}
+
+void DisplayServerX11::window_set_mode(WindowMode p_mode, WindowID p_window) {
+	ERR_FAIL_COND(windows.has(p_window));
+	WindowData &wd = windows[p_window];
+
+	WindowMode old_mode = window_get_mode(p_window);
+	if (old_mode == p_mode) {
+		return; // do nothing
+	}
+	//remove all "extra" modes
+
+	switch (old_mode) {
+		case WINDOW_MODE_WINDOWED: {
+			//do nothing
+		} break;
+		case WINDOW_MODE_MINIMIZED: {
+			//Un-Minimize
+			// Using ICCCM -- Inter-Client Communication Conventions Manual
+			XEvent xev;
+			Atom wm_change = XInternAtom(x11_display, "WM_CHANGE_STATE", False);
+
+			memset(&xev, 0, sizeof(xev));
+			xev.type = ClientMessage;
+			xev.xclient.window = wd.x11_window;
+			xev.xclient.message_type = wm_change;
+			xev.xclient.format = 32;
+			xev.xclient.data.l[0] = WM_NormalState;
+
+			XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+
+			Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
+			Atom wm_hidden = XInternAtom(x11_display, "_NET_WM_STATE_HIDDEN", False);
+
+			memset(&xev, 0, sizeof(xev));
+			xev.type = ClientMessage;
+			xev.xclient.window = wd.x11_window;
+			xev.xclient.message_type = wm_state;
+			xev.xclient.format = 32;
+			xev.xclient.data.l[0] = _NET_WM_STATE_ADD;
+			xev.xclient.data.l[1] = wm_hidden;
+
+			XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+		} break;
+		case WINDOW_MODE_FULLSCREEN: {
+			//Remove full-screen
+			_set_wm_fullscreen(p_window, false);
+
+			//un-maximize required for always on top
+			bool on_top = window_get_flag(WINDOW_FLAG_ALWAYS_ON_TOP, p_window);
+
+			wd.fullscreen = false;
+
+			window_set_position(wd.last_position_before_fs, p_window);
+
+			if (on_top) {
+				_set_wm_maximized(p_window, false);
+			}
+
+		} break;
+		case WINDOW_MODE_MAXIMIZED: {
+
+			_set_wm_maximized(p_window, false);
+		} break;
+	}
+
+	switch (p_mode) {
+		case WINDOW_MODE_WINDOWED: {
+			//do nothing
+		} break;
+		case WINDOW_MODE_MINIMIZED: {
+			// Using ICCCM -- Inter-Client Communication Conventions Manual
+			XEvent xev;
+			Atom wm_change = XInternAtom(x11_display, "WM_CHANGE_STATE", False);
+
+			memset(&xev, 0, sizeof(xev));
+			xev.type = ClientMessage;
+			xev.xclient.window = wd.x11_window;
+			xev.xclient.message_type = wm_change;
+			xev.xclient.format = 32;
+			xev.xclient.data.l[0] = WM_IconicState;
+
+			XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+
+			Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
+			Atom wm_hidden = XInternAtom(x11_display, "_NET_WM_STATE_HIDDEN", False);
+
+			memset(&xev, 0, sizeof(xev));
+			xev.type = ClientMessage;
+			xev.xclient.window = wd.x11_window;
+			xev.xclient.message_type = wm_state;
+			xev.xclient.format = 32;
+			xev.xclient.data.l[0] = _NET_WM_STATE_ADD;
+			xev.xclient.data.l[1] = wm_hidden;
+
+			XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+		} break;
+		case WINDOW_MODE_FULLSCREEN: {
+			wd.last_position_before_fs = window_get_position(p_window);
+			if (window_get_flag(WINDOW_FLAG_ALWAYS_ON_TOP, p_window)) {
+				_set_wm_maximized(p_window, true);
+			}
+			_set_wm_fullscreen(p_window, true);
+			wd.fullscreen = true;
+		} break;
+		case WINDOW_MODE_MAXIMIZED: {
+
+			_set_wm_maximized(p_window, true);
+
+		} break;
+	}
+}
+
+DisplayServer::WindowMode DisplayServerX11::window_get_mode(WindowID p_window) const {
+	ERR_FAIL_COND_V(windows.has(p_window), WINDOW_MODE_WINDOWED);
+	const WindowData &wd = windows[p_window];
+
+	if (wd.fullscreen) { //if fullscreen, it's not in another mode
+		return WINDOW_MODE_FULLSCREEN;
+	}
+	{ //test maximized
+		// Using EWMH -- Extended Window Manager Hints
+		Atom property = XInternAtom(x11_display, "_NET_WM_STATE", False);
+		Atom type;
+		int format;
+		unsigned long len;
+		unsigned long remaining;
+		unsigned char *data = NULL;
+		bool retval = false;
+
+		int result = XGetWindowProperty(
+				x11_display,
+				wd.x11_window,
+				property,
+				0,
+				1024,
+				False,
+				XA_ATOM,
+				&type,
+				&format,
+				&len,
+				&remaining,
+				&data);
+
+		if (result == Success) {
+			Atom *atoms = (Atom *)data;
+			Atom wm_max_horz = XInternAtom(x11_display, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
+			Atom wm_max_vert = XInternAtom(x11_display, "_NET_WM_STATE_MAXIMIZED_VERT", False);
+			bool found_wm_max_horz = false;
+			bool found_wm_max_vert = false;
+
+			for (uint64_t i = 0; i < len; i++) {
+				if (atoms[i] == wm_max_horz)
+					found_wm_max_horz = true;
+				if (atoms[i] == wm_max_vert)
+					found_wm_max_vert = true;
+
+				if (found_wm_max_horz && found_wm_max_vert) {
+					retval = true;
+					break;
+				}
+			}
+		}
+
+		XFree(data);
+		if (retval) {
+			return WINDOW_MODE_MAXIMIZED;
+		}
+	}
+
+	{ // test minimzed
+		// Using ICCCM -- Inter-Client Communication Conventions Manual
+		Atom property = XInternAtom(x11_display, "WM_STATE", True);
+		Atom type;
+		int format;
+		unsigned long len;
+		unsigned long remaining;
+		unsigned char *data = NULL;
+
+		int result = XGetWindowProperty(
+				x11_display,
+				wd.x11_window,
+				property,
+				0,
+				32,
+				False,
+				AnyPropertyType,
+				&type,
+				&format,
+				&len,
+				&remaining,
+				&data);
+
+		if (result == Success) {
+			long *state = (long *)data;
+			if (state[0] == WM_IconicState)
+				return WINDOW_MODE_MINIMIZED;
+		}
+	}
+
+	// all other discarded, return windowed.
+
+	return WINDOW_MODE_WINDOWED;
+}
+
+void DisplayServerX11::window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window) {
+	ERR_FAIL_COND(windows.has(p_window));
+	WindowData &wd = windows[p_window];
+
+	switch (p_flag) {
+		case WINDOW_FLAG_RESIZE_DISABLED: {
+			XSizeHints *xsh;
+			xsh = XAllocSizeHints();
+			if (p_enabled) {
+				Size2 size = window_get_size(p_window);
+
+				xsh->flags = PMinSize | PMaxSize;
+				xsh->min_width = size.x;
+				xsh->max_width = size.x;
+				xsh->min_height = size.y;
+				xsh->max_height = size.y;
+			} else {
+				xsh->flags = 0L;
+				if (wd.min_size != Size2()) {
+					xsh->flags |= PMinSize;
+					xsh->min_width = wd.min_size.x;
+					xsh->min_height = wd.min_size.y;
+				}
+				if (wd.max_size != Size2()) {
+					xsh->flags |= PMaxSize;
+					xsh->max_width = wd.max_size.x;
+					xsh->max_height = wd.max_size.y;
+				}
+			}
+
+			XSetWMNormalHints(x11_display, wd.x11_window, xsh);
+			XFree(xsh);
+
+			wd.resize_disabled = p_enabled;
+
+			XFlush(x11_display);
+
+		} break;
+		case WINDOW_FLAG_BORDERLESS: {
+
+			Hints hints;
+			Atom property;
+			hints.flags = 2;
+			hints.decorations = p_enabled ? 0 : 1;
+			property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True);
+			XChangeProperty(x11_display, wd.x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5);
+
+			// Preserve window size
+			window_set_size(window_get_size(p_window), p_window);
+
+			wd.borderless = p_enabled;
+		} break;
+		case WINDOW_FLAG_ALWAYS_ON_TOP: {
+
+			if (p_enabled && wd.fullscreen) {
+				_set_wm_maximized(p_window, true);
+			}
+
+			Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
+			Atom wm_above = XInternAtom(x11_display, "_NET_WM_STATE_ABOVE", False);
+
+			XClientMessageEvent xev;
+			memset(&xev, 0, sizeof(xev));
+			xev.type = ClientMessage;
+			xev.window = wd.x11_window;
+			xev.message_type = wm_state;
+			xev.format = 32;
+			xev.data.l[0] = p_enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
+			xev.data.l[1] = wm_above;
+			xev.data.l[3] = 1;
+			XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent *)&xev);
+
+			if (!p_enabled && !wd.fullscreen) {
+				_set_wm_maximized(p_window, false);
+			}
+			wd.on_top = p_enabled;
+
+		} break;
+		case WINDOW_FLAG_TRANSPARENT: {
+			//todo reimplement
+		} break;
+		default: {
+		}
+	}
+}
+bool DisplayServerX11::window_get_flag(WindowFlags p_flag, WindowID p_window) const {
+	ERR_FAIL_COND_V(windows.has(p_window), false);
+	const WindowData &wd = windows[p_window];
+
+	switch (p_flag) {
+		case WINDOW_FLAG_RESIZE_DISABLED: {
+
+			return wd.resize_disabled;
+		} break;
+		case WINDOW_FLAG_BORDERLESS: {
+
+			bool borderless = wd.borderless;
+			Atom prop = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True);
+			if (prop != None) {
+
+				Atom type;
+				int format;
+				unsigned long len;
+				unsigned long remaining;
+				unsigned char *data = NULL;
+				if (XGetWindowProperty(x11_display, wd.x11_window, prop, 0, sizeof(Hints), False, AnyPropertyType, &type, &format, &len, &remaining, &data) == Success) {
+					if (data && (format == 32) && (len >= 5)) {
+						borderless = !((Hints *)data)->decorations;
+					}
+					XFree(data);
+				}
+			}
+			return borderless;
+		} break;
+		case WINDOW_FLAG_ALWAYS_ON_TOP: {
+
+			return wd.on_top;
+		} break;
+		case WINDOW_FLAG_TRANSPARENT: {
+			//todo reimplement
+		} break;
+		default: {
+		}
+	}
+
+	return false;
+}
+
+void DisplayServerX11::window_request_attention(WindowID p_window) {
+	ERR_FAIL_COND(windows.has(p_window));
+	WindowData &wd = windows[p_window];
+	// Using EWMH -- Extended Window Manager Hints
+	//
+	// Sets the _NET_WM_STATE_DEMANDS_ATTENTION atom for WM_STATE
+	// Will be unset by the window manager after user react on the request for attention
+
+	XEvent xev;
+	Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
+	Atom wm_attention = XInternAtom(x11_display, "_NET_WM_STATE_DEMANDS_ATTENTION", False);
+
+	memset(&xev, 0, sizeof(xev));
+	xev.type = ClientMessage;
+	xev.xclient.window = wd.x11_window;
+	xev.xclient.message_type = wm_state;
+	xev.xclient.format = 32;
+	xev.xclient.data.l[0] = _NET_WM_STATE_ADD;
+	xev.xclient.data.l[1] = wm_attention;
+
+	XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+	XFlush(x11_display);
+}
+
+void DisplayServerX11::window_move_to_foreground(WindowID p_window) {
+	ERR_FAIL_COND(windows.has(p_window));
+	WindowData &wd = windows[p_window];
+
+	XEvent xev;
+	Atom net_active_window = XInternAtom(x11_display, "_NET_ACTIVE_WINDOW", False);
+
+	memset(&xev, 0, sizeof(xev));
+	xev.type = ClientMessage;
+	xev.xclient.window = wd.x11_window;
+	xev.xclient.message_type = net_active_window;
+	xev.xclient.format = 32;
+	xev.xclient.data.l[0] = 1;
+	xev.xclient.data.l[1] = CurrentTime;
+
+	XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+	XFlush(x11_display);
+}
+
+bool DisplayServerX11::window_can_draw(WindowID p_window) const {
+	//this seems to be all that is provided by X11
+	return window_get_mode(p_window) != WINDOW_MODE_MINIMIZED;
+}
+
+void DisplayServerX11::window_set_ime_active(const bool p_active, WindowID p_window) {
+	ERR_FAIL_COND(windows.has(p_window));
+	WindowData &wd = windows[p_window];
+
+	wd.im_active = p_active;
+
+	if (!wd.xic)
+		return;
+
+	if (p_active) {
+		XSetICFocus(wd.xic);
+		window_set_ime_position(wd.im_position, p_window);
+	} else {
+		XUnsetICFocus(wd.xic);
+	}
+}
+void DisplayServerX11::window_set_ime_position(const Point2i &p_pos, WindowID p_window) {
+	ERR_FAIL_COND(windows.has(p_window));
+	WindowData &wd = windows[p_window];
+
+	wd.im_position = p_pos;
+
+	if (!wd.xic)
+		return;
+
+	::XPoint spot;
+	spot.x = short(p_pos.x);
+	spot.y = short(p_pos.y);
+	XVaNestedList preedit_attr = XVaCreateNestedList(0, XNSpotLocation, &spot, NULL);
+	XSetICValues(wd.xic, XNPreeditAttributes, preedit_attr, NULL);
+	XFree(preedit_attr);
+}
+
+void DisplayServerX11::cursor_set_shape(CursorShape p_shape) {
+	ERR_FAIL_INDEX(p_shape, CURSOR_MAX);
+
+	if (p_shape == current_cursor) {
+		return;
+	}
+
+	if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) {
+		if (cursors[p_shape] != None) {
+			for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+				XDefineCursor(x11_display, E->get().x11_window, cursors[p_shape]);
+			}
+		} else if (cursors[CURSOR_ARROW] != None) {
+			for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+				XDefineCursor(x11_display, E->get().x11_window, cursors[CURSOR_ARROW]);
+			}
+		}
+	}
+
+	current_cursor = p_shape;
+}
+DisplayServerX11::CursorShape DisplayServerX11::cursor_get_shape() const {
+	return current_cursor;
+}
+void DisplayServerX11::cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
+
+	if (p_cursor.is_valid()) {
+
+		Map<CursorShape, Vector<Variant>>::Element *cursor_c = cursors_cache.find(p_shape);
+
+		if (cursor_c) {
+			if (cursor_c->get()[0] == p_cursor && cursor_c->get()[1] == p_hotspot) {
+				cursor_set_shape(p_shape);
+				return;
+			}
+
+			cursors_cache.erase(p_shape);
+		}
+
+		Ref<Texture2D> texture = p_cursor;
+		Ref<AtlasTexture> atlas_texture = p_cursor;
+		Ref<Image> image;
+		Size2 texture_size;
+		Rect2 atlas_rect;
+
+		if (texture.is_valid()) {
+			image = texture->get_data();
+		}
+
+		if (!image.is_valid() && atlas_texture.is_valid()) {
+			texture = atlas_texture->get_atlas();
+
+			atlas_rect.size.width = texture->get_width();
+			atlas_rect.size.height = texture->get_height();
+			atlas_rect.position.x = atlas_texture->get_region().position.x;
+			atlas_rect.position.y = atlas_texture->get_region().position.y;
+
+			texture_size.width = atlas_texture->get_region().size.x;
+			texture_size.height = atlas_texture->get_region().size.y;
+		} else if (image.is_valid()) {
+			texture_size.width = texture->get_width();
+			texture_size.height = texture->get_height();
+		}
+
+		ERR_FAIL_COND(!texture.is_valid());
+		ERR_FAIL_COND(p_hotspot.x < 0 || p_hotspot.y < 0);
+		ERR_FAIL_COND(texture_size.width > 256 || texture_size.height > 256);
+		ERR_FAIL_COND(p_hotspot.x > texture_size.width || p_hotspot.y > texture_size.height);
+
+		image = texture->get_data();
+
+		ERR_FAIL_COND(!image.is_valid());
+
+		// Create the cursor structure
+		XcursorImage *cursor_image = XcursorImageCreate(texture_size.width, texture_size.height);
+		XcursorUInt image_size = texture_size.width * texture_size.height;
+		XcursorDim size = sizeof(XcursorPixel) * image_size;
+
+		cursor_image->version = 1;
+		cursor_image->size = size;
+		cursor_image->xhot = p_hotspot.x;
+		cursor_image->yhot = p_hotspot.y;
+
+		// allocate memory to contain the whole file
+		cursor_image->pixels = (XcursorPixel *)memalloc(size);
+
+		for (XcursorPixel index = 0; index < image_size; index++) {
+			int row_index = floor(index / texture_size.width) + atlas_rect.position.y;
+			int column_index = (index % int(texture_size.width)) + atlas_rect.position.x;
+
+			if (atlas_texture.is_valid()) {
+				column_index = MIN(column_index, atlas_rect.size.width - 1);
+				row_index = MIN(row_index, atlas_rect.size.height - 1);
+			}
+
+			*(cursor_image->pixels + index) = image->get_pixel(column_index, row_index).to_argb32();
+		}
+
+		ERR_FAIL_COND(cursor_image->pixels == NULL);
+
+		// Save it for a further usage
+		cursors[p_shape] = XcursorImageLoadCursor(x11_display, cursor_image);
+
+		Vector<Variant> params;
+		params.push_back(p_cursor);
+		params.push_back(p_hotspot);
+		cursors_cache.insert(p_shape, params);
+
+		if (p_shape == current_cursor) {
+			if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) {
+				for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+					XDefineCursor(x11_display, E->get().x11_window, cursors[p_shape]);
+				}
+			}
+		}
+
+		memfree(cursor_image->pixels);
+		XcursorImageDestroy(cursor_image);
+	} else {
+		// Reset to default system cursor
+		if (img[p_shape]) {
+			cursors[p_shape] = XcursorImageLoadCursor(x11_display, img[p_shape]);
+		}
+
+		CursorShape c = current_cursor;
+		current_cursor = CURSOR_MAX;
+		cursor_set_shape(c);
+
+		cursors_cache.erase(p_shape);
+	}
+}
+
+DisplayServerX11::LatinKeyboardVariant DisplayServerX11::get_latin_keyboard_variant() const {
+	XkbDescRec *xkbdesc = XkbAllocKeyboard();
+	ERR_FAIL_COND_V(!xkbdesc, LATIN_KEYBOARD_QWERTY);
+
+	XkbGetNames(x11_display, XkbSymbolsNameMask, xkbdesc);
+	ERR_FAIL_COND_V(!xkbdesc->names, LATIN_KEYBOARD_QWERTY);
+	ERR_FAIL_COND_V(!xkbdesc->names->symbols, LATIN_KEYBOARD_QWERTY);
+
+	char *layout = XGetAtomName(x11_display, xkbdesc->names->symbols);
+	ERR_FAIL_COND_V(!layout, LATIN_KEYBOARD_QWERTY);
+
+	Vector<String> info = String(layout).split("+");
+	ERR_FAIL_INDEX_V(1, info.size(), LATIN_KEYBOARD_QWERTY);
+
+	if (info[1].find("colemak") != -1) {
+		return LATIN_KEYBOARD_COLEMAK;
+	} else if (info[1].find("qwertz") != -1) {
+		return LATIN_KEYBOARD_QWERTZ;
+	} else if (info[1].find("azerty") != -1) {
+		return LATIN_KEYBOARD_AZERTY;
+	} else if (info[1].find("qzerty") != -1) {
+		return LATIN_KEYBOARD_QZERTY;
+	} else if (info[1].find("dvorak") != -1) {
+		return LATIN_KEYBOARD_DVORAK;
+	} else if (info[1].find("neo") != -1) {
+		return LATIN_KEYBOARD_NEO;
+	}
+
+	return LATIN_KEYBOARD_QWERTY;
+}
+
+DisplayServerX11::Property DisplayServerX11::_read_property(Display *p_display, Window p_window, Atom p_property) {
+
+	Atom actual_type;
+	int actual_format;
+	unsigned long nitems;
+	unsigned long bytes_after;
+	unsigned char *ret = 0;
+
+	int read_bytes = 1024;
+
+	//Keep trying to read the property until there are no
+	//bytes unread.
+	do {
+		if (ret != 0)
+			XFree(ret);
+
+		XGetWindowProperty(p_display, p_window, p_property, 0, read_bytes, False, AnyPropertyType,
+				&actual_type, &actual_format, &nitems, &bytes_after,
+				&ret);
+
+		read_bytes *= 2;
+
+	} while (bytes_after != 0);
+
+	Property p = { ret, actual_format, (int)nitems, actual_type };
+
+	return p;
+}
+
+static Atom pick_target_from_list(Display *p_display, Atom *p_list, int p_count) {
+
+	static const char *target_type = "text/uri-list";
+
+	for (int i = 0; i < p_count; i++) {
+
+		Atom atom = p_list[i];
+
+		if (atom != None && String(XGetAtomName(p_display, atom)) == target_type)
+			return atom;
+	}
+	return None;
+}
+
+static Atom pick_target_from_atoms(Display *p_disp, Atom p_t1, Atom p_t2, Atom p_t3) {
+
+	static const char *target_type = "text/uri-list";
+	if (p_t1 != None && String(XGetAtomName(p_disp, p_t1)) == target_type)
+		return p_t1;
+
+	if (p_t2 != None && String(XGetAtomName(p_disp, p_t2)) == target_type)
+		return p_t2;
+
+	if (p_t3 != None && String(XGetAtomName(p_disp, p_t3)) == target_type)
+		return p_t3;
+
+	return None;
+}
+
+void DisplayServerX11::_get_key_modifier_state(unsigned int p_x11_state, Ref<InputEventWithModifiers> state) {
+
+	state->set_shift((p_x11_state & ShiftMask));
+	state->set_control((p_x11_state & ControlMask));
+	state->set_alt((p_x11_state & Mod1Mask /*|| p_x11_state&Mod5Mask*/)); //altgr should not count as alt
+	state->set_metakey((p_x11_state & Mod4Mask));
+}
+
+unsigned int DisplayServerX11::_get_mouse_button_state(unsigned int p_x11_button, int p_x11_type) {
+
+	unsigned int mask = 1 << (p_x11_button - 1);
+
+	if (p_x11_type == ButtonPress) {
+		last_button_state |= mask;
+	} else {
+		last_button_state &= ~mask;
+	}
+
+	return last_button_state;
+}
+
+void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event, bool p_echo) {
+
+	WindowData wd = windows[p_window];
+	// X11 functions don't know what const is
+	XKeyEvent *xkeyevent = p_event;
+
+	// This code was pretty difficult to write.
+	// The docs stink and every toolkit seems to
+	// do it in a different way.
+
+	/* Phase 1, obtain a proper keysym */
+
+	// This was also very difficult to figure out.
+	// You'd expect you could just use Keysym provided by
+	// XKeycodeToKeysym to obtain internationalized
+	// input.. WRONG!!
+	// you must use XLookupString (???) which not only wastes
+	// cycles generating an unnecessary string, but also
+	// still works in half the cases. (won't handle deadkeys)
+	// For more complex input methods (deadkeys and more advanced)
+	// you have to use XmbLookupString (??).
+	// So.. then you have to chosse which of both results
+	// you want to keep.
+	// This is a real bizarreness and cpu waster.
+
+	KeySym keysym_keycode = 0; // keysym used to find a keycode
+	KeySym keysym_unicode = 0; // keysym used to find unicode
+
+	// XLookupString returns keysyms usable as nice keycodes.
+	char str[256 + 1];
+	XKeyEvent xkeyevent_no_mod = *xkeyevent;
+	xkeyevent_no_mod.state &= ~ShiftMask;
+	xkeyevent_no_mod.state &= ~ControlMask;
+	XLookupString(xkeyevent, str, 256, &keysym_unicode, NULL);
+	XLookupString(&xkeyevent_no_mod, NULL, 0, &keysym_keycode, NULL);
+
+	// Meanwhile, XLookupString returns keysyms useful for unicode.
+
+	if (!xmbstring) {
+		// keep a temporary buffer for the string
+		xmbstring = (char *)memalloc(sizeof(char) * 8);
+		xmblen = 8;
+	}
+
+	if (xkeyevent->type == KeyPress && wd.xic) {
+
+		Status status;
+#ifdef X_HAVE_UTF8_STRING
+		int utf8len = 8;
+		char *utf8string = (char *)memalloc(sizeof(char) * utf8len);
+		int utf8bytes = Xutf8LookupString(wd.xic, xkeyevent, utf8string,
+				utf8len - 1, &keysym_unicode, &status);
+		if (status == XBufferOverflow) {
+			utf8len = utf8bytes + 1;
+			utf8string = (char *)memrealloc(utf8string, utf8len);
+			utf8bytes = Xutf8LookupString(wd.xic, xkeyevent, utf8string,
+					utf8len - 1, &keysym_unicode, &status);
+		}
+		utf8string[utf8bytes] = '\0';
+
+		if (status == XLookupChars) {
+			bool keypress = xkeyevent->type == KeyPress;
+			unsigned int keycode = KeyMappingX11::get_keycode(keysym_keycode);
+			unsigned int physical_keycode = KeyMappingX11::get_scancode(xkeyevent->keycode);
+
+			if (keycode >= 'a' && keycode <= 'z')
+				keycode -= 'a' - 'A';
+
+			String tmp;
+			tmp.parse_utf8(utf8string, utf8bytes);
+			for (int i = 0; i < tmp.length(); i++) {
+				Ref<InputEventKey> k;
+				k.instance();
+				if (physical_keycode == 0 && keycode == 0 && tmp[i] == 0) {
+					continue;
+				}
+
+				if (keycode == 0) {
+					keycode = physical_keycode;
+				}
+
+				_get_key_modifier_state(xkeyevent->state, k);
+
+				k->set_unicode(tmp[i]);
+
+				k->set_pressed(keypress);
+
+				k->set_keycode(keycode);
+
+				k->set_physical_keycode(physical_keycode);
+
+				k->set_echo(false);
+
+				if (k->get_keycode() == KEY_BACKTAB) {
+					//make it consistent across platforms.
+					k->set_keycode(KEY_TAB);
+					k->set_physical_keycode(KEY_TAB);
+					k->set_shift(true);
+				}
+
+				Input::get_singleton()->accumulate_input_event(k);
+			}
+			memfree(utf8string);
+			return;
+		}
+		memfree(utf8string);
+#else
+		do {
+
+			int mnbytes = XmbLookupString(xic, xkeyevent, xmbstring, xmblen - 1, &keysym_unicode, &status);
+			xmbstring[mnbytes] = '\0';
+
+			if (status == XBufferOverflow) {
+				xmblen = mnbytes + 1;
+				xmbstring = (char *)memrealloc(xmbstring, xmblen);
+			}
+		} while (status == XBufferOverflow);
+#endif
+	}
+
+	/* Phase 2, obtain a Godot keycode from the keysym */
+
+	// KeyMappingX11 just translated the X11 keysym to a PIGUI
+	// keysym, so it works in all platforms the same.
+
+	unsigned int keycode = KeyMappingX11::get_keycode(keysym_keycode);
+	unsigned int physical_keycode = KeyMappingX11::get_scancode(xkeyevent->keycode);
+
+	/* Phase 3, obtain a unicode character from the keysym */
+
+	// KeyMappingX11 also translates keysym to unicode.
+	// It does a binary search on a table to translate
+	// most properly.
+	unsigned int unicode = keysym_unicode > 0 ? KeyMappingX11::get_unicode_from_keysym(keysym_unicode) : 0;
+
+	/* Phase 4, determine if event must be filtered */
+
+	// This seems to be a side-effect of using XIM.
+	// XEventFilter looks like a core X11 function,
+	// but it's actually just used to see if we must
+	// ignore a deadkey, or events XIM determines
+	// must not reach the actual gui.
+	// Guess it was a design problem of the extension
+
+	bool keypress = xkeyevent->type == KeyPress;
+
+	if (physical_keycode == 0 && keycode == 0 && unicode == 0) {
+		return;
+	}
+
+	if (keycode == 0) {
+		keycode = physical_keycode;
+	}
+
+	/* Phase 5, determine modifier mask */
+
+	// No problems here, except I had no way to
+	// know Mod1 was ALT and Mod4 was META (applekey/winkey)
+	// just tried Mods until i found them.
+
+	//print_verbose("mod1: "+itos(xkeyevent->state&Mod1Mask)+" mod 5: "+itos(xkeyevent->state&Mod5Mask));
+
+	Ref<InputEventKey> k;
+	k.instance();
+
+	_get_key_modifier_state(xkeyevent->state, k);
+
+	/* Phase 6, determine echo character */
+
+	// Echo characters in X11 are a keyrelease and a keypress
+	// one after the other with the (almot) same timestamp.
+	// To detect them, i use XPeekEvent and check that their
+	// difference in time is below a threshold.
+
+	if (xkeyevent->type != KeyPress) {
+
+		p_echo = false;
+
+		// make sure there are events pending,
+		// so this call won't block.
+		if (XPending(x11_display) > 0) {
+			XEvent peek_event;
+			XPeekEvent(x11_display, &peek_event);
+
+			// I'm using a threshold of 5 msecs,
+			// since sometimes there seems to be a little
+			// jitter. I'm still not convinced that all this approach
+			// is correct, but the xorg developers are
+			// not very helpful today.
+
+#define ABSDIFF(x, y) (((x) < (y)) ? ((y) - (x)) : ((x) - (y)))
+			::Time threshold = ABSDIFF(peek_event.xkey.time, xkeyevent->time);
+#undef ABSDIFF
+			if (peek_event.type == KeyPress && threshold < 5) {
+				KeySym rk;
+				XLookupString((XKeyEvent *)&peek_event, str, 256, &rk, NULL);
+				if (rk == keysym_keycode) {
+					XEvent event;
+					XNextEvent(x11_display, &event); //erase next event
+					_handle_key_event(p_window, (XKeyEvent *)&event, true);
+					return; //ignore current, echo next
+				}
+			}
+
+			// use the time from peek_event so it always works
+		}
+
+		// save the time to check for echo when keypress happens
+	}
+
+	/* Phase 7, send event to Window */
+
+	k->set_pressed(keypress);
+
+	if (keycode >= 'a' && keycode <= 'z')
+		keycode -= 'a' - 'A';
+
+	k->set_keycode(keycode);
+	k->set_physical_keycode(physical_keycode);
+	k->set_unicode(unicode);
+	k->set_echo(p_echo);
+
+	if (k->get_keycode() == KEY_BACKTAB) {
+		//make it consistent across platforms.
+		k->set_keycode(KEY_TAB);
+		k->set_physical_keycode(KEY_TAB);
+		k->set_shift(true);
+	}
+
+	//don't set mod state if modifier keys are released by themselves
+	//else event.is_action() will not work correctly here
+	if (!k->is_pressed()) {
+		if (k->get_keycode() == KEY_SHIFT)
+			k->set_shift(false);
+		else if (k->get_keycode() == KEY_CONTROL)
+			k->set_control(false);
+		else if (k->get_keycode() == KEY_ALT)
+			k->set_alt(false);
+		else if (k->get_keycode() == KEY_META)
+			k->set_metakey(false);
+	}
+
+	bool last_is_pressed = Input::get_singleton()->is_key_pressed(k->get_keycode());
+	if (k->is_pressed()) {
+		if (last_is_pressed) {
+			k->set_echo(true);
+		}
+	}
+
+	Input::get_singleton()->accumulate_input_event(k);
+}
+
+void DisplayServerX11::_xim_destroy_callback(::XIM im, ::XPointer client_data,
+		::XPointer call_data) {
+
+	WARN_PRINT("Input method stopped");
+	DisplayServerX11 *ds = reinterpret_cast<DisplayServerX11 *>(client_data);
+	ds->xim = NULL;
+
+	for (Map<WindowID, WindowData>::Element *E = ds->windows.front(); E; E = E->next()) {
+		E->get().xic = NULL;
+	}
+}
+
+void DisplayServerX11::_window_changed(XEvent *event) {
+
+	WindowID window_id = MAIN_WINDOW_ID;
+
+	//assign the event to the relevant window
+	for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+		if (event->xany.window == E->get().x11_window) {
+			window_id = E->key();
+			break;
+		}
+	}
+
+	WindowData &wd = windows[window_id];
+
+	if (wd.xic) {
+		//  Not portable.
+		window_set_ime_position(Point2(0, 1));
+	}
+	if ((event->xconfigure.width == wd.size.width) &&
+			(event->xconfigure.height == wd.size.height))
+		return;
+
+	wd.size.width = event->xconfigure.width;
+	wd.size.height = event->xconfigure.height;
+
+#if defined(VULKAN_ENABLED)
+	if (video_driver == "vulkan") {
+		context_vulkan->window_resize(wd.vulkan_window, wd.size.width, wd.size.height);
+	}
+#endif
+}
+
+void DisplayServerX11::process_events() {
+	do_mouse_warp = false;
+
+	// Is the current mouse mode one where it needs to be grabbed.
+	bool mouse_mode_grab = mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED;
+
+	while (XPending(x11_display) > 0) {
+		XEvent event;
+		XNextEvent(x11_display, &event);
+
+		WindowID window_id = MAIN_WINDOW_ID;
+
+		//assign the event to the relevant window
+		for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+			if (event.xany.window == E->get().x11_window) {
+				window_id = E->key();
+				break;
+			}
+		}
+
+		if (XFilterEvent(&event, None)) {
+			continue;
+		}
+
+		if (XGetEventData(x11_display, &event.xcookie)) {
+
+			if (event.xcookie.type == GenericEvent && event.xcookie.extension == xi.opcode) {
+
+				XIDeviceEvent *event_data = (XIDeviceEvent *)event.xcookie.data;
+				int index = event_data->detail;
+				Vector2 pos = Vector2(event_data->event_x, event_data->event_y);
+
+				switch (event_data->evtype) {
+					case XI_HierarchyChanged:
+					case XI_DeviceChanged: {
+						_refresh_device_info();
+					} break;
+					case XI_RawMotion: {
+						XIRawEvent *raw_event = (XIRawEvent *)event_data;
+						int device_id = raw_event->deviceid;
+
+						// Determine the axis used (called valuators in XInput for some forsaken reason)
+						//  Mask is a bitmask indicating which axes are involved.
+						//  We are interested in the values of axes 0 and 1.
+						if (raw_event->valuators.mask_len <= 0) {
+							break;
+						}
+
+						const double *values = raw_event->raw_values;
+
+						double rel_x = 0.0;
+						double rel_y = 0.0;
+						double pressure = 0.0;
+						double tilt_x = 0.0;
+						double tilt_y = 0.0;
+
+						if (XIMaskIsSet(raw_event->valuators.mask, VALUATOR_ABSX)) {
+							rel_x = *values;
+							values++;
+						}
+
+						if (XIMaskIsSet(raw_event->valuators.mask, VALUATOR_ABSY)) {
+							rel_y = *values;
+							values++;
+						}
+
+						if (XIMaskIsSet(raw_event->valuators.mask, VALUATOR_PRESSURE)) {
+							pressure = *values;
+							values++;
+						}
+
+						if (XIMaskIsSet(raw_event->valuators.mask, VALUATOR_TILTX)) {
+							tilt_x = *values;
+							values++;
+						}
+
+						if (XIMaskIsSet(raw_event->valuators.mask, VALUATOR_TILTY)) {
+							tilt_y = *values;
+						}
+
+						Map<int, Vector3>::Element *pen_info = xi.pen_devices.find(device_id);
+						if (pen_info) {
+							Vector3 mult = pen_info->value();
+							if (mult.x != 0.0) xi.pressure = pressure / mult.x;
+							if ((mult.y != 0.0) && (mult.z != 0.0)) xi.tilt = Vector2(tilt_x / mult.y, tilt_y / mult.z);
+						}
+
+						// https://bugs.freedesktop.org/show_bug.cgi?id=71609
+						// http://lists.libsdl.org/pipermail/commits-libsdl.org/2015-June/000282.html
+						if (raw_event->time == xi.last_relative_time && rel_x == xi.relative_motion.x && rel_y == xi.relative_motion.y) {
+							break; // Flush duplicate to avoid overly fast motion
+						}
+
+						xi.old_raw_pos.x = xi.raw_pos.x;
+						xi.old_raw_pos.y = xi.raw_pos.y;
+						xi.raw_pos.x = rel_x;
+						xi.raw_pos.y = rel_y;
+
+						Map<int, Vector2>::Element *abs_info = xi.absolute_devices.find(device_id);
+
+						if (abs_info) {
+							// Absolute mode device
+							Vector2 mult = abs_info->value();
+
+							xi.relative_motion.x += (xi.raw_pos.x - xi.old_raw_pos.x) * mult.x;
+							xi.relative_motion.y += (xi.raw_pos.y - xi.old_raw_pos.y) * mult.y;
+						} else {
+							// Relative mode device
+							xi.relative_motion.x = xi.raw_pos.x;
+							xi.relative_motion.y = xi.raw_pos.y;
+						}
+
+						xi.last_relative_time = raw_event->time;
+					} break;
+#ifdef TOUCH_ENABLED
+					case XI_TouchBegin: // Fall-through
+							// Disabled hand-in-hand with the grabbing
+							//XIAllowTouchEvents(x11_display, event_data->deviceid, event_data->detail, x11_window, XIAcceptTouch);
+
+					case XI_TouchEnd: {
+
+						bool is_begin = event_data->evtype == XI_TouchBegin;
+
+						Ref<InputEventScreenTouch> st;
+						st.instance();
+						st->set_window_id(window_id);
+						st->set_index(index);
+						st->set_position(pos);
+						st->set_pressed(is_begin);
+
+						if (is_begin) {
+							if (xi.state.has(index)) // Defensive
+								break;
+							xi.state[index] = pos;
+							if (xi.state.size() == 1) {
+								// X11 may send a motion event when a touch gesture begins, that would result
+								// in a spurious mouse motion event being sent to Godot; remember it to be able to filter it out
+								xi.mouse_pos_to_filter = pos;
+							}
+							Input::get_singleton()->accumulate_input_event(st);
+						} else {
+							if (!xi.state.has(index)) // Defensive
+								break;
+							xi.state.erase(index);
+							Input::get_singleton()->accumulate_input_event(st);
+						}
+					} break;
+
+					case XI_TouchUpdate: {
+
+						Map<int, Vector2>::Element *curr_pos_elem = xi.state.find(index);
+						if (!curr_pos_elem) { // Defensive
+							break;
+						}
+
+						if (curr_pos_elem->value() != pos) {
+
+							Ref<InputEventScreenDrag> sd;
+							sd.instance();
+							sd->set_window_id(window_id);
+							sd->set_index(index);
+							sd->set_position(pos);
+							sd->set_relative(pos - curr_pos_elem->value());
+							Input::get_singleton()->accumulate_input_event(sd);
+
+							curr_pos_elem->value() = pos;
+						}
+					} break;
+#endif
+				}
+			}
+		}
+		XFreeEventData(x11_display, &event.xcookie);
+
+		switch (event.type) {
+			case Expose:
+				Main::force_redraw();
+				break;
+
+			case NoExpose:
+				minimized = true;
+				break;
+
+			case VisibilityNotify: {
+				XVisibilityEvent *visibility = (XVisibilityEvent *)&event;
+				minimized = (visibility->state == VisibilityFullyObscured);
+			} break;
+			case LeaveNotify: {
+				if (!mouse_mode_grab)
+					Input::get_singleton()->parse_notification(MainLoop::NOTIFICATION_WM_MOUSE_EXIT);
+
+			} break;
+			case EnterNotify: {
+				if (!mouse_mode_grab)
+					Input::get_singleton()->parse_notification(MainLoop::NOTIFICATION_WM_MOUSE_ENTER);
+			} break;
+			case FocusIn:
+				minimized = false;
+				window_has_focus = true;
+				Input::get_singleton()->parse_notification(MainLoop::NOTIFICATION_WM_FOCUS_IN);
+				window_focused = true;
+
+				if (mouse_mode_grab) {
+					// Show and update the cursor if confined and the window regained focus.
+
+					for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+
+						if (mouse_mode == MOUSE_MODE_CONFINED)
+							XUndefineCursor(x11_display, E->get().x11_window);
+						else if (mouse_mode == MOUSE_MODE_CAPTURED) // or re-hide it in captured mode
+							XDefineCursor(x11_display, E->get().x11_window, null_cursor);
+
+						XGrabPointer(
+								x11_display, E->get().x11_window, True,
+								ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
+								GrabModeAsync, GrabModeAsync, E->get().x11_window, None, CurrentTime);
+					}
+				}
+#ifdef TOUCH_ENABLED
+				// Grab touch devices to avoid OS gesture interference
+				/*for (int i = 0; i < xi.touch_devices.size(); ++i) {
+					XIGrabDevice(x11_display, xi.touch_devices[i], x11_window, CurrentTime, None, XIGrabModeAsync, XIGrabModeAsync, False, &xi.touch_event_mask);
+				}*/
+#endif
+				if (windows[window_id].xic) {
+					XSetICFocus(windows[window_id].xic);
+				}
+				break;
+
+			case FocusOut:
+				window_has_focus = false;
+				Input::get_singleton()->release_pressed_events();
+				Input::get_singleton()->parse_notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT);
+				window_focused = false;
+
+				if (mouse_mode_grab) {
+					for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+
+						//dear X11, I try, I really try, but you never work, you do whathever you want.
+						if (mouse_mode == MOUSE_MODE_CAPTURED) {
+							// Show the cursor if we're in captured mode so it doesn't look weird.
+							XUndefineCursor(x11_display, E->get().x11_window);
+						}
+					}
+					XUngrabPointer(x11_display, CurrentTime);
+				}
+#ifdef TOUCH_ENABLED
+				// Ungrab touch devices so input works as usual while we are unfocused
+				/*for (int i = 0; i < xi.touch_devices.size(); ++i) {
+					XIUngrabDevice(x11_display, xi.touch_devices[i], CurrentTime);
+				}*/
+
+				// Release every pointer to avoid sticky points
+				for (Map<int, Vector2>::Element *E = xi.state.front(); E; E = E->next()) {
+
+					Ref<InputEventScreenTouch> st;
+					st.instance();
+					st->set_index(E->key());
+					st->set_window_id(window_id);
+					st->set_position(E->get());
+					Input::get_singleton()->accumulate_input_event(st);
+				}
+				xi.state.clear();
+#endif
+				if (windows[window_id].xic) {
+					XSetICFocus(windows[window_id].xic);
+				}
+				break;
+
+			case ConfigureNotify:
+				_window_changed(&event);
+				break;
+			case ButtonPress:
+			case ButtonRelease: {
+
+				/* exit in case of a mouse button press */
+				last_timestamp = event.xbutton.time;
+				if (mouse_mode == MOUSE_MODE_CAPTURED) {
+					event.xbutton.x = last_mouse_pos.x;
+					event.xbutton.y = last_mouse_pos.y;
+				}
+
+				Ref<InputEventMouseButton> mb;
+				mb.instance();
+
+				mb->set_window_id(window_id);
+				_get_key_modifier_state(event.xbutton.state, mb);
+				mb->set_button_index(event.xbutton.button);
+				if (mb->get_button_index() == 2)
+					mb->set_button_index(3);
+				else if (mb->get_button_index() == 3)
+					mb->set_button_index(2);
+				mb->set_button_mask(_get_mouse_button_state(mb->get_button_index(), event.xbutton.type));
+				mb->set_position(Vector2(event.xbutton.x, event.xbutton.y));
+				mb->set_global_position(mb->get_position());
+
+				mb->set_pressed((event.type == ButtonPress));
+
+				if (event.type == ButtonPress) {
+
+					uint64_t diff = OS::get_singleton()->get_ticks_usec() / 1000 - last_click_ms;
+
+					if (mb->get_button_index() == last_click_button_index) {
+
+						if (diff < 400 && Vector2(last_click_pos).distance_to(Vector2(event.xbutton.x, event.xbutton.y)) < 5) {
+
+							last_click_ms = 0;
+							last_click_pos = Point2i(-100, -100);
+							last_click_button_index = -1;
+							mb->set_doubleclick(true);
+						}
+
+					} else if (mb->get_button_index() < 4 || mb->get_button_index() > 7) {
+						last_click_button_index = mb->get_button_index();
+					}
+
+					if (!mb->is_doubleclick()) {
+						last_click_ms += diff;
+						last_click_pos = Point2i(event.xbutton.x, event.xbutton.y);
+					}
+				}
+
+				Input::get_singleton()->accumulate_input_event(mb);
+
+			} break;
+			case MotionNotify: {
+
+				// The X11 API requires filtering one-by-one through the motion
+				// notify events, in order to figure out which event is the one
+				// generated by warping the mouse pointer.
+
+				while (true) {
+					if (mouse_mode == MOUSE_MODE_CAPTURED && event.xmotion.x == windows[MAIN_WINDOW_ID].size.width / 2 && event.xmotion.y == windows[MAIN_WINDOW_ID].size.height / 2) {
+						//this is likely the warp event since it was warped here
+						center = Vector2(event.xmotion.x, event.xmotion.y);
+						break;
+					}
+
+					if (XPending(x11_display) > 0) {
+						XEvent tevent;
+						XPeekEvent(x11_display, &tevent);
+						if (tevent.type == MotionNotify) {
+							XNextEvent(x11_display, &event);
+						} else {
+							break;
+						}
+					} else {
+						break;
+					}
+				}
+
+				last_timestamp = event.xmotion.time;
+
+				// Motion is also simple.
+				// A little hack is in order
+				// to be able to send relative motion events.
+				Point2i pos(event.xmotion.x, event.xmotion.y);
+
+				// Avoidance of spurious mouse motion (see handling of touch)
+				bool filter = false;
+				// Adding some tolerance to match better Point2i to Vector2
+				if (xi.state.size() && Vector2(pos).distance_squared_to(xi.mouse_pos_to_filter) < 2) {
+					filter = true;
+				}
+				// Invalidate to avoid filtering a possible legitimate similar event coming later
+				xi.mouse_pos_to_filter = Vector2(1e10, 1e10);
+				if (filter) {
+					break;
+				}
+
+				if (mouse_mode == MOUSE_MODE_CAPTURED) {
+					if (xi.relative_motion.x == 0 && xi.relative_motion.y == 0) {
+						break;
+					}
+
+					Point2i new_center = pos;
+					pos = last_mouse_pos + xi.relative_motion;
+					center = new_center;
+					do_mouse_warp = window_has_focus; // warp the cursor if we're focused in
+				}
+
+				if (!last_mouse_pos_valid) {
+
+					last_mouse_pos = pos;
+					last_mouse_pos_valid = true;
+				}
+
+				// Hackish but relative mouse motion is already handled in the RawMotion event.
+				//  RawMotion does not provide the absolute mouse position (whereas MotionNotify does).
+				//  Therefore, RawMotion cannot be the authority on absolute mouse position.
+				//  RawMotion provides more precision than MotionNotify, which doesn't sense subpixel motion.
+				//  Therefore, MotionNotify cannot be the authority on relative mouse motion.
+				//  This means we need to take a combined approach...
+				Point2i rel;
+
+				// Only use raw input if in capture mode. Otherwise use the classic behavior.
+				if (mouse_mode == MOUSE_MODE_CAPTURED) {
+					rel = xi.relative_motion;
+				} else {
+					rel = pos - last_mouse_pos;
+				}
+
+				// Reset to prevent lingering motion
+				xi.relative_motion.x = 0;
+				xi.relative_motion.y = 0;
+
+				if (mouse_mode == MOUSE_MODE_CAPTURED) {
+					pos = Point2i(windows[MAIN_WINDOW_ID].size.width / 2, windows[MAIN_WINDOW_ID].size.height / 2);
+				}
+
+				Ref<InputEventMouseMotion> mm;
+				mm.instance();
+
+				mm->set_window_id(window_id);
+				mm->set_pressure(xi.pressure);
+				mm->set_tilt(xi.tilt);
+
+				// Make the absolute position integral so it doesn't look _too_ weird :)
+				Point2i posi(pos);
+
+				_get_key_modifier_state(event.xmotion.state, mm);
+				mm->set_button_mask(mouse_get_button_state());
+				mm->set_position(posi);
+				mm->set_global_position(posi);
+				Input::get_singleton()->set_mouse_position(posi);
+				mm->set_speed(Input::get_singleton()->get_last_mouse_speed());
+
+				mm->set_relative(rel);
+
+				last_mouse_pos = pos;
+
+				// printf("rel: %d,%d\n", rel.x, rel.y );
+				// Don't propagate the motion event unless we have focus
+				// this is so that the relative motion doesn't get messed up
+				// after we regain focus.
+				if (window_has_focus || !mouse_mode_grab)
+					Input::get_singleton()->accumulate_input_event(mm);
+
+			} break;
+			case KeyPress:
+			case KeyRelease: {
+
+				last_timestamp = event.xkey.time;
+
+				// key event is a little complex, so
+				// it will be handled in its own function.
+				_handle_key_event(window_id, (XKeyEvent *)&event);
+			} break;
+			case SelectionRequest: {
+
+				XSelectionRequestEvent *req;
+				XEvent e, respond;
+				e = event;
+
+				req = &(e.xselectionrequest);
+				if (req->target == XInternAtom(x11_display, "UTF8_STRING", 0) ||
+						req->target == XInternAtom(x11_display, "COMPOUND_TEXT", 0) ||
+						req->target == XInternAtom(x11_display, "TEXT", 0) ||
+						req->target == XA_STRING ||
+						req->target == XInternAtom(x11_display, "text/plain;charset=utf-8", 0) ||
+						req->target == XInternAtom(x11_display, "text/plain", 0)) {
+					CharString clip = clipboard_get().utf8();
+					XChangeProperty(x11_display,
+							req->requestor,
+							req->property,
+							req->target,
+							8,
+							PropModeReplace,
+							(unsigned char *)clip.get_data(),
+							clip.length());
+					respond.xselection.property = req->property;
+				} else if (req->target == XInternAtom(x11_display, "TARGETS", 0)) {
+
+					Atom data[7];
+					data[0] = XInternAtom(x11_display, "TARGETS", 0);
+					data[1] = XInternAtom(x11_display, "UTF8_STRING", 0);
+					data[2] = XInternAtom(x11_display, "COMPOUND_TEXT", 0);
+					data[3] = XInternAtom(x11_display, "TEXT", 0);
+					data[4] = XA_STRING;
+					data[5] = XInternAtom(x11_display, "text/plain;charset=utf-8", 0);
+					data[6] = XInternAtom(x11_display, "text/plain", 0);
+
+					XChangeProperty(x11_display,
+							req->requestor,
+							req->property,
+							XA_ATOM,
+							32,
+							PropModeReplace,
+							(unsigned char *)&data,
+							sizeof(data) / sizeof(data[0]));
+					respond.xselection.property = req->property;
+
+				} else {
+					char *targetname = XGetAtomName(x11_display, req->target);
+					printf("No Target '%s'\n", targetname);
+					if (targetname)
+						XFree(targetname);
+					respond.xselection.property = None;
+				}
+
+				respond.xselection.type = SelectionNotify;
+				respond.xselection.display = req->display;
+				respond.xselection.requestor = req->requestor;
+				respond.xselection.selection = req->selection;
+				respond.xselection.target = req->target;
+				respond.xselection.time = req->time;
+				XSendEvent(x11_display, req->requestor, True, NoEventMask, &respond);
+				XFlush(x11_display);
+			} break;
+
+			case SelectionNotify:
+
+				if (event.xselection.target == requested) {
+
+					Property p = _read_property(x11_display, windows[window_id].x11_window, XInternAtom(x11_display, "PRIMARY", 0));
+
+					Vector<String> files = String((char *)p.data).split("\n", false);
+					for (int i = 0; i < files.size(); i++) {
+						files.write[i] = files[i].replace("file://", "").http_unescape().strip_edges();
+					}
+					Input::get_singleton()->parse_drop_files(files);
+
+					//Reply that all is well.
+					XClientMessageEvent m;
+					memset(&m, 0, sizeof(m));
+					m.type = ClientMessage;
+					m.display = x11_display;
+					m.window = xdnd_source_window;
+					m.message_type = xdnd_finished;
+					m.format = 32;
+					m.data.l[0] = windows[window_id].x11_window;
+					m.data.l[1] = 1;
+					m.data.l[2] = xdnd_action_copy; //We only ever copy.
+
+					XSendEvent(x11_display, xdnd_source_window, False, NoEventMask, (XEvent *)&m);
+				}
+				break;
+
+			case ClientMessage:
+
+				if ((unsigned int)event.xclient.data.l[0] == (unsigned int)wm_delete)
+					Input::get_singleton()->parse_notification(MainLoop::NOTIFICATION_WM_QUIT_REQUEST);
+
+				else if ((unsigned int)event.xclient.message_type == (unsigned int)xdnd_enter) {
+
+					//File(s) have been dragged over the window, check for supported target (text/uri-list)
+					xdnd_version = (event.xclient.data.l[1] >> 24);
+					Window source = event.xclient.data.l[0];
+					bool more_than_3 = event.xclient.data.l[1] & 1;
+					if (more_than_3) {
+						Property p = _read_property(x11_display, source, XInternAtom(x11_display, "XdndTypeList", False));
+						requested = pick_target_from_list(x11_display, (Atom *)p.data, p.nitems);
+					} else
+						requested = pick_target_from_atoms(x11_display, event.xclient.data.l[2], event.xclient.data.l[3], event.xclient.data.l[4]);
+				} else if ((unsigned int)event.xclient.message_type == (unsigned int)xdnd_position) {
+
+					//xdnd position event, reply with an XDND status message
+					//just depending on type of data for now
+					XClientMessageEvent m;
+					memset(&m, 0, sizeof(m));
+					m.type = ClientMessage;
+					m.display = event.xclient.display;
+					m.window = event.xclient.data.l[0];
+					m.message_type = xdnd_status;
+					m.format = 32;
+					m.data.l[0] = windows[window_id].x11_window;
+					m.data.l[1] = (requested != None);
+					m.data.l[2] = 0; //empty rectangle
+					m.data.l[3] = 0;
+					m.data.l[4] = xdnd_action_copy;
+
+					XSendEvent(x11_display, event.xclient.data.l[0], False, NoEventMask, (XEvent *)&m);
+					XFlush(x11_display);
+				} else if ((unsigned int)event.xclient.message_type == (unsigned int)xdnd_drop) {
+
+					if (requested != None) {
+						xdnd_source_window = event.xclient.data.l[0];
+						if (xdnd_version >= 1)
+							XConvertSelection(x11_display, xdnd_selection, requested, XInternAtom(x11_display, "PRIMARY", 0), windows[window_id].x11_window, event.xclient.data.l[2]);
+						else
+							XConvertSelection(x11_display, xdnd_selection, requested, XInternAtom(x11_display, "PRIMARY", 0), windows[window_id].x11_window, CurrentTime);
+					} else {
+						//Reply that we're not interested.
+						XClientMessageEvent m;
+						memset(&m, 0, sizeof(m));
+						m.type = ClientMessage;
+						m.display = event.xclient.display;
+						m.window = event.xclient.data.l[0];
+						m.message_type = xdnd_finished;
+						m.format = 32;
+						m.data.l[0] = windows[window_id].x11_window;
+						m.data.l[1] = 0;
+						m.data.l[2] = None; //Failed.
+						XSendEvent(x11_display, event.xclient.data.l[0], False, NoEventMask, (XEvent *)&m);
+					}
+				}
+				break;
+			default:
+				break;
+		}
+	}
+
+	XFlush(x11_display);
+
+	if (do_mouse_warp) {
+
+		XWarpPointer(x11_display, None, windows[MAIN_WINDOW_ID].x11_window,
+				0, 0, 0, 0, (int)windows[MAIN_WINDOW_ID].size.width / 2, (int)windows[MAIN_WINDOW_ID].size.height / 2);
+
+		/*
+		Window root, child;
+		int root_x, root_y;
+		int win_x, win_y;
+		unsigned int mask;
+		XQueryPointer( x11_display, x11_window, &root, &child, &root_x, &root_y, &win_x, &win_y, &mask );
+
+		printf("Root: %d,%d\n", root_x, root_y);
+		printf("Win: %d,%d\n", win_x, win_y);
+		*/
+	}
+
+	Input::get_singleton()->flush_accumulated_events();
+}
+
+void DisplayServerX11::release_rendering_thread() {
+	WARN_PRINT("Rendering thread not supported by this display server.");
+}
+void DisplayServerX11::make_rendering_thread() {
+	WARN_PRINT("Rendering thread not supported by this display server.");
+}
+void DisplayServerX11::swap_buffers() {
+	WARN_PRINT("Swap buffers not supported by this display server.");
+}
+
+void DisplayServerX11::set_native_icon(const String &p_filename) {
+	WARN_PRINT("Native icon not supported by this display server.");
+}
+void DisplayServerX11::set_icon(const Ref<Image> &p_icon) {
+	WARN_PRINT("Icon not supported by this display server.");
+}
+
+DisplayServer *DisplayServerX11::create_func(const String &p_video_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
+
+	return memnew(DisplayServerX11(p_video_driver, p_mode, p_flags, p_resolution, r_error));
+}
+
+DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, const Vector2i &p_resolution) {
+
+	//Create window
+
+	long visualMask = VisualScreenMask;
+	int numberOfVisuals;
+	XVisualInfo vInfoTemplate = {};
+	vInfoTemplate.screen = DefaultScreen(x11_display);
+	XVisualInfo *visualInfo = XGetVisualInfo(x11_display, visualMask, &vInfoTemplate, &numberOfVisuals);
+
+	Colormap colormap = XCreateColormap(x11_display, RootWindow(x11_display, vInfoTemplate.screen), visualInfo->visual, AllocNone);
+
+	XSetWindowAttributes windowAttributes = {};
+	windowAttributes.colormap = colormap;
+	windowAttributes.background_pixel = 0xFFFFFFFF;
+	windowAttributes.border_pixel = 0;
+	windowAttributes.event_mask = KeyPressMask | KeyReleaseMask | StructureNotifyMask | ExposureMask;
+
+	unsigned long valuemask = CWBorderPixel | CWColormap | CWEventMask;
+
+	WindowID id;
+	{
+		WindowData wd;
+		wd.x11_window = XCreateWindow(x11_display, RootWindow(x11_display, visualInfo->screen), 0, 0, OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height, 0, visualInfo->depth, InputOutput, visualInfo->visual, valuemask, &windowAttributes);
+
+		//set_class_hint(x11_display, wd.x11_window);
+		XMapWindow(x11_display, wd.x11_window);
+		XFlush(x11_display);
+
+		XSync(x11_display, False);
+		//XSetErrorHandler(oldHandler);
+
+		XFree(visualInfo);
+
+#if defined(VULKAN_ENABLED)
+		if (context_vulkan) {
+			wd.vulkan_window = context_vulkan->window_create(wd.x11_window, x11_display, p_resolution.width, p_resolution.height);
+			ERR_FAIL_COND_V_MSG(wd.vulkan_window == -1, INVALID_WINDOW_ID, "Can't create a Vulkan window");
+		}
+#endif
+
+		//associate PID
+
+		// make PID known to X11
+		{
+			const long pid = OS::get_singleton()->get_process_id();
+			Atom net_wm_pid = XInternAtom(x11_display, "_NET_WM_PID", False);
+			XChangeProperty(x11_display, wd.x11_window, net_wm_pid, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&pid, 1);
+		}
+
+		long im_event_mask = 0;
+
+		{
+			XIEventMask all_event_mask;
+			XSetWindowAttributes new_attr;
+
+			new_attr.event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask |
+								  ButtonReleaseMask | EnterWindowMask |
+								  LeaveWindowMask | PointerMotionMask |
+								  Button1MotionMask |
+								  Button2MotionMask | Button3MotionMask |
+								  Button4MotionMask | Button5MotionMask |
+								  ButtonMotionMask | KeymapStateMask |
+								  ExposureMask | VisibilityChangeMask |
+								  StructureNotifyMask |
+								  SubstructureNotifyMask | SubstructureRedirectMask |
+								  FocusChangeMask | PropertyChangeMask |
+								  ColormapChangeMask | OwnerGrabButtonMask |
+								  im_event_mask;
+
+			XChangeWindowAttributes(x11_display, wd.x11_window, CWEventMask, &new_attr);
+
+			static unsigned char all_mask_data[XIMaskLen(XI_LASTEVENT)] = {};
+
+			all_event_mask.deviceid = XIAllDevices;
+			all_event_mask.mask_len = sizeof(all_mask_data);
+			all_event_mask.mask = all_mask_data;
+
+			XISetMask(all_event_mask.mask, XI_HierarchyChanged);
+
+#ifdef TOUCH_ENABLED
+			if (xi.touch_devices.size()) {
+				XISetMask(all_event_mask.mask, XI_TouchBegin);
+				XISetMask(all_event_mask.mask, XI_TouchUpdate);
+				XISetMask(all_event_mask.mask, XI_TouchEnd);
+				XISetMask(all_event_mask.mask, XI_TouchOwnership);
+			}
+#endif
+
+			XISelectEvents(x11_display, wd.x11_window, &all_event_mask, 1);
+		}
+
+		/* set the titlebar name */
+		XStoreName(x11_display, wd.x11_window, "Godot");
+		XSetWMProtocols(x11_display, wd.x11_window, &wm_delete, 1);
+		XChangeProperty(x11_display, wd.x11_window, xdnd_aware, XA_ATOM, 32, PropModeReplace, (unsigned char *)&xdnd_version, 1);
+
+		if (xim && xim_style) {
+
+			wd.xic = XCreateIC(xim, XNInputStyle, xim_style, XNClientWindow, wd.x11_window, XNFocusWindow, wd.x11_window, (char *)NULL);
+			if (XGetICValues(wd.xic, XNFilterEvents, &im_event_mask, NULL) != NULL) {
+				WARN_PRINT("XGetICValues couldn't obtain XNFilterEvents value");
+				XDestroyIC(wd.xic);
+				wd.xic = NULL;
+			}
+			if (wd.xic) {
+				XUnsetICFocus(wd.xic);
+			} else {
+				WARN_PRINT("XCreateIC couldn't create wd.xic");
+			}
+		} else {
+
+			wd.xic = NULL;
+			WARN_PRINT("XCreateIC couldn't create wd.xic");
+		}
+
+		id = window_id_counter++;
+
+		windows[id] = wd;
+	}
+
+	WindowData &wd = windows[id];
+
+	window_set_mode(p_mode, id);
+
+	//set cursor
+	if (cursors[current_cursor] != None) {
+
+		XDefineCursor(x11_display, wd.x11_window, cursors[current_cursor]);
+	}
+	return id;
+}
+
+DisplayServerX11::DisplayServerX11(const String &p_video_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
+
+	r_error = OK;
+
+	last_button_state = 0;
+
+	xmbstring = NULL;
+
+	last_click_ms = 0;
+	last_click_button_index = -1;
+	last_click_pos = Point2i(-100, -100);
+
+	last_timestamp = 0;
+	last_mouse_pos_valid = false;
+	last_keyrelease_time = 0;
+
+	if (OS::get_singleton()->get_render_thread_mode() == OS::RENDER_SEPARATE_THREAD) {
+		XInitThreads();
+	}
+
+	/** XLIB INITIALIZATION **/
+	x11_display = XOpenDisplay(NULL);
+
+	if (!x11_display) {
+		ERR_PRINT("X11 Display is not available");
+		r_error = ERR_UNAVAILABLE;
+		return;
+	}
+
+	char *modifiers = NULL;
+	Bool xkb_dar = False;
+	XAutoRepeatOn(x11_display);
+	xkb_dar = XkbSetDetectableAutoRepeat(x11_display, True, NULL);
+
+	// Try to support IME if detectable auto-repeat is supported
+	if (xkb_dar == True) {
+
+#ifdef X_HAVE_UTF8_STRING
+		// Xutf8LookupString will be used later instead of XmbLookupString before
+		// the multibyte sequences can be converted to unicode string.
+		modifiers = XSetLocaleModifiers("");
+#endif
+	}
+
+	if (modifiers == NULL) {
+		if (OS::get_singleton()->is_stdout_verbose()) {
+			WARN_PRINT("IME is disabled");
+		}
+		XSetLocaleModifiers("@im=none");
+		WARN_PRINT("Error setting locale modifiers");
+	}
+
+	const char *err;
+	xrr_get_monitors = NULL;
+	xrr_free_monitors = NULL;
+	int xrandr_major = 0;
+	int xrandr_minor = 0;
+	int event_base, error_base;
+	xrandr_ext_ok = XRRQueryExtension(x11_display, &event_base, &error_base);
+	xrandr_handle = dlopen("libXrandr.so.2", RTLD_LAZY);
+	if (!xrandr_handle) {
+		err = dlerror();
+		fprintf(stderr, "could not load libXrandr.so.2, Error: %s\n", err);
+	} else {
+		XRRQueryVersion(x11_display, &xrandr_major, &xrandr_minor);
+		if (((xrandr_major << 8) | xrandr_minor) >= 0x0105) {
+			xrr_get_monitors = (xrr_get_monitors_t)dlsym(xrandr_handle, "XRRGetMonitors");
+			if (!xrr_get_monitors) {
+				err = dlerror();
+				fprintf(stderr, "could not find symbol XRRGetMonitors\nError: %s\n", err);
+			} else {
+				xrr_free_monitors = (xrr_free_monitors_t)dlsym(xrandr_handle, "XRRFreeMonitors");
+				if (!xrr_free_monitors) {
+					err = dlerror();
+					fprintf(stderr, "could not find XRRFreeMonitors\nError: %s\n", err);
+					xrr_get_monitors = NULL;
+				}
+			}
+		}
+	}
+
+	if (!_refresh_device_info()) {
+		OS::get_singleton()->alert("Your system does not support XInput 2.\n"
+								   "Please upgrade your distribution.",
+				"Unable to initialize XInput");
+		r_error = ERR_UNAVAILABLE;
+		return;
+	}
+
+	xim = XOpenIM(x11_display, NULL, NULL, NULL);
+
+	if (xim == NULL) {
+		WARN_PRINT("XOpenIM failed");
+		xim_style = 0L;
+	} else {
+		::XIMCallback im_destroy_callback;
+		im_destroy_callback.client_data = (::XPointer)(this);
+		im_destroy_callback.callback = (::XIMProc)(_xim_destroy_callback);
+		if (XSetIMValues(xim, XNDestroyCallback, &im_destroy_callback,
+					NULL) != NULL) {
+			WARN_PRINT("Error setting XIM destroy callback");
+		}
+
+		::XIMStyles *xim_styles = NULL;
+		xim_style = 0L;
+		char *imvalret = XGetIMValues(xim, XNQueryInputStyle, &xim_styles, NULL);
+		if (imvalret != NULL || xim_styles == NULL) {
+			fprintf(stderr, "Input method doesn't support any styles\n");
+		}
+
+		if (xim_styles) {
+			xim_style = 0L;
+			for (int i = 0; i < xim_styles->count_styles; i++) {
+
+				if (xim_styles->supported_styles[i] ==
+						(XIMPreeditNothing | XIMStatusNothing)) {
+
+					xim_style = xim_styles->supported_styles[i];
+					break;
+				}
+			}
+
+			XFree(xim_styles);
+		}
+		XFree(imvalret);
+	}
+
+	/* Atorm internment */
+	wm_delete = XInternAtom(x11_display, "WM_DELETE_WINDOW", true);
+	//Set Xdnd (drag & drop) support
+	xdnd_aware = XInternAtom(x11_display, "XdndAware", False);
+	xdnd_version = 5;
+	xdnd_enter = XInternAtom(x11_display, "XdndEnter", False);
+	xdnd_position = XInternAtom(x11_display, "XdndPosition", False);
+	xdnd_status = XInternAtom(x11_display, "XdndStatus", False);
+	xdnd_action_copy = XInternAtom(x11_display, "XdndActionCopy", False);
+	xdnd_drop = XInternAtom(x11_display, "XdndDrop", False);
+	xdnd_finished = XInternAtom(x11_display, "XdndFinished", False);
+	xdnd_selection = XInternAtom(x11_display, "XdndSelection", False);
+
+	//!!!!!!!!!!!!!!!!!!!!!!!!!!
+	//TODO - do Vulkan and GLES2 support checks, driver selection and fallback
+	video_driver = p_video_driver;
+
+#ifndef _MSC_VER
+#warning Forcing vulkan video driver because OpenGL not implemented yet
+#endif
+	video_driver = "vulkan";
+
+#if defined(VULKAN_ENABLED)
+	if (video_driver == "vulkan") {
+
+		context_vulkan = memnew(VulkanContextX11);
+		if (context_vulkan->initialize() != OK) {
+			memdelete(context_vulkan);
+			context_vulkan = NULL;
+			r_error = ERR_CANT_CREATE;
+			ERR_FAIL_MSG("Could not initialize Vulkan");
+		}
+
+		//temporary
+		rendering_device_vulkan = memnew(RenderingDeviceVulkan);
+		rendering_device_vulkan->initialize(context_vulkan);
+
+		RasterizerRD::make_current();
+	}
+#endif
+	// Init context and rendering device
+#if defined(OPENGL_ENABLED)
+	if (video_driver == "opengl_es") {
+		if (getenv("DRI_PRIME") == NULL) {
+			int use_prime = -1;
+
+			if (getenv("PRIMUS_DISPLAY") ||
+					getenv("PRIMUS_libGLd") ||
+					getenv("PRIMUS_libGLa") ||
+					getenv("PRIMUS_libGL") ||
+					getenv("PRIMUS_LOAD_GLOBAL") ||
+					getenv("BUMBLEBEE_SOCKET")) {
+
+				print_verbose("Optirun/primusrun detected. Skipping GPU detection");
+				use_prime = 0;
+			}
+
+			if (getenv("LD_LIBRARY_PATH")) {
+				String ld_library_path(getenv("LD_LIBRARY_PATH"));
+				Vector<String> libraries = ld_library_path.split(":");
+
+				for (int i = 0; i < libraries.size(); ++i) {
+					if (FileAccess::exists(libraries[i] + "/libGL.so.1") ||
+							FileAccess::exists(libraries[i] + "/libGL.so")) {
+
+						print_verbose("Custom libGL override detected. Skipping GPU detection");
+						use_prime = 0;
+					}
+				}
+			}
+
+			if (use_prime == -1) {
+				print_verbose("Detecting GPUs, set DRI_PRIME in the environment to override GPU detection logic.");
+				use_prime = detect_prime();
+			}
+
+			if (use_prime) {
+				print_line("Found discrete GPU, setting DRI_PRIME=1 to use it.");
+				print_line("Note: Set DRI_PRIME=0 in the environment to disable Godot from using the discrete GPU.");
+				setenv("DRI_PRIME", "1", 1);
+			}
+		}
+
+		ContextGL_X11::ContextType opengl_api_type = ContextGL_X11::GLES_2_0_COMPATIBLE;
+
+		context_gles2 = memnew(ContextGL_X11(x11_display, x11_window, current_videomode, opengl_api_type));
+
+		if (context_gles2->initialize() != OK) {
+			memdelete(context_gles2);
+			context_gles2 = NULL;
+			ERR_FAIL_V(ERR_UNAVAILABLE);
+		}
+
+		context_gles2->set_use_vsync(current_videomode.use_vsync);
+
+		if (RasterizerGLES2::is_viable() == OK) {
+			RasterizerGLES2::register_config();
+			RasterizerGLES2::make_current();
+		} else {
+			memdelete(context_gles2);
+			context_gles2 = NULL;
+			ERR_FAIL_V(ERR_UNAVAILABLE);
+		}
+	}
+#endif
+
+	WindowID main_window = _create_window(p_mode, p_resolution);
+	for (int i = 0; i < WINDOW_FLAG_MAX; i++) {
+		if (p_flags & (1 << i)) {
+			window_set_flag(WindowFlags(i), true, main_window);
+		}
+	}
+
+	/*
+	visual_server = memnew(VisualServerRaster);
+	if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) {
+		visual_server = memnew(VisualServerWrapMT(visual_server, get_render_thread_mode() == RENDER_SEPARATE_THREAD));
+	}
+	*/
+
+	{
+		//set all event master mask
+		XIEventMask all_master_event_mask;
+		static unsigned char all_master_mask_data[XIMaskLen(XI_LASTEVENT)] = {};
+		all_master_event_mask.deviceid = XIAllMasterDevices;
+		all_master_event_mask.mask_len = sizeof(all_master_mask_data);
+		all_master_event_mask.mask = all_master_mask_data;
+		XISetMask(all_master_event_mask.mask, XI_DeviceChanged);
+		XISetMask(all_master_event_mask.mask, XI_RawMotion);
+		XISelectEvents(x11_display, DefaultRootWindow(x11_display), &all_master_event_mask, 1);
+	}
+
+	// Disabled by now since grabbing also blocks mouse events
+	// (they are received as extended events instead of standard events)
+	/*XIClearMask(xi.touch_event_mask.mask, XI_TouchOwnership);
+
+	// Grab touch devices to avoid OS gesture interference
+	for (int i = 0; i < xi.touch_devices.size(); ++i) {
+		XIGrabDevice(x11_display, xi.touch_devices[i], x11_window, CurrentTime, None, XIGrabModeAsync, XIGrabModeAsync, False, &xi.touch_event_mask);
+	}*/
+
+	cursor_size = XcursorGetDefaultSize(x11_display);
+	cursor_theme = XcursorGetTheme(x11_display);
+
+	if (!cursor_theme) {
+		print_verbose("XcursorGetTheme could not get cursor theme");
+		cursor_theme = "default";
+	}
+
+	for (int i = 0; i < CURSOR_MAX; i++) {
+
+		cursors[i] = None;
+		img[i] = NULL;
+	}
+
+	current_cursor = CURSOR_ARROW;
+
+	for (int i = 0; i < CURSOR_MAX; i++) {
+
+		static const char *cursor_file[] = {
+			"left_ptr",
+			"xterm",
+			"hand2",
+			"cross",
+			"watch",
+			"left_ptr_watch",
+			"fleur",
+			"dnd-move",
+			"crossed_circle",
+			"v_double_arrow",
+			"h_double_arrow",
+			"size_bdiag",
+			"size_fdiag",
+			"move",
+			"row_resize",
+			"col_resize",
+			"question_arrow"
+		};
+
+		img[i] = XcursorLibraryLoadImage(cursor_file[i], cursor_theme, cursor_size);
+		if (!img[i]) {
+			const char *fallback = NULL;
+
+			switch (i) {
+				case CURSOR_POINTING_HAND:
+					fallback = "pointer";
+					break;
+				case CURSOR_CROSS:
+					fallback = "crosshair";
+					break;
+				case CURSOR_WAIT:
+					fallback = "wait";
+					break;
+				case CURSOR_BUSY:
+					fallback = "progress";
+					break;
+				case CURSOR_DRAG:
+					fallback = "grabbing";
+					break;
+				case CURSOR_CAN_DROP:
+					fallback = "hand1";
+					break;
+				case CURSOR_FORBIDDEN:
+					fallback = "forbidden";
+					break;
+				case CURSOR_VSIZE:
+					fallback = "ns-resize";
+					break;
+				case CURSOR_HSIZE:
+					fallback = "ew-resize";
+					break;
+				case CURSOR_BDIAGSIZE:
+					fallback = "fd_double_arrow";
+					break;
+				case CURSOR_FDIAGSIZE:
+					fallback = "bd_double_arrow";
+					break;
+				case CURSOR_MOVE:
+					img[i] = img[CURSOR_DRAG];
+					break;
+				case CURSOR_VSPLIT:
+					fallback = "sb_v_double_arrow";
+					break;
+				case CURSOR_HSPLIT:
+					fallback = "sb_h_double_arrow";
+					break;
+				case CURSOR_HELP:
+					fallback = "help";
+					break;
+			}
+			if (fallback != NULL) {
+				img[i] = XcursorLibraryLoadImage(fallback, cursor_theme, cursor_size);
+			}
+		}
+		if (img[i]) {
+			cursors[i] = XcursorImageLoadCursor(x11_display, img[i]);
+		} else {
+			print_verbose("Failed loading custom cursor: " + String(cursor_file[i]));
+		}
+	}
+
+	{
+		// Creating an empty/transparent cursor
+
+		// Create 1x1 bitmap
+		Pixmap cursormask = XCreatePixmap(x11_display,
+				RootWindow(x11_display, DefaultScreen(x11_display)), 1, 1, 1);
+
+		// Fill with zero
+		XGCValues xgc;
+		xgc.function = GXclear;
+		GC gc = XCreateGC(x11_display, cursormask, GCFunction, &xgc);
+		XFillRectangle(x11_display, cursormask, gc, 0, 0, 1, 1);
+
+		// Color value doesn't matter. Mask zero means no foreground or background will be drawn
+		XColor col = {};
+
+		Cursor cursor = XCreatePixmapCursor(x11_display,
+				cursormask, // source (using cursor mask as placeholder, since it'll all be ignored)
+				cursormask, // mask
+				&col, &col, 0, 0);
+
+		XFreePixmap(x11_display, cursormask);
+		XFreeGC(x11_display, gc);
+
+		if (cursor == None) {
+			ERR_PRINT("FAILED CREATING CURSOR");
+		}
+
+		null_cursor = cursor;
+	}
+	cursor_set_shape(CURSOR_BUSY);
+
+	requested = None;
+
+	visual_server->init();
+
+	window_has_focus = true; // Set focus to true at init
+
+	/*if (p_desired.layered) {
+		set_window_per_pixel_transparency_enabled(true);
+	}*/
+
+	XEvent xevent;
+	while (XPending(x11_display) > 0) {
+		XNextEvent(x11_display, &xevent);
+		if (xevent.type == ConfigureNotify) {
+			_window_changed(&xevent);
+		}
+	}
+
+	_update_real_mouse_position(windows[MAIN_WINDOW_ID]);
+
+	r_error = OK;
+}
+DisplayServerX11::~DisplayServerX11() {
+}
+
+#endif // X11 enabled

+ 315 - 0
platform/x11/display_server_x11.h

@@ -0,0 +1,315 @@
+/*************************************************************************/
+/*  display_server_x11.h                                                 */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* 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.                */
+/*************************************************************************/
+
+#ifndef DISPLAY_SERVER_X11_H
+#define DISPLAY_SERVER_X11_H
+
+#ifdef X11_ENABLED
+
+#include "servers/display_server.h"
+
+#include "core/input/input.h"
+#include "crash_handler_x11.h"
+#include "drivers/alsa/audio_driver_alsa.h"
+#include "drivers/alsamidi/midi_driver_alsamidi.h"
+#include "drivers/pulseaudio/audio_driver_pulseaudio.h"
+#include "drivers/unix/os_unix.h"
+#include "joypad_linux.h"
+#include "servers/audio_server.h"
+#include "servers/visual/rasterizer.h"
+#include "servers/visual_server.h"
+
+#if defined(OPENGL_ENABLED)
+#include "context_gl_x11.h"
+#endif
+
+#if defined(VULKAN_ENABLED)
+#include "drivers/vulkan/rendering_device_vulkan.h"
+#include "platform/x11/vulkan_context_x11.h"
+#endif
+
+#include <X11/Xcursor/Xcursor.h>
+#include <X11/Xlib.h>
+#include <X11/extensions/XInput2.h>
+#include <X11/extensions/Xrandr.h>
+#include <X11/keysym.h>
+
+// Hints for X11 fullscreen
+typedef struct {
+	unsigned long flags;
+	unsigned long functions;
+	unsigned long decorations;
+	long inputMode;
+	unsigned long status;
+} Hints;
+
+typedef struct _xrr_monitor_info {
+	Atom name;
+	Bool primary;
+	Bool automatic;
+	int noutput;
+	int x;
+	int y;
+	int width;
+	int height;
+	int mwidth;
+	int mheight;
+	RROutput *outputs;
+} xrr_monitor_info;
+
+#undef CursorShape
+
+class DisplayServerX11 : public DisplayServer {
+	//No need to register, it's platform-specific and nothing is added
+	//GDCLASS(DisplayServerX11, DisplayServer)
+
+	Atom wm_delete;
+	Atom xdnd_enter;
+	Atom xdnd_position;
+	Atom xdnd_status;
+	Atom xdnd_action_copy;
+	Atom xdnd_drop;
+	Atom xdnd_finished;
+	Atom xdnd_selection;
+	Atom xdnd_aware;
+	Atom requested;
+	int xdnd_version;
+
+#if defined(OPENGL_ENABLED)
+	ContextGL_X11 *context_gles2;
+#endif
+#if defined(VULKAN_ENABLED)
+	VulkanContextX11 *context_vulkan;
+	RenderingDeviceVulkan *rendering_device_vulkan;
+#endif
+
+	//Rasterizer *rasterizer;
+	VisualServer *visual_server;
+
+	struct WindowData {
+		Window x11_window;
+		::XIC xic;
+#if defined(VULKAN_ENABLED)
+		int vulkan_window;
+#endif
+		Size2i min_size;
+		Size2i max_size;
+		Size2i size;
+		Size2i im_position;
+		bool im_active = false;
+
+		//better to guess on the fly, given WM can change it
+		//WindowMode mode;
+		bool fullscreen = false; //OS can't exit from this mode
+		bool on_top = false;
+		bool borderless = false;
+		bool resize_disabled = false;
+		Vector2i last_position_before_fs;
+	};
+
+	Map<WindowID, WindowData> windows;
+
+	WindowID window_id_counter = MAIN_WINDOW_ID;
+	WindowID _create_window(WindowMode p_mode, const Vector2i &p_resolution);
+
+	String internal_clipboard;
+	Window xdnd_source_window;
+	::Display *x11_display;
+	char *xmbstring;
+	int xmblen;
+	unsigned long last_timestamp;
+	::Time last_keyrelease_time;
+	::XIM xim;
+	::XIMStyle xim_style;
+	static void _xim_destroy_callback(::XIM im, ::XPointer client_data,
+			::XPointer call_data);
+
+	Point2i last_mouse_pos;
+	bool last_mouse_pos_valid;
+	Point2i last_click_pos;
+	uint64_t last_click_ms;
+	int last_click_button_index;
+	uint32_t last_button_state;
+
+	struct {
+		int opcode;
+		Vector<int> touch_devices;
+		Map<int, Vector2> absolute_devices;
+		Map<int, Vector3> pen_devices;
+		XIEventMask all_event_mask;
+		Map<int, Vector2> state;
+		double pressure;
+		Vector2 tilt;
+		Vector2 mouse_pos_to_filter;
+		Vector2 relative_motion;
+		Vector2 raw_pos;
+		Vector2 old_raw_pos;
+		::Time last_relative_time;
+	} xi;
+
+	bool _refresh_device_info();
+
+	unsigned int _get_mouse_button_state(unsigned int p_x11_button, int p_x11_type);
+	void _get_key_modifier_state(unsigned int p_x11_state, Ref<InputEventWithModifiers> state);
+	void _flush_mouse_motion();
+
+	MouseMode mouse_mode;
+	Point2i center;
+
+	void _handle_key_event(WindowID p_window, XKeyEvent *p_event, bool p_echo = false);
+
+	bool force_quit;
+	bool minimized;
+	bool window_has_focus;
+	bool do_mouse_warp;
+
+	const char *cursor_theme;
+	int cursor_size;
+	XcursorImage *img[CURSOR_MAX];
+	Cursor cursors[CURSOR_MAX];
+	Cursor null_cursor;
+	CursorShape current_cursor;
+	Map<CursorShape, Vector<Variant>> cursors_cache;
+
+	bool layered_window;
+
+	String video_driver;
+	bool window_focused;
+	//void set_wm_border(bool p_enabled);
+	void set_wm_fullscreen(bool p_enabled);
+	void set_wm_above(bool p_enabled);
+
+	typedef xrr_monitor_info *(*xrr_get_monitors_t)(Display *dpy, Window window, Bool get_active, int *nmonitors);
+	typedef void (*xrr_free_monitors_t)(xrr_monitor_info *monitors);
+	xrr_get_monitors_t xrr_get_monitors;
+	xrr_free_monitors_t xrr_free_monitors;
+	void *xrandr_handle;
+	Bool xrandr_ext_ok;
+
+	struct Property {
+		unsigned char *data;
+		int format, nitems;
+		Atom type;
+	};
+	static Property _read_property(Display *p_display, Window p_window, Atom p_property);
+
+	void _update_real_mouse_position(const WindowData &wd);
+	void _set_wm_fullscreen(WindowID p_window, bool p_enabled);
+	void _set_wm_maximized(WindowID p_window, bool p_enabled);
+
+protected:
+	void _window_changed(XEvent *event);
+
+public:
+	virtual bool has_feature(Feature p_feature) const;
+	virtual String get_name() const;
+
+	virtual void alert(const String &p_alert, const String &p_title = "ALERT!");
+
+	virtual void mouse_set_mode(MouseMode p_mode);
+	virtual MouseMode mouse_get_mode() const;
+
+	virtual void mouse_warp_to_position(const Point2i &p_to);
+	virtual Point2i mouse_get_position() const;
+	virtual int mouse_get_button_state() const;
+
+	virtual void clipboard_set(const String &p_text);
+	virtual String clipboard_get() const;
+
+	virtual int get_screen_count() const;
+	virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
+	virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
+	virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
+	virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
+
+	virtual Vector<int> get_window_list() const;
+
+	virtual WindowID create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i());
+	virtual void delete_sub_window(WindowID p_id);
+
+	virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID);
+
+	virtual int window_get_current_screen(WindowID p_window = MAIN_WINDOW_ID) const;
+	virtual void window_set_current_screen(int p_screen, WindowID p_window = MAIN_WINDOW_ID);
+
+	virtual Point2i window_get_position(WindowID p_window = MAIN_WINDOW_ID) const;
+	virtual void window_set_position(const Point2i &p_position, WindowID p_window = MAIN_WINDOW_ID);
+
+	virtual void window_set_max_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID);
+	virtual Size2i window_get_max_size(WindowID p_window = MAIN_WINDOW_ID) const;
+
+	virtual void window_set_min_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID);
+	virtual Size2i window_get_min_size(WindowID p_window = MAIN_WINDOW_ID) const;
+
+	virtual void window_set_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID);
+	virtual Size2i window_get_size(WindowID p_window = MAIN_WINDOW_ID) const;
+	virtual Size2i window_get_real_size(WindowID p_window = MAIN_WINDOW_ID) const;
+
+	virtual void window_set_mode(WindowMode p_mode, WindowID p_window = MAIN_WINDOW_ID);
+	virtual WindowMode window_get_mode(WindowID p_window = MAIN_WINDOW_ID) const;
+
+	virtual bool window_is_maximize_allowed(WindowID p_window = MAIN_WINDOW_ID) const;
+
+	virtual void window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window = MAIN_WINDOW_ID);
+	virtual bool window_get_flag(WindowFlags p_flag, WindowID p_window = MAIN_WINDOW_ID) const;
+
+	virtual void window_request_attention(WindowID p_window = MAIN_WINDOW_ID);
+
+	virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID);
+
+	virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const;
+
+	virtual void window_set_ime_active(const bool p_active, WindowID p_window = MAIN_WINDOW_ID);
+	virtual void window_set_ime_position(const Point2i &p_pos, WindowID p_window = MAIN_WINDOW_ID);
+
+	virtual void cursor_set_shape(CursorShape p_shape);
+	virtual CursorShape cursor_get_shape() const;
+	virtual void cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
+
+	virtual LatinKeyboardVariant get_latin_keyboard_variant() const;
+
+	virtual void process_events();
+
+	virtual void release_rendering_thread();
+	virtual void make_rendering_thread();
+	virtual void swap_buffers();
+
+	virtual void set_native_icon(const String &p_filename);
+	virtual void set_icon(const Ref<Image> &p_icon);
+
+	static DisplayServer *create_func(const String &p_video_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+
+	DisplayServerX11(const String &p_video_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+	~DisplayServerX11();
+};
+
+#endif // X11 enabled
+
+#endif // DISPLAY_SERVER_X11_H

+ 11 - 11
platform/x11/joypad_linux.cpp

@@ -71,7 +71,7 @@ void JoypadLinux::Joypad::reset() {
 	dpad = 0;
 	dpad = 0;
 	fd = -1;
 	fd = -1;
 
 
-	InputDefault::JoyAxis jx;
+	Input::JoyAxis jx;
 	jx.min = -1;
 	jx.min = -1;
 	jx.value = 0.0f;
 	jx.value = 0.0f;
 	for (int i = 0; i < MAX_ABS; i++) {
 	for (int i = 0; i < MAX_ABS; i++) {
@@ -80,7 +80,7 @@ void JoypadLinux::Joypad::reset() {
 	}
 	}
 }
 }
 
 
-JoypadLinux::JoypadLinux(InputDefault *in) {
+JoypadLinux::JoypadLinux(Input *in) {
 	exit_udev = false;
 	exit_udev = false;
 	input = in;
 	input = in;
 	joy_thread = Thread::create(joy_thread_func, this);
 	joy_thread = Thread::create(joy_thread_func, this);
@@ -436,11 +436,11 @@ void JoypadLinux::joypad_vibration_stop(int p_id, uint64_t p_timestamp) {
 	joy.ff_effect_timestamp = p_timestamp;
 	joy.ff_effect_timestamp = p_timestamp;
 }
 }
 
 
-InputDefault::JoyAxis JoypadLinux::axis_correct(const input_absinfo *p_abs, int p_value) const {
+Input::JoyAxis JoypadLinux::axis_correct(const input_absinfo *p_abs, int p_value) const {
 
 
 	int min = p_abs->minimum;
 	int min = p_abs->minimum;
 	int max = p_abs->maximum;
 	int max = p_abs->maximum;
-	InputDefault::JoyAxis jx;
+	Input::JoyAxis jx;
 
 
 	if (min < 0) {
 	if (min < 0) {
 		jx.min = -1;
 		jx.min = -1;
@@ -492,11 +492,11 @@ void JoypadLinux::process_joypads() {
 							case ABS_HAT0X:
 							case ABS_HAT0X:
 								if (ev.value != 0) {
 								if (ev.value != 0) {
 									if (ev.value < 0)
 									if (ev.value < 0)
-										joy->dpad |= InputDefault::HAT_MASK_LEFT;
+										joy->dpad |= Input::HAT_MASK_LEFT;
 									else
 									else
-										joy->dpad |= InputDefault::HAT_MASK_RIGHT;
+										joy->dpad |= Input::HAT_MASK_RIGHT;
 								} else
 								} else
-									joy->dpad &= ~(InputDefault::HAT_MASK_LEFT | InputDefault::HAT_MASK_RIGHT);
+									joy->dpad &= ~(Input::HAT_MASK_LEFT | Input::HAT_MASK_RIGHT);
 
 
 								input->joy_hat(i, joy->dpad);
 								input->joy_hat(i, joy->dpad);
 								break;
 								break;
@@ -504,11 +504,11 @@ void JoypadLinux::process_joypads() {
 							case ABS_HAT0Y:
 							case ABS_HAT0Y:
 								if (ev.value != 0) {
 								if (ev.value != 0) {
 									if (ev.value < 0)
 									if (ev.value < 0)
-										joy->dpad |= InputDefault::HAT_MASK_UP;
+										joy->dpad |= Input::HAT_MASK_UP;
 									else
 									else
-										joy->dpad |= InputDefault::HAT_MASK_DOWN;
+										joy->dpad |= Input::HAT_MASK_DOWN;
 								} else
 								} else
-									joy->dpad &= ~(InputDefault::HAT_MASK_UP | InputDefault::HAT_MASK_DOWN);
+									joy->dpad &= ~(Input::HAT_MASK_UP | Input::HAT_MASK_DOWN);
 
 
 								input->joy_hat(i, joy->dpad);
 								input->joy_hat(i, joy->dpad);
 								break;
 								break;
@@ -517,7 +517,7 @@ void JoypadLinux::process_joypads() {
 								if (ev.code >= MAX_ABS)
 								if (ev.code >= MAX_ABS)
 									return;
 									return;
 								if (joy->abs_map[ev.code] != -1 && joy->abs_info[ev.code]) {
 								if (joy->abs_map[ev.code] != -1 && joy->abs_info[ev.code]) {
-									InputDefault::JoyAxis value = axis_correct(joy->abs_info[ev.code], ev.value);
+									Input::JoyAxis value = axis_correct(joy->abs_info[ev.code], ev.value);
 									joy->curr_axis[joy->abs_map[ev.code]] = value;
 									joy->curr_axis[joy->abs_map[ev.code]] = value;
 								}
 								}
 								break;
 								break;

+ 5 - 5
platform/x11/joypad_linux.h

@@ -33,15 +33,15 @@
 #define JOYPAD_LINUX_H
 #define JOYPAD_LINUX_H
 
 
 #ifdef JOYDEV_ENABLED
 #ifdef JOYDEV_ENABLED
+#include "core/input/input.h"
 #include "core/os/mutex.h"
 #include "core/os/mutex.h"
 #include "core/os/thread.h"
 #include "core/os/thread.h"
-#include "main/input_default.h"
 
 
 struct input_absinfo;
 struct input_absinfo;
 
 
 class JoypadLinux {
 class JoypadLinux {
 public:
 public:
-	JoypadLinux(InputDefault *in);
+	JoypadLinux(Input *in);
 	~JoypadLinux();
 	~JoypadLinux();
 	void process_joypads();
 	void process_joypads();
 
 
@@ -53,7 +53,7 @@ private:
 	};
 	};
 
 
 	struct Joypad {
 	struct Joypad {
-		InputDefault::JoyAxis curr_axis[MAX_ABS];
+		Input::JoyAxis curr_axis[MAX_ABS];
 		int key_map[MAX_KEY];
 		int key_map[MAX_KEY];
 		int abs_map[MAX_ABS];
 		int abs_map[MAX_ABS];
 		int dpad;
 		int dpad;
@@ -74,7 +74,7 @@ private:
 	bool exit_udev;
 	bool exit_udev;
 	Mutex joy_mutex;
 	Mutex joy_mutex;
 	Thread *joy_thread;
 	Thread *joy_thread;
-	InputDefault *input;
+	Input *input;
 	Joypad joypads[JOYPADS_MAX];
 	Joypad joypads[JOYPADS_MAX];
 	Vector<String> attached_devices;
 	Vector<String> attached_devices;
 
 
@@ -95,7 +95,7 @@ private:
 	void joypad_vibration_start(int p_id, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp);
 	void joypad_vibration_start(int p_id, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp);
 	void joypad_vibration_stop(int p_id, uint64_t p_timestamp);
 	void joypad_vibration_stop(int p_id, uint64_t p_timestamp);
 
 
-	InputDefault::JoyAxis axis_correct(const input_absinfo *p_abs, int p_value) const;
+	Input::JoyAxis axis_correct(const input_absinfo *p_abs, int p_value) const;
 };
 };
 
 
 #endif
 #endif

+ 1 - 1
platform/x11/os_x11.cpp

@@ -651,7 +651,7 @@ Error OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
 
 
 	AudioDriverManager::initialize(p_audio_driver);
 	AudioDriverManager::initialize(p_audio_driver);
 
 
-	input = memnew(InputDefault);
+	input = memnew(Input);
 
 
 	window_has_focus = true; // Set focus to true at init
 	window_has_focus = true; // Set focus to true at init
 #ifdef JOYDEV_ENABLED
 #ifdef JOYDEV_ENABLED

+ 2 - 3
platform/x11/os_x11.h

@@ -31,14 +31,13 @@
 #ifndef OS_X11_H
 #ifndef OS_X11_H
 #define OS_X11_H
 #define OS_X11_H
 
 
-#include "core/os/input.h"
+#include "core/input/input.h"
 #include "crash_handler_x11.h"
 #include "crash_handler_x11.h"
 #include "drivers/alsa/audio_driver_alsa.h"
 #include "drivers/alsa/audio_driver_alsa.h"
 #include "drivers/alsamidi/midi_driver_alsamidi.h"
 #include "drivers/alsamidi/midi_driver_alsamidi.h"
 #include "drivers/pulseaudio/audio_driver_pulseaudio.h"
 #include "drivers/pulseaudio/audio_driver_pulseaudio.h"
 #include "drivers/unix/os_unix.h"
 #include "drivers/unix/os_unix.h"
 #include "joypad_linux.h"
 #include "joypad_linux.h"
-#include "main/input_default.h"
 #include "servers/audio_server.h"
 #include "servers/audio_server.h"
 #include "servers/visual/rasterizer.h"
 #include "servers/visual/rasterizer.h"
 #include "servers/visual_server.h"
 #include "servers/visual_server.h"
@@ -181,7 +180,7 @@ class OS_X11 : public OS_Unix {
 	CursorShape current_cursor;
 	CursorShape current_cursor;
 	Map<CursorShape, Vector<Variant>> cursors_cache;
 	Map<CursorShape, Vector<Variant>> cursors_cache;
 
 
-	InputDefault *input;
+	Input *input;
 
 
 #ifdef JOYDEV_ENABLED
 #ifdef JOYDEV_ENABLED
 	JoypadLinux *joypad;
 	JoypadLinux *joypad;

+ 2 - 1
scene/2d/canvas_item.cpp

@@ -29,9 +29,10 @@
 /*************************************************************************/
 /*************************************************************************/
 
 
 #include "canvas_item.h"
 #include "canvas_item.h"
+
+#include "core/input/input.h"
 #include "core/message_queue.h"
 #include "core/message_queue.h"
 #include "core/method_bind_ext.gen.inc"
 #include "core/method_bind_ext.gen.inc"
-#include "core/os/input.h"
 #include "scene/main/canvas_layer.h"
 #include "scene/main/canvas_layer.h"
 #include "scene/main/viewport.h"
 #include "scene/main/viewport.h"
 #include "scene/resources/font.h"
 #include "scene/resources/font.h"

+ 2 - 2
scene/2d/touch_screen_button.cpp

@@ -30,8 +30,8 @@
 
 
 #include "touch_screen_button.h"
 #include "touch_screen_button.h"
 
 
-#include "core/input_map.h"
-#include "core/os/input.h"
+#include "core/input/input.h"
+#include "core/input/input_map.h"
 #include "core/os/os.h"
 #include "core/os/os.h"
 
 
 void TouchScreenButton::set_texture(const Ref<Texture2D> &p_texture) {
 void TouchScreenButton::set_texture(const Ref<Texture2D> &p_texture) {

+ 1 - 1
scene/3d/arvr_nodes.cpp

@@ -29,7 +29,7 @@
 /*************************************************************************/
 /*************************************************************************/
 
 
 #include "arvr_nodes.h"
 #include "arvr_nodes.h"
-#include "core/os/input.h"
+#include "core/input/input.h"
 #include "servers/arvr/arvr_interface.h"
 #include "servers/arvr/arvr_interface.h"
 #include "servers/arvr_server.h"
 #include "servers/arvr_server.h"
 
 

+ 1 - 1
scene/gui/color_picker.cpp

@@ -30,7 +30,7 @@
 
 
 #include "color_picker.h"
 #include "color_picker.h"
 
 
-#include "core/os/input.h"
+#include "core/input/input.h"
 #include "core/os/keyboard.h"
 #include "core/os/keyboard.h"
 #include "core/os/os.h"
 #include "core/os/os.h"
 
 

+ 1 - 1
scene/gui/graph_edit.cpp

@@ -30,7 +30,7 @@
 
 
 #include "graph_edit.h"
 #include "graph_edit.h"
 
 
-#include "core/os/input.h"
+#include "core/input/input.h"
 #include "core/os/keyboard.h"
 #include "core/os/keyboard.h"
 #include "scene/gui/box_container.h"
 #include "scene/gui/box_container.h"
 
 

+ 1 - 1
scene/gui/popup_menu.cpp

@@ -30,7 +30,7 @@
 
 
 #include "popup_menu.h"
 #include "popup_menu.h"
 
 
-#include "core/os/input.h"
+#include "core/input/input.h"
 #include "core/os/keyboard.h"
 #include "core/os/keyboard.h"
 #include "core/os/os.h"
 #include "core/os/os.h"
 #include "core/print_string.h"
 #include "core/print_string.h"

+ 1 - 1
scene/gui/shortcut.h

@@ -31,7 +31,7 @@
 #ifndef SHORTCUT_H
 #ifndef SHORTCUT_H
 #define SHORTCUT_H
 #define SHORTCUT_H
 
 
-#include "core/os/input_event.h"
+#include "core/input/input_event.h"
 #include "core/resource.h"
 #include "core/resource.h"
 
 
 class ShortCut : public Resource {
 class ShortCut : public Resource {

+ 1 - 1
scene/gui/spin_box.cpp

@@ -29,8 +29,8 @@
 /*************************************************************************/
 /*************************************************************************/
 
 
 #include "spin_box.h"
 #include "spin_box.h"
+#include "core/input/input.h"
 #include "core/math/expression.h"
 #include "core/math/expression.h"
-#include "core/os/input.h"
 
 
 Size2 SpinBox::get_minimum_size() const {
 Size2 SpinBox::get_minimum_size() const {
 
 

+ 1 - 1
scene/gui/text_edit.cpp

@@ -30,8 +30,8 @@
 
 
 #include "text_edit.h"
 #include "text_edit.h"
 
 
+#include "core/input/input.h"
 #include "core/message_queue.h"
 #include "core/message_queue.h"
-#include "core/os/input.h"
 #include "core/os/keyboard.h"
 #include "core/os/keyboard.h"
 #include "core/os/os.h"
 #include "core/os/os.h"
 #include "core/project_settings.h"
 #include "core/project_settings.h"

+ 1 - 1
scene/gui/tree.cpp

@@ -30,8 +30,8 @@
 
 
 #include "tree.h"
 #include "tree.h"
 
 
+#include "core/input/input.h"
 #include "core/math/math_funcs.h"
 #include "core/math/math_funcs.h"
-#include "core/os/input.h"
 #include "core/os/keyboard.h"
 #include "core/os/keyboard.h"
 #include "core/os/os.h"
 #include "core/os/os.h"
 #include "core/print_string.h"
 #include "core/print_string.h"

+ 2 - 2
scene/main/scene_tree.cpp

@@ -31,6 +31,7 @@
 #include "scene_tree.h"
 #include "scene_tree.h"
 
 
 #include "core/debugger/engine_debugger.h"
 #include "core/debugger/engine_debugger.h"
+#include "core/input/input.h"
 #include "core/io/marshalls.h"
 #include "core/io/marshalls.h"
 #include "core/io/resource_loader.h"
 #include "core/io/resource_loader.h"
 #include "core/message_queue.h"
 #include "core/message_queue.h"
@@ -39,7 +40,6 @@
 #include "core/os/os.h"
 #include "core/os/os.h"
 #include "core/print_string.h"
 #include "core/print_string.h"
 #include "core/project_settings.h"
 #include "core/project_settings.h"
-#include "main/input_default.h"
 #include "node.h"
 #include "node.h"
 #include "scene/debugger/scene_debugger.h"
 #include "scene/debugger/scene_debugger.h"
 #include "scene/resources/dynamic_font.h"
 #include "scene/resources/dynamic_font.h"
@@ -668,7 +668,7 @@ void SceneTree::_notification(int p_notification) {
 
 
 		case NOTIFICATION_WM_FOCUS_IN: {
 		case NOTIFICATION_WM_FOCUS_IN: {
 
 
-			InputDefault *id = Object::cast_to<InputDefault>(Input::get_singleton());
+			Input *id = Input::get_singleton();
 			if (id) {
 			if (id) {
 				id->ensure_touch_mouse_raised();
 				id->ensure_touch_mouse_raised();
 			}
 			}

+ 1 - 1
scene/main/viewport.cpp

@@ -32,7 +32,7 @@
 
 
 #include "core/core_string_names.h"
 #include "core/core_string_names.h"
 #include "core/debugger/engine_debugger.h"
 #include "core/debugger/engine_debugger.h"
-#include "core/os/input.h"
+#include "core/input/input.h"
 #include "core/os/os.h"
 #include "core/os/os.h"
 #include "core/project_settings.h"
 #include "core/project_settings.h"
 #include "scene/2d/collision_object_2d.h"
 #include "scene/2d/collision_object_2d.h"

+ 1 - 1
servers/arvr/arvr_positional_tracker.cpp

@@ -29,7 +29,7 @@
 /*************************************************************************/
 /*************************************************************************/
 
 
 #include "arvr_positional_tracker.h"
 #include "arvr_positional_tracker.h"
-#include "core/os/input.h"
+#include "core/input/input.h"
 
 
 void ARVRPositionalTracker::_bind_methods() {
 void ARVRPositionalTracker::_bind_methods() {
 	BIND_ENUM_CONSTANT(TRACKER_HAND_UNKNOWN);
 	BIND_ENUM_CONSTANT(TRACKER_HAND_UNKNOWN);

+ 374 - 0
servers/display_server.cpp

@@ -0,0 +1,374 @@
+/*************************************************************************/
+/*  display_server.cpp                                                   */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#include "display_server.h"
+
+DisplayServer *DisplayServer::singleton = nullptr;
+
+void DisplayServer::global_menu_add_item(const String &p_menu, const String &p_label, const Variant &p_signal, const Variant &p_meta) {
+	WARN_PRINT("Global menus not supported by this display server.");
+}
+void DisplayServer::global_menu_add_separator(const String &p_menu) {
+	WARN_PRINT("Global menus not supported by this display server.");
+}
+void DisplayServer::global_menu_remove_item(const String &p_menu, int p_idx) {
+	WARN_PRINT("Global menus not supported by this display server.");
+}
+void DisplayServer::global_menu_clear(const String &p_menu) {
+	WARN_PRINT("Global menus not supported by this display server.");
+}
+
+void DisplayServer::mouse_set_mode(MouseMode p_mode) {
+	WARN_PRINT("Mouse is not supported by this display server.");
+}
+DisplayServer::MouseMode DisplayServer::mouse_get_mode() const {
+	return MOUSE_MODE_VISIBLE;
+}
+
+void DisplayServer::mouse_warp_to_position(const Point2i &p_to) {
+	WARN_PRINT("Mouse warping is not supported by this display server.");
+}
+Point2i DisplayServer::mouse_get_position() const {
+	ERR_FAIL_V_MSG(Point2i(), "Mouse is not supported by this display server.");
+}
+int DisplayServer::mouse_get_button_state() const {
+	ERR_FAIL_V_MSG(0, "Mouse is not supported by this display server.");
+}
+
+void DisplayServer::clipboard_set(const String &p_text) {
+	WARN_PRINT("Clipboard is not supported by this display server.");
+}
+String DisplayServer::clipboard_get() const {
+	ERR_FAIL_V_MSG(String(), "Clipboard is not supported by this display server.");
+}
+
+void DisplayServer::screen_set_orientation(ScreenOrientation p_orientation, int p_screen) {
+	WARN_PRINT("Orientation not supported by this display server.");
+}
+DisplayServer::ScreenOrientation DisplayServer::screen_get_orientation(int p_screen) const {
+	return SCREEN_LANDSCAPE;
+}
+
+DisplayServer::WindowID DisplayServer::create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i) {
+	ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Sub-windows not supported by this display server.");
+}
+void DisplayServer::delete_sub_window(WindowID p_id) {
+	ERR_FAIL_MSG("Sub-windows not supported by this display server.");
+}
+
+void DisplayServer::window_set_ime_active(const bool p_active, WindowID p_window) {
+	WARN_PRINT("IME not supported by this display server.");
+}
+void DisplayServer::window_set_ime_position(const Point2i &p_pos, WindowID p_window) {
+	WARN_PRINT("IME not supported by this display server.");
+}
+
+Point2i DisplayServer::ime_get_selection() const {
+	ERR_FAIL_V_MSG(Point2i(), "IME or NOTIFICATION_WM_IME_UPDATE not supported by this display server.");
+}
+String DisplayServer::ime_get_text() const {
+	ERR_FAIL_V_MSG(String(), "IME or NOTIFICATION_WM_IME_UPDATEnot supported by this display server.");
+}
+
+void DisplayServer::console_set_visible(bool p_enabled) {
+	WARN_PRINT("Console window not supported by this display server.");
+}
+bool DisplayServer::is_console_visible() const {
+	return false;
+}
+
+void DisplayServer::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect) {
+	WARN_PRINT("Virtual keyboard not supported by this display server.");
+}
+void DisplayServer::virtual_keyboard_hide() {
+	WARN_PRINT("Virtual keyboard not supported by this display server.");
+}
+
+// returns height of the currently shown keyboard (0 if keyboard is hidden)
+int DisplayServer::virtual_keyboard_get_height() const {
+	ERR_FAIL_V_MSG(0, "Virtual keyboad not supported by this display server.");
+}
+
+void DisplayServer::cursor_set_shape(CursorShape p_shape) {
+	WARN_PRINT("Cursor shape not supported by this display server.");
+}
+DisplayServer::CursorShape DisplayServer::cursor_get_shape() const {
+	return CURSOR_ARROW;
+}
+void DisplayServer::cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
+	WARN_PRINT("Custom cursor shape not supported by this display server.");
+}
+
+bool DisplayServer::get_swap_ok_cancel() {
+	return false;
+}
+
+void DisplayServer::enable_for_stealing_focus(OS::ProcessID pid) {
+}
+
+//plays video natively, in fullscreen, only implemented in mobile for now, likely not possible to implement on linux also.
+Error DisplayServer::native_video_play(String p_path, float p_volume, String p_audio_track, String p_subtitle_track, int p_screen) {
+	ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "Native video not supported by this display server.");
+}
+bool DisplayServer::native_video_is_playing() const {
+	return false;
+}
+void DisplayServer::native_video_pause() {
+	WARN_PRINT("Native video not supported by this display server.");
+}
+void DisplayServer::native_video_unpause() {
+	WARN_PRINT("Native video not supported by this display server.");
+}
+void DisplayServer::native_video_stop() {
+	WARN_PRINT("Native video not supported by this display server.");
+}
+
+Error DisplayServer::dialog_show(String p_title, String p_description, Vector<String> p_buttons, const Callable &p_callback) {
+	WARN_PRINT("Native dialogs not supported by this display server.");
+	return OK;
+}
+Error DisplayServer::dialog_input_text(String p_title, String p_description, String p_partial, const Callable &p_callback) {
+	WARN_PRINT("Native dialogs not supported by this display server.");
+	return OK;
+}
+
+DisplayServer::LatinKeyboardVariant DisplayServer::get_latin_keyboard_variant() const {
+	return LATIN_KEYBOARD_QWERTY;
+}
+
+void DisplayServer::force_process_and_drop_events() {
+}
+
+void DisplayServer::release_rendering_thread() {
+	WARN_PRINT("Rendering thread not supported by this display server.");
+}
+void DisplayServer::make_rendering_thread() {
+	WARN_PRINT("Rendering thread not supported by this display server.");
+}
+void DisplayServer::swap_buffers() {
+	WARN_PRINT("Swap buffers not supported by this display server.");
+}
+
+void DisplayServer::set_native_icon(const String &p_filename) {
+	WARN_PRINT("Native icon not supported by this display server.");
+}
+void DisplayServer::set_icon(const Ref<Image> &p_icon) {
+	WARN_PRINT("Iconnot supported by this display server.");
+}
+
+void DisplayServer::_bind_methods() {
+
+	ClassDB::bind_method(D_METHOD("has_feature", "feature"), &DisplayServer::has_feature);
+	ClassDB::bind_method(D_METHOD("get_name"), &DisplayServer::get_name);
+
+	ClassDB::bind_method(D_METHOD("global_menu_add_item", "menu", "label", "id", "meta"), &DisplayServer::global_menu_add_item);
+	ClassDB::bind_method(D_METHOD("global_menu_add_separator", "menu"), &DisplayServer::global_menu_add_separator);
+	ClassDB::bind_method(D_METHOD("global_menu_remove_item", "menu", "idx"), &DisplayServer::global_menu_remove_item);
+	ClassDB::bind_method(D_METHOD("global_menu_clear", "menu"), &DisplayServer::global_menu_clear);
+
+	ClassDB::bind_method(D_METHOD("alert", "text", "title"), &DisplayServer::alert, DEFVAL("Alert!"));
+
+	ClassDB::bind_method(D_METHOD("mouse_set_mode", "mouse_mode"), &DisplayServer::mouse_set_mode);
+	ClassDB::bind_method(D_METHOD("mouse_get_mode"), &DisplayServer::mouse_get_mode);
+
+	ClassDB::bind_method(D_METHOD("mouse_warp_to_position", "position"), &DisplayServer::mouse_warp_to_position);
+	ClassDB::bind_method(D_METHOD("mouse_get_position"), &DisplayServer::mouse_get_position);
+	ClassDB::bind_method(D_METHOD("mouse_get_button_state"), &DisplayServer::mouse_get_button_state);
+
+	ClassDB::bind_method(D_METHOD("clipboard_set", "clipboard"), &DisplayServer::clipboard_set);
+	ClassDB::bind_method(D_METHOD("clipboard_get"), &DisplayServer::clipboard_get);
+
+	ClassDB::bind_method(D_METHOD("get_screen_count"), &DisplayServer::get_screen_count);
+	ClassDB::bind_method(D_METHOD("screen_get_position", "screen"), &DisplayServer::screen_get_position, DEFVAL(SCREEN_OF_MAIN_WINDOW));
+	ClassDB::bind_method(D_METHOD("screen_get_size", "screen"), &DisplayServer::screen_get_size, DEFVAL(SCREEN_OF_MAIN_WINDOW));
+	ClassDB::bind_method(D_METHOD("screen_get_dpi", "screen"), &DisplayServer::screen_get_dpi, DEFVAL(SCREEN_OF_MAIN_WINDOW));
+	ClassDB::bind_method(D_METHOD("screen_is_touchscreen", "screen"), &DisplayServer::screen_is_touchscreen, DEFVAL(SCREEN_OF_MAIN_WINDOW));
+
+	ClassDB::bind_method(D_METHOD("screen_set_orientation", "orientation", "screen"), &DisplayServer::screen_set_orientation, DEFVAL(SCREEN_OF_MAIN_WINDOW));
+	ClassDB::bind_method(D_METHOD("screen_get_orientation", "screen"), &DisplayServer::screen_get_orientation, DEFVAL(SCREEN_OF_MAIN_WINDOW));
+
+	ClassDB::bind_method(D_METHOD("get_window_list"), &DisplayServer::get_window_list);
+
+	ClassDB::bind_method(D_METHOD("create_sub_window", "mode", "rect"), &DisplayServer::create_sub_window, DEFVAL(Rect2i()));
+	ClassDB::bind_method(D_METHOD("delete_sub_window", "window_id"), &DisplayServer::delete_sub_window);
+
+	ClassDB::bind_method(D_METHOD("window_set_title", "title", "window_id"), &DisplayServer::window_set_title, DEFVAL(MAIN_WINDOW_ID));
+
+	ClassDB::bind_method(D_METHOD("window_get_current_screen", "window_id"), &DisplayServer::window_get_current_screen, DEFVAL(MAIN_WINDOW_ID));
+	ClassDB::bind_method(D_METHOD("window_set_current_screen", "screen", "window_id"), &DisplayServer::window_set_current_screen, DEFVAL(MAIN_WINDOW_ID));
+
+	ClassDB::bind_method(D_METHOD("window_get_position", "window_id"), &DisplayServer::window_get_position, DEFVAL(MAIN_WINDOW_ID));
+	ClassDB::bind_method(D_METHOD("window_set_position", "position", "window_id"), &DisplayServer::window_set_position, DEFVAL(MAIN_WINDOW_ID));
+
+	ClassDB::bind_method(D_METHOD("window_get_size", "window_id"), &DisplayServer::window_get_size, DEFVAL(MAIN_WINDOW_ID));
+	ClassDB::bind_method(D_METHOD("window_set_size", "size", "window_id"), &DisplayServer::window_set_size, DEFVAL(MAIN_WINDOW_ID));
+
+	ClassDB::bind_method(D_METHOD("window_get_max_size", "window_id"), &DisplayServer::window_get_max_size, DEFVAL(MAIN_WINDOW_ID));
+	ClassDB::bind_method(D_METHOD("window_set_max_size", "max_size", "window_id"), &DisplayServer::window_set_max_size, DEFVAL(MAIN_WINDOW_ID));
+
+	ClassDB::bind_method(D_METHOD("window_get_min_size", "window_id"), &DisplayServer::window_get_min_size, DEFVAL(MAIN_WINDOW_ID));
+	ClassDB::bind_method(D_METHOD("window_set_min_size", "min_size", "window_id"), &DisplayServer::window_set_min_size, DEFVAL(MAIN_WINDOW_ID));
+
+	ClassDB::bind_method(D_METHOD("window_get_real_size", "window_id"), &DisplayServer::window_get_real_size, DEFVAL(MAIN_WINDOW_ID));
+
+	ClassDB::bind_method(D_METHOD("window_get_mode", "window_id"), &DisplayServer::window_get_mode, DEFVAL(MAIN_WINDOW_ID));
+	ClassDB::bind_method(D_METHOD("window_set_mode", "mode", "window_id"), &DisplayServer::window_set_mode, DEFVAL(MAIN_WINDOW_ID));
+
+	ClassDB::bind_method(D_METHOD("window_set_flag", "flag", "enabled", "window_id"), &DisplayServer::window_set_flag, DEFVAL(MAIN_WINDOW_ID));
+	ClassDB::bind_method(D_METHOD("window_get_flag", "flag", "window_id"), &DisplayServer::window_get_flag, DEFVAL(MAIN_WINDOW_ID));
+
+	ClassDB::bind_method(D_METHOD("window_request_attention", "window_id"), &DisplayServer::window_request_attention, DEFVAL(MAIN_WINDOW_ID));
+
+	ClassDB::bind_method(D_METHOD("window_move_to_foreground", "window_id"), &DisplayServer::window_move_to_foreground, DEFVAL(MAIN_WINDOW_ID));
+	ClassDB::bind_method(D_METHOD("window_can_draw", "window_id"), &DisplayServer::window_can_draw, DEFVAL(MAIN_WINDOW_ID));
+
+	ClassDB::bind_method(D_METHOD("window_set_ime_active", "active", "window_id"), &DisplayServer::window_set_ime_active, DEFVAL(MAIN_WINDOW_ID));
+	ClassDB::bind_method(D_METHOD("window_set_ime_position", "position", "window_id"), &DisplayServer::window_set_ime_position, DEFVAL(MAIN_WINDOW_ID));
+
+	ClassDB::bind_method(D_METHOD("ime_get_selection"), &DisplayServer::ime_get_selection);
+	ClassDB::bind_method(D_METHOD("ime_get_text"), &DisplayServer::ime_get_text);
+
+	ClassDB::bind_method(D_METHOD("console_set_visible", "console_visible"), &DisplayServer::console_set_visible);
+	ClassDB::bind_method(D_METHOD("is_console_visible"), &DisplayServer::is_console_visible);
+
+	ClassDB::bind_method(D_METHOD("virtual_keyboard_show", "existing_text", "position"), &DisplayServer::virtual_keyboard_show, DEFVAL(Rect2i()));
+	ClassDB::bind_method(D_METHOD("virtual_keyboard_hide"), &DisplayServer::virtual_keyboard_hide);
+
+	ClassDB::bind_method(D_METHOD("virtual_keyboard_get_height"), &DisplayServer::virtual_keyboard_get_height);
+
+	ClassDB::bind_method(D_METHOD("cursor_set_shape", "shape"), &DisplayServer::cursor_set_shape);
+	ClassDB::bind_method(D_METHOD("cursor_get_shape"), &DisplayServer::cursor_get_shape);
+	ClassDB::bind_method(D_METHOD("cursor_set_custom_image", "cursor", "shape", "hotspot"), &DisplayServer::cursor_set_custom_image);
+
+	ClassDB::bind_method(D_METHOD("get_swap_ok_cancel"), &DisplayServer::get_swap_ok_cancel);
+
+	ClassDB::bind_method(D_METHOD("enable_for_stealing_focus", "process_id"), &DisplayServer::enable_for_stealing_focus);
+
+	ClassDB::bind_method(D_METHOD("native_video_play", "path", "volume", "audio_track", "subtitle_track"), &DisplayServer::native_video_play);
+	ClassDB::bind_method(D_METHOD("native_video_is_playing"), &DisplayServer::native_video_is_playing);
+	ClassDB::bind_method(D_METHOD("native_video_stop"), &DisplayServer::native_video_stop);
+	ClassDB::bind_method(D_METHOD("native_video_pause"), &DisplayServer::native_video_pause);
+	ClassDB::bind_method(D_METHOD("native_video_unpause"), &DisplayServer::native_video_unpause);
+
+	ClassDB::bind_method(D_METHOD("dialog_show", "title", "description", "buttons", "callback"), &DisplayServer::dialog_show);
+	ClassDB::bind_method(D_METHOD("dialog_input_text", "title", "description", "existing_text", "callback"), &DisplayServer::dialog_show);
+
+	ClassDB::bind_method(D_METHOD("get_latin_keyboard_variant"), &DisplayServer::get_latin_keyboard_variant);
+
+	ClassDB::bind_method(D_METHOD("process_events"), &DisplayServer::process_events);
+	ClassDB::bind_method(D_METHOD("force_process_and_drop_events"), &DisplayServer::force_process_and_drop_events);
+
+	ClassDB::bind_method(D_METHOD("set_native_icon", "filename"), &DisplayServer::set_native_icon);
+	ClassDB::bind_method(D_METHOD("set_icon", "image"), &DisplayServer::set_icon);
+
+	BIND_ENUM_CONSTANT(FEATURE_GLOBAL_MENU);
+	BIND_ENUM_CONSTANT(FEATURE_SUBWINDOWS);
+	BIND_ENUM_CONSTANT(FEATURE_TOUCHSCREEN);
+	BIND_ENUM_CONSTANT(FEATURE_MOUSE);
+	BIND_ENUM_CONSTANT(FEATURE_MOUSE_WARP);
+	BIND_ENUM_CONSTANT(FEATURE_CLIPBOARD);
+	BIND_ENUM_CONSTANT(FEATURE_VIRTUAL_KEYBOARD);
+	BIND_ENUM_CONSTANT(FEATURE_CURSOR_SHAPE);
+	BIND_ENUM_CONSTANT(FEATURE_CUSTOM_CURSOR_SHAPE);
+	BIND_ENUM_CONSTANT(FEATURE_NATIVE_VIDEO);
+	BIND_ENUM_CONSTANT(FEATURE_NATIVE_DIALOG);
+	BIND_ENUM_CONSTANT(FEATURE_CONSOLE_WINDOW);
+	BIND_ENUM_CONSTANT(FEATURE_IME);
+	BIND_ENUM_CONSTANT(FEATURE_WINDOW_TRANSPARENCY);
+	BIND_ENUM_CONSTANT(FEATURE_HIDPI);
+	BIND_ENUM_CONSTANT(FEATURE_ICON);
+	BIND_ENUM_CONSTANT(FEATURE_NATIVE_ICON);
+	BIND_ENUM_CONSTANT(FEATURE_ORIENTATION);
+	BIND_ENUM_CONSTANT(FEATURE_SWAP_BUFFERS);
+
+	BIND_ENUM_CONSTANT(MOUSE_MODE_VISIBLE);
+	BIND_ENUM_CONSTANT(MOUSE_MODE_HIDDEN);
+	BIND_ENUM_CONSTANT(MOUSE_MODE_CAPTURED);
+	BIND_ENUM_CONSTANT(MOUSE_MODE_CONFINED);
+
+	BIND_CONSTANT(SCREEN_OF_MAIN_WINDOW);
+	BIND_CONSTANT(MAIN_WINDOW_ID);
+	BIND_CONSTANT(INVALID_WINDOW_ID);
+
+	BIND_ENUM_CONSTANT(SCREEN_LANDSCAPE);
+	BIND_ENUM_CONSTANT(SCREEN_PORTRAIT);
+	BIND_ENUM_CONSTANT(SCREEN_REVERSE_LANDSCAPE);
+	BIND_ENUM_CONSTANT(SCREEN_REVERSE_PORTRAIT);
+	BIND_ENUM_CONSTANT(SCREEN_SENSOR_LANDSCAPE);
+	BIND_ENUM_CONSTANT(SCREEN_SENSOR_PORTRAIT);
+	BIND_ENUM_CONSTANT(SCREEN_SENSOR);
+
+	BIND_ENUM_CONSTANT(CURSOR_ARROW);
+	BIND_ENUM_CONSTANT(CURSOR_IBEAM);
+	BIND_ENUM_CONSTANT(CURSOR_POINTING_HAND);
+	BIND_ENUM_CONSTANT(CURSOR_CROSS);
+	BIND_ENUM_CONSTANT(CURSOR_WAIT);
+	BIND_ENUM_CONSTANT(CURSOR_BUSY);
+	BIND_ENUM_CONSTANT(CURSOR_DRAG);
+	BIND_ENUM_CONSTANT(CURSOR_CAN_DROP);
+	BIND_ENUM_CONSTANT(CURSOR_FORBIDDEN);
+	BIND_ENUM_CONSTANT(CURSOR_VSIZE);
+	BIND_ENUM_CONSTANT(CURSOR_HSIZE);
+	BIND_ENUM_CONSTANT(CURSOR_BDIAGSIZE);
+	BIND_ENUM_CONSTANT(CURSOR_FDIAGSIZE);
+	BIND_ENUM_CONSTANT(CURSOR_MOVE);
+	BIND_ENUM_CONSTANT(CURSOR_VSPLIT);
+	BIND_ENUM_CONSTANT(CURSOR_HSPLIT);
+	BIND_ENUM_CONSTANT(CURSOR_HELP);
+	BIND_ENUM_CONSTANT(CURSOR_MAX);
+
+	BIND_ENUM_CONSTANT(WINDOW_MODE_WINDOWED);
+	BIND_ENUM_CONSTANT(WINDOW_MODE_MINIMIZED);
+	BIND_ENUM_CONSTANT(WINDOW_MODE_MAXIMIZED);
+	BIND_ENUM_CONSTANT(WINDOW_MODE_FULLSCREEN);
+
+	BIND_ENUM_CONSTANT(WINDOW_FLAG_RESIZE_DISABLED);
+	BIND_ENUM_CONSTANT(WINDOW_FLAG_BORDERLESS);
+	BIND_ENUM_CONSTANT(WINDOW_FLAG_ALWAYS_ON_TOP);
+	BIND_ENUM_CONSTANT(WINDOW_FLAG_TRANSPARENT);
+	BIND_ENUM_CONSTANT(WINDOW_FLAG_MAX);
+	BIND_ENUM_CONSTANT(WINDOW_FLAG_RESIZE_DISABLED_BIT);
+	BIND_ENUM_CONSTANT(WINDOW_FLAG_BORDERLESS_BIT);
+	BIND_ENUM_CONSTANT(WINDOW_FLAG_ALWAYS_ON_TOP_BIT);
+	BIND_ENUM_CONSTANT(WINDOW_FLAG_TRANSPARENT_BIT);
+
+	BIND_ENUM_CONSTANT(LATIN_KEYBOARD_QWERTY);
+	BIND_ENUM_CONSTANT(LATIN_KEYBOARD_QWERTZ);
+	BIND_ENUM_CONSTANT(LATIN_KEYBOARD_AZERTY);
+	BIND_ENUM_CONSTANT(LATIN_KEYBOARD_QZERTY);
+	BIND_ENUM_CONSTANT(LATIN_KEYBOARD_DVORAK);
+	BIND_ENUM_CONSTANT(LATIN_KEYBOARD_NEO);
+	BIND_ENUM_CONSTANT(LATIN_KEYBOARD_COLEMAK);
+}
+DisplayServer::DisplayServer() {
+	singleton = this;
+}
+DisplayServer::~DisplayServer() {
+}

+ 273 - 0
servers/display_server.h

@@ -0,0 +1,273 @@
+/*************************************************************************/
+/*  display_server.h                                                     */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* 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.                */
+/*************************************************************************/
+
+#ifndef DISPLAY_SERVER_H
+#define DISPLAY_SERVER_H
+
+#include "core/os/os.h"
+#include "core/resource.h"
+
+class DisplayServer : public Object {
+	GDCLASS(DisplayServer, Object)
+
+	static DisplayServer *singleton;
+
+protected:
+	static void _bind_methods();
+
+public:
+	enum Feature {
+		FEATURE_GLOBAL_MENU,
+		FEATURE_SUBWINDOWS,
+		FEATURE_TOUCHSCREEN,
+		FEATURE_MOUSE,
+		FEATURE_MOUSE_WARP,
+		FEATURE_CLIPBOARD,
+		FEATURE_VIRTUAL_KEYBOARD,
+		FEATURE_CURSOR_SHAPE,
+		FEATURE_CUSTOM_CURSOR_SHAPE,
+		FEATURE_NATIVE_VIDEO,
+		FEATURE_NATIVE_DIALOG,
+		FEATURE_CONSOLE_WINDOW,
+		FEATURE_IME,
+		FEATURE_WINDOW_TRANSPARENCY,
+		FEATURE_HIDPI,
+		FEATURE_ICON,
+		FEATURE_NATIVE_ICON,
+		FEATURE_ORIENTATION,
+		FEATURE_SWAP_BUFFERS
+
+	};
+
+	virtual bool has_feature(Feature p_feature) const = 0;
+	virtual String get_name() const = 0;
+
+	virtual void global_menu_add_item(const String &p_menu, const String &p_label, const Variant &p_signal, const Variant &p_meta);
+	virtual void global_menu_add_separator(const String &p_menu);
+	virtual void global_menu_remove_item(const String &p_menu, int p_idx);
+	virtual void global_menu_clear(const String &p_menu);
+
+	virtual void alert(const String &p_alert, const String &p_title = "ALERT!") = 0;
+
+	enum MouseMode {
+		MOUSE_MODE_VISIBLE,
+		MOUSE_MODE_HIDDEN,
+		MOUSE_MODE_CAPTURED,
+		MOUSE_MODE_CONFINED
+	};
+
+	virtual void mouse_set_mode(MouseMode p_mode);
+	virtual MouseMode mouse_get_mode() const;
+
+	virtual void mouse_warp_to_position(const Point2i &p_to);
+	virtual Point2i mouse_get_position() const;
+	virtual int mouse_get_button_state() const;
+
+	virtual void clipboard_set(const String &p_text);
+	virtual String clipboard_get() const;
+
+	enum {
+		SCREEN_OF_MAIN_WINDOW = -1
+	};
+
+	virtual int get_screen_count() const = 0;
+	virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const = 0;
+	virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const = 0;
+	virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const = 0;
+	virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const = 0;
+
+	enum ScreenOrientation {
+
+		SCREEN_LANDSCAPE,
+		SCREEN_PORTRAIT,
+		SCREEN_REVERSE_LANDSCAPE,
+		SCREEN_REVERSE_PORTRAIT,
+		SCREEN_SENSOR_LANDSCAPE,
+		SCREEN_SENSOR_PORTRAIT,
+		SCREEN_SENSOR,
+	};
+
+	virtual void screen_set_orientation(ScreenOrientation p_orientation, int p_screen = SCREEN_OF_MAIN_WINDOW);
+	ScreenOrientation screen_get_orientation(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
+
+	enum {
+		MAIN_WINDOW_ID = 0,
+		INVALID_WINDOW_ID = -1
+	};
+
+	typedef int WindowID;
+
+	virtual Vector<int> get_window_list() const = 0;
+
+	enum WindowMode {
+		WINDOW_MODE_WINDOWED,
+		WINDOW_MODE_MINIMIZED,
+		WINDOW_MODE_MAXIMIZED,
+		WINDOW_MODE_FULLSCREEN
+	};
+
+	enum WindowFlags {
+		WINDOW_FLAG_RESIZE_DISABLED,
+		WINDOW_FLAG_BORDERLESS,
+		WINDOW_FLAG_ALWAYS_ON_TOP,
+		WINDOW_FLAG_TRANSPARENT,
+		WINDOW_FLAG_MAX,
+		WINDOW_FLAG_RESIZE_DISABLED_BIT = (1 << WINDOW_FLAG_RESIZE_DISABLED),
+		WINDOW_FLAG_BORDERLESS_BIT = (1 << WINDOW_FLAG_BORDERLESS),
+		WINDOW_FLAG_ALWAYS_ON_TOP_BIT = (1 << WINDOW_FLAG_ALWAYS_ON_TOP),
+		WINDOW_FLAG_TRANSPARENT_BIT = (1 << WINDOW_FLAG_TRANSPARENT)
+	};
+
+	virtual WindowID create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i = Rect2i());
+	virtual void delete_sub_window(WindowID p_id);
+
+	virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID) = 0;
+
+	virtual int window_get_current_screen(WindowID p_window = MAIN_WINDOW_ID) const = 0;
+	virtual void window_set_current_screen(int p_screen, WindowID p_window = MAIN_WINDOW_ID) = 0;
+
+	virtual Point2i window_get_position(WindowID p_window = MAIN_WINDOW_ID) const = 0;
+	virtual void window_set_position(const Point2i &p_position, WindowID p_window = MAIN_WINDOW_ID) = 0;
+
+	virtual void window_set_max_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID) = 0;
+	virtual Size2i window_get_max_size(WindowID p_window = MAIN_WINDOW_ID) const = 0;
+
+	virtual void window_set_min_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID) = 0;
+	virtual Size2i window_get_min_size(WindowID p_window = MAIN_WINDOW_ID) const = 0;
+
+	virtual void window_set_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID) = 0;
+	virtual Size2i window_get_size(WindowID p_window = MAIN_WINDOW_ID) const = 0;
+	virtual Size2i window_get_real_size(WindowID p_window = MAIN_WINDOW_ID) const = 0; // FIXME: Find clearer name for this.
+
+	virtual void window_set_mode(WindowMode p_mode, WindowID p_window = MAIN_WINDOW_ID) = 0;
+	virtual WindowMode window_get_mode(WindowID p_window = MAIN_WINDOW_ID) const = 0;
+
+	virtual bool window_is_maximize_allowed(WindowID p_window = MAIN_WINDOW_ID) const = 0;
+
+	virtual void window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window = MAIN_WINDOW_ID) = 0;
+	virtual bool window_get_flag(WindowFlags p_flag, WindowID p_window = MAIN_WINDOW_ID) const = 0;
+
+	virtual void window_request_attention(WindowID p_window = MAIN_WINDOW_ID) = 0;
+	virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) = 0;
+
+	virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const = 0;
+
+	virtual void window_set_ime_active(const bool p_active, WindowID p_window = MAIN_WINDOW_ID);
+	virtual void window_set_ime_position(const Point2i &p_pos, WindowID p_window = MAIN_WINDOW_ID);
+
+	virtual Point2i ime_get_selection() const;
+	virtual String ime_get_text() const;
+
+	virtual void console_set_visible(bool p_enabled);
+	virtual bool is_console_visible() const;
+
+	virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2());
+	virtual void virtual_keyboard_hide();
+
+	// returns height of the currently shown virtual keyboard (0 if keyboard is hidden)
+	virtual int virtual_keyboard_get_height() const;
+
+	enum CursorShape {
+		CURSOR_ARROW,
+		CURSOR_IBEAM,
+		CURSOR_POINTING_HAND,
+		CURSOR_CROSS,
+		CURSOR_WAIT,
+		CURSOR_BUSY,
+		CURSOR_DRAG,
+		CURSOR_CAN_DROP,
+		CURSOR_FORBIDDEN,
+		CURSOR_VSIZE,
+		CURSOR_HSIZE,
+		CURSOR_BDIAGSIZE,
+		CURSOR_FDIAGSIZE,
+		CURSOR_MOVE,
+		CURSOR_VSPLIT,
+		CURSOR_HSPLIT,
+		CURSOR_HELP,
+		CURSOR_MAX
+	};
+	virtual void cursor_set_shape(CursorShape p_shape);
+	virtual CursorShape cursor_get_shape() const;
+	virtual void cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
+
+	virtual bool get_swap_ok_cancel();
+
+	virtual void enable_for_stealing_focus(OS::ProcessID pid);
+
+	//plays video natively, in fullscreen, only implemented in mobile for now, likely not possible to implement on linux also.
+	virtual Error native_video_play(String p_path, float p_volume, String p_audio_track, String p_subtitle_track, int p_screen = SCREEN_OF_MAIN_WINDOW);
+	virtual bool native_video_is_playing() const;
+	virtual void native_video_pause();
+	virtual void native_video_unpause();
+	virtual void native_video_stop();
+
+	virtual Error dialog_show(String p_title, String p_description, Vector<String> p_buttons, const Callable &p_callback);
+	virtual Error dialog_input_text(String p_title, String p_description, String p_partial, const Callable &p_callback);
+
+	enum LatinKeyboardVariant {
+		LATIN_KEYBOARD_QWERTY,
+		LATIN_KEYBOARD_QWERTZ,
+		LATIN_KEYBOARD_AZERTY,
+		LATIN_KEYBOARD_QZERTY,
+		LATIN_KEYBOARD_DVORAK,
+		LATIN_KEYBOARD_NEO,
+		LATIN_KEYBOARD_COLEMAK,
+	};
+
+	virtual LatinKeyboardVariant get_latin_keyboard_variant() const;
+
+	virtual void process_events() = 0;
+
+	virtual void force_process_and_drop_events();
+
+	virtual void release_rendering_thread();
+	virtual void make_rendering_thread();
+	virtual void swap_buffers();
+
+	virtual void set_native_icon(const String &p_filename);
+	virtual void set_icon(const Ref<Image> &p_icon);
+
+	typedef Vector<String> *(*GetSupportedVideoDriversFunction)();
+	typedef DisplayServer *(*CreateFunction)(const String &, WindowMode, uint32_t, const Size2i &, Error &r_error); //video driver, window mode, resolution
+
+	DisplayServer();
+	~DisplayServer();
+};
+
+VARIANT_ENUM_CAST(DisplayServer::Feature)
+VARIANT_ENUM_CAST(DisplayServer::MouseMode)
+VARIANT_ENUM_CAST(DisplayServer::ScreenOrientation)
+VARIANT_ENUM_CAST(DisplayServer::WindowMode)
+VARIANT_ENUM_CAST(DisplayServer::WindowFlags)
+VARIANT_ENUM_CAST(DisplayServer::CursorShape)
+VARIANT_ENUM_CAST(DisplayServer::LatinKeyboardVariant)
+
+#endif // DISPLAY_SERVER_H

+ 3 - 0
servers/register_server_types.cpp

@@ -29,6 +29,7 @@
 /*************************************************************************/
 /*************************************************************************/
 
 
 #include "register_server_types.h"
 #include "register_server_types.h"
+
 #include "core/engine.h"
 #include "core/engine.h"
 #include "core/project_settings.h"
 #include "core/project_settings.h"
 
 
@@ -56,6 +57,7 @@
 #include "audio_server.h"
 #include "audio_server.h"
 #include "camera/camera_feed.h"
 #include "camera/camera_feed.h"
 #include "camera_server.h"
 #include "camera_server.h"
+#include "display_server.h"
 #include "navigation_2d_server.h"
 #include "navigation_2d_server.h"
 #include "navigation_server.h"
 #include "navigation_server.h"
 #include "physics/physics_server_sw.h"
 #include "physics/physics_server_sw.h"
@@ -95,6 +97,7 @@ void register_server_types() {
 
 
 	OS::get_singleton()->set_has_server_feature_callback(has_server_feature_callback);
 	OS::get_singleton()->set_has_server_feature_callback(has_server_feature_callback);
 
 
+	ClassDB::register_virtual_class<DisplayServer>();
 	ClassDB::register_virtual_class<VisualServer>();
 	ClassDB::register_virtual_class<VisualServer>();
 	ClassDB::register_class<AudioServer>();
 	ClassDB::register_class<AudioServer>();
 	ClassDB::register_virtual_class<PhysicsServer>();
 	ClassDB::register_virtual_class<PhysicsServer>();