summaryrefslogtreecommitdiff
path: root/platform/linuxbsd
diff options
context:
space:
mode:
Diffstat (limited to 'platform/linuxbsd')
-rw-r--r--platform/linuxbsd/detect.py6
-rw-r--r--platform/linuxbsd/display_server_x11.cpp394
-rw-r--r--platform/linuxbsd/display_server_x11.h19
-rw-r--r--platform/linuxbsd/platform_config.h12
4 files changed, 302 insertions, 129 deletions
diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py
index 3eb4c44bc1..f5e2c72bbc 100644
--- a/platform/linuxbsd/detect.py
+++ b/platform/linuxbsd/detect.py
@@ -35,6 +35,11 @@ def can_build():
print("xinerama not found.. x11 disabled.")
return False
+ x11_error = os.system("pkg-config xext --modversion > /dev/null ")
+ if x11_error:
+ print("xext not found.. x11 disabled.")
+ return False
+
x11_error = os.system("pkg-config xrandr --modversion > /dev/null ")
if x11_error:
print("xrandr not found.. x11 disabled.")
@@ -194,6 +199,7 @@ def configure(env):
env.ParseConfig("pkg-config x11 --cflags --libs")
env.ParseConfig("pkg-config xcursor --cflags --libs")
env.ParseConfig("pkg-config xinerama --cflags --libs")
+ env.ParseConfig("pkg-config xext --cflags --libs")
env.ParseConfig("pkg-config xrandr --cflags --libs")
env.ParseConfig("pkg-config xrender --cflags --libs")
env.ParseConfig("pkg-config xi --cflags --libs")
diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp
index fe9e253cc9..8b0d08d1cb 100644
--- a/platform/linuxbsd/display_server_x11.cpp
+++ b/platform/linuxbsd/display_server_x11.cpp
@@ -50,6 +50,7 @@
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#include <X11/extensions/Xinerama.h>
+#include <X11/extensions/shape.h>
// ICCCM
#define WM_NormalState 1L // window normal state
@@ -321,23 +322,19 @@ bool DisplayServerX11::_refresh_device_info() {
}
void DisplayServerX11::_flush_mouse_motion() {
- while (true) {
- if (XPending(x11_display) > 0) {
- XEvent event;
- XPeekEvent(x11_display, &event);
-
- if (XGetEventData(x11_display, &event.xcookie) && event.xcookie.type == GenericEvent && event.xcookie.extension == xi.opcode) {
- XIDeviceEvent *event_data = (XIDeviceEvent *)event.xcookie.data;
-
- if (event_data->evtype == XI_RawMotion) {
- XNextEvent(x11_display, &event);
- } else {
- break;
- }
- } else {
- break;
+ // Block events polling while flushing motion events.
+ MutexLock mutex_lock(events_mutex);
+
+ for (uint32_t event_index = 0; event_index < polled_events.size(); ++event_index) {
+ XEvent &event = polled_events[event_index];
+ if (XGetEventData(x11_display, &event.xcookie) && event.xcookie.type == GenericEvent && event.xcookie.extension == xi.opcode) {
+ XIDeviceEvent *event_data = (XIDeviceEvent *)event.xcookie.data;
+ if (event_data->evtype == XI_RawMotion) {
+ XFreeEventData(x11_display, &event.xcookie);
+ polled_events.remove(event_index--);
+ continue;
}
- } else {
+ XFreeEventData(x11_display, &event.xcookie);
break;
}
}
@@ -450,12 +447,25 @@ int DisplayServerX11::mouse_get_button_state() const {
void DisplayServerX11::clipboard_set(const String &p_text) {
_THREAD_SAFE_METHOD_
- internal_clipboard = p_text;
+ {
+ // The clipboard content can be accessed while polling for events.
+ MutexLock mutex_lock(events_mutex);
+ internal_clipboard = p_text;
+ }
+
XSetSelectionOwner(x11_display, XA_PRIMARY, windows[MAIN_WINDOW_ID].x11_window, CurrentTime);
XSetSelectionOwner(x11_display, XInternAtom(x11_display, "CLIPBOARD", 0), windows[MAIN_WINDOW_ID].x11_window, CurrentTime);
}
-static String _clipboard_get_impl(Atom p_source, Window x11_window, ::Display *x11_display, String p_internal_clipboard, Atom target) {
+Bool DisplayServerX11::_predicate_clipboard_selection(Display *display, XEvent *event, XPointer arg) {
+ if (event->type == SelectionNotify && event->xselection.requestor == *(Window *)arg) {
+ return True;
+ } else {
+ return False;
+ }
+}
+
+String DisplayServerX11::_clipboard_get_impl(Atom p_source, Window x11_window, Atom target) const {
String ret;
Atom type;
@@ -463,23 +473,27 @@ static String _clipboard_get_impl(Atom p_source, Window x11_window, ::Display *x
int format, result;
unsigned long len, bytes_left, dummy;
unsigned char *data;
- Window Sown = XGetSelectionOwner(x11_display, p_source);
+ Window selection_owner = XGetSelectionOwner(x11_display, p_source);
- if (Sown == x11_window) {
- return p_internal_clipboard;
- };
+ if (selection_owner == x11_window) {
+ return internal_clipboard;
+ }
- if (Sown != None) {
- XConvertSelection(x11_display, p_source, target, selection,
- x11_window, CurrentTime);
- XFlush(x11_display);
- while (true) {
+ if (selection_owner != None) {
+ {
+ // Block events polling while processing selection events.
+ MutexLock mutex_lock(events_mutex);
+
+ XConvertSelection(x11_display, p_source, target, selection,
+ x11_window, CurrentTime);
+
+ XFlush(x11_display);
+
+ // Blocking wait for predicate to be True
+ // and remove the event from the queue.
XEvent event;
- XNextEvent(x11_display, &event);
- if (event.type == SelectionNotify && event.xselection.requestor == x11_window) {
- break;
- };
- };
+ XIfEvent(x11_display, &event, _predicate_clipboard_selection, (XPointer)&x11_window);
+ }
//
// Do not get any data, see how much data is there
@@ -513,14 +527,14 @@ static String _clipboard_get_impl(Atom p_source, Window x11_window, ::Display *x
return ret;
}
-static String _clipboard_get(Atom p_source, Window x11_window, ::Display *x11_display, String p_internal_clipboard) {
+String DisplayServerX11::_clipboard_get(Atom p_source, Window x11_window) const {
String ret;
Atom utf8_atom = XInternAtom(x11_display, "UTF8_STRING", True);
if (utf8_atom != None) {
- ret = _clipboard_get_impl(p_source, x11_window, x11_display, p_internal_clipboard, utf8_atom);
+ ret = _clipboard_get_impl(p_source, x11_window, utf8_atom);
}
- if (ret == "") {
- ret = _clipboard_get_impl(p_source, x11_window, x11_display, p_internal_clipboard, XA_STRING);
+ if (ret.empty()) {
+ ret = _clipboard_get_impl(p_source, x11_window, XA_STRING);
}
return ret;
}
@@ -529,11 +543,11 @@ String DisplayServerX11::clipboard_get() const {
_THREAD_SAFE_METHOD_
String ret;
- ret = _clipboard_get(XInternAtom(x11_display, "CLIPBOARD", 0), windows[MAIN_WINDOW_ID].x11_window, x11_display, internal_clipboard);
+ ret = _clipboard_get(XInternAtom(x11_display, "CLIPBOARD", 0), windows[MAIN_WINDOW_ID].x11_window);
- if (ret == "") {
- ret = _clipboard_get(XA_PRIMARY, windows[MAIN_WINDOW_ID].x11_window, x11_display, internal_clipboard);
- };
+ if (ret.empty()) {
+ ret = _clipboard_get(XA_PRIMARY, windows[MAIN_WINDOW_ID].x11_window);
+ }
return ret;
}
@@ -782,6 +796,38 @@ void DisplayServerX11::window_set_title(const String &p_title, WindowID p_window
XChangeProperty(x11_display, wd.x11_window, _net_wm_name, utf8_string, 8, PropModeReplace, (unsigned char *)p_title.utf8().get_data(), p_title.utf8().length());
}
+void DisplayServerX11::window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window) {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ const WindowData &wd = windows[p_window];
+
+ int event_base, error_base;
+ const Bool ext_okay = XShapeQueryExtension(x11_display, &event_base, &error_base);
+ if (ext_okay) {
+ Region region;
+ if (p_region.size() == 0) {
+ region = XCreateRegion();
+ XRectangle rect;
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = window_get_real_size(p_window).x;
+ rect.height = window_get_real_size(p_window).y;
+ XUnionRectWithRegion(&rect, region, region);
+ } else {
+ XPoint *points = (XPoint *)memalloc(sizeof(XPoint) * p_region.size());
+ for (int i = 0; i < p_region.size(); i++) {
+ points[i].x = p_region[i].x;
+ points[i].y = p_region[i].y;
+ }
+ region = XPolygonRegion(points, p_region.size(), EvenOddRule);
+ memfree(points);
+ }
+ XShapeCombineRegion(x11_display, wd.x11_window, ShapeInput, 0, 0, region, ShapeSet);
+ XDestroyRegion(region);
+ }
+}
+
void DisplayServerX11::window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window) {
_THREAD_SAFE_METHOD_
@@ -1616,10 +1662,16 @@ void DisplayServerX11::window_set_ime_active(const bool p_active, WindowID p_win
return;
}
+ // Block events polling while changing input focus
+ // because it triggers some event polling internally.
if (p_active) {
- XSetICFocus(wd.xic);
+ {
+ MutexLock mutex_lock(events_mutex);
+ XSetICFocus(wd.xic);
+ }
window_set_ime_position(wd.im_position, p_window);
} else {
+ MutexLock mutex_lock(events_mutex);
XUnsetICFocus(wd.xic);
}
}
@@ -1640,7 +1692,14 @@ void DisplayServerX11::window_set_ime_position(const Point2i &p_pos, WindowID p_
spot.x = short(p_pos.x);
spot.y = short(p_pos.y);
XVaNestedList preedit_attr = XVaCreateNestedList(0, XNSpotLocation, &spot, nullptr);
- XSetICValues(wd.xic, XNPreeditAttributes, preedit_attr, nullptr);
+
+ {
+ // Block events polling during this call
+ // because it triggers some event polling internally.
+ MutexLock mutex_lock(events_mutex);
+ XSetICValues(wd.xic, XNPreeditAttributes, preedit_attr, nullptr);
+ }
+
XFree(preedit_attr);
}
@@ -1960,7 +2019,7 @@ unsigned int DisplayServerX11::_get_mouse_button_state(unsigned int p_x11_button
return last_button_state;
}
-void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event, bool p_echo) {
+void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event, LocalVector<XEvent> &p_events, uint32_t &p_event_index, bool p_echo) {
WindowData wd = windows[p_window];
// X11 functions don't know what const is
XKeyEvent *xkeyevent = p_event;
@@ -2097,7 +2156,7 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event,
/* Phase 4, determine if event must be filtered */
// This seems to be a side-effect of using XIM.
- // XEventFilter looks like a core X11 function,
+ // XFilterEvent looks like a core X11 function,
// but it's actually just used to see if we must
// ignore a deadkey, or events XIM determines
// must not reach the actual gui.
@@ -2131,17 +2190,16 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event,
// Echo characters in X11 are a keyrelease and a keypress
// one after the other with the (almot) same timestamp.
- // To detect them, i use XPeekEvent and check that their
- // difference in time is below a threshold.
+ // To detect them, i compare to the next event in list and
+ // check that their difference in time is below a threshold.
if (xkeyevent->type != KeyPress) {
p_echo = false;
// make sure there are events pending,
// so this call won't block.
- if (XPending(x11_display) > 0) {
- XEvent peek_event;
- XPeekEvent(x11_display, &peek_event);
+ if (p_event_index + 1 < p_events.size()) {
+ XEvent &peek_event = p_events[p_event_index + 1];
// I'm using a threshold of 5 msecs,
// since sometimes there seems to be a little
@@ -2156,9 +2214,9 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event,
KeySym rk;
XLookupString((XKeyEvent *)&peek_event, str, 256, &rk, nullptr);
if (rk == keysym_keycode) {
- XEvent event;
- XNextEvent(x11_display, &event); //erase next event
- _handle_key_event(p_window, (XKeyEvent *)&event, true);
+ // Consume to next event.
+ ++p_event_index;
+ _handle_key_event(p_window, (XKeyEvent *)&peek_event, p_events, p_event_index, true);
return; //ignore current, echo next
}
}
@@ -2213,6 +2271,66 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event,
Input::get_singleton()->accumulate_input_event(k);
}
+void DisplayServerX11::_handle_selection_request_event(XSelectionRequestEvent *p_event) {
+ XEvent respond;
+ if (p_event->target == XInternAtom(x11_display, "UTF8_STRING", 0) ||
+ p_event->target == XInternAtom(x11_display, "COMPOUND_TEXT", 0) ||
+ p_event->target == XInternAtom(x11_display, "TEXT", 0) ||
+ p_event->target == XA_STRING ||
+ p_event->target == XInternAtom(x11_display, "text/plain;charset=utf-8", 0) ||
+ p_event->target == XInternAtom(x11_display, "text/plain", 0)) {
+ // Directly using internal clipboard because we know our window
+ // is the owner during a selection request.
+ CharString clip = internal_clipboard.utf8();
+ XChangeProperty(x11_display,
+ p_event->requestor,
+ p_event->property,
+ p_event->target,
+ 8,
+ PropModeReplace,
+ (unsigned char *)clip.get_data(),
+ clip.length());
+ respond.xselection.property = p_event->property;
+ } else if (p_event->target == XInternAtom(x11_display, "TARGETS", 0)) {
+ Atom data[7];
+ data[0] = XInternAtom(x11_display, "TARGETS", 0);
+ data[1] = XInternAtom(x11_display, "UTF8_STRING", 0);
+ data[2] = XInternAtom(x11_display, "COMPOUND_TEXT", 0);
+ data[3] = XInternAtom(x11_display, "TEXT", 0);
+ data[4] = XA_STRING;
+ data[5] = XInternAtom(x11_display, "text/plain;charset=utf-8", 0);
+ data[6] = XInternAtom(x11_display, "text/plain", 0);
+
+ XChangeProperty(x11_display,
+ p_event->requestor,
+ p_event->property,
+ XA_ATOM,
+ 32,
+ PropModeReplace,
+ (unsigned char *)&data,
+ sizeof(data) / sizeof(data[0]));
+ respond.xselection.property = p_event->property;
+
+ } else {
+ char *targetname = XGetAtomName(x11_display, p_event->target);
+ printf("No Target '%s'\n", targetname);
+ if (targetname) {
+ XFree(targetname);
+ }
+ respond.xselection.property = None;
+ }
+
+ respond.xselection.type = SelectionNotify;
+ respond.xselection.display = p_event->display;
+ respond.xselection.requestor = p_event->requestor;
+ respond.xselection.selection = p_event->selection;
+ respond.xselection.target = p_event->target;
+ respond.xselection.time = p_event->time;
+
+ XSendEvent(x11_display, p_event->requestor, True, NoEventMask, &respond);
+ XFlush(x11_display);
+}
+
void DisplayServerX11::_xim_destroy_callback(::XIM im, ::XPointer client_data,
::XPointer call_data) {
WARN_PRINT("Input method stopped");
@@ -2325,6 +2443,65 @@ void DisplayServerX11::_send_window_event(const WindowData &wd, WindowEvent p_ev
}
}
+void DisplayServerX11::_poll_events_thread(void *ud) {
+ DisplayServerX11 *display_server = (DisplayServerX11 *)ud;
+ display_server->_poll_events();
+}
+
+Bool DisplayServerX11::_predicate_all_events(Display *display, XEvent *event, XPointer arg) {
+ // Just accept all events.
+ return True;
+}
+
+void DisplayServerX11::_poll_events() {
+ int x11_fd = ConnectionNumber(x11_display);
+ fd_set in_fds;
+
+ while (!events_thread_done) {
+ XFlush(x11_display);
+
+ FD_ZERO(&in_fds);
+ FD_SET(x11_fd, &in_fds);
+
+ struct timeval tv;
+ tv.tv_usec = 0;
+ tv.tv_sec = 1;
+
+ // Wait for next event or timeout.
+ int num_ready_fds = select(x11_fd + 1, &in_fds, NULL, NULL, &tv);
+ if (num_ready_fds < 0) {
+ ERR_PRINT("_poll_events: select error: " + itos(errno));
+ }
+
+ // Process events from the queue.
+ {
+ MutexLock mutex_lock(events_mutex);
+
+ // Non-blocking wait for next event
+ // and remove it from the queue.
+ XEvent ev;
+ while (XCheckIfEvent(x11_display, &ev, _predicate_all_events, nullptr)) {
+ // Check if the input manager wants to process the event.
+ if (XFilterEvent(&ev, None)) {
+ // Event has been filtered by the Input Manager,
+ // it has to be ignored and a new one will be received.
+ continue;
+ }
+
+ // Handle selection request events directly in the event thread, because
+ // communication through the x server takes several events sent back and forth
+ // and we don't want to block other programs while processing only one each frame.
+ if (ev.type == SelectionRequest) {
+ _handle_selection_request_event(&(ev.xselectionrequest));
+ continue;
+ }
+
+ polled_events.push_back(ev);
+ }
+ }
+ }
+}
+
void DisplayServerX11::process_events() {
_THREAD_SAFE_METHOD_
@@ -2368,13 +2545,16 @@ void DisplayServerX11::process_events() {
xi.tilt = Vector2();
xi.pressure_supported = false;
- while (XPending(x11_display) > 0) {
- XEvent event;
- XNextEvent(x11_display, &event);
+ LocalVector<XEvent> events;
+ {
+ // Block events polling while flushing events.
+ MutexLock mutex_lock(events_mutex);
+ events = polled_events;
+ polled_events.clear();
+ }
- if (XFilterEvent(&event, None)) {
- continue;
- }
+ for (uint32_t event_index = 0; event_index < events.size(); ++event_index) {
+ XEvent &event = events[event_index];
WindowID window_id = MAIN_WINDOW_ID;
@@ -2633,6 +2813,9 @@ void DisplayServerX11::process_events() {
}*/
#endif
if (wd.xic) {
+ // Block events polling while changing input focus
+ // because it triggers some event polling internally.
+ MutexLock mutex_lock(events_mutex);
XSetICFocus(wd.xic);
}
@@ -2682,7 +2865,10 @@ void DisplayServerX11::process_events() {
xi.state.clear();
#endif
if (wd.xic) {
- XSetICFocus(wd.xic);
+ // Block events polling while changing input focus
+ // because it triggers some event polling internally.
+ MutexLock mutex_lock(events_mutex);
+ XUnsetICFocus(wd.xic);
}
} break;
@@ -2801,11 +2987,11 @@ void DisplayServerX11::process_events() {
break;
}
- if (XPending(x11_display) > 0) {
- XEvent tevent;
- XPeekEvent(x11_display, &tevent);
- if (tevent.type == MotionNotify) {
- XNextEvent(x11_display, &event);
+ if (event_index + 1 < events.size()) {
+ const XEvent &next_event = events[event_index + 1];
+ if (next_event.type == MotionNotify) {
+ ++event_index;
+ event = next_event;
} else {
break;
}
@@ -2936,67 +3122,7 @@ void DisplayServerX11::process_events() {
// key event is a little complex, so
// it will be handled in its own function.
- _handle_key_event(window_id, (XKeyEvent *)&event);
- } break;
- case SelectionRequest: {
- XSelectionRequestEvent *req;
- XEvent e, respond;
- e = event;
-
- req = &(e.xselectionrequest);
- if (req->target == XInternAtom(x11_display, "UTF8_STRING", 0) ||
- req->target == XInternAtom(x11_display, "COMPOUND_TEXT", 0) ||
- req->target == XInternAtom(x11_display, "TEXT", 0) ||
- req->target == XA_STRING ||
- req->target == XInternAtom(x11_display, "text/plain;charset=utf-8", 0) ||
- req->target == XInternAtom(x11_display, "text/plain", 0)) {
- CharString clip = clipboard_get().utf8();
- XChangeProperty(x11_display,
- req->requestor,
- req->property,
- req->target,
- 8,
- PropModeReplace,
- (unsigned char *)clip.get_data(),
- clip.length());
- respond.xselection.property = req->property;
- } else if (req->target == XInternAtom(x11_display, "TARGETS", 0)) {
- Atom data[7];
- data[0] = XInternAtom(x11_display, "TARGETS", 0);
- data[1] = XInternAtom(x11_display, "UTF8_STRING", 0);
- data[2] = XInternAtom(x11_display, "COMPOUND_TEXT", 0);
- data[3] = XInternAtom(x11_display, "TEXT", 0);
- data[4] = XA_STRING;
- data[5] = XInternAtom(x11_display, "text/plain;charset=utf-8", 0);
- data[6] = XInternAtom(x11_display, "text/plain", 0);
-
- XChangeProperty(x11_display,
- req->requestor,
- req->property,
- XA_ATOM,
- 32,
- PropModeReplace,
- (unsigned char *)&data,
- sizeof(data) / sizeof(data[0]));
- respond.xselection.property = req->property;
-
- } else {
- char *targetname = XGetAtomName(x11_display, req->target);
- printf("No Target '%s'\n", targetname);
- if (targetname) {
- XFree(targetname);
- }
- respond.xselection.property = None;
- }
-
- respond.xselection.type = SelectionNotify;
- respond.xselection.display = req->display;
- respond.xselection.requestor = req->requestor;
- respond.xselection.selection = req->selection;
- respond.xselection.target = req->target;
- respond.xselection.time = req->time;
- XSendEvent(x11_display, req->requestor, True, NoEventMask, &respond);
- XFlush(x11_display);
+ _handle_key_event(window_id, (XKeyEvent *)&event, events, event_index);
} break;
case SelectionNotify:
@@ -3391,6 +3517,10 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u
XChangeProperty(x11_display, wd.x11_window, xdnd_aware, XA_ATOM, 32, PropModeReplace, (unsigned char *)&xdnd_version, 1);
if (xim && xim_style) {
+ // Block events polling while changing input focus
+ // because it triggers some event polling internally.
+ MutexLock mutex_lock(events_mutex);
+
wd.xic = XCreateIC(xim, XNInputStyle, xim_style, XNClientWindow, wd.x11_window, XNFocusWindow, wd.x11_window, (char *)nullptr);
if (XGetICValues(wd.xic, XNFilterEvents, &im_event_mask, nullptr) != nullptr) {
WARN_PRINT("XGetICValues couldn't obtain XNFilterEvents value");
@@ -3542,7 +3672,12 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
xrandr_handle = dlopen("libXrandr.so.2", RTLD_LAZY);
if (!xrandr_handle) {
err = dlerror();
- fprintf(stderr, "could not load libXrandr.so.2, Error: %s\n", err);
+ // For some arcane reason, NetBSD now ships libXrandr.so.3 while the rest of the world has libXrandr.so.2...
+ // In case this happens for other X11 platforms in the future, let's give it a try too before failing.
+ xrandr_handle = dlopen("libXrandr.so.3", RTLD_LAZY);
+ if (!xrandr_handle) {
+ fprintf(stderr, "could not load libXrandr.so.2, Error: %s\n", err);
+ }
} else {
XRRQueryVersion(x11_display, &xrandr_major, &xrandr_minor);
if (((xrandr_major << 8) | xrandr_minor) >= 0x0105) {
@@ -3888,12 +4023,19 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
}
}
+ events_thread = Thread::create(_poll_events_thread, this);
+
_update_real_mouse_position(windows[MAIN_WINDOW_ID]);
r_error = OK;
}
DisplayServerX11::~DisplayServerX11() {
+ events_thread_done = true;
+ Thread::wait_to_finish(events_thread);
+ memdelete(events_thread);
+ events_thread = nullptr;
+
//destroy all windows
for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
#ifdef VULKAN_ENABLED
diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h
index 57cee910a0..740bf81fd9 100644
--- a/platform/linuxbsd/display_server_x11.h
+++ b/platform/linuxbsd/display_server_x11.h
@@ -36,6 +36,7 @@
#include "servers/display_server.h"
#include "core/input/input.h"
+#include "core/local_vector.h"
#include "drivers/alsa/audio_driver_alsa.h"
#include "drivers/alsamidi/midi_driver_alsamidi.h"
#include "drivers/pulseaudio/audio_driver_pulseaudio.h"
@@ -202,7 +203,11 @@ class DisplayServerX11 : public DisplayServer {
MouseMode mouse_mode;
Point2i center;
- void _handle_key_event(WindowID p_window, XKeyEvent *p_event, bool p_echo = false);
+ void _handle_key_event(WindowID p_window, XKeyEvent *p_event, LocalVector<XEvent> &p_events, uint32_t &p_event_index, bool p_echo = false);
+ void _handle_selection_request_event(XSelectionRequestEvent *p_event);
+
+ String _clipboard_get_impl(Atom p_source, Window x11_window, Atom target) const;
+ String _clipboard_get(Atom p_source, Window x11_window) const;
//bool minimized;
//bool window_has_focus;
@@ -252,6 +257,16 @@ class DisplayServerX11 : public DisplayServer {
static void _dispatch_input_events(const Ref<InputEvent> &p_event);
void _dispatch_input_event(const Ref<InputEvent> &p_event);
+ mutable Mutex events_mutex;
+ Thread *events_thread = nullptr;
+ bool events_thread_done = false;
+ LocalVector<XEvent> polled_events;
+ static void _poll_events_thread(void *ud);
+ void _poll_events();
+
+ static Bool _predicate_all_events(Display *display, XEvent *event, XPointer arg);
+ static Bool _predicate_clipboard_selection(Display *display, XEvent *event, XPointer arg);
+
protected:
void _window_changed(XEvent *event);
@@ -291,6 +306,8 @@ public:
virtual ObjectID window_get_attached_instance_id(WindowID p_window = MAIN_WINDOW_ID) const;
virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID);
+ virtual void window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window = MAIN_WINDOW_ID);
+
virtual void window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
virtual void window_set_window_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
virtual void window_set_input_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
diff --git a/platform/linuxbsd/platform_config.h b/platform/linuxbsd/platform_config.h
index 764666681f..571ad03db0 100644
--- a/platform/linuxbsd/platform_config.h
+++ b/platform/linuxbsd/platform_config.h
@@ -31,7 +31,15 @@
#ifdef __linux__
#include <alloca.h>
#endif
-#if defined(__FreeBSD__) || defined(__OpenBSD__)
-#include <stdlib.h>
+
+#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
+#include <stdlib.h> // alloca
+// FreeBSD and OpenBSD use pthread_set_name_np, while other platforms,
+// include NetBSD, use pthread_setname_np. NetBSD's version however requires
+// a different format, we handle this directly in thread_posix.
+#ifdef __NetBSD__
+#define PTHREAD_NETBSD_SET_NAME
+#else
#define PTHREAD_BSD_SET_NAME
#endif
+#endif