diff options
Diffstat (limited to 'platform/linuxbsd')
-rw-r--r-- | platform/linuxbsd/detect.py | 21 | ||||
-rw-r--r-- | platform/linuxbsd/display_server_x11.cpp | 230 | ||||
-rw-r--r-- | platform/linuxbsd/display_server_x11.h | 18 | ||||
-rw-r--r-- | platform/linuxbsd/joypad_linux.cpp | 6 | ||||
-rw-r--r-- | platform/linuxbsd/os_linuxbsd.cpp | 59 | ||||
-rw-r--r-- | platform/linuxbsd/os_linuxbsd.h | 3 | ||||
-rw-r--r-- | platform/linuxbsd/vulkan_context_x11.cpp | 1 |
7 files changed, 248 insertions, 90 deletions
diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py index ab643b254a..03c85d09ad 100644 --- a/platform/linuxbsd/detect.py +++ b/platform/linuxbsd/detect.py @@ -261,27 +261,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 bf9c9b1766..07cb6a23e8 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: @@ -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; @@ -1077,7 +1086,7 @@ float DisplayServerX11::screen_get_refresh_rate(int p_screen) const { monitors = xrr_get_monitors(x11_display, windows[MAIN_WINDOW_ID].x11_window, true, &count); ERR_FAIL_INDEX_V(p_screen, count, SCREEN_REFRESH_RATE_FALLBACK); } else { - ERR_PRINT("An error occured while trying to get the screen refresh rate."); + ERR_PRINT("An error occurred while trying to get the screen refresh rate."); return SCREEN_REFRESH_RATE_FALLBACK; } @@ -1105,14 +1114,14 @@ float DisplayServerX11::screen_get_refresh_rate(int p_screen) const { } } - ERR_PRINT("An error occured while trying to get the screen refresh rate."); // We should have returned the refresh rate by now. An error must have occured. + ERR_PRINT("An error occurred while trying to get the screen refresh rate."); // We should have returned the refresh rate by now. An error must have occurred. return SCREEN_REFRESH_RATE_FALLBACK; } else { - ERR_PRINT("An error occured while trying to get the screen refresh rate."); + ERR_PRINT("An error occurred while trying to get the screen refresh rate."); return SCREEN_REFRESH_RATE_FALLBACK; } } - ERR_PRINT("An error occured while trying to get the screen refresh rate."); + ERR_PRINT("An error occurred while trying to get the screen refresh rate."); return SCREEN_REFRESH_RATE_FALLBACK; } @@ -1173,6 +1182,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); @@ -1183,7 +1193,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]; @@ -1458,8 +1470,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); } } @@ -2073,6 +2085,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: { } } @@ -2114,6 +2138,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: { } } @@ -2427,8 +2457,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. @@ -2438,7 +2467,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); } @@ -2465,9 +2493,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) + ")."); } @@ -2530,7 +2556,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; } } @@ -2539,15 +2565,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; } @@ -2869,7 +2895,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(); @@ -3028,23 +3054,36 @@ void DisplayServerX11::_dispatch_input_event(const Ref<InputEvent> &p_event) { Variant ret; Callable::CallError ce; + { + List<WindowID>::Element *E = popup_list.front(); + 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); } } } @@ -3136,6 +3175,108 @@ 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) { + WindowData &wd = windows[p_window]; + if (wd.is_popup) { + // Close all popups, up to current popup parent, or every popup if new window is not transient. + List<WindowID>::Element *E = popup_list.back(); + while (E) { + if (wd.transient_parent != E->get() || wd.transient_parent == INVALID_WINDOW_ID) { + _send_window_event(windows[E->get()], DisplayServerX11::WINDOW_EVENT_CLOSE_REQUEST); + List<WindowID>::Element *F = E->prev(); + popup_list.erase(E); + E = F; + } else { + break; + } + } + + time_since_popup = OS::get_singleton()->get_ticks_msec(); + popup_list.push_back(p_window); + } +} + +void DisplayServerX11::popup_close(WindowID p_window) { + List<WindowID>::Element *E = popup_list.find(p_window); + while (E) { + _send_window_event(windows[E->get()], DisplayServerX11::WINDOW_EVENT_CLOSE_REQUEST); + List<WindowID>::Element *F = E->next(); + popup_list.erase(E); + E = F; + } +} + +void DisplayServerX11::mouse_process_popups() { + 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 *E = popup_list.back(); + 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 { + _send_window_event(windows[E->get()], DisplayServerX11::WINDOW_EVENT_CLOSE_REQUEST); + List<WindowID>::Element *F = E->prev(); + popup_list.erase(E); + E = F; + } + } + } + } + last_mouse_monitor_mask = mask; + last_mouse_monitor_pos = pos; + } + } +} + void DisplayServerX11::process_events() { _THREAD_SAFE_METHOD_ @@ -3144,6 +3285,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; @@ -3374,7 +3517,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; @@ -3517,10 +3660,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); } @@ -3561,7 +3708,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); } @@ -3776,6 +3923,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(); } @@ -3818,6 +3966,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]); } @@ -4121,21 +4270,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; @@ -4146,7 +4294,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); } @@ -4243,7 +4391,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); @@ -4794,7 +4942,7 @@ DisplayServerX11::~DisplayServerX11() { if (img[i] != nullptr) { XcursorImageDestroy(img[i]); } - }; + } if (xim) { XCloseIM(xim); diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h index 2d07361deb..63d32d939d 100644 --- a/platform/linuxbsd/display_server_x11.h +++ b/platform/linuxbsd/display_server_x11.h @@ -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; @@ -283,6 +291,10 @@ 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; @@ -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/joypad_linux.cpp b/platform/linuxbsd/joypad_linux.cpp index 8e963238e3..65d53b266f 100644 --- a/platform/linuxbsd/joypad_linux.cpp +++ b/platform/linuxbsd/joypad_linux.cpp @@ -238,7 +238,7 @@ void JoypadLinux::close_joypad(int p_id) { if (p_id == -1) { for (int i = 0; i < JOYPADS_MAX; i++) { close_joypad(i); - }; + } return; } else if (p_id < 0) { return; @@ -251,7 +251,7 @@ void JoypadLinux::close_joypad(int p_id) { joy.fd = -1; attached_devices.remove_at(attached_devices.find(joy.devpath)); input->joy_connection_changed(p_id, false, ""); - }; + } } static String _hex_str(uint8_t p_byte) { @@ -516,7 +516,7 @@ void JoypadLinux::process_joypads() { } if (len == 0 || (len < 0 && errno != EAGAIN)) { close_joypad(i); - }; + } if (joy->force_feedback) { uint64_t timestamp = input->get_joy_vibration_timestamp(i); diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp index e95a865636..86874687ad 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" @@ -141,6 +142,20 @@ String OS_LinuxBSD::get_unique_id() const { 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.")); + + while (!f->eof_reached()) { + const String line = f->get_line(); + if (line.find("model name") != -1) { + return line.split(":")[1].strip_edges(); + } + } + + ERR_FAIL_V_MSG("", String("Couldn't get the CPU model name from `/proc/cpuinfo`. Returning an empty string.")); +} + void OS_LinuxBSD::finalize() { if (main_loop) { memdelete(main_loop); @@ -342,7 +357,7 @@ void OS_LinuxBSD::run() { if (Main::iteration()) { break; } - }; + } main_loop->finalize(); } @@ -384,9 +399,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) { @@ -416,14 +433,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; } } @@ -454,18 +471,15 @@ Error OS_LinuxBSD::move_to_trash(const String &p_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); } @@ -488,29 +502,31 @@ 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"); + 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(); // 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 + "\""); + 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; @@ -518,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\""); + DirAccessRef 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 ad6e4cd168..d3857e85f8 100644 --- a/platform/linuxbsd/os_linuxbsd.h +++ b/platform/linuxbsd/os_linuxbsd.h @@ -39,8 +39,6 @@ #include "drivers/unix/os_unix.h" #include "joypad_linux.h" #include "servers/audio_server.h" -#include "servers/rendering/renderer_compositor.h" -#include "servers/rendering_server.h" class OS_LinuxBSD : public OS_Unix { virtual void delete_main_loop() override; @@ -89,6 +87,7 @@ public: virtual Error shell_open(String p_uri) override; virtual String get_unique_id() const override; + virtual String get_processor_name() const override; virtual void alert(const String &p_alert, const String &p_title = "ALERT!") override; diff --git a/platform/linuxbsd/vulkan_context_x11.cpp b/platform/linuxbsd/vulkan_context_x11.cpp index e2fd8c76d2..b4f585726f 100644 --- a/platform/linuxbsd/vulkan_context_x11.cpp +++ b/platform/linuxbsd/vulkan_context_x11.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "vulkan_context_x11.h" + #ifdef USE_VOLK #include <volk.h> #else |