summaryrefslogtreecommitdiffstats
path: root/platform/linuxbsd/x11
diff options
context:
space:
mode:
Diffstat (limited to 'platform/linuxbsd/x11')
-rw-r--r--platform/linuxbsd/x11/SCsub2
-rw-r--r--platform/linuxbsd/x11/detect_prime_x11.cpp14
-rw-r--r--platform/linuxbsd/x11/display_server_x11.cpp453
-rw-r--r--platform/linuxbsd/x11/display_server_x11.h23
-rw-r--r--platform/linuxbsd/x11/gl_manager_x11.cpp9
-rw-r--r--platform/linuxbsd/x11/gl_manager_x11.h1
-rw-r--r--platform/linuxbsd/x11/key_mapping_x11.cpp24
-rw-r--r--platform/linuxbsd/x11/key_mapping_x11.h2
-rw-r--r--platform/linuxbsd/x11/rendering_context_driver_vulkan_x11.cpp (renamed from platform/linuxbsd/x11/vulkan_context_x11.cpp)37
-rw-r--r--platform/linuxbsd/x11/rendering_context_driver_vulkan_x11.h (renamed from platform/linuxbsd/x11/vulkan_context_x11.h)27
10 files changed, 489 insertions, 103 deletions
diff --git a/platform/linuxbsd/x11/SCsub b/platform/linuxbsd/x11/SCsub
index bbfaaf10d1..75fe584ad5 100644
--- a/platform/linuxbsd/x11/SCsub
+++ b/platform/linuxbsd/x11/SCsub
@@ -21,7 +21,7 @@ if env["use_sowrap"]:
)
if env["vulkan"]:
- source_files.append("vulkan_context_x11.cpp")
+ source_files.append("rendering_context_driver_vulkan_x11.cpp")
if env["opengl3"]:
env.Append(CPPDEFINES=["GLAD_GLX_NO_X11"])
diff --git a/platform/linuxbsd/x11/detect_prime_x11.cpp b/platform/linuxbsd/x11/detect_prime_x11.cpp
index 2b5776ce54..c2cb02b937 100644
--- a/platform/linuxbsd/x11/detect_prime_x11.cpp
+++ b/platform/linuxbsd/x11/detect_prime_x11.cpp
@@ -137,6 +137,19 @@ void create_context() {
XFree(vi);
}
+int silent_error_handler(Display *display, XErrorEvent *error) {
+ static char message[1024];
+ XGetErrorText(display, error->error_code, message, sizeof(message));
+ print_verbose(vformat("XServer error: %s"
+ "\n Major opcode of failed request: %d"
+ "\n Serial number of failed request: %d"
+ "\n Current serial number in output stream: %d",
+ String::utf8(message), (uint64_t)error->request_code, (uint64_t)error->minor_code, (uint64_t)error->serial));
+
+ quick_exit(1);
+ return 0;
+}
+
int detect_prime() {
pid_t p;
int priorities[2] = {};
@@ -189,6 +202,7 @@ int detect_prime() {
// cleaning up these processes, and fork() makes a copy
// of all globals.
CoreGlobals::leak_reporting_enabled = false;
+ XSetErrorHandler(&silent_error_handler);
char string[201];
diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp
index fe81da76d3..35bfe81827 100644
--- a/platform/linuxbsd/x11/display_server_x11.cpp
+++ b/platform/linuxbsd/x11/display_server_x11.cpp
@@ -39,6 +39,7 @@
#include "core/math/math_funcs.h"
#include "core/string/print_string.h"
#include "core/string/ustring.h"
+#include "drivers/png/png_driver_common.h"
#include "main/main.h"
#include "scene/resources/atlas_texture.h"
@@ -363,6 +364,10 @@ bool DisplayServerX11::is_dark_mode() const {
}
}
+void DisplayServerX11::set_system_theme_change_callback(const Callable &p_callable) {
+ portal_desktop->set_system_theme_change_callback(p_callable);
+}
+
Error DisplayServerX11::file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback) {
WindowID window_id = last_focused_window;
@@ -371,7 +376,18 @@ Error DisplayServerX11::file_dialog_show(const String &p_title, const String &p_
}
String xid = vformat("x11:%x", (uint64_t)windows[window_id].x11_window);
- return portal_desktop->file_dialog_show(last_focused_window, xid, p_title, p_current_directory, p_filename, p_mode, p_filters, p_callback);
+ return portal_desktop->file_dialog_show(last_focused_window, xid, p_title, p_current_directory, String(), p_filename, p_mode, p_filters, TypedArray<Dictionary>(), p_callback, false);
+}
+
+Error DisplayServerX11::file_dialog_with_options_show(const String &p_title, const String &p_current_directory, const String &p_root, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const TypedArray<Dictionary> &p_options, const Callable &p_callback) {
+ WindowID window_id = last_focused_window;
+
+ if (!windows.has(window_id)) {
+ window_id = MAIN_WINDOW_ID;
+ }
+
+ String xid = vformat("x11:%x", (uint64_t)windows[window_id].x11_window);
+ return portal_desktop->file_dialog_show(last_focused_window, xid, p_title, p_current_directory, p_root, p_filename, p_mode, p_filters, p_options, p_callback, true);
}
#endif
@@ -519,7 +535,7 @@ Bool DisplayServerX11::_predicate_clipboard_selection(Display *display, XEvent *
}
Bool DisplayServerX11::_predicate_clipboard_incr(Display *display, XEvent *event, XPointer arg) {
- if (event->type == PropertyNotify && event->xproperty.state == PropertyNewValue) {
+ if (event->type == PropertyNotify && event->xproperty.state == PropertyNewValue && event->xproperty.atom == *(Atom *)arg) {
return True;
} else {
return False;
@@ -593,7 +609,7 @@ String DisplayServerX11::_clipboard_get_impl(Atom p_source, Window x11_window, A
// Non-blocking wait for next event and remove it from the queue.
XEvent ev;
- while (XCheckIfEvent(x11_display, &ev, _predicate_clipboard_incr, nullptr)) {
+ while (XCheckIfEvent(x11_display, &ev, _predicate_clipboard_incr, (XPointer)&selection)) {
result = XGetWindowProperty(x11_display, x11_window,
selection, // selection type
0, LONG_MAX, // offset - len
@@ -664,6 +680,74 @@ String DisplayServerX11::_clipboard_get_impl(Atom p_source, Window x11_window, A
return ret;
}
+Atom DisplayServerX11::_clipboard_get_image_target(Atom p_source, Window x11_window) const {
+ Atom target = XInternAtom(x11_display, "TARGETS", 0);
+ Atom png = XInternAtom(x11_display, "image/png", 0);
+ Atom *valid_targets = nullptr;
+ unsigned long atom_count = 0;
+
+ Window selection_owner = XGetSelectionOwner(x11_display, p_source);
+ if (selection_owner != None && selection_owner != x11_window) {
+ // Block events polling while processing selection events.
+ MutexLock mutex_lock(events_mutex);
+
+ Atom selection = XA_PRIMARY;
+ XConvertSelection(x11_display, p_source, target, selection, x11_window, CurrentTime);
+
+ XFlush(x11_display);
+
+ // Blocking wait for predicate to be True and remove the event from the queue.
+ XEvent event;
+ XIfEvent(x11_display, &event, _predicate_clipboard_selection, (XPointer)&x11_window);
+ // Do not get any data, see how much data is there.
+ Atom type;
+ int format, result;
+ unsigned long len, bytes_left, dummy;
+ XGetWindowProperty(x11_display, x11_window,
+ selection, // Tricky..
+ 0, 0, // offset - len
+ 0, // Delete 0==FALSE
+ XA_ATOM, // flag
+ &type, // return type
+ &format, // return format
+ &len, &bytes_left, // data length
+ (unsigned char **)&valid_targets);
+
+ if (valid_targets) {
+ XFree(valid_targets);
+ valid_targets = nullptr;
+ }
+
+ if (type == XA_ATOM && bytes_left > 0) {
+ // Data is ready and can be processed all at once.
+ result = XGetWindowProperty(x11_display, x11_window,
+ selection, 0, bytes_left / 4, 0,
+ XA_ATOM, &type, &format,
+ &len, &dummy, (unsigned char **)&valid_targets);
+ if (result == Success) {
+ atom_count = len;
+ } else {
+ print_verbose("Failed to get selection data.");
+ return None;
+ }
+ } else {
+ return None;
+ }
+ } else {
+ return None;
+ }
+ for (unsigned long i = 0; i < atom_count; i++) {
+ Atom atom = valid_targets[i];
+ if (atom == png) {
+ XFree(valid_targets);
+ return png;
+ }
+ }
+
+ XFree(valid_targets);
+ return None;
+}
+
String DisplayServerX11::_clipboard_get(Atom p_source, Window x11_window) const {
String ret;
Atom utf8_atom = XInternAtom(x11_display, "UTF8_STRING", True);
@@ -702,6 +786,158 @@ String DisplayServerX11::clipboard_get_primary() const {
return ret;
}
+Ref<Image> DisplayServerX11::clipboard_get_image() const {
+ _THREAD_SAFE_METHOD_
+ Atom clipboard = XInternAtom(x11_display, "CLIPBOARD", 0);
+ Window x11_window = windows[MAIN_WINDOW_ID].x11_window;
+ Ref<Image> ret;
+ Atom target = _clipboard_get_image_target(clipboard, x11_window);
+ if (target == None) {
+ return ret;
+ }
+
+ Window selection_owner = XGetSelectionOwner(x11_display, clipboard);
+
+ if (selection_owner != None && selection_owner != x11_window) {
+ // Block events polling while processing selection events.
+ MutexLock mutex_lock(events_mutex);
+
+ // Identifier for the property the other window
+ // will send the converted data to.
+ Atom transfer_prop = XA_PRIMARY;
+ XConvertSelection(x11_display,
+ clipboard, // source selection
+ target, // format to convert to
+ transfer_prop, // output property
+ x11_window, CurrentTime);
+
+ XFlush(x11_display);
+
+ // Blocking wait for predicate to be True and remove the event from the queue.
+ XEvent event;
+ XIfEvent(x11_display, &event, _predicate_clipboard_selection, (XPointer)&x11_window);
+
+ // Do not get any data, see how much data is there.
+ Atom type;
+ int format, result;
+ unsigned long len, bytes_left, dummy;
+ unsigned char *data;
+ XGetWindowProperty(x11_display, x11_window,
+ transfer_prop, // Property data is transferred through
+ 0, 1, // offset, len (4 so we can get the size if INCR is used)
+ 0, // Delete 0==FALSE
+ AnyPropertyType, // flag
+ &type, // return type
+ &format, // return format
+ &len, &bytes_left, // data length
+ &data);
+
+ if (type == XInternAtom(x11_display, "INCR", 0)) {
+ ERR_FAIL_COND_V_MSG(len != 1, ret, "Incremental transfer initial value was not length.");
+
+ // Data is going to be received incrementally.
+ DEBUG_LOG_X11("INCR selection started.\n");
+
+ LocalVector<uint8_t> incr_data;
+ uint32_t data_size = 0;
+ bool success = false;
+
+ // Initial response is the lower bound of the length of the transferred data.
+ incr_data.resize(*(unsigned long *)data);
+ XFree(data);
+ data = nullptr;
+
+ // Delete INCR property to notify the owner.
+ XDeleteProperty(x11_display, x11_window, transfer_prop);
+
+ // Process events from the queue.
+ bool done = false;
+ while (!done) {
+ if (!_wait_for_events()) {
+ // Error or timeout, abort.
+ break;
+ }
+ // Non-blocking wait for next event and remove it from the queue.
+ XEvent ev;
+ while (XCheckIfEvent(x11_display, &ev, _predicate_clipboard_incr, (XPointer)&transfer_prop)) {
+ result = XGetWindowProperty(x11_display, x11_window,
+ transfer_prop, // output property
+ 0, LONG_MAX, // offset - len
+ True, // delete property to notify the owner
+ AnyPropertyType, // flag
+ &type, // return type
+ &format, // return format
+ &len, &bytes_left, // data length
+ &data);
+
+ DEBUG_LOG_X11("PropertyNotify: len=%lu, format=%i\n", len, format);
+
+ if (result == Success) {
+ if (data && (len > 0)) {
+ uint32_t prev_size = incr_data.size();
+ // New chunk, resize to be safe and append data.
+ incr_data.resize(MAX(data_size + len, prev_size));
+ memcpy(incr_data.ptr() + data_size, data, len);
+ data_size += len;
+ } else if (!(format == 0 && len == 0)) {
+ // For unclear reasons the first GetWindowProperty always returns a length and format of 0.
+ // Otherwise, last chunk, process finished.
+ done = true;
+ success = true;
+ }
+ } else {
+ print_verbose("Failed to get selection data chunk.");
+ done = true;
+ }
+
+ if (data) {
+ XFree(data);
+ data = nullptr;
+ }
+
+ if (done) {
+ break;
+ }
+ }
+ }
+
+ if (success && (data_size > 0)) {
+ ret.instantiate();
+ PNGDriverCommon::png_to_image(incr_data.ptr(), incr_data.size(), false, ret);
+ }
+ } else if (bytes_left > 0) {
+ if (data) {
+ XFree(data);
+ data = nullptr;
+ }
+ // Data is ready and can be processed all at once.
+ result = XGetWindowProperty(x11_display, x11_window,
+ transfer_prop, 0, bytes_left + 4, 0,
+ AnyPropertyType, &type, &format,
+ &len, &dummy, &data);
+ if (result == Success) {
+ ret.instantiate();
+ PNGDriverCommon::png_to_image((uint8_t *)data, bytes_left, false, ret);
+ } else {
+ print_verbose("Failed to get selection data.");
+ }
+
+ if (data) {
+ XFree(data);
+ }
+ }
+ }
+
+ return ret;
+}
+
+bool DisplayServerX11::clipboard_has_image() const {
+ Atom target = _clipboard_get_image_target(
+ XInternAtom(x11_display, "CLIPBOARD", 0),
+ windows[MAIN_WINDOW_ID].x11_window);
+ return target != None;
+}
+
Bool DisplayServerX11::_predicate_clipboard_save_targets(Display *display, XEvent *event, XPointer arg) {
if (event->xany.window == *(Window *)arg) {
return (event->type == SelectionRequest) ||
@@ -1350,7 +1586,7 @@ float DisplayServerX11::screen_get_refresh_rate(int p_screen) const {
//Use xrandr to get screen refresh rate.
if (xrandr_ext_ok) {
- XRRScreenResources *screen_info = XRRGetScreenResources(x11_display, windows[MAIN_WINDOW_ID].x11_window);
+ XRRScreenResources *screen_info = XRRGetScreenResourcesCurrent(x11_display, windows[MAIN_WINDOW_ID].x11_window);
if (screen_info) {
RRMode current_mode = 0;
xrr_monitor_info *monitors = nullptr;
@@ -1438,7 +1674,11 @@ DisplayServer::WindowID DisplayServerX11::create_sub_window(WindowMode p_mode, V
window_set_flag(WindowFlags(i), true, id);
}
}
-
+#ifdef RD_ENABLED
+ if (rendering_device) {
+ rendering_device->screen_create(id);
+ }
+#endif
return id;
}
@@ -1486,9 +1726,13 @@ void DisplayServerX11::delete_sub_window(WindowID p_id) {
window_set_transient(p_id, INVALID_WINDOW_ID);
}
-#ifdef VULKAN_ENABLED
- if (context_vulkan) {
- context_vulkan->window_destroy(p_id);
+#if defined(RD_ENABLED)
+ if (rendering_device) {
+ rendering_device->screen_free(p_id);
+ }
+
+ if (rendering_context) {
+ rendering_context->window_destroy(p_id);
}
#endif
#ifdef GLES3_ENABLED
@@ -1789,8 +2033,8 @@ void DisplayServerX11::window_set_transient(WindowID p_window, WindowID p_parent
// RevertToPointerRoot is used to make sure we don't lose all focus in case
// a subwindow and its parent are both destroyed.
if (!wd_window.no_focus && !wd_window.is_popup && wd_window.focused) {
- if ((xwa.map_state == IsViewable) && !wd_parent.no_focus && !wd_window.is_popup) {
- XSetInputFocus(x11_display, wd_parent.x11_window, RevertToPointerRoot, CurrentTime);
+ if ((xwa.map_state == IsViewable) && !wd_parent.no_focus && !wd_window.is_popup && _window_focus_check()) {
+ _set_input_focus(wd_parent.x11_window, RevertToPointerRoot);
}
}
} else {
@@ -2012,9 +2256,9 @@ void DisplayServerX11::window_set_size(const Size2i p_size, WindowID p_window) {
}
// Keep rendering context window size in sync
-#if defined(VULKAN_ENABLED)
- if (context_vulkan) {
- context_vulkan->window_resize(p_window, xwa.width, xwa.height);
+#if defined(RD_ENABLED)
+ if (rendering_context) {
+ rendering_context->window_set_size(p_window, xwa.width, xwa.height);
}
#endif
#if defined(GLES3_ENABLED)
@@ -2670,10 +2914,15 @@ void DisplayServerX11::window_move_to_foreground(WindowID p_window) {
XFlush(x11_display);
}
+DisplayServerX11::WindowID DisplayServerX11::get_focused_window() const {
+ return last_focused_window;
+}
+
bool DisplayServerX11::window_is_focused(WindowID p_window) const {
_THREAD_SAFE_METHOD_
ERR_FAIL_COND_V(!windows.has(p_window), false);
+
const WindowData &wd = windows[p_window];
return wd.focused;
@@ -2724,8 +2973,8 @@ void DisplayServerX11::window_set_ime_active(const bool p_active, WindowID p_win
XWindowAttributes xwa;
XSync(x11_display, False);
XGetWindowAttributes(x11_display, wd.x11_xim_window, &xwa);
- if (xwa.map_state == IsViewable) {
- XSetInputFocus(x11_display, wd.x11_xim_window, RevertToParent, CurrentTime);
+ if (xwa.map_state == IsViewable && _window_focus_check()) {
+ _set_input_focus(wd.x11_xim_window, RevertToParent);
}
XSetICFocus(wd.xic);
} else {
@@ -3275,6 +3524,7 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event,
bool keypress = xkeyevent->type == KeyPress;
Key keycode = KeyMappingX11::get_keycode(keysym_keycode);
Key physical_keycode = KeyMappingX11::get_scancode(xkeyevent->keycode);
+ KeyLocation key_location = KeyMappingX11::get_location(xkeyevent->keycode);
if (keycode >= Key::A + 32 && keycode <= Key::Z + 32) {
keycode -= 'a' - 'A';
@@ -3312,6 +3562,8 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event,
k->set_unicode(fix_unicode(tmp[i]));
}
+ k->set_location(key_location);
+
k->set_echo(false);
if (k->get_keycode() == Key::BACKTAB) {
@@ -3337,6 +3589,8 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event,
Key keycode = KeyMappingX11::get_keycode(keysym_keycode);
Key physical_keycode = KeyMappingX11::get_scancode(xkeyevent->keycode);
+ KeyLocation key_location = KeyMappingX11::get_location(xkeyevent->keycode);
+
/* Phase 3, obtain a unicode character from the keysym */
// KeyMappingX11 also translates keysym to unicode.
@@ -3436,6 +3690,9 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event,
if (keypress) {
k->set_unicode(fix_unicode(unicode));
}
+
+ k->set_location(key_location);
+
k->set_echo(p_echo);
if (k->get_keycode() == Key::BACKTAB) {
@@ -3654,7 +3911,7 @@ void DisplayServerX11::_xim_preedit_draw_callback(::XIM xim, ::XPointer client_d
ds->im_selection = Point2i();
}
- OS_Unix::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_OS_IME_UPDATE);
+ callable_mp((Object *)OS_Unix::get_singleton()->get_main_loop(), &Object::notification).call_deferred(MainLoop::NOTIFICATION_OS_IME_UPDATE, false);
}
}
@@ -3724,9 +3981,9 @@ void DisplayServerX11::_window_changed(XEvent *event) {
wd.position = new_rect.position;
wd.size = new_rect.size;
-#if defined(VULKAN_ENABLED)
- if (context_vulkan) {
- context_vulkan->window_resize(window_id, wd.size.width, wd.size.height);
+#if defined(RD_ENABLED)
+ if (rendering_context) {
+ rendering_context->window_set_size(window_id, wd.size.width, wd.size.height);
}
#endif
#if defined(GLES3_ENABLED)
@@ -3798,6 +4055,18 @@ void DisplayServerX11::_send_window_event(const WindowData &wd, WindowEvent p_ev
}
}
+void DisplayServerX11::_set_input_focus(Window p_window, int p_revert_to) {
+ Window focused_window;
+ int focus_ret_state;
+ XGetInputFocus(x11_display, &focused_window, &focus_ret_state);
+
+ // Only attempt to change focus if the window isn't already focused, in order to
+ // prevent issues with Godot stealing input focus with alternative window managers.
+ if (p_window != focused_window) {
+ XSetInputFocus(x11_display, p_window, p_revert_to, CurrentTime);
+ }
+}
+
void DisplayServerX11::_poll_events_thread(void *ud) {
DisplayServerX11 *display_server = static_cast<DisplayServerX11 *>(ud);
display_server->_poll_events();
@@ -4007,6 +4276,22 @@ bool DisplayServerX11::mouse_process_popups() {
return closed;
}
+bool DisplayServerX11::_window_focus_check() {
+ Window focused_window;
+ int focus_ret_state;
+ XGetInputFocus(x11_display, &focused_window, &focus_ret_state);
+
+ bool has_focus = false;
+ for (const KeyValue<int, DisplayServerX11::WindowData> &wid : windows) {
+ if (wid.value.x11_window == focused_window) {
+ has_focus = true;
+ break;
+ }
+ }
+
+ return has_focus;
+}
+
void DisplayServerX11::process_events() {
_THREAD_SAFE_METHOD_
@@ -4251,6 +4536,7 @@ void DisplayServerX11::process_events() {
sd->set_index(index);
sd->set_position(pos);
sd->set_relative(pos - curr_pos_elem->value);
+ sd->set_relative_screen_position(sd->get_relative());
Input::get_singleton()->parse_input_event(sd);
curr_pos_elem->value = pos;
@@ -4278,8 +4564,8 @@ void DisplayServerX11::process_events() {
// Set focus when menu window is started.
// RevertToPointerRoot is used to make sure we don't lose all focus in case
// a subwindow and its parent are both destroyed.
- if ((xwa.map_state == IsViewable) && !wd.no_focus && !wd.is_popup) {
- XSetInputFocus(x11_display, wd.x11_window, RevertToPointerRoot, CurrentTime);
+ if ((xwa.map_state == IsViewable) && !wd.no_focus && !wd.is_popup && _window_focus_check()) {
+ _set_input_focus(wd.x11_window, RevertToPointerRoot);
}
// Have we failed to set fullscreen while the window was unmapped?
@@ -4454,8 +4740,8 @@ void DisplayServerX11::process_events() {
// Set focus when menu window is re-used.
// RevertToPointerRoot is used to make sure we don't lose all focus in case
// a subwindow and its parent are both destroyed.
- if ((xwa.map_state == IsViewable) && !wd.no_focus && !wd.is_popup) {
- XSetInputFocus(x11_display, wd.x11_window, RevertToPointerRoot, CurrentTime);
+ if ((xwa.map_state == IsViewable) && !wd.no_focus && !wd.is_popup && _window_focus_check()) {
+ _set_input_focus(wd.x11_window, RevertToPointerRoot);
}
_window_changed(&event);
@@ -4499,7 +4785,7 @@ void DisplayServerX11::process_events() {
// RevertToPointerRoot is used to make sure we don't lose all focus in case
// a subwindow and its parent are both destroyed.
if (!wd.no_focus && !wd.is_popup) {
- XSetInputFocus(x11_display, wd.x11_window, RevertToPointerRoot, CurrentTime);
+ _set_input_focus(wd.x11_window, RevertToPointerRoot);
}
uint64_t diff = OS::get_singleton()->get_ticks_usec() / 1000 - last_click_ms;
@@ -4672,8 +4958,10 @@ void DisplayServerX11::process_events() {
mm->set_position(pos);
mm->set_global_position(pos);
mm->set_velocity(Input::get_singleton()->get_last_mouse_velocity());
+ mm->set_screen_velocity(mm->get_velocity());
mm->set_relative(rel);
+ mm->set_relative_screen_position(rel);
last_mouse_pos = pos;
@@ -5023,9 +5311,9 @@ void DisplayServerX11::set_icon(const Ref<Image> &p_icon) {
void DisplayServerX11::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
_THREAD_SAFE_METHOD_
-#if defined(VULKAN_ENABLED)
- if (context_vulkan) {
- context_vulkan->set_vsync_mode(p_window, p_vsync_mode);
+#if defined(RD_ENABLED)
+ if (rendering_context) {
+ rendering_context->window_set_vsync_mode(p_window, p_vsync_mode);
}
#endif
@@ -5041,9 +5329,9 @@ void DisplayServerX11::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mo
DisplayServer::VSyncMode DisplayServerX11::window_get_vsync_mode(WindowID p_window) const {
_THREAD_SAFE_METHOD_
-#if defined(VULKAN_ENABLED)
- if (context_vulkan) {
- return context_vulkan->get_vsync_mode(p_window);
+#if defined(RD_ENABLED)
+ if (rendering_context) {
+ return rendering_context->window_get_vsync_mode(p_window);
}
#endif
#if defined(GLES3_ENABLED)
@@ -5385,10 +5673,24 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V
_update_size_hints(id);
-#if defined(VULKAN_ENABLED)
- if (context_vulkan) {
- Error err = context_vulkan->window_create(id, p_vsync_mode, wd.x11_window, x11_display, win_rect.size.width, win_rect.size.height);
- ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't create a Vulkan window");
+#if defined(RD_ENABLED)
+ if (rendering_context) {
+ union {
+#ifdef VULKAN_ENABLED
+ RenderingContextDriverVulkanX11::WindowPlatformData vulkan;
+#endif
+ } wpd;
+#ifdef VULKAN_ENABLED
+ if (rendering_driver == "vulkan") {
+ wpd.vulkan.window = wd.x11_window;
+ wpd.vulkan.display = x11_display;
+ }
+#endif
+ Error err = rendering_context->window_create(id, &wpd);
+ ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, vformat("Can't create a %s window", rendering_driver));
+
+ rendering_context->window_set_size(id, win_rect.size.width, win_rect.size.height);
+ rendering_context->window_set_vsync_mode(id, p_vsync_mode);
}
#endif
#ifdef GLES3_ENABLED
@@ -5787,14 +6089,20 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
rendering_driver = p_rendering_driver;
bool driver_found = false;
+#if defined(RD_ENABLED)
#if defined(VULKAN_ENABLED)
if (rendering_driver == "vulkan") {
- context_vulkan = memnew(VulkanContextX11);
- if (context_vulkan->initialize() != OK) {
- memdelete(context_vulkan);
- context_vulkan = nullptr;
+ rendering_context = memnew(RenderingContextDriverVulkanX11);
+ }
+#endif
+
+ if (rendering_context) {
+ if (rendering_context->initialize() != OK) {
+ ERR_PRINT(vformat("Could not initialize %s", rendering_driver));
+ memdelete(rendering_context);
+ rendering_context = nullptr;
r_error = ERR_CANT_CREATE;
- ERR_FAIL_MSG("Could not initialize Vulkan");
+ return;
}
driver_found = true;
}
@@ -5844,33 +6152,36 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
}
}
if (rendering_driver == "opengl3") {
- GLManager_X11::ContextType opengl_api_type = GLManager_X11::GLES_3_0_COMPATIBLE;
-
- gl_manager = memnew(GLManager_X11(p_resolution, opengl_api_type));
-
- if (gl_manager->initialize(x11_display) != OK) {
+ gl_manager = memnew(GLManager_X11(p_resolution, GLManager_X11::GLES_3_0_COMPATIBLE));
+ if (gl_manager->initialize(x11_display) != OK || gl_manager->open_display(x11_display) != OK) {
memdelete(gl_manager);
gl_manager = nullptr;
- r_error = ERR_UNAVAILABLE;
- return;
+ bool fallback = GLOBAL_GET("rendering/gl_compatibility/fallback_to_gles");
+ if (fallback) {
+ WARN_PRINT("Your video card drivers seem not to support the required OpenGL version, switching to OpenGLES.");
+ rendering_driver = "opengl3_es";
+ } else {
+ r_error = ERR_UNAVAILABLE;
+ ERR_FAIL_MSG("Could not initialize OpenGL.");
+ }
+ } else {
+ driver_found = true;
+ RasterizerGLES3::make_current(true);
}
- driver_found = true;
-
- RasterizerGLES3::make_current(true);
}
+
if (rendering_driver == "opengl3_es") {
gl_manager_egl = memnew(GLManagerEGL_X11);
-
if (gl_manager_egl->initialize() != OK) {
memdelete(gl_manager_egl);
gl_manager_egl = nullptr;
r_error = ERR_UNAVAILABLE;
- return;
+ ERR_FAIL_MSG("Could not initialize OpenGLES.");
}
driver_found = true;
-
RasterizerGLES3::make_current(false);
}
+
#endif
if (!driver_found) {
r_error = ERR_UNAVAILABLE;
@@ -5884,7 +6195,8 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
if (p_screen == SCREEN_OF_MAIN_WINDOW) {
p_screen = SCREEN_PRIMARY;
}
- window_position = screen_get_position(p_screen) + (screen_get_size(p_screen) - p_resolution) / 2;
+ Rect2i scr_rect = screen_get_usable_rect(p_screen);
+ window_position = scr_rect.position + (scr_rect.size - p_resolution) / 2;
}
WindowID main_window = _create_window(p_mode, p_vsync_mode, p_flags, Rect2i(window_position, p_resolution));
@@ -5899,11 +6211,11 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
}
show_window(main_window);
-#if defined(VULKAN_ENABLED)
- if (rendering_driver == "vulkan") {
- //temporary
- rendering_device_vulkan = memnew(RenderingDeviceVulkan);
- rendering_device_vulkan->initialize(context_vulkan);
+#if defined(RD_ENABLED)
+ if (rendering_context) {
+ rendering_device = memnew(RenderingDevice);
+ rendering_device->initialize(rendering_context, MAIN_WINDOW_ID);
+ rendering_device->screen_create(MAIN_WINDOW_ID);
RendererCompositorRD::make_current();
}
@@ -6077,9 +6389,13 @@ DisplayServerX11::~DisplayServerX11() {
//destroy all windows
for (KeyValue<WindowID, WindowData> &E : windows) {
-#ifdef VULKAN_ENABLED
- if (context_vulkan) {
- context_vulkan->window_destroy(E.key);
+#if defined(RD_ENABLED)
+ if (rendering_device) {
+ rendering_device->screen_free(E.key);
+ }
+
+ if (rendering_context) {
+ rendering_context->window_destroy(E.key);
}
#endif
#ifdef GLES3_ENABLED
@@ -6121,16 +6437,15 @@ DisplayServerX11::~DisplayServerX11() {
#endif
//destroy drivers
-#if defined(VULKAN_ENABLED)
- if (rendering_device_vulkan) {
- rendering_device_vulkan->finalize();
- memdelete(rendering_device_vulkan);
- rendering_device_vulkan = nullptr;
+#if defined(RD_ENABLED)
+ if (rendering_device) {
+ memdelete(rendering_device);
+ rendering_device = nullptr;
}
- if (context_vulkan) {
- memdelete(context_vulkan);
- context_vulkan = nullptr;
+ if (rendering_context) {
+ memdelete(rendering_context);
+ rendering_context = nullptr;
}
#endif
diff --git a/platform/linuxbsd/x11/display_server_x11.h b/platform/linuxbsd/x11/display_server_x11.h
index 9706a4aa11..a5cbe34d26 100644
--- a/platform/linuxbsd/x11/display_server_x11.h
+++ b/platform/linuxbsd/x11/display_server_x11.h
@@ -57,10 +57,12 @@
#include "x11/gl_manager_x11_egl.h"
#endif
-#if defined(VULKAN_ENABLED)
-#include "x11/vulkan_context_x11.h"
+#if defined(RD_ENABLED)
+#include "servers/rendering/rendering_device.h"
-#include "drivers/vulkan/rendering_device_vulkan.h"
+#if defined(VULKAN_ENABLED)
+#include "x11/rendering_context_driver_vulkan_x11.h"
+#endif
#endif
#if defined(DBUS_ENABLED)
@@ -141,9 +143,9 @@ class DisplayServerX11 : public DisplayServer {
GLManager_X11 *gl_manager = nullptr;
GLManagerEGL_X11 *gl_manager_egl = nullptr;
#endif
-#if defined(VULKAN_ENABLED)
- VulkanContextX11 *context_vulkan = nullptr;
- RenderingDeviceVulkan *rendering_device_vulkan = nullptr;
+#if defined(RD_ENABLED)
+ RenderingContextDriver *rendering_context = nullptr;
+ RenderingDevice *rendering_device = nullptr;
#endif
#if defined(DBUS_ENABLED)
@@ -304,6 +306,7 @@ class DisplayServerX11 : public DisplayServer {
String _clipboard_get_impl(Atom p_source, Window x11_window, Atom target) const;
String _clipboard_get(Atom p_source, Window x11_window) const;
+ Atom _clipboard_get_image_target(Atom p_source, Window x11_window) const;
void _clipboard_transfer_ownership(Atom p_source, Window x11_window) const;
bool do_mouse_warp = false;
@@ -351,10 +354,12 @@ class DisplayServerX11 : public DisplayServer {
Context context = CONTEXT_ENGINE;
WindowID _get_focused_window_or_popup() const;
+ bool _window_focus_check();
void _send_window_event(const WindowData &wd, WindowEvent p_event);
static void _dispatch_input_events(const Ref<InputEvent> &p_event);
void _dispatch_input_event(const Ref<InputEvent> &p_event);
+ void _set_input_focus(Window p_window, int p_revert_to);
mutable Mutex events_mutex;
Thread events_thread;
@@ -395,8 +400,10 @@ public:
#if defined(DBUS_ENABLED)
virtual bool is_dark_mode_supported() const override;
virtual bool is_dark_mode() const override;
+ virtual void set_system_theme_change_callback(const Callable &p_callable) override;
virtual Error file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback) override;
+ virtual Error file_dialog_with_options_show(const String &p_title, const String &p_current_directory, const String &p_root, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const TypedArray<Dictionary> &p_options, const Callable &p_callback) override;
#endif
virtual void mouse_set_mode(MouseMode p_mode) override;
@@ -408,6 +415,8 @@ public:
virtual void clipboard_set(const String &p_text) override;
virtual String clipboard_get() const override;
+ virtual Ref<Image> clipboard_get_image() const override;
+ virtual bool clipboard_has_image() const override;
virtual void clipboard_set_primary(const String &p_text) override;
virtual String clipboard_get_primary() const override;
@@ -486,6 +495,8 @@ public:
virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) override;
virtual bool window_is_focused(WindowID p_window = MAIN_WINDOW_ID) const override;
+ virtual WindowID get_focused_window() const override;
+
virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const override;
virtual bool can_any_window_draw() const override;
diff --git a/platform/linuxbsd/x11/gl_manager_x11.cpp b/platform/linuxbsd/x11/gl_manager_x11.cpp
index 95947301cf..602dd784e0 100644
--- a/platform/linuxbsd/x11/gl_manager_x11.cpp
+++ b/platform/linuxbsd/x11/gl_manager_x11.cpp
@@ -208,6 +208,15 @@ XVisualInfo GLManager_X11::get_vi(Display *p_display, Error &r_error) {
return _displays[display_id].x_vi;
}
+Error GLManager_X11::open_display(Display *p_display) {
+ int gldisplay_id = _find_or_create_display(p_display);
+ if (gldisplay_id < 0) {
+ return ERR_CANT_CREATE;
+ } else {
+ return OK;
+ }
+}
+
Error GLManager_X11::window_create(DisplayServer::WindowID p_window_id, ::Window p_window, Display *p_display, int p_width, int p_height) {
// make sure vector is big enough...
// we can mirror the external vector, it is simpler
diff --git a/platform/linuxbsd/x11/gl_manager_x11.h b/platform/linuxbsd/x11/gl_manager_x11.h
index d3a25506a8..235c7d22f9 100644
--- a/platform/linuxbsd/x11/gl_manager_x11.h
+++ b/platform/linuxbsd/x11/gl_manager_x11.h
@@ -129,6 +129,7 @@ public:
void *get_glx_context(DisplayServer::WindowID p_window_id);
+ Error open_display(Display *p_display);
GLManager_X11(const Vector2i &p_size, ContextType p_context_type);
~GLManager_X11();
};
diff --git a/platform/linuxbsd/x11/key_mapping_x11.cpp b/platform/linuxbsd/x11/key_mapping_x11.cpp
index 0f709872cb..b589a2a573 100644
--- a/platform/linuxbsd/x11/key_mapping_x11.cpp
+++ b/platform/linuxbsd/x11/key_mapping_x11.cpp
@@ -88,7 +88,6 @@ void KeyMappingX11::initialize() {
xkeysym_map[XK_KP_Equal] = Key::EQUAL;
xkeysym_map[XK_KP_Separator] = Key::COMMA;
xkeysym_map[XK_KP_Decimal] = Key::KP_PERIOD;
- xkeysym_map[XK_KP_Delete] = Key::KP_PERIOD;
xkeysym_map[XK_KP_Multiply] = Key::KP_MULTIPLY;
xkeysym_map[XK_KP_Divide] = Key::KP_DIVIDE;
xkeysym_map[XK_KP_Subtract] = Key::KP_SUBTRACT;
@@ -105,6 +104,7 @@ void KeyMappingX11::initialize() {
xkeysym_map[XK_KP_9] = Key::KP_9;
// Same keys but with numlock off.
xkeysym_map[XK_KP_Insert] = Key::INSERT;
+ xkeysym_map[XK_KP_Delete] = Key::KEY_DELETE;
xkeysym_map[XK_KP_End] = Key::END;
xkeysym_map[XK_KP_Down] = Key::DOWN;
xkeysym_map[XK_KP_Page_Down] = Key::PAGEDOWN;
@@ -1113,6 +1113,20 @@ void KeyMappingX11::initialize() {
xkeysym_unicode_map[0x13BD] = 0x0153;
xkeysym_unicode_map[0x13BE] = 0x0178;
xkeysym_unicode_map[0x20AC] = 0x20AC;
+
+ // Scancode to physical location map.
+ // Ctrl.
+ location_map[0x25] = KeyLocation::LEFT;
+ location_map[0x69] = KeyLocation::RIGHT;
+ // Shift.
+ location_map[0x32] = KeyLocation::LEFT;
+ location_map[0x3E] = KeyLocation::RIGHT;
+ // Alt.
+ location_map[0x40] = KeyLocation::LEFT;
+ location_map[0x6C] = KeyLocation::RIGHT;
+ // Meta.
+ location_map[0x85] = KeyLocation::LEFT;
+ location_map[0x86] = KeyLocation::RIGHT;
}
Key KeyMappingX11::get_keycode(KeySym p_keysym) {
@@ -1173,3 +1187,11 @@ char32_t KeyMappingX11::get_unicode_from_keysym(KeySym p_keysym) {
}
return 0;
}
+
+KeyLocation KeyMappingX11::get_location(unsigned int p_code) {
+ const KeyLocation *location = location_map.getptr(p_code);
+ if (location) {
+ return *location;
+ }
+ return KeyLocation::UNSPECIFIED;
+}
diff --git a/platform/linuxbsd/x11/key_mapping_x11.h b/platform/linuxbsd/x11/key_mapping_x11.h
index ae8fd67f27..a51ee5f48e 100644
--- a/platform/linuxbsd/x11/key_mapping_x11.h
+++ b/platform/linuxbsd/x11/key_mapping_x11.h
@@ -54,6 +54,7 @@ class KeyMappingX11 {
static inline HashMap<unsigned int, Key, HashMapHasherKeys> scancode_map;
static inline HashMap<Key, unsigned int, HashMapHasherKeys> scancode_map_inv;
static inline HashMap<KeySym, char32_t, HashMapHasherKeys> xkeysym_unicode_map;
+ static inline HashMap<unsigned int, KeyLocation, HashMapHasherKeys> location_map;
KeyMappingX11() {}
@@ -64,6 +65,7 @@ public:
static unsigned int get_xlibcode(Key p_keysym);
static Key get_scancode(unsigned int p_code);
static char32_t get_unicode_from_keysym(KeySym p_keysym);
+ static KeyLocation get_location(unsigned int p_code);
};
#endif // KEY_MAPPING_X11_H
diff --git a/platform/linuxbsd/x11/vulkan_context_x11.cpp b/platform/linuxbsd/x11/rendering_context_driver_vulkan_x11.cpp
index d240480f61..bf44062266 100644
--- a/platform/linuxbsd/x11/vulkan_context_x11.cpp
+++ b/platform/linuxbsd/x11/rendering_context_driver_vulkan_x11.cpp
@@ -1,5 +1,5 @@
/**************************************************************************/
-/* vulkan_context_x11.cpp */
+/* rendering_context_driver_vulkan_x11.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -30,7 +30,7 @@
#ifdef VULKAN_ENABLED
-#include "vulkan_context_x11.h"
+#include "rendering_context_driver_vulkan_x11.h"
#ifdef USE_VOLK
#include <volk.h>
@@ -38,28 +38,33 @@
#include <vulkan/vulkan.h>
#endif
-const char *VulkanContextX11::_get_platform_surface_extension() const {
+const char *RenderingContextDriverVulkanX11::_get_platform_surface_extension() const {
return VK_KHR_XLIB_SURFACE_EXTENSION_NAME;
}
-Error VulkanContextX11::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, ::Window p_window, Display *p_display, int p_width, int p_height) {
- VkXlibSurfaceCreateInfoKHR createInfo;
- createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
- createInfo.pNext = nullptr;
- createInfo.flags = 0;
- createInfo.dpy = p_display;
- createInfo.window = p_window;
+RenderingContextDriver::SurfaceID RenderingContextDriverVulkanX11::surface_create(const void *p_platform_data) {
+ const WindowPlatformData *wpd = (const WindowPlatformData *)(p_platform_data);
- VkSurfaceKHR surface;
- VkResult err = vkCreateXlibSurfaceKHR(get_instance(), &createInfo, nullptr, &surface);
- ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
- return _window_create(p_window_id, p_vsync_mode, surface, p_width, p_height);
+ VkXlibSurfaceCreateInfoKHR create_info = {};
+ create_info.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
+ create_info.dpy = wpd->display;
+ create_info.window = wpd->window;
+
+ VkSurfaceKHR vk_surface = VK_NULL_HANDLE;
+ VkResult err = vkCreateXlibSurfaceKHR(instance_get(), &create_info, nullptr, &vk_surface);
+ ERR_FAIL_COND_V(err != VK_SUCCESS, SurfaceID());
+
+ Surface *surface = memnew(Surface);
+ surface->vk_surface = vk_surface;
+ return SurfaceID(surface);
}
-VulkanContextX11::VulkanContextX11() {
+RenderingContextDriverVulkanX11::RenderingContextDriverVulkanX11() {
+ // Does nothing.
}
-VulkanContextX11::~VulkanContextX11() {
+RenderingContextDriverVulkanX11::~RenderingContextDriverVulkanX11() {
+ // Does nothing.
}
#endif // VULKAN_ENABLED
diff --git a/platform/linuxbsd/x11/vulkan_context_x11.h b/platform/linuxbsd/x11/rendering_context_driver_vulkan_x11.h
index 294fdc710e..d525b69ec7 100644
--- a/platform/linuxbsd/x11/vulkan_context_x11.h
+++ b/platform/linuxbsd/x11/rendering_context_driver_vulkan_x11.h
@@ -1,5 +1,5 @@
/**************************************************************************/
-/* vulkan_context_x11.h */
+/* rendering_context_driver_vulkan_x11.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,25 +28,32 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#ifndef VULKAN_CONTEXT_X11_H
-#define VULKAN_CONTEXT_X11_H
+#ifndef RENDERING_CONTEXT_DRIVER_VULKAN_X11_H
+#define RENDERING_CONTEXT_DRIVER_VULKAN_X11_H
#ifdef VULKAN_ENABLED
-#include "drivers/vulkan/vulkan_context.h"
+#include "drivers/vulkan/rendering_context_driver_vulkan.h"
#include <X11/Xlib.h>
-class VulkanContextX11 : public VulkanContext {
- virtual const char *_get_platform_surface_extension() const;
+class RenderingContextDriverVulkanX11 : public RenderingContextDriverVulkan {
+private:
+ virtual const char *_get_platform_surface_extension() const override final;
+
+protected:
+ SurfaceID surface_create(const void *p_platform_data) override final;
public:
- Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, ::Window p_window, Display *p_display, int p_width, int p_height);
+ struct WindowPlatformData {
+ ::Window window;
+ Display *display;
+ };
- VulkanContextX11();
- ~VulkanContextX11();
+ RenderingContextDriverVulkanX11();
+ ~RenderingContextDriverVulkanX11();
};
#endif // VULKAN_ENABLED
-#endif // VULKAN_CONTEXT_X11_H
+#endif // RENDERING_CONTEXT_DRIVER_VULKAN_X11_H