diff options
Diffstat (limited to 'platform/linuxbsd')
-rw-r--r-- | platform/linuxbsd/detect.py | 24 | ||||
-rw-r--r-- | platform/linuxbsd/display_server_x11.cpp | 254 | ||||
-rw-r--r-- | platform/linuxbsd/display_server_x11.h | 26 | ||||
-rw-r--r-- | platform/linuxbsd/export/export.cpp | 121 | ||||
-rw-r--r-- | platform/linuxbsd/export/export_plugin.cpp | 200 | ||||
-rw-r--r-- | platform/linuxbsd/export/export_plugin.h | 52 | ||||
-rw-r--r-- | platform/linuxbsd/gl_manager_x11.h | 15 | ||||
-rw-r--r-- | platform/linuxbsd/godot_linuxbsd.cpp | 10 | ||||
-rw-r--r-- | platform/linuxbsd/joypad_linux.cpp | 2 | ||||
-rw-r--r-- | platform/linuxbsd/os_linuxbsd.cpp | 63 | ||||
-rw-r--r-- | platform/linuxbsd/os_linuxbsd.h | 2 |
11 files changed, 540 insertions, 229 deletions
diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py index ab643b254a..39f9b99108 100644 --- a/platform/linuxbsd/detect.py +++ b/platform/linuxbsd/detect.py @@ -115,7 +115,7 @@ def configure(env): ## Architecture - is64 = sys.maxsize > 2 ** 32 + is64 = sys.maxsize > 2**32 if env["bits"] == "default": env["bits"] = "64" if is64 else "32" @@ -162,6 +162,7 @@ def configure(env): if env["use_ubsan"] or env["use_asan"] or env["use_lsan"] or env["use_tsan"] or env["use_msan"]: env.extra_suffix += ".san" + env.Append(CCFLAGS=["-DSANITIZERS_ENABLED"]) if env["use_ubsan"]: env.Append( @@ -261,27 +262,6 @@ def configure(env): if not env["builtin_libpng"]: env.ParseConfig("pkg-config libpng16 --cflags --libs") - if not env["builtin_bullet"]: - # We need at least version 2.90 - min_bullet_version = "2.90" - - import subprocess - - bullet_version = subprocess.check_output(["pkg-config", "bullet", "--modversion"]).strip() - if str(bullet_version) < min_bullet_version: - # Abort as system bullet was requested but too old - print( - "Bullet: System version {0} does not match minimal requirements ({1}). Aborting.".format( - bullet_version, min_bullet_version - ) - ) - sys.exit(255) - env.ParseConfig("pkg-config bullet --cflags --libs") - - if False: # not env['builtin_assimp']: - # FIXME: Add min version check - env.ParseConfig("pkg-config assimp --cflags --libs") - if not env["builtin_enet"]: env.ParseConfig("pkg-config libenet --cflags --libs") diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp index 56663b0623..acc7d1bc30 100644 --- a/platform/linuxbsd/display_server_x11.cpp +++ b/platform/linuxbsd/display_server_x11.cpp @@ -109,6 +109,15 @@ struct Hints { unsigned long status = 0; }; +static String get_atom_name(Display *p_disp, Atom p_atom) { + char *name = XGetAtomName(p_disp, p_atom); + ERR_FAIL_NULL_V_MSG(name, String(), "Atom is invalid."); + String ret; + ret.parse_utf8(name); + XFree(name); + return ret; +} + bool DisplayServerX11::has_feature(Feature p_feature) const { switch (p_feature) { case FEATURE_SUBWINDOWS: @@ -354,15 +363,15 @@ DisplayServerX11::MouseMode DisplayServerX11::mouse_get_mode() const { return mouse_mode; } -void DisplayServerX11::mouse_warp_to_position(const Point2i &p_to) { +void DisplayServerX11::warp_mouse(const Point2i &p_position) { _THREAD_SAFE_METHOD_ if (mouse_mode == MOUSE_MODE_CAPTURED) { - last_mouse_pos = p_to; + last_mouse_pos = p_position; } else { WindowID window_id = windows.has(last_focused_window) ? last_focused_window : MAIN_WINDOW_ID; XWarpPointer(x11_display, None, windows[window_id].x11_window, - 0, 0, 0, 0, (int)p_to.x, (int)p_to.y); + 0, 0, 0, 0, (int)p_position.x, (int)p_position.y); } } @@ -435,7 +444,7 @@ String DisplayServerX11::_clipboard_get_impl(Atom p_source, Window x11_window, A Window selection_owner = XGetSelectionOwner(x11_display, p_source); if (selection_owner == x11_window) { static const char *target_type = "PRIMARY"; - if (p_source != None && String(XGetAtomName(x11_display, p_source)) == target_type) { + if (p_source != None && get_atom_name(x11_display, p_source) == target_type) { return internal_clipboard_primary; } else { return internal_clipboard; @@ -1186,6 +1195,7 @@ void DisplayServerX11::show_window(WindowID p_id) { _THREAD_SAFE_METHOD_ const WindowData &wd = windows[p_id]; + popup_open(p_id); DEBUG_LOG_X11("show_window: %lu (%u) \n", wd.x11_window, p_id); @@ -1196,7 +1206,9 @@ void DisplayServerX11::delete_sub_window(WindowID p_id) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_id)); - ERR_FAIL_COND_MSG(p_id == MAIN_WINDOW_ID, "Main window can't be deleted"); //ma + ERR_FAIL_COND_MSG(p_id == MAIN_WINDOW_ID, "Main window can't be deleted"); + + popup_close(p_id); WindowData &wd = windows[p_id]; @@ -1471,8 +1483,8 @@ void DisplayServerX11::window_set_transient(WindowID p_window, WindowID p_parent // 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.menu_type && !wd_window.no_focus && wd_window.focused) { - if (!wd_parent.no_focus) { + if (!wd_window.no_focus && !wd_window.is_popup && wd_window.focused) { + if (!wd_parent.no_focus && !wd_window.is_popup) { XSetInputFocus(x11_display, wd_parent.x11_window, RevertToPointerRoot, CurrentTime); } } @@ -1733,8 +1745,15 @@ bool DisplayServerX11::_window_maximize_check(WindowID p_window, const char *p_a if (result == Success && data) { Atom *atoms = (Atom *)data; - Atom wm_act_max_horz = XInternAtom(x11_display, "_NET_WM_ACTION_MAXIMIZE_HORZ", False); - Atom wm_act_max_vert = XInternAtom(x11_display, "_NET_WM_ACTION_MAXIMIZE_VERT", False); + Atom wm_act_max_horz; + Atom wm_act_max_vert; + if (strcmp(p_atom_name, "_NET_WM_STATE") == 0) { + wm_act_max_horz = XInternAtom(x11_display, "_NET_WM_STATE_MAXIMIZED_HORZ", False); + wm_act_max_vert = XInternAtom(x11_display, "_NET_WM_STATE_MAXIMIZED_VERT", False); + } else { + wm_act_max_horz = XInternAtom(x11_display, "_NET_WM_ACTION_MAXIMIZE_HORZ", False); + wm_act_max_vert = XInternAtom(x11_display, "_NET_WM_ACTION_MAXIMIZE_VERT", False); + } bool found_wm_act_max_horz = false; bool found_wm_act_max_vert = false; @@ -2086,6 +2105,18 @@ void DisplayServerX11::window_set_flag(WindowFlags p_flag, bool p_enabled, Windo case WINDOW_FLAG_TRANSPARENT: { //todo reimplement } break; + case WINDOW_FLAG_NO_FOCUS: { + wd.no_focus = p_enabled; + } break; + case WINDOW_FLAG_POPUP: { + XWindowAttributes xwa; + XSync(x11_display, False); + XGetWindowAttributes(x11_display, wd.x11_window, &xwa); + + ERR_FAIL_COND_MSG(p_window == MAIN_WINDOW_ID, "Main window can't be popup."); + ERR_FAIL_COND_MSG((xwa.map_state == IsViewable) && (wd.is_popup != p_enabled), "Popup flag can't changed while window is opened."); + wd.is_popup = p_enabled; + } break; default: { } } @@ -2127,6 +2158,12 @@ bool DisplayServerX11::window_get_flag(WindowFlags p_flag, WindowID p_window) co case WINDOW_FLAG_TRANSPARENT: { //todo reimplement } break; + case WINDOW_FLAG_NO_FOCUS: { + return wd.no_focus; + } break; + case WINDOW_FLAG_POPUP: { + return wd.is_popup; + } break; default: { } } @@ -2440,8 +2477,7 @@ String DisplayServerX11::keyboard_get_layout_language(int p_index) const { Atom names = kbd->names->symbols; if (names != None) { - char *name = XGetAtomName(x11_display, names); - Vector<String> info = String(name).split("+"); + Vector<String> info = get_atom_name(x11_display, names).split("+"); if (p_index >= 0 && p_index < _group_count) { if (p_index + 1 < info.size()) { ret = info[p_index + 1]; // Skip "pc" at the start and "inet"/"group" at the end of symbols. @@ -2451,7 +2487,6 @@ String DisplayServerX11::keyboard_get_layout_language(int p_index) const { } else { ERR_PRINT("Index " + itos(p_index) + "is out of bounds (" + itos(_group_count) + ")."); } - XFree(name); } XkbFreeKeyboard(kbd, 0, true); } @@ -2478,9 +2513,7 @@ String DisplayServerX11::keyboard_get_layout_name(int p_index) const { } if (p_index >= 0 && p_index < _group_count) { - char *full_name = XGetAtomName(x11_display, groups[p_index]); - ret.parse_utf8(full_name); - XFree(full_name); + ret = get_atom_name(x11_display, groups[p_index]); } else { ERR_PRINT("Index " + itos(p_index) + "is out of bounds (" + itos(_group_count) + ")."); } @@ -2543,7 +2576,7 @@ static Atom pick_target_from_list(Display *p_display, Atom *p_list, int p_count) for (int i = 0; i < p_count; i++) { Atom atom = p_list[i]; - if (atom != None && String(XGetAtomName(p_display, atom)) == target_type) { + if (atom != None && get_atom_name(p_display, atom) == target_type) { return atom; } } @@ -2552,15 +2585,15 @@ static Atom pick_target_from_list(Display *p_display, Atom *p_list, int p_count) static Atom pick_target_from_atoms(Display *p_disp, Atom p_t1, Atom p_t2, Atom p_t3) { static const char *target_type = "text/uri-list"; - if (p_t1 != None && String(XGetAtomName(p_disp, p_t1)) == target_type) { + if (p_t1 != None && get_atom_name(p_disp, p_t1) == target_type) { return p_t1; } - if (p_t2 != None && String(XGetAtomName(p_disp, p_t2)) == target_type) { + if (p_t2 != None && get_atom_name(p_disp, p_t2) == target_type) { return p_t2; } - if (p_t3 != None && String(XGetAtomName(p_disp, p_t3)) == target_type) { + if (p_t3 != None && get_atom_name(p_disp, p_t3) == target_type) { return p_t3; } @@ -2882,7 +2915,7 @@ Atom DisplayServerX11::_process_selection_request_target(Atom p_target, Window p // is the owner during a selection request. CharString clip; static const char *target_type = "PRIMARY"; - if (p_selection != None && String(XGetAtomName(x11_display, p_selection)) == target_type) { + if (p_selection != None && get_atom_name(x11_display, p_selection) == target_type) { clip = internal_clipboard_primary.utf8(); } else { clip = internal_clipboard.utf8(); @@ -3032,7 +3065,7 @@ void DisplayServerX11::_window_changed(XEvent *event) { } void DisplayServerX11::_dispatch_input_events(const Ref<InputEvent> &p_event) { - ((DisplayServerX11 *)(get_singleton()))->_dispatch_input_event(p_event); + static_cast<DisplayServerX11 *>(get_singleton())->_dispatch_input_event(p_event); } void DisplayServerX11::_dispatch_input_event(const Ref<InputEvent> &p_event) { @@ -3041,23 +3074,36 @@ void DisplayServerX11::_dispatch_input_event(const Ref<InputEvent> &p_event) { Variant ret; Callable::CallError ce; + { + List<WindowID>::Element *E = popup_list.back(); + if (E && Object::cast_to<InputEventKey>(*p_event)) { + // Redirect keyboard input to active popup. + 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); + } + } + return; + } + } + Ref<InputEventFromWindow> event_from_window = p_event; if (event_from_window.is_valid() && event_from_window->get_window_id() != INVALID_WINDOW_ID) { - //send to a window - ERR_FAIL_COND(!windows.has(event_from_window->get_window_id())); - Callable callable = windows[event_from_window->get_window_id()].input_event_callback; - if (callable.is_null()) { - return; + // Send to a single window. + 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.call((const Variant **)&evp, 1, ret, ce); } else { - //send to all windows + // Send to all windows. for (KeyValue<WindowID, WindowData> &E : windows) { Callable callable = E.value.input_event_callback; - if (callable.is_null()) { - continue; + if (callable.is_valid()) { + callable.call((const Variant **)&evp, 1, ret, ce); } - callable.call((const Variant **)&evp, 1, ret, ce); } } } @@ -3073,7 +3119,7 @@ void DisplayServerX11::_send_window_event(const WindowData &wd, WindowEvent p_ev } void DisplayServerX11::_poll_events_thread(void *ud) { - DisplayServerX11 *display_server = (DisplayServerX11 *)ud; + DisplayServerX11 *display_server = static_cast<DisplayServerX11 *>(ud); display_server->_poll_events(); } @@ -3149,6 +3195,121 @@ void DisplayServerX11::_check_pending_events(LocalVector<XEvent> &r_events) { } } +DisplayServer::WindowID DisplayServerX11::window_get_active_popup() const { + const List<WindowID>::Element *E = popup_list.back(); + if (E) { + return E->get(); + } else { + return INVALID_WINDOW_ID; + } +} + +void DisplayServerX11::window_set_popup_safe_rect(WindowID p_window, const Rect2i &p_rect) { + _THREAD_SAFE_METHOD_ + + ERR_FAIL_COND(!windows.has(p_window)); + WindowData &wd = windows[p_window]; + wd.parent_safe_rect = p_rect; +} + +Rect2i DisplayServerX11::window_get_popup_safe_rect(WindowID p_window) const { + _THREAD_SAFE_METHOD_ + + ERR_FAIL_COND_V(!windows.has(p_window), Rect2i()); + const WindowData &wd = windows[p_window]; + return wd.parent_safe_rect; +} + +void DisplayServerX11::popup_open(WindowID p_window) { + _THREAD_SAFE_METHOD_ + + WindowData &wd = windows[p_window]; + if (wd.is_popup) { + // 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(); + while (E) { + if (wd.transient_parent != E->get() || wd.transient_parent == INVALID_WINDOW_ID) { + C = E; + E = E->prev(); + } else { + break; + } + } + if (C) { + _send_window_event(windows[C->get()], DisplayServerX11::WINDOW_EVENT_CLOSE_REQUEST); + } + + time_since_popup = OS::get_singleton()->get_ticks_msec(); + popup_list.push_back(p_window); + } +} + +void DisplayServerX11::popup_close(WindowID p_window) { + _THREAD_SAFE_METHOD_ + + List<WindowID>::Element *E = popup_list.find(p_window); + while (E) { + List<WindowID>::Element *F = E->next(); + WindowID win_id = E->get(); + popup_list.erase(E); + + _send_window_event(windows[win_id], DisplayServerX11::WINDOW_EVENT_CLOSE_REQUEST); + E = F; + } +} + +void DisplayServerX11::mouse_process_popups() { + _THREAD_SAFE_METHOD_ + + if (popup_list.is_empty()) { + return; + } + + uint64_t delta = OS::get_singleton()->get_ticks_msec() - time_since_popup; + if (delta < 250) { + return; + } + + 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)) { + XWindowAttributes root_attrs; + XGetWindowAttributes(x11_display, root, &root_attrs); + Vector2i pos = Vector2i(root_attrs.x + root_x, root_attrs.y + root_y); + if ((pos != last_mouse_monitor_pos) || (mask != last_mouse_monitor_mask)) { + if (((mask & Button1Mask) || (mask & Button2Mask) || (mask & Button3Mask) || (mask & Button4Mask) || (mask & Button5Mask))) { + List<WindowID>::Element *C = nullptr; + List<WindowID>::Element *E = popup_list.back(); + // Find top popup to close. + while (E) { + // Popup window area. + Rect2i win_rect = Rect2i(window_get_position(E->get()), window_get_size(E->get())); + // Area of the parent window, which responsible for opening sub-menu. + Rect2i safe_rect = window_get_popup_safe_rect(E->get()); + if (win_rect.has_point(pos)) { + break; + } else if (safe_rect != Rect2i() && safe_rect.has_point(pos)) { + break; + } else { + C = E; + E = E->prev(); + } + } + if (C) { + _send_window_event(windows[C->get()], DisplayServerX11::WINDOW_EVENT_CLOSE_REQUEST); + } + } + } + last_mouse_monitor_mask = mask; + last_mouse_monitor_pos = pos; + } + } +} + void DisplayServerX11::process_events() { _THREAD_SAFE_METHOD_ @@ -3157,6 +3318,8 @@ void DisplayServerX11::process_events() { ++frame; #endif + mouse_process_popups(); + if (app_focused) { //verify that one of the windows has focus, else send focus out notification bool focus_found = false; @@ -3387,7 +3550,7 @@ 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 (wd.menu_type && !wd.no_focus) { + if (!wd.no_focus && !wd.is_popup) { XSetInputFocus(x11_display, wd.x11_window, RevertToPointerRoot, CurrentTime); } } break; @@ -3530,10 +3693,14 @@ 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 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 (wd.menu_type && !wd.no_focus) { + if ((xwa.map_state == IsViewable) && !wd.no_focus && !wd.is_popup) { XSetInputFocus(x11_display, wd.x11_window, RevertToPointerRoot, CurrentTime); } @@ -3574,7 +3741,7 @@ void DisplayServerX11::process_events() { // Ensure window focus on click. // 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) { + if (!wd.no_focus && !wd.is_popup) { XSetInputFocus(x11_display, wd.x11_window, RevertToPointerRoot, CurrentTime); } @@ -3789,6 +3956,7 @@ void DisplayServerX11::process_events() { Property p = _read_property(x11_display, windows[window_id].x11_window, XInternAtom(x11_display, "PRIMARY", 0)); Vector<String> files = String((char *)p.data).split("\n", false); + XFree(p.data); for (int i = 0; i < files.size(); i++) { files.write[i] = files[i].replace("file://", "").uri_decode().strip_edges(); } @@ -3831,6 +3999,7 @@ void DisplayServerX11::process_events() { if (more_than_3) { Property p = _read_property(x11_display, source, XInternAtom(x11_display, "XdndTypeList", False)); requested = pick_target_from_list(x11_display, (Atom *)p.data, p.nitems); + XFree(p.data); } else { requested = pick_target_from_atoms(x11_display, event.xclient.data.l[2], event.xclient.data.l[3], event.xclient.data.l[4]); } @@ -4134,21 +4303,20 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V WindowID id = window_id_counter++; WindowData &wd = windows[id]; - if ((id != MAIN_WINDOW_ID) && (p_flags & WINDOW_FLAG_BORDERLESS_BIT)) { - wd.menu_type = true; - } - if (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) { - wd.menu_type = true; wd.no_focus = true; } + if (p_flags & WINDOW_FLAG_POPUP_BIT) { + wd.is_popup = true; + } + // Setup for menu subwindows: // - override_redirect forces the WM not to interfere with the window, to avoid delays due to // handling decorations and placement. // On the other hand, focus changes need to be handled manually when this is set. // - save_under is a hint for the WM to keep the content of windows behind to avoid repaint. - if (wd.menu_type) { + if (wd.is_popup || wd.no_focus) { windowAttributes.override_redirect = True; windowAttributes.save_under = True; valuemask |= CWOverrideRedirect | CWSaveUnder; @@ -4159,7 +4327,7 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V // Enable receiving notification when the window is initialized (MapNotify) // so the focus can be set at the right time. - if (wd.menu_type && !wd.no_focus) { + if (!wd.no_focus && !wd.is_popup) { XSelectInput(x11_display, wd.x11_window, StructureNotifyMask); } @@ -4256,7 +4424,7 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V } } - if (wd.menu_type) { + if (wd.is_popup || wd.no_focus) { // Set Utility type to disable fade animations. Atom type_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE_UTILITY", False); Atom wt_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE", False); diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h index 2d07361deb..cd673d94d9 100644 --- a/platform/linuxbsd/display_server_x11.h +++ b/platform/linuxbsd/display_server_x11.h @@ -108,7 +108,7 @@ class DisplayServerX11 : public DisplayServer { #endif #if defined(DBUS_ENABLED) - FreeDesktopScreenSaver *screensaver; + FreeDesktopScreenSaver *screensaver = nullptr; bool keep_screen_on = false; #endif @@ -133,7 +133,6 @@ class DisplayServerX11 : public DisplayServer { ObjectID instance_id; - bool menu_type = false; bool no_focus = false; //better to guess on the fly, given WM can change it @@ -145,12 +144,21 @@ class DisplayServerX11 : public DisplayServer { Vector2i last_position_before_fs; bool focused = true; bool minimized = false; + bool is_popup = false; + + Rect2i parent_safe_rect; unsigned int focus_order = 0; }; Map<WindowID, WindowData> windows; + unsigned int last_mouse_monitor_mask = 0; + Vector2i last_mouse_monitor_pos; + uint64_t time_since_popup = 0; + + List<WindowID> popup_list; + WindowID last_focused_window = INVALID_WINDOW_ID; WindowID window_id_counter = MAIN_WINDOW_ID; @@ -160,7 +168,7 @@ class DisplayServerX11 : public DisplayServer { String internal_clipboard_primary; Window xdnd_source_window; ::Display *x11_display; - char *xmbstring; + char *xmbstring = nullptr; int xmblen; unsigned long last_timestamp; ::Time last_keyrelease_time; @@ -241,7 +249,7 @@ class DisplayServerX11 : public DisplayServer { typedef void (*xrr_free_monitors_t)(xrr_monitor_info *monitors); xrr_get_monitors_t xrr_get_monitors; xrr_free_monitors_t xrr_free_monitors; - void *xrandr_handle; + void *xrandr_handle = nullptr; Bool xrandr_ext_ok; struct Property { @@ -283,13 +291,17 @@ protected: void _window_changed(XEvent *event); public: + void mouse_process_popups(); + void popup_open(WindowID p_window); + void popup_close(WindowID p_window); + virtual bool has_feature(Feature p_feature) const override; virtual String get_name() const override; virtual void mouse_set_mode(MouseMode p_mode) override; virtual MouseMode mouse_get_mode() const override; - virtual void mouse_warp_to_position(const Point2i &p_to) override; + virtual void warp_mouse(const Point2i &p_position) override; virtual Point2i mouse_get_position() const override; virtual MouseButton mouse_get_button_state() const override; @@ -317,6 +329,10 @@ public: virtual void show_window(WindowID p_id) override; virtual void delete_sub_window(WindowID p_id) override; + virtual WindowID window_get_active_popup() const override; + virtual void window_set_popup_safe_rect(WindowID p_window, const Rect2i &p_rect) override; + virtual Rect2i window_get_popup_safe_rect(WindowID p_window) const override; + virtual WindowID get_window_at_screen_position(const Point2i &p_position) const override; virtual int64_t window_get_native_handle(HandleType p_handle_type, WindowID p_window = MAIN_WINDOW_ID) const override; diff --git a/platform/linuxbsd/export/export.cpp b/platform/linuxbsd/export/export.cpp index f05d2faa11..ec83e52f09 100644 --- a/platform/linuxbsd/export/export.cpp +++ b/platform/linuxbsd/export/export.cpp @@ -30,15 +30,10 @@ #include "export.h" -#include "core/io/file_access.h" -#include "editor/editor_export.h" -#include "platform/linuxbsd/logo.gen.h" -#include "scene/resources/texture.h" - -static Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size); +#include "export_plugin.h" void register_linuxbsd_exporter() { - Ref<EditorExportPlatformPC> platform; + Ref<EditorExportPlatformLinuxBSD> platform; platform.instantiate(); Ref<Image> img = memnew(Image(_linuxbsd_logo)); @@ -47,120 +42,10 @@ void register_linuxbsd_exporter() { logo->create_from_image(img); platform->set_logo(logo); platform->set_name("Linux/X11"); - platform->set_extension("x86"); + platform->set_extension("x86_32"); platform->set_extension("x86_64", "binary_format/64_bits"); - platform->set_release_32("linux_x11_32_release"); - platform->set_debug_32("linux_x11_32_debug"); - platform->set_release_64("linux_x11_64_release"); - platform->set_debug_64("linux_x11_64_debug"); platform->set_os_name("LinuxBSD"); platform->set_chmod_flags(0755); - platform->set_fixup_embedded_pck_func(&fixup_embedded_pck); EditorExport::get_singleton()->add_export_platform(platform); } - -static Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) { - // Patch the header of the "pck" section in the ELF file so that it corresponds to the embedded data - - FileAccess *f = FileAccess::open(p_path, FileAccess::READ_WRITE); - if (!f) { - return ERR_CANT_OPEN; - } - - // Read and check ELF magic number - { - uint32_t magic = f->get_32(); - if (magic != 0x464c457f) { // 0x7F + "ELF" - f->close(); - return ERR_FILE_CORRUPT; - } - } - - // Read program architecture bits from class field - - int bits = f->get_8() * 32; - - if (bits == 32 && p_embedded_size >= 0x100000000) { - f->close(); - ERR_FAIL_V_MSG(ERR_INVALID_DATA, "32-bit executables cannot have embedded data >= 4 GiB."); - } - - // Get info about the section header table - - int64_t section_table_pos; - int64_t section_header_size; - if (bits == 32) { - section_header_size = 40; - f->seek(0x20); - section_table_pos = f->get_32(); - f->seek(0x30); - } else { // 64 - section_header_size = 64; - f->seek(0x28); - section_table_pos = f->get_64(); - f->seek(0x3c); - } - int num_sections = f->get_16(); - int string_section_idx = f->get_16(); - - // Load the strings table - uint8_t *strings; - { - // Jump to the strings section header - f->seek(section_table_pos + string_section_idx * section_header_size); - - // Read strings data size and offset - int64_t string_data_pos; - int64_t string_data_size; - if (bits == 32) { - f->seek(f->get_position() + 0x10); - string_data_pos = f->get_32(); - string_data_size = f->get_32(); - } else { // 64 - f->seek(f->get_position() + 0x18); - string_data_pos = f->get_64(); - string_data_size = f->get_64(); - } - - // Read strings data - f->seek(string_data_pos); - strings = (uint8_t *)memalloc(string_data_size); - if (!strings) { - f->close(); - return ERR_OUT_OF_MEMORY; - } - f->get_buffer(strings, string_data_size); - } - - // Search for the "pck" section - - bool found = false; - for (int i = 0; i < num_sections; ++i) { - int64_t section_header_pos = section_table_pos + i * section_header_size; - f->seek(section_header_pos); - - uint32_t name_offset = f->get_32(); - if (strcmp((char *)strings + name_offset, "pck") == 0) { - // "pck" section found, let's patch! - - if (bits == 32) { - f->seek(section_header_pos + 0x10); - f->store_32(p_embedded_start); - f->store_32(p_embedded_size); - } else { // 64 - f->seek(section_header_pos + 0x18); - f->store_64(p_embedded_start); - f->store_64(p_embedded_size); - } - - found = true; - break; - } - } - - memfree(strings); - f->close(); - - return found ? OK : ERR_FILE_CORRUPT; -} diff --git a/platform/linuxbsd/export/export_plugin.cpp b/platform/linuxbsd/export/export_plugin.cpp new file mode 100644 index 0000000000..9f7fab6ee8 --- /dev/null +++ b/platform/linuxbsd/export/export_plugin.cpp @@ -0,0 +1,200 @@ +/*************************************************************************/ +/* export_plugin.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "export_plugin.h" + +#include "core/config/project_settings.h" +#include "editor/editor_node.h" + +Error EditorExportPlatformLinuxBSD::_export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path) { + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE); + ERR_FAIL_COND_V(f.is_null(), ERR_CANT_CREATE); + + f->store_line("#!/bin/sh"); + f->store_line("echo -ne '\\033c\\033]0;" + p_app_name + "\\a'"); + f->store_line("base_path=\"$(dirname \"$(realpath \"$0\")\")\""); + f->store_line("\"$base_path/" + p_pkg_name + "\" \"$@\""); + + return OK; +} + +Error EditorExportPlatformLinuxBSD::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) { + Error err = EditorExportPlatformPC::export_project(p_preset, p_debug, p_path, p_flags); + + if (err != OK) { + return err; + } + + String app_name; + if (String(ProjectSettings::get_singleton()->get("application/config/name")) != "") { + app_name = String(ProjectSettings::get_singleton()->get("application/config/name")); + } else { + app_name = "Unnamed"; + } + app_name = OS::get_singleton()->get_safe_dir_name(app_name); + + // Save console script. + if (err == OK) { + int con_scr = p_preset->get("debug/export_console_script"); + if ((con_scr == 1 && p_debug) || (con_scr == 2)) { + String scr_path = p_path.get_basename() + ".sh"; + err = _export_debug_script(p_preset, app_name, p_path.get_file(), scr_path); + FileAccess::set_unix_permissions(scr_path, 0755); + } + } + + return err; +} + +void EditorExportPlatformLinuxBSD::set_extension(const String &p_extension, const String &p_feature_key) { + extensions[p_feature_key] = p_extension; +} + +String EditorExportPlatformLinuxBSD::get_template_file_name(const String &p_target, const String &p_arch) const { + return "linux_x11_" + p_arch + "_" + p_target; +} + +List<String> EditorExportPlatformLinuxBSD::get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const { + List<String> list; + for (const KeyValue<String, String> &E : extensions) { + if (p_preset->get(E.key)) { + list.push_back(extensions[E.key]); + return list; + } + } + + if (extensions.has("default")) { + list.push_back(extensions["default"]); + return list; + } + + return list; +} + +Error EditorExportPlatformLinuxBSD::fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) const { + // Patch the header of the "pck" section in the ELF file so that it corresponds to the embedded data + + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ_WRITE); + if (f.is_null()) { + return ERR_CANT_OPEN; + } + + // Read and check ELF magic number + { + uint32_t magic = f->get_32(); + if (magic != 0x464c457f) { // 0x7F + "ELF" + return ERR_FILE_CORRUPT; + } + } + + // Read program architecture bits from class field + + int bits = f->get_8() * 32; + + if (bits == 32 && p_embedded_size >= 0x100000000) { + ERR_FAIL_V_MSG(ERR_INVALID_DATA, "32-bit executables cannot have embedded data >= 4 GiB."); + } + + // Get info about the section header table + + int64_t section_table_pos; + int64_t section_header_size; + if (bits == 32) { + section_header_size = 40; + f->seek(0x20); + section_table_pos = f->get_32(); + f->seek(0x30); + } else { // 64 + section_header_size = 64; + f->seek(0x28); + section_table_pos = f->get_64(); + f->seek(0x3c); + } + int num_sections = f->get_16(); + int string_section_idx = f->get_16(); + + // Load the strings table + uint8_t *strings; + { + // Jump to the strings section header + f->seek(section_table_pos + string_section_idx * section_header_size); + + // Read strings data size and offset + int64_t string_data_pos; + int64_t string_data_size; + if (bits == 32) { + f->seek(f->get_position() + 0x10); + string_data_pos = f->get_32(); + string_data_size = f->get_32(); + } else { // 64 + f->seek(f->get_position() + 0x18); + string_data_pos = f->get_64(); + string_data_size = f->get_64(); + } + + // Read strings data + f->seek(string_data_pos); + strings = (uint8_t *)memalloc(string_data_size); + if (!strings) { + return ERR_OUT_OF_MEMORY; + } + f->get_buffer(strings, string_data_size); + } + + // Search for the "pck" section + + bool found = false; + for (int i = 0; i < num_sections; ++i) { + int64_t section_header_pos = section_table_pos + i * section_header_size; + f->seek(section_header_pos); + + uint32_t name_offset = f->get_32(); + if (strcmp((char *)strings + name_offset, "pck") == 0) { + // "pck" section found, let's patch! + + if (bits == 32) { + f->seek(section_header_pos + 0x10); + f->store_32(p_embedded_start); + f->store_32(p_embedded_size); + } else { // 64 + f->seek(section_header_pos + 0x18); + f->store_64(p_embedded_start); + f->store_64(p_embedded_size); + } + + found = true; + break; + } + } + + memfree(strings); + + return found ? OK : ERR_FILE_CORRUPT; +} diff --git a/platform/linuxbsd/export/export_plugin.h b/platform/linuxbsd/export/export_plugin.h new file mode 100644 index 0000000000..f46fc68e1d --- /dev/null +++ b/platform/linuxbsd/export/export_plugin.h @@ -0,0 +1,52 @@ +/*************************************************************************/ +/* export_plugin.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef LINUXBSD_EXPORT_PLUGIN_H +#define LINUXBSD_EXPORT_PLUGIN_H + +#include "core/io/file_access.h" +#include "editor/editor_export.h" +#include "editor/editor_settings.h" +#include "platform/linuxbsd/logo.gen.h" +#include "scene/resources/texture.h" + +class EditorExportPlatformLinuxBSD : public EditorExportPlatformPC { + Map<String, String> extensions; + Error _export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path); + +public: + void set_extension(const String &p_extension, const String &p_feature_key = "default"); + virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override; + virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override; + virtual String get_template_file_name(const String &p_target, const String &p_arch) const override; + virtual Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) const override; +}; + +#endif diff --git a/platform/linuxbsd/gl_manager_x11.h b/platform/linuxbsd/gl_manager_x11.h index 0bb0a446ab..fb2c74a2b6 100644 --- a/platform/linuxbsd/gl_manager_x11.h +++ b/platform/linuxbsd/gl_manager_x11.h @@ -52,21 +52,20 @@ public: private: // any data specific to the window struct GLWindow { - GLWindow() { in_use = false; } - bool in_use; + bool in_use = false; // the external ID .. should match the GL window number .. unused I think - DisplayServer::WindowID window_id; - int width; - int height; + DisplayServer::WindowID window_id = DisplayServer::INVALID_WINDOW_ID; + int width = 0; + int height = 0; ::Window x11_window; - int gldisplay_id; + int gldisplay_id = 0; }; struct GLDisplay { GLDisplay() { context = nullptr; } ~GLDisplay(); - GLManager_X11_Private *context; + GLManager_X11_Private *context = nullptr; ::Display *x11_display; XVisualInfo x_vi; XSetWindowAttributes x_swa; @@ -82,7 +81,7 @@ private: LocalVector<GLWindow> _windows; LocalVector<GLDisplay> _displays; - GLWindow *_current_window; + GLWindow *_current_window = nullptr; void _internal_set_current_window(GLWindow *p_win); diff --git a/platform/linuxbsd/godot_linuxbsd.cpp b/platform/linuxbsd/godot_linuxbsd.cpp index 7c9f81bd3f..9fe00568fb 100644 --- a/platform/linuxbsd/godot_linuxbsd.cpp +++ b/platform/linuxbsd/godot_linuxbsd.cpp @@ -33,10 +33,20 @@ #include <stdlib.h> #include <unistd.h> +#if defined(SANITIZERS_ENABLED) +#include <sys/resource.h> +#endif + #include "main/main.h" #include "os_linuxbsd.h" int main(int argc, char *argv[]) { +#if defined(SANITIZERS_ENABLED) + // Note: Set stack size to be at least 30 MB (vs 8 MB default) to avoid overflow, address sanitizer can increase stack usage up to 3 times. + struct rlimit stack_lim = { 0x1E00000, 0x1E00000 }; + setrlimit(RLIMIT_STACK, &stack_lim); +#endif + OS_LinuxBSD os; setlocale(LC_CTYPE, ""); diff --git a/platform/linuxbsd/joypad_linux.cpp b/platform/linuxbsd/joypad_linux.cpp index 65d53b266f..22a9518a25 100644 --- a/platform/linuxbsd/joypad_linux.cpp +++ b/platform/linuxbsd/joypad_linux.cpp @@ -95,7 +95,7 @@ JoypadLinux::~JoypadLinux() { void JoypadLinux::joy_thread_func(void *p_user) { if (p_user) { - JoypadLinux *joy = (JoypadLinux *)p_user; + JoypadLinux *joy = static_cast<JoypadLinux *>(p_user); joy->run_joypad_thread(); } } diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp index d876932a83..bf142f8804 100644 --- a/platform/linuxbsd/os_linuxbsd.cpp +++ b/platform/linuxbsd/os_linuxbsd.cpp @@ -32,6 +32,7 @@ #include "core/io/dir_access.h" #include "main/main.h" +#include "servers/display_server.h" #ifdef X11_ENABLED #include "display_server_x11.h" @@ -130,20 +131,19 @@ void OS_LinuxBSD::initialize_joypads() { String OS_LinuxBSD::get_unique_id() const { static String machine_id; if (machine_id.is_empty()) { - if (FileAccess *f = FileAccess::open("/etc/machine-id", FileAccess::READ)) { + Ref<FileAccess> f = FileAccess::open("/etc/machine-id", FileAccess::READ); + if (f.is_valid()) { while (machine_id.is_empty() && !f->eof_reached()) { machine_id = f->get_line().strip_edges(); } - f->close(); - memdelete(f); } } return machine_id; } String OS_LinuxBSD::get_processor_name() const { - FileAccessRef f = FileAccess::open("/proc/cpuinfo", FileAccess::READ); - ERR_FAIL_COND_V_MSG(!f, "", String("Couldn't open `/proc/cpuinfo` to get the CPU model name. Returning an empty string.")); + Ref<FileAccess> f = FileAccess::open("/proc/cpuinfo", FileAccess::READ); + ERR_FAIL_COND_V_MSG(f.is_null(), "", String("Couldn't open `/proc/cpuinfo` to get the CPU model name. Returning an empty string.")); while (!f->eof_reached()) { const String line = f->get_line(); @@ -398,9 +398,11 @@ static String get_mountpoint(const String &p_path) { } Error OS_LinuxBSD::move_to_trash(const String &p_path) { + String path = p_path.rstrip("/"); // Strip trailing slash when path points to a directory + int err_code; List<String> args; - args.push_back(p_path); + args.push_back(path); args.push_front("trash"); // The command is `gio trash <file_name>` so we need to add it to args. Error result = execute("gio", args, nullptr, &err_code); // For GNOME based machines. if (result == OK && !err_code) { @@ -430,14 +432,14 @@ Error OS_LinuxBSD::move_to_trash(const String &p_path) { // If the commands `kioclient5`, `gio` or `gvfs-trash` don't exist on the system we do it manually. String trash_path = ""; - String mnt = get_mountpoint(p_path); + String mnt = get_mountpoint(path); // If there is a directory "[Mountpoint]/.Trash-[UID], use it as the trash can. if (!mnt.is_empty()) { - String path(mnt + "/.Trash-" + itos(getuid())); + String mountpoint_trash_path(mnt + "/.Trash-" + itos(getuid())); struct stat s; - if (!stat(path.utf8().get_data(), &s)) { - trash_path = path; + if (!stat(mountpoint_trash_path.utf8().get_data(), &s)) { + trash_path = mountpoint_trash_path; } } @@ -462,24 +464,21 @@ Error OS_LinuxBSD::move_to_trash(const String &p_path) { // Create needed directories for decided trash can location. { - DirAccessRef dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Ref<DirAccess> dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); Error err = dir_access->make_dir_recursive(trash_path); // Issue an error if trash can is not created properly. ERR_FAIL_COND_V_MSG(err != OK, err, "Could not create the trash path \"" + trash_path + "\""); err = dir_access->make_dir_recursive(trash_path + "/files"); - ERR_FAIL_COND_V_MSG(err != OK, err, "Could not create the trash path \"" + trash_path + "\"/files"); + ERR_FAIL_COND_V_MSG(err != OK, err, "Could not create the trash path \"" + trash_path + "/files\""); err = dir_access->make_dir_recursive(trash_path + "/info"); - ERR_FAIL_COND_V_MSG(err != OK, err, "Could not create the trash path \"" + trash_path + "\"/info"); + ERR_FAIL_COND_V_MSG(err != OK, err, "Could not create the trash path \"" + trash_path + "/info\""); } // The trash can is successfully created, now we check that we don't exceed our file name length limit. // If the file name is too long trim it so we can add the identifying number and ".trashinfo". // Assumes that the file name length limit is 255 characters. - String file_name = p_path.get_file(); - if (file_name.length() == 0) { - file_name = p_path.get_base_dir().get_file(); - } + String file_name = path.get_file(); if (file_name.length() > 240) { file_name = file_name.substr(0, file_name.length() - 15); } @@ -502,29 +501,32 @@ Error OS_LinuxBSD::move_to_trash(const String &p_path) { } file_name = fn; + String renamed_path = path.get_base_dir() + "/" + file_name; + // Generates the .trashinfo file OS::Date date = OS::get_singleton()->get_date(false); OS::Time time = OS::get_singleton()->get_time(false); String timestamp = vformat("%04d-%02d-%02dT%02d:%02d:", date.year, (int)date.month, date.day, time.hour, time.minute); timestamp = vformat("%s%02d", timestamp, time.second); // vformat only supports up to 6 arguments. - String trash_info = "[Trash Info]\nPath=" + p_path.uri_encode() + "\nDeletionDate=" + timestamp + "\n"; + String trash_info = "[Trash Info]\nPath=" + path.uri_encode() + "\nDeletionDate=" + timestamp + "\n"; { Error err; - FileAccessRef file = FileAccess::open(trash_path + "/info/" + file_name + ".trashinfo", FileAccess::WRITE, &err); - ERR_FAIL_COND_V_MSG(err != OK, err, "Can't create trashinfo file:" + trash_path + "/info/" + file_name + ".trashinfo"); - file->store_string(trash_info); - file->close(); + { + Ref<FileAccess> file = FileAccess::open(trash_path + "/info/" + file_name + ".trashinfo", FileAccess::WRITE, &err); + ERR_FAIL_COND_V_MSG(err != OK, err, "Can't create trashinfo file: \"" + trash_path + "/info/" + file_name + ".trashinfo\""); + file->store_string(trash_info); + } // Rename our resource before moving it to the trash can. - DirAccessRef dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - err = dir_access->rename(p_path, p_path.get_base_dir() + "/" + file_name); - ERR_FAIL_COND_V_MSG(err != OK, err, "Can't rename file \"" + p_path + "\""); + Ref<DirAccess> dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + err = dir_access->rename(path, renamed_path); + ERR_FAIL_COND_V_MSG(err != OK, err, "Can't rename file \"" + path + "\" to \"" + renamed_path + "\""); } // Move the given resource to the trash can. // Do not use DirAccess:rename() because it can't move files across multiple mountpoints. List<String> mv_args; - mv_args.push_back(p_path.get_base_dir() + "/" + file_name); + mv_args.push_back(renamed_path); mv_args.push_back(trash_path + "/files"); { int retval; @@ -532,11 +534,10 @@ Error OS_LinuxBSD::move_to_trash(const String &p_path) { // Issue an error if "mv" failed to move the given resource to the trash can. if (err != OK || retval != 0) { - ERR_PRINT("move_to_trash: Could not move the resource \"" + p_path + "\" to the trash can \"" + trash_path + "/files\""); - DirAccess *dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - err = dir_access->rename(p_path.get_base_dir() + "/" + file_name, p_path); - memdelete(dir_access); - ERR_FAIL_COND_V_MSG(err != OK, err, "Could not rename " + p_path.get_base_dir() + "/" + file_name + " back to its original name:" + p_path); + ERR_PRINT("move_to_trash: Could not move the resource \"" + path + "\" to the trash can \"" + trash_path + "/files\""); + Ref<DirAccess> dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + err = dir_access->rename(renamed_path, path); + ERR_FAIL_COND_V_MSG(err != OK, err, "Could not rename \"" + renamed_path + "\" back to its original name: \"" + path + "\""); return FAILED; } } diff --git a/platform/linuxbsd/os_linuxbsd.h b/platform/linuxbsd/os_linuxbsd.h index d3857e85f8..7b912ddee3 100644 --- a/platform/linuxbsd/os_linuxbsd.h +++ b/platform/linuxbsd/os_linuxbsd.h @@ -63,7 +63,7 @@ class OS_LinuxBSD : public OS_Unix { CrashHandler crash_handler; - MainLoop *main_loop; + MainLoop *main_loop = nullptr; protected: virtual void initialize() override; |