diff options
Diffstat (limited to 'platform/linuxbsd/x11/display_server_x11.cpp')
-rw-r--r-- | platform/linuxbsd/x11/display_server_x11.cpp | 177 |
1 files changed, 119 insertions, 58 deletions
diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp index 9174b65b1b..0e4c723a87 100644 --- a/platform/linuxbsd/x11/display_server_x11.cpp +++ b/platform/linuxbsd/x11/display_server_x11.cpp @@ -502,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) { @@ -1007,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); } @@ -1068,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); @@ -1097,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)); } } @@ -1503,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); @@ -1531,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)); } } @@ -2256,7 +2296,7 @@ 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 @@ -2531,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; @@ -3068,8 +3108,7 @@ void DisplayServerX11::cursor_set_custom_image(const Ref<Resource> &p_cursor, Cu cursors_cache.erase(p_shape); } - Rect2 atlas_rect; - Ref<Image> image = _get_cursor_image_from_resource(p_cursor, p_hotspot, atlas_rect); + Ref<Image> image = _get_cursor_image_from_resource(p_cursor, p_hotspot); ERR_FAIL_COND(image.is_null()); Vector2i texture_size = image->get_size(); @@ -3087,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_rect.has_area()) { - 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(); } @@ -3338,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 @@ -4162,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(); @@ -4193,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; } } @@ -4734,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) { @@ -4995,7 +5031,14 @@ void DisplayServerX11::process_events() { } if (windows[window_id].drop_files_callback.is_valid()) { - windows[window_id].drop_files_callback.call(files); + 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. @@ -5179,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."); } @@ -5320,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(); @@ -5752,10 +5812,11 @@ 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 |