summaryrefslogtreecommitdiffstats
path: root/platform/linuxbsd/x11/display_server_x11.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'platform/linuxbsd/x11/display_server_x11.cpp')
-rw-r--r--platform/linuxbsd/x11/display_server_x11.cpp504
1 files changed, 313 insertions, 191 deletions
diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp
index 1660101598..0e4c723a87 100644
--- a/platform/linuxbsd/x11/display_server_x11.cpp
+++ b/platform/linuxbsd/x11/display_server_x11.cpp
@@ -41,7 +41,6 @@
#include "core/string/ustring.h"
#include "drivers/png/png_driver_common.h"
#include "main/main.h"
-#include "scene/resources/atlas_texture.h"
#if defined(VULKAN_ENABLED)
#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
@@ -110,6 +109,11 @@ static String get_atom_name(Display *p_disp, Atom p_atom) {
bool DisplayServerX11::has_feature(Feature p_feature) const {
switch (p_feature) {
+#ifndef DISABLE_DEPRECATED
+ case FEATURE_GLOBAL_MENU: {
+ return (native_menu && native_menu->has_feature(NativeMenu::FEATURE_GLOBAL_MENU));
+ } break;
+#endif
case FEATURE_SUBWINDOWS:
#ifdef TOUCH_ENABLED
case FEATURE_TOUCHSCREEN:
@@ -124,8 +128,10 @@ bool DisplayServerX11::has_feature(Feature p_feature) const {
//case FEATURE_HIDPI:
case FEATURE_ICON:
#ifdef DBUS_ENABLED
- case FEATURE_NATIVE_DIALOG:
+ case FEATURE_NATIVE_DIALOG_FILE:
#endif
+ //case FEATURE_NATIVE_DIALOG:
+ //case FEATURE_NATIVE_DIALOG_INPUT:
//case FEATURE_NATIVE_ICON:
case FEATURE_SWAP_BUFFERS:
#ifdef DBUS_ENABLED
@@ -364,6 +370,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;
@@ -372,7 +382,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
@@ -481,7 +502,34 @@ Point2i DisplayServerX11::mouse_get_position() const {
}
BitField<MouseButtonMask> DisplayServerX11::mouse_get_button_state() const {
- return last_button_state;
+ int number_of_screens = XScreenCount(x11_display);
+ for (int i = 0; i < number_of_screens; i++) {
+ Window root, child;
+ int root_x, root_y, win_x, win_y;
+ unsigned int mask;
+ if (XQueryPointer(x11_display, XRootWindow(x11_display, i), &root, &child, &root_x, &root_y, &win_x, &win_y, &mask)) {
+ BitField<MouseButtonMask> last_button_state = 0;
+
+ if (mask & Button1Mask) {
+ last_button_state.set_flag(MouseButtonMask::LEFT);
+ }
+ if (mask & Button2Mask) {
+ last_button_state.set_flag(MouseButtonMask::MIDDLE);
+ }
+ if (mask & Button3Mask) {
+ last_button_state.set_flag(MouseButtonMask::RIGHT);
+ }
+ if (mask & Button4Mask) {
+ last_button_state.set_flag(MouseButtonMask::MB_XBUTTON1);
+ }
+ if (mask & Button5Mask) {
+ last_button_state.set_flag(MouseButtonMask::MB_XBUTTON2);
+ }
+
+ return last_button_state;
+ }
+ }
+ return 0;
}
void DisplayServerX11::clipboard_set(const String &p_text) {
@@ -672,7 +720,7 @@ Atom DisplayServerX11::_clipboard_get_image_target(Atom p_source, Window x11_win
unsigned long atom_count = 0;
Window selection_owner = XGetSelectionOwner(x11_display, p_source);
- if (selection_owner != None) {
+ if (selection_owner != None && selection_owner != x11_window) {
// Block events polling while processing selection events.
MutexLock mutex_lock(events_mutex);
@@ -783,7 +831,7 @@ Ref<Image> DisplayServerX11::clipboard_get_image() const {
Window selection_owner = XGetSelectionOwner(x11_display, clipboard);
- if (selection_owner != None) {
+ if (selection_owner != None && selection_owner != x11_window) {
// Block events polling while processing selection events.
MutexLock mutex_lock(events_mutex);
@@ -986,7 +1034,8 @@ int DisplayServerX11::get_screen_count() const {
if (xinerama_ext_ok && XineramaQueryExtension(x11_display, &event_base, &error_base)) {
XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &count);
XFree(xsi);
- } else {
+ }
+ if (count == 0) {
count = XScreenCount(x11_display);
}
@@ -1047,25 +1096,29 @@ Rect2i DisplayServerX11::_screen_get_rect(int p_screen) const {
ERR_FAIL_COND_V(p_screen < 0, rect);
// Using Xinerama Extension.
+ bool found = false;
int event_base, error_base;
if (xinerama_ext_ok && XineramaQueryExtension(x11_display, &event_base, &error_base)) {
int count;
XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &count);
-
- // Check if screen is valid.
- if (p_screen < count) {
- rect.position.x = xsi[p_screen].x_org;
- rect.position.y = xsi[p_screen].y_org;
- rect.size.width = xsi[p_screen].width;
- rect.size.height = xsi[p_screen].height;
- } else {
- ERR_PRINT("Invalid screen index: " + itos(p_screen) + "(count: " + itos(count) + ").");
- }
-
if (xsi) {
+ if (count > 0) {
+ // Check if screen is valid.
+ if (p_screen < count) {
+ rect.position.x = xsi[p_screen].x_org;
+ rect.position.y = xsi[p_screen].y_org;
+ rect.size.width = xsi[p_screen].width;
+ rect.size.height = xsi[p_screen].height;
+ found = true;
+ } else {
+ ERR_PRINT(vformat("Invalid screen index: %d (count: %d).", p_screen, count));
+ }
+ }
XFree(xsi);
}
- } else {
+ }
+
+ if (!found) {
int count = XScreenCount(x11_display);
if (p_screen < count) {
Window root = XRootWindow(x11_display, p_screen);
@@ -1076,7 +1129,7 @@ Rect2i DisplayServerX11::_screen_get_rect(int p_screen) const {
rect.size.width = xwa.width;
rect.size.height = xwa.height;
} else {
- ERR_PRINT("Invalid screen index: " + itos(p_screen) + "(count: " + itos(count) + ").");
+ ERR_PRINT(vformat("Invalid screen index: %d (count: %d).", p_screen, count));
}
}
@@ -1482,25 +1535,33 @@ Ref<Image> DisplayServerX11::screen_get_image(int p_screen) const {
XImage *image = nullptr;
+ bool found = false;
int event_base, error_base;
if (xinerama_ext_ok && XineramaQueryExtension(x11_display, &event_base, &error_base)) {
int xin_count;
XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &xin_count);
- if (p_screen < xin_count) {
- int x_count = XScreenCount(x11_display);
- for (int i = 0; i < x_count; i++) {
- Window root = XRootWindow(x11_display, i);
- XWindowAttributes root_attrs;
- XGetWindowAttributes(x11_display, root, &root_attrs);
- if ((xsi[p_screen].x_org >= root_attrs.x) && (xsi[p_screen].x_org <= root_attrs.x + root_attrs.width) && (xsi[p_screen].y_org >= root_attrs.y) && (xsi[p_screen].y_org <= root_attrs.y + root_attrs.height)) {
- image = XGetImage(x11_display, root, xsi[p_screen].x_org, xsi[p_screen].y_org, xsi[p_screen].width, xsi[p_screen].height, AllPlanes, ZPixmap);
- break;
+ if (xsi) {
+ if (xin_count > 0) {
+ if (p_screen < xin_count) {
+ int x_count = XScreenCount(x11_display);
+ for (int i = 0; i < x_count; i++) {
+ Window root = XRootWindow(x11_display, i);
+ XWindowAttributes root_attrs;
+ XGetWindowAttributes(x11_display, root, &root_attrs);
+ if ((xsi[p_screen].x_org >= root_attrs.x) && (xsi[p_screen].x_org <= root_attrs.x + root_attrs.width) && (xsi[p_screen].y_org >= root_attrs.y) && (xsi[p_screen].y_org <= root_attrs.y + root_attrs.height)) {
+ found = true;
+ image = XGetImage(x11_display, root, xsi[p_screen].x_org, xsi[p_screen].y_org, xsi[p_screen].width, xsi[p_screen].height, AllPlanes, ZPixmap);
+ break;
+ }
+ }
+ } else {
+ ERR_PRINT(vformat("Invalid screen index: %d (count: %d).", p_screen, xin_count));
}
}
- } else {
- ERR_FAIL_V_MSG(Ref<Image>(), "Invalid screen index: " + itos(p_screen) + "(count: " + itos(xin_count) + ").");
+ XFree(xsi);
}
- } else {
+ }
+ if (!found) {
int x_count = XScreenCount(x11_display);
if (p_screen < x_count) {
Window root = XRootWindow(x11_display, p_screen);
@@ -1510,7 +1571,7 @@ Ref<Image> DisplayServerX11::screen_get_image(int p_screen) const {
image = XGetImage(x11_display, root, root_attrs.x, root_attrs.y, root_attrs.width, root_attrs.height, AllPlanes, ZPixmap);
} else {
- ERR_FAIL_V_MSG(Ref<Image>(), "Invalid screen index: " + itos(p_screen) + "(count: " + itos(x_count) + ").");
+ ERR_PRINT(vformat("Invalid screen index: %d (count: %d).", p_screen, x_count));
}
}
@@ -1571,7 +1632,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;
@@ -1659,7 +1720,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;
}
@@ -1707,9 +1772,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
@@ -1968,8 +2037,7 @@ void DisplayServerX11::window_set_current_screen(int p_screen, WindowID p_window
Size2i wsize = window_get_size(p_window);
wpos += srect.position;
if (srect != Rect2i()) {
- wpos.x = CLAMP(wpos.x, srect.position.x, srect.position.x + srect.size.width - wsize.width / 3);
- wpos.y = CLAMP(wpos.y, srect.position.y, srect.position.y + srect.size.height - wsize.height / 3);
+ wpos = wpos.clamp(srect.position, srect.position + srect.size - wsize / 3);
}
window_set_position(wpos, p_window);
}
@@ -2010,8 +2078,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 {
@@ -2197,8 +2265,7 @@ void DisplayServerX11::window_set_size(const Size2i p_size, WindowID p_window) {
ERR_FAIL_COND(!windows.has(p_window));
Size2i size = p_size;
- size.x = MAX(1, size.x);
- size.y = MAX(1, size.y);
+ size = size.maxi(1);
WindowData &wd = windows[p_window];
@@ -2229,13 +2296,13 @@ void DisplayServerX11::window_set_size(const Size2i p_size, WindowID p_window) {
break;
}
- usleep(10000);
+ OS::get_singleton()->delay_usec(10'000);
}
// 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)
@@ -2504,7 +2571,7 @@ void DisplayServerX11::_set_wm_maximized(WindowID p_window, bool p_enabled) {
// 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);
+ OS::get_singleton()->delay_usec(10'000);
}
}
wd.maximized = p_enabled;
@@ -2891,10 +2958,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;
@@ -2945,8 +3017,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 {
@@ -3036,39 +3108,9 @@ void DisplayServerX11::cursor_set_custom_image(const Ref<Resource> &p_cursor, Cu
cursors_cache.erase(p_shape);
}
- Ref<Texture2D> texture = p_cursor;
- ERR_FAIL_COND(!texture.is_valid());
- Ref<AtlasTexture> atlas_texture = p_cursor;
- Size2i texture_size;
- Rect2i atlas_rect;
-
- if (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 {
- texture_size.width = texture->get_width();
- texture_size.height = texture->get_height();
- }
-
- 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);
-
- Ref<Image> image = texture->get_image();
-
- ERR_FAIL_COND(!image.is_valid());
- if (image->is_compressed()) {
- image = image->duplicate(true);
- Error err = image->decompress();
- ERR_FAIL_COND_MSG(err != OK, "Couldn't decompress VRAM-compressed custom mouse cursor image. Switch to a lossless compression mode in the Import dock.");
- }
+ Ref<Image> image = _get_cursor_image_from_resource(p_cursor, p_hotspot);
+ ERR_FAIL_COND(image.is_null());
+ Vector2i texture_size = image->get_size();
// Create the cursor structure
XcursorImage *cursor_image = XcursorImageCreate(texture_size.width, texture_size.height);
@@ -3084,13 +3126,8 @@ void DisplayServerX11::cursor_set_custom_image(const Ref<Resource> &p_cursor, Cu
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);
- }
+ int row_index = floor(index / texture_size.width);
+ int column_index = index % int(texture_size.width);
*(cursor_image->pixels + index) = image->get_pixel(column_index, row_index).to_argb32();
}
@@ -3335,18 +3372,6 @@ void DisplayServerX11::_get_key_modifier_state(unsigned int p_x11_state, Ref<Inp
state->set_meta_pressed((p_x11_state & Mod4Mask));
}
-BitField<MouseButtonMask> DisplayServerX11::_get_mouse_button_state(MouseButton p_x11_button, int p_x11_type) {
- MouseButtonMask mask = mouse_button_to_mask(p_x11_button);
-
- if (p_x11_type == ButtonPress) {
- last_button_state.set_flag(mask);
- } else {
- last_button_state.clear_flag(mask);
- }
-
- return last_button_state;
-}
-
void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event, LocalVector<XEvent> &p_events, uint32_t &p_event_index, bool p_echo) {
WindowData &wd = windows[p_window];
// X11 functions don't know what const is
@@ -3496,6 +3521,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';
@@ -3533,6 +3559,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) {
@@ -3558,6 +3586,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.
@@ -3657,6 +3687,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) {
@@ -3875,7 +3908,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);
}
}
@@ -3945,9 +3978,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)
@@ -4019,6 +4052,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();
@@ -4139,8 +4184,11 @@ void DisplayServerX11::popup_open(WindowID p_window) {
}
}
+ // Detect tooltips and other similar popups that shouldn't block input to their parent.
+ bool ignores_input = window_get_flag(WINDOW_FLAG_NO_FOCUS, p_window) && window_get_flag(WINDOW_FLAG_MOUSE_PASSTHROUGH, p_window);
+
WindowData &wd = windows[p_window];
- if (wd.is_popup || has_popup_ancestor) {
+ if (wd.is_popup || (has_popup_ancestor && !ignores_input)) {
// Find current popup parent, or root popup if new window is not transient.
List<WindowID>::Element *C = nullptr;
List<WindowID>::Element *E = popup_list.back();
@@ -4170,7 +4218,10 @@ void DisplayServerX11::popup_close(WindowID p_window) {
WindowID win_id = E->get();
popup_list.erase(E);
- _send_window_event(windows[win_id], DisplayServerX11::WINDOW_EVENT_CLOSE_REQUEST);
+ if (win_id != p_window) {
+ // Only request close on related windows, not this window. We are already processing it.
+ _send_window_event(windows[win_id], DisplayServerX11::WINDOW_EVENT_CLOSE_REQUEST);
+ }
E = F;
}
}
@@ -4228,8 +4279,26 @@ 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_
+ ERR_FAIL_COND(!Thread::is_main_thread());
+
+ _THREAD_SAFE_LOCK_
#ifdef DISPLAY_SERVER_X11_DEBUG_LOGS_ENABLED
static int frame = 0;
@@ -4472,6 +4541,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;
@@ -4499,8 +4569,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?
@@ -4666,19 +4736,6 @@ void DisplayServerX11::process_events() {
break;
}
- const WindowData &wd = windows[window_id];
-
- XWindowAttributes xwa;
- XSync(x11_display, False);
- XGetWindowAttributes(x11_display, wd.x11_window, &xwa);
-
- // 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);
- }
-
_window_changed(&event);
} break;
@@ -4705,12 +4762,20 @@ void DisplayServerX11::process_events() {
} else if (mb->get_button_index() == MouseButton::MIDDLE) {
mb->set_button_index(MouseButton::RIGHT);
}
- 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 (mb->is_pressed() && mb->get_button_index() >= MouseButton::WHEEL_UP && mb->get_button_index() <= MouseButton::WHEEL_RIGHT) {
+ MouseButtonMask mask = mouse_button_to_mask(mb->get_button_index());
+ BitField<MouseButtonMask> scroll_mask = mouse_get_button_state();
+ scroll_mask.set_flag(mask);
+ mb->set_button_mask(scroll_mask);
+ } else {
+ mb->set_button_mask(mouse_get_button_state());
+ }
+
const WindowData &wd = windows[window_id];
if (event.type == ButtonPress) {
@@ -4720,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;
@@ -4893,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;
@@ -4963,8 +5030,15 @@ void DisplayServerX11::process_events() {
files.write[i] = files[i].replace("file://", "").uri_decode();
}
- if (!windows[window_id].drop_files_callback.is_null()) {
- windows[window_id].drop_files_callback.call(files);
+ if (windows[window_id].drop_files_callback.is_valid()) {
+ Variant v_files = files;
+ const Variant *v_args[1] = { &v_files };
+ Variant ret;
+ Callable::CallError ce;
+ windows[window_id].drop_files_callback.callp((const Variant **)&v_args, 1, ret, ce);
+ if (ce.error != Callable::CallError::CALL_OK) {
+ ERR_PRINT(vformat("Failed to execute drop files callback: %s.", Variant::get_callable_error_text(windows[window_id].drop_files_callback, v_args, 1, ce)));
+ }
}
//Reply that all is well.
@@ -5068,6 +5142,14 @@ void DisplayServerX11::process_events() {
*/
}
+#ifdef DBUS_ENABLED
+ if (portal_desktop) {
+ portal_desktop->process_file_dialog_callbacks();
+ }
+#endif
+
+ _THREAD_SAFE_UNLOCK_
+
Input::get_singleton()->flush_buffered_events();
}
@@ -5082,17 +5164,6 @@ void DisplayServerX11::release_rendering_thread() {
#endif
}
-void DisplayServerX11::make_rendering_thread() {
-#if defined(GLES3_ENABLED)
- if (gl_manager) {
- gl_manager->make_current();
- }
- if (gl_manager_egl) {
- gl_manager_egl->make_current();
- }
-#endif
-}
-
void DisplayServerX11::swap_buffers() {
#if defined(GLES3_ENABLED)
if (gl_manager) {
@@ -5151,6 +5222,23 @@ void DisplayServerX11::set_context(Context p_context) {
}
}
+bool DisplayServerX11::is_window_transparency_available() const {
+ CharString net_wm_cm_name = vformat("_NET_WM_CM_S%d", XDefaultScreen(x11_display)).ascii();
+ Atom net_wm_cm = XInternAtom(x11_display, net_wm_cm_name.get_data(), False);
+ if (net_wm_cm == None) {
+ return false;
+ }
+ if (XGetSelectionOwner(x11_display, net_wm_cm) == None) {
+ return false;
+ }
+#if defined(RD_ENABLED)
+ if (rendering_device && !rendering_device->is_composite_alpha_supported()) {
+ return false;
+ }
+#endif
+ return OS::get_singleton()->is_layered_allowed();
+}
+
void DisplayServerX11::set_native_icon(const String &p_filename) {
WARN_PRINT("Native icon not supported by this display server.");
}
@@ -5183,7 +5271,7 @@ void DisplayServerX11::set_icon(const Ref<Image> &p_icon) {
if (g_set_icon_error) {
g_set_icon_error = false;
- WARN_PRINT("Icon too large, attempting to resize icon.");
+ WARN_PRINT(vformat("Icon too large (%dx%d), attempting to downscale icon.", w, h));
int new_width, new_height;
if (w > h) {
@@ -5244,9 +5332,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
@@ -5262,9 +5350,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)
@@ -5292,8 +5380,8 @@ Vector<String> DisplayServerX11::get_rendering_drivers_func() {
return drivers;
}
-DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error) {
- DisplayServer *ds = memnew(DisplayServerX11(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, p_screen, r_error));
+DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, Error &r_error) {
+ DisplayServer *ds = memnew(DisplayServerX11(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, p_screen, p_context, r_error));
if (r_error != OK) {
if (p_rendering_driver == "vulkan") {
String executable_name = OS::get_singleton()->get_executable_path().get_file();
@@ -5422,8 +5510,7 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V
} else {
Rect2i srect = screen_get_usable_rect(rq_screen);
Point2i wpos = p_rect.position;
- wpos.x = CLAMP(wpos.x, srect.position.x, srect.position.x + srect.size.width - p_rect.size.width / 3);
- wpos.y = CLAMP(wpos.y, srect.position.y, srect.position.y + srect.size.height - p_rect.size.height / 3);
+ wpos = wpos.clamp(srect.position, srect.position + srect.size - p_rect.size / 3);
win_rect.position = wpos;
}
@@ -5606,10 +5693,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
@@ -5711,9 +5812,12 @@ static ::XIMStyle _get_best_xim_style(const ::XIMStyle &p_style_a, const ::XIMSt
return p_style_a;
}
-DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error) {
+DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, Error &r_error) {
KeyMappingX11::initialize();
+ native_menu = memnew(NativeMenu);
+ context = p_context;
+
#ifdef SOWRAP_ENABLED
#ifdef DEBUG_ENABLED
int dylibloader_verbose = 1;
@@ -6008,14 +6112,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;
}
@@ -6065,33 +6175,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;
@@ -6105,7 +6218,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));
@@ -6120,11 +6234,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();
}
@@ -6296,11 +6410,20 @@ DisplayServerX11::~DisplayServerX11() {
events_thread_done.set();
events_thread.wait_to_finish();
+ if (native_menu) {
+ memdelete(native_menu);
+ native_menu = nullptr;
+ }
+
//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
@@ -6342,16 +6465,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