diff options
Diffstat (limited to 'platform/linuxbsd/display_server_x11.cpp')
-rw-r--r-- | platform/linuxbsd/display_server_x11.cpp | 428 |
1 files changed, 294 insertions, 134 deletions
diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp index 5829711698..66dea6cf1b 100644 --- a/platform/linuxbsd/display_server_x11.cpp +++ b/platform/linuxbsd/display_server_x11.cpp @@ -196,6 +196,7 @@ bool DisplayServerX11::_refresh_device_info() { xi.absolute_devices.clear(); xi.touch_devices.clear(); + xi.pen_inverted_devices.clear(); int dev_count; XIDeviceInfo *info = XIQueryDevice(x11_display, XIAllDevices, &dev_count); @@ -205,7 +206,7 @@ bool DisplayServerX11::_refresh_device_info() { if (!dev->enabled) { continue; } - if (!(dev->use == XIMasterPointer || dev->use == XIFloatingSlave)) { + if (!(dev->use == XISlavePointer || dev->use == XIFloatingSlave)) { continue; } @@ -274,6 +275,7 @@ bool DisplayServerX11::_refresh_device_info() { xi.pen_pressure_range[dev->deviceid] = Vector2(pressure_min, pressure_max); xi.pen_tilt_x_range[dev->deviceid] = Vector2(tilt_x_min, tilt_x_max); xi.pen_tilt_y_range[dev->deviceid] = Vector2(tilt_y_min, tilt_y_max); + xi.pen_inverted_devices[dev->deviceid] = String(dev->name).findn("eraser") > 0; } XIFreeDeviceInfo(info); @@ -320,8 +322,8 @@ bool DisplayServerX11::tts_is_paused() const { return tts->is_paused(); } -Array DisplayServerX11::tts_get_voices() const { - ERR_FAIL_COND_V(!tts, Array()); +TypedArray<Dictionary> DisplayServerX11::tts_get_voices() const { + ERR_FAIL_COND_V(!tts, TypedArray<Dictionary>()); return tts->get_voices(); } @@ -347,6 +349,28 @@ void DisplayServerX11::tts_stop() { #endif +#ifdef DBUS_ENABLED + +bool DisplayServerX11::is_dark_mode_supported() const { + return portal_desktop->is_supported(); +} + +bool DisplayServerX11::is_dark_mode() const { + switch (portal_desktop->get_appearance_color_scheme()) { + case 1: + // Prefers dark theme. + return true; + case 2: + // Prefers light theme. + return false; + default: + // Preference unknown. + return false; + } +} + +#endif + void DisplayServerX11::mouse_set_mode(MouseMode p_mode) { _THREAD_SAFE_METHOD_ @@ -373,7 +397,10 @@ void DisplayServerX11::mouse_set_mode(MouseMode p_mode) { if (mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED || mouse_mode == MOUSE_MODE_CONFINED_HIDDEN) { //flush pending motion events _flush_mouse_motion(); - WindowID window_id = windows.has(last_focused_window) ? last_focused_window : MAIN_WINDOW_ID; + WindowID window_id = _get_focused_window_or_popup(); + if (!windows.has(window_id)) { + window_id = MAIN_WINDOW_ID; + } WindowData &window = windows[window_id]; if (XGrabPointer( @@ -409,7 +436,11 @@ void DisplayServerX11::warp_mouse(const Point2i &p_position) { if (mouse_mode == MOUSE_MODE_CAPTURED) { last_mouse_pos = p_position; } else { - WindowID window_id = windows.has(last_focused_window) ? last_focused_window : MAIN_WINDOW_ID; + WindowID window_id = _get_focused_window_or_popup(); + if (!windows.has(window_id)) { + window_id = MAIN_WINDOW_ID; + } + XWarpPointer(x11_display, None, windows[window_id].x11_window, 0, 0, 0, 0, (int)p_position.x, (int)p_position.y); } @@ -991,7 +1022,7 @@ Rect2i DisplayServerX11::screen_get_usable_rect(int p_screen) const { Rect2i left_rect(pos.x, pos.y + left_start_y, left, left_end_y - left_start_y); if (left_rect.size.x > 0) { Rect2i intersection = rect.intersection(left_rect); - if (!intersection.has_no_area() && intersection.size.x < rect.size.x) { + if (intersection.has_area() && intersection.size.x < rect.size.x) { rect.position.x = left_rect.size.x; rect.size.x = rect.size.x - intersection.size.x; } @@ -1000,7 +1031,7 @@ Rect2i DisplayServerX11::screen_get_usable_rect(int p_screen) const { Rect2i right_rect(pos.x + size.x - right, pos.y + right_start_y, right, right_end_y - right_start_y); if (right_rect.size.x > 0) { Rect2i intersection = rect.intersection(right_rect); - if (!intersection.has_no_area() && right_rect.size.x < rect.size.x) { + if (intersection.has_area() && right_rect.size.x < rect.size.x) { rect.size.x = intersection.position.x - rect.position.x; } } @@ -1008,7 +1039,7 @@ Rect2i DisplayServerX11::screen_get_usable_rect(int p_screen) const { Rect2i top_rect(pos.x + top_start_x, pos.y, top_end_x - top_start_x, top); if (top_rect.size.y > 0) { Rect2i intersection = rect.intersection(top_rect); - if (!intersection.has_no_area() && intersection.size.y < rect.size.y) { + if (intersection.has_area() && intersection.size.y < rect.size.y) { rect.position.y = top_rect.size.y; rect.size.y = rect.size.y - intersection.size.y; } @@ -1017,7 +1048,7 @@ Rect2i DisplayServerX11::screen_get_usable_rect(int p_screen) const { Rect2i bottom_rect(pos.x + bottom_start_x, pos.y + size.y - bottom, bottom_end_x - bottom_start_x, bottom); if (bottom_rect.size.y > 0) { Rect2i intersection = rect.intersection(bottom_rect); - if (!intersection.has_no_area() && right_rect.size.y < rect.size.y) { + if (intersection.has_area() && right_rect.size.y < rect.size.y) { rect.size.y = intersection.position.y - rect.position.y; } } @@ -1255,7 +1286,7 @@ void DisplayServerX11::delete_sub_window(WindowID p_id) { DEBUG_LOG_X11("delete_sub_window: %lu (%u) \n", wd.x11_window, p_id); while (wd.transient_children.size()) { - window_set_transient(wd.transient_children.front()->get(), INVALID_WINDOW_ID); + window_set_transient(*wd.transient_children.begin(), INVALID_WINDOW_ID); } if (wd.transient_parent != INVALID_WINDOW_ID) { @@ -1487,8 +1518,8 @@ void DisplayServerX11::window_set_current_screen(int p_screen, WindowID p_window 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); + Vector2 ofs = window_get_position(p_window) - screen_get_position(window_get_current_screen(p_window)); + window_set_position(ofs + screen_get_position(p_screen), p_window); } } } @@ -1520,11 +1551,15 @@ void DisplayServerX11::window_set_transient(WindowID p_window, WindowID p_parent XSetTransientForHint(x11_display, wd_window.x11_window, None); + XWindowAttributes xwa; + XSync(x11_display, False); + XGetWindowAttributes(x11_display, wd_parent.x11_window, &xwa); + // Set focus to parent sub window to avoid losing all focus when closing a nested sub-menu. // 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 (!wd_parent.no_focus && !wd_window.is_popup) { + if ((xwa.map_state == IsViewable) && !wd_parent.no_focus && !wd_window.is_popup) { XSetInputFocus(x11_display, wd_parent.x11_window, RevertToPointerRoot, CurrentTime); } } @@ -1817,6 +1852,105 @@ bool DisplayServerX11::_window_maximize_check(WindowID p_window, const char *p_a return retval; } +bool DisplayServerX11::_window_minimize_check(WindowID p_window) const { + const WindowData &wd = windows[p_window]; + + // Using ICCCM -- Inter-Client Communication Conventions Manual + Atom property = XInternAtom(x11_display, "WM_STATE", True); + if (property == None) { + return false; + } + + Atom type; + int format; + unsigned long len; + unsigned long remaining; + unsigned char *data = nullptr; + + int result = XGetWindowProperty( + x11_display, + wd.x11_window, + property, + 0, + 32, + False, + AnyPropertyType, + &type, + &format, + &len, + &remaining, + &data); + + if (result == Success && data) { + long *state = (long *)data; + if (state[0] == WM_IconicState) { + XFree(data); + return true; + } + XFree(data); + } + + return false; +} + +bool DisplayServerX11::_window_fullscreen_check(WindowID p_window) const { + ERR_FAIL_COND_V(!windows.has(p_window), false); + const WindowData &wd = windows[p_window]; + + // 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 = nullptr; + bool retval = false; + + if (property == None) { + return retval; + } + + 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_fullscreen = XInternAtom(x11_display, "_NET_WM_STATE_FULLSCREEN", False); + for (uint64_t i = 0; i < len; i++) { + if (atoms[i] == wm_fullscreen) { + retval = true; + break; + } + } + XFree(data); + } + + return retval; +} + +void DisplayServerX11::_validate_mode_on_map(WindowID p_window) { + // Check if we applied any window modes that didn't take effect while unmapped + const WindowData &wd = windows[p_window]; + if (wd.fullscreen && !_window_fullscreen_check(p_window)) { + _set_wm_fullscreen(p_window, true); + } else if (wd.maximized && !_window_maximize_check(p_window, "_NET_WM_STATE")) { + _set_wm_maximized(p_window, true); + } else if (wd.minimized && !_window_minimize_check(p_window)) { + _set_wm_minimized(p_window, true); + } +} + bool DisplayServerX11::window_is_maximize_allowed(WindowID p_window) const { _THREAD_SAFE_METHOD_ return _window_maximize_check(p_window, "_NET_WM_ALLOWED_ACTIONS"); @@ -1851,6 +1985,37 @@ void DisplayServerX11::_set_wm_maximized(WindowID p_window, bool p_enabled) { usleep(10000); } } + wd.maximized = p_enabled; +} + +void DisplayServerX11::_set_wm_minimized(WindowID p_window, bool p_enabled) { + WindowData &wd = windows[p_window]; + // 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] = p_enabled ? WM_IconicState : 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] = p_enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE; + xev.xclient.data.l[1] = wm_hidden; + + XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); + wd.minimized = p_enabled; } void DisplayServerX11::_set_wm_fullscreen(WindowID p_window, bool p_enabled) { @@ -1932,32 +2097,7 @@ void DisplayServerX11::window_set_mode(WindowMode p_mode, WindowID p_window) { //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); + _set_wm_minimized(p_window, false); } break; case WINDOW_MODE_EXCLUSIVE_FULLSCREEN: case WINDOW_MODE_FULLSCREEN: { @@ -1986,31 +2126,7 @@ void DisplayServerX11::window_set_mode(WindowMode p_mode, WindowID p_window) { //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); + _set_wm_minimized(p_window, true); } break; case WINDOW_MODE_EXCLUSIVE_FULLSCREEN: case WINDOW_MODE_FULLSCREEN: { @@ -2045,40 +2161,9 @@ DisplayServer::WindowMode DisplayServerX11::window_get_mode(WindowID p_window) c return WINDOW_MODE_MAXIMIZED; } - { // Test minimized. - // Using ICCCM -- Inter-Client Communication Conventions Manual - Atom property = XInternAtom(x11_display, "WM_STATE", True); - if (property == None) { - return WINDOW_MODE_WINDOWED; - } - - Atom type; - int format; - unsigned long len; - unsigned long remaining; - unsigned char *data = nullptr; - - int result = XGetWindowProperty( - x11_display, - wd.x11_window, - property, - 0, - 32, - False, - AnyPropertyType, - &type, - &format, - &len, - &remaining, - &data); - - if (result == Success && data) { - long *state = (long *)data; - if (state[0] == WM_IconicState) { - XFree(data); - return WINDOW_MODE_MINIMIZED; - } - XFree(data); + { + if (_window_minimize_check(p_window)) { + return WINDOW_MODE_MINIMIZED; } } @@ -2143,7 +2228,7 @@ void DisplayServerX11::window_set_flag(WindowFlags p_flag, bool p_enabled, Windo } break; case WINDOW_FLAG_TRANSPARENT: { - //todo reimplement + wd.layered_window = p_enabled; } break; case WINDOW_FLAG_NO_FOCUS: { wd.no_focus = p_enabled; @@ -2196,7 +2281,7 @@ bool DisplayServerX11::window_get_flag(WindowFlags p_flag, WindowID p_window) co return wd.on_top; } break; case WINDOW_FLAG_TRANSPARENT: { - //todo reimplement + return wd.layered_window; } break; case WINDOW_FLAG_NO_FOCUS: { return wd.no_focus; @@ -3099,10 +3184,19 @@ void DisplayServerX11::_window_changed(XEvent *event) { Variant *rectp = ▭ Variant ret; Callable::CallError ce; - wd.rect_changed_callback.call((const Variant **)&rectp, 1, ret, ce); + wd.rect_changed_callback.callp((const Variant **)&rectp, 1, ret, ce); } } +DisplayServer::WindowID DisplayServerX11::_get_focused_window_or_popup() const { + const List<WindowID>::Element *E = popup_list.back(); + if (E) { + return E->get(); + } + + return last_focused_window; +} + void DisplayServerX11::_dispatch_input_events(const Ref<InputEvent> &p_event) { static_cast<DisplayServerX11 *>(get_singleton())->_dispatch_input_event(p_event); } @@ -3120,7 +3214,7 @@ void DisplayServerX11::_dispatch_input_event(const Ref<InputEvent> &p_event) { if (windows.has(E->get())) { Callable callable = windows[E->get()].input_event_callback; if (callable.is_valid()) { - callable.call((const Variant **)&evp, 1, ret, ce); + callable.callp((const Variant **)&evp, 1, ret, ce); } } return; @@ -3133,7 +3227,7 @@ void DisplayServerX11::_dispatch_input_event(const Ref<InputEvent> &p_event) { if (windows.has(event_from_window->get_window_id())) { Callable callable = windows[event_from_window->get_window_id()].input_event_callback; if (callable.is_valid()) { - callable.call((const Variant **)&evp, 1, ret, ce); + callable.callp((const Variant **)&evp, 1, ret, ce); } } } else { @@ -3141,7 +3235,7 @@ void DisplayServerX11::_dispatch_input_event(const Ref<InputEvent> &p_event) { for (KeyValue<WindowID, WindowData> &E : windows) { Callable callable = E.value.input_event_callback; if (callable.is_valid()) { - callable.call((const Variant **)&evp, 1, ret, ce); + callable.callp((const Variant **)&evp, 1, ret, ce); } } } @@ -3153,7 +3247,7 @@ void DisplayServerX11::_send_window_event(const WindowData &wd, WindowEvent p_ev Variant *eventp = &event; Variant ret; Callable::CallError ce; - wd.event_callback.call((const Variant **)&eventp, 1, ret, ce); + wd.event_callback.callp((const Variant **)&eventp, 1, ret, ce); } } @@ -3298,19 +3392,20 @@ void DisplayServerX11::popup_close(WindowID p_window) { } } -void DisplayServerX11::mouse_process_popups() { +bool DisplayServerX11::mouse_process_popups() { _THREAD_SAFE_METHOD_ if (popup_list.is_empty()) { - return; + return false; } uint64_t delta = OS::get_singleton()->get_ticks_msec() - time_since_popup; if (delta < 250) { - return; + return false; } int number_of_screens = XScreenCount(x11_display); + bool closed = false; for (int i = 0; i < number_of_screens; i++) { Window root, child; int root_x, root_y, win_x, win_y; @@ -3340,6 +3435,7 @@ void DisplayServerX11::mouse_process_popups() { } if (C) { _send_window_event(windows[C->get()], DisplayServerX11::WINDOW_EVENT_CLOSE_REQUEST); + closed = true; } } } @@ -3347,6 +3443,7 @@ void DisplayServerX11::mouse_process_popups() { last_mouse_monitor_pos = pos; } } + return closed; } void DisplayServerX11::process_events() { @@ -3357,7 +3454,7 @@ void DisplayServerX11::process_events() { ++frame; #endif - mouse_process_popups(); + bool ignore_events = mouse_process_popups(); if (app_focused) { //verify that one of the windows has focus, else send focus out notification @@ -3407,6 +3504,10 @@ void DisplayServerX11::process_events() { for (uint32_t event_index = 0; event_index < events.size(); ++event_index) { XEvent &event = events[event_index]; + if (ignore_events) { + XFreeEventData(x11_display, &event.xcookie); + continue; + } WindowID window_id = MAIN_WINDOW_ID; @@ -3431,7 +3532,7 @@ void DisplayServerX11::process_events() { } break; case XI_RawMotion: { XIRawEvent *raw_event = (XIRawEvent *)event_data; - int device_id = raw_event->deviceid; + int device_id = raw_event->sourceid; // Determine the axis used (called valuators in XInput for some forsaken reason) // Mask is a bitmask indicating which axes are involved. @@ -3497,6 +3598,11 @@ void DisplayServerX11::process_events() { values++; } + HashMap<int, bool>::Iterator pen_inverted = xi.pen_inverted_devices.find(device_id); + if (pen_inverted) { + xi.pen_inverted = pen_inverted->value; + } + // 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) { @@ -3586,17 +3692,26 @@ void DisplayServerX11::process_events() { 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 started. // 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) { + if ((xwa.map_state == IsViewable) && !wd.no_focus && !wd.is_popup) { XSetInputFocus(x11_display, wd.x11_window, RevertToPointerRoot, CurrentTime); } + + // Have we failed to set fullscreen while the window was unmapped? + _validate_mode_on_map(window_id); } break; case Expose: { DEBUG_LOG_X11("[%u] Expose window=%lu (%u), count='%u' \n", frame, event.xexpose.window, window_id, event.xexpose.count); + windows[window_id].fullscreen = _window_fullscreen_check(window_id); + Main::force_redraw(); } break; @@ -3609,8 +3724,7 @@ void DisplayServerX11::process_events() { case VisibilityNotify: { DEBUG_LOG_X11("[%u] VisibilityNotify window=%lu (%u), state=%u \n", frame, event.xvisibility.window, window_id, event.xvisibility.state); - XVisibilityEvent *visibility = (XVisibilityEvent *)&event; - windows[window_id].minimized = (visibility->state == VisibilityFullyObscured); + windows[window_id].minimized = _window_minimize_check(window_id); } break; case LeaveNotify: { @@ -3838,7 +3952,11 @@ void DisplayServerX11::process_events() { // 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. - WindowID focused_window_id = windows.has(last_focused_window) ? last_focused_window : MAIN_WINDOW_ID; + WindowID focused_window_id = _get_focused_window_or_popup(); + if (!windows.has(focused_window_id)) { + focused_window_id = MAIN_WINDOW_ID; + } + while (true) { if (mouse_mode == MOUSE_MODE_CAPTURED && event.xmotion.x == windows[focused_window_id].size.width / 2 && event.xmotion.y == windows[focused_window_id].size.height / 2) { //this is likely the warp event since it was warped here @@ -3929,6 +4047,7 @@ void DisplayServerX11::process_events() { mm->set_pressure(bool(mouse_get_button_state() & MouseButton::MASK_LEFT) ? 1.0f : 0.0f); } mm->set_tilt(xi.tilt); + mm->set_pen_inverted(xi.pen_inverted); _get_key_modifier_state(event.xmotion.state, mm); mm->set_button_mask((MouseButton)mouse_get_button_state()); @@ -4005,7 +4124,7 @@ void DisplayServerX11::process_events() { Variant *vp = &v; Variant ret; Callable::CallError ce; - windows[window_id].drop_files_callback.call((const Variant **)&vp, 1, ret, ce); + windows[window_id].drop_files_callback.callp((const Variant **)&vp, 1, ret, ce); } //Reply that all is well. @@ -4112,13 +4231,17 @@ void DisplayServerX11::process_events() { void DisplayServerX11::release_rendering_thread() { #if defined(GLES3_ENABLED) - gl_manager->release_current(); + if (gl_manager) { + gl_manager->release_current(); + } #endif } void DisplayServerX11::make_rendering_thread() { #if defined(GLES3_ENABLED) - gl_manager->make_current(); + if (gl_manager) { + gl_manager->make_current(); + } #endif } @@ -4323,13 +4446,41 @@ DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, W DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) { //Create window - long visualMask = VisualScreenMask; - int numberOfVisuals; - XVisualInfo vInfoTemplate = {}; - vInfoTemplate.screen = DefaultScreen(x11_display); - XVisualInfo *visualInfo = XGetVisualInfo(x11_display, visualMask, &vInfoTemplate, &numberOfVisuals); + XVisualInfo visualInfo; + bool vi_selected = false; - Colormap colormap = XCreateColormap(x11_display, RootWindow(x11_display, vInfoTemplate.screen), visualInfo->visual, AllocNone); +#ifdef GLES3_ENABLED + if (gl_manager) { + visualInfo = gl_manager->get_vi(x11_display); + vi_selected = true; + } +#endif + + if (!vi_selected) { + long visualMask = VisualScreenMask; + int numberOfVisuals; + XVisualInfo vInfoTemplate = {}; + vInfoTemplate.screen = DefaultScreen(x11_display); + XVisualInfo *vi_list = XGetVisualInfo(x11_display, visualMask, &vInfoTemplate, &numberOfVisuals); + ERR_FAIL_COND_V(!vi_list, INVALID_WINDOW_ID); + + visualInfo = vi_list[0]; + if (OS::get_singleton()->is_layered_allowed()) { + for (int i = 0; i < numberOfVisuals; i++) { + XRenderPictFormat *pict_format = XRenderFindVisualFormat(x11_display, vi_list[i].visual); + if (!pict_format) { + continue; + } + visualInfo = vi_list[i]; + if (pict_format->direct.alphaMask > 0) { + break; + } + } + } + XFree(vi_list); + } + + Colormap colormap = XCreateColormap(x11_display, RootWindow(x11_display, visualInfo.screen), visualInfo.visual, AllocNone); XSetWindowAttributes windowAttributes = {}; windowAttributes.colormap = colormap; @@ -4339,6 +4490,13 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V unsigned long valuemask = CWBorderPixel | CWColormap | CWEventMask; + if (OS::get_singleton()->is_layered_allowed()) { + windowAttributes.background_pixmap = None; + windowAttributes.background_pixel = 0; + windowAttributes.border_pixmap = None; + valuemask |= CWBackPixel; + } + WindowID id = window_id_counter++; WindowData &wd = windows[id]; @@ -4362,7 +4520,7 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V } { - wd.x11_window = XCreateWindow(x11_display, RootWindow(x11_display, visualInfo->screen), p_rect.position.x, p_rect.position.y, p_rect.size.width > 0 ? p_rect.size.width : 1, p_rect.size.height > 0 ? p_rect.size.height : 1, 0, visualInfo->depth, InputOutput, visualInfo->visual, valuemask, &windowAttributes); + wd.x11_window = XCreateWindow(x11_display, RootWindow(x11_display, visualInfo.screen), p_rect.position.x, p_rect.position.y, p_rect.size.width > 0 ? p_rect.size.width : 1, p_rect.size.height > 0 ? p_rect.size.height : 1, 0, visualInfo.depth, InputOutput, visualInfo.visual, valuemask, &windowAttributes); // Enable receiving notification when the window is initialized (MapNotify) // so the focus can be set at the right time. @@ -4499,8 +4657,6 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V XSync(x11_display, False); //XSetErrorHandler(oldHandler); - - XFree(visualInfo); } window_set_mode(p_mode, id); @@ -4764,6 +4920,8 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode } } show_window(main_window); + XSync(x11_display, False); + _validate_mode_on_map(main_window); #if defined(VULKAN_ENABLED) if (rendering_driver == "vulkan") { @@ -4910,21 +5068,22 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode } cursor_set_shape(CURSOR_BUSY); - XEvent xevent; - while (XPending(x11_display) > 0) { - XNextEvent(x11_display, &xevent); - if (xevent.type == ConfigureNotify) { - _window_changed(&xevent); - } + // Search the X11 event queue for ConfigureNotify events and process all + // that are currently queued early, so we can get the final window size + // for correctly drawing of the bootsplash. + XEvent config_event; + while (XCheckTypedEvent(x11_display, ConfigureNotify, &config_event)) { + _window_changed(&config_event); } - events_thread.start(_poll_events_thread, this); _update_real_mouse_position(windows[MAIN_WINDOW_ID]); #ifdef DBUS_ENABLED screensaver = memnew(FreeDesktopScreenSaver); - screen_set_keep_on(GLOBAL_DEF("display/window/energy_saving/keep_screen_on", true)); + screen_set_keep_on(GLOBAL_GET("display/window/energy_saving/keep_screen_on")); + + portal_desktop = memnew(FreeDesktopPortalDesktop); #endif r_error = OK; @@ -5010,6 +5169,7 @@ DisplayServerX11::~DisplayServerX11() { #ifdef DBUS_ENABLED memdelete(screensaver); + memdelete(portal_desktop); #endif } |