summaryrefslogtreecommitdiff
path: root/platform/x11
diff options
context:
space:
mode:
Diffstat (limited to 'platform/x11')
-rw-r--r--platform/x11/SCsub9
-rw-r--r--platform/x11/context_gl_x11.cpp4
-rw-r--r--platform/x11/detect.py17
-rw-r--r--platform/x11/export/export.cpp3
-rw-r--r--platform/x11/os_x11.cpp297
-rw-r--r--platform/x11/os_x11.h20
-rw-r--r--platform/x11/power_x11.cpp6
7 files changed, 292 insertions, 64 deletions
diff --git a/platform/x11/SCsub b/platform/x11/SCsub
index aabc49149f..38dd2ddd88 100644
--- a/platform/x11/SCsub
+++ b/platform/x11/SCsub
@@ -4,9 +4,9 @@ import os
Import('env')
def make_debug(target, source, env):
- os.system('objcopy --only-keep-debug %s %s.debug' % (target[0], target[0]))
+ os.system('objcopy --only-keep-debug %s %s.debugsymbols' % (target[0], target[0]))
os.system('strip --strip-debug --strip-unneeded %s' % (target[0]))
- os.system('objcopy --add-gnu-debuglink=%s.debug %s' % (target[0], target[0]))
+ os.system('objcopy --add-gnu-debuglink=%s.debugsymbols %s' % (target[0], target[0]))
common_x11 = [
"context_gl_x11.cpp",
@@ -17,6 +17,7 @@ common_x11 = [
"power_x11.cpp",
]
-binary = env.Program('#bin/godot', ['godot_x11.cpp'] + common_x11)
+prog = env.add_program('#bin/godot', ['godot_x11.cpp'] + common_x11)
+
if env["debug_symbols"] == "full" or env["debug_symbols"] == "yes":
- env.AddPostAction(binary, make_debug)
+ env.AddPostAction(prog, make_debug)
diff --git a/platform/x11/context_gl_x11.cpp b/platform/x11/context_gl_x11.cpp
index 4f9d4a84b9..61c6b3c9dd 100644
--- a/platform/x11/context_gl_x11.cpp
+++ b/platform/x11/context_gl_x11.cpp
@@ -228,8 +228,8 @@ bool ContextGL_X11::is_using_vsync() const {
return use_vsync;
}
-ContextGL_X11::ContextGL_X11(::Display *p_x11_display, ::Window &p_x11_window, const OS::VideoMode &p_default_video_mode, bool p_opengl_3_context)
- : x11_window(p_x11_window) {
+ContextGL_X11::ContextGL_X11(::Display *p_x11_display, ::Window &p_x11_window, const OS::VideoMode &p_default_video_mode, bool p_opengl_3_context) :
+ x11_window(p_x11_window) {
default_video_mode = p_default_video_mode;
x11_display = p_x11_display;
diff --git a/platform/x11/detect.py b/platform/x11/detect.py
index 6bd0ac8317..09bf57c5f1 100644
--- a/platform/x11/detect.py
+++ b/platform/x11/detect.py
@@ -55,6 +55,7 @@ def get_opts():
BoolVariable('pulseaudio', 'Detect & use pulseaudio', True),
BoolVariable('udev', 'Use udev for gamepad connection callbacks', False),
EnumVariable('debug_symbols', 'Add debug symbols to release version', 'yes', ('yes', 'no', 'full')),
+ BoolVariable('touch', 'Enable touch events', True),
]
@@ -141,6 +142,14 @@ def configure(env):
env.ParseConfig('pkg-config xinerama --cflags --libs')
env.ParseConfig('pkg-config xrandr --cflags --libs')
+ if (env['touch']):
+ x11_error = os.system("pkg-config xi --modversion > /dev/null ")
+ if (x11_error):
+ print("xi not found.. cannot build with touch. Aborting.")
+ sys.exit(255)
+ env.ParseConfig('pkg-config xi --cflags --libs')
+ env.Append(CPPFLAGS=['-DTOUCH_ENABLED'])
+
# FIXME: Check for existence of the libs before parsing their flags with pkg-config
if not env['builtin_openssl']:
@@ -149,6 +158,7 @@ def configure(env):
if not env['builtin_libwebp']:
env.ParseConfig('pkg-config libwebp --cflags --libs')
+
# freetype depends on libpng and zlib, so bundling one of them while keeping others
# as shared libraries leads to weird issues
if env['builtin_freetype'] or env['builtin_libpng'] or env['builtin_zlib']:
@@ -236,7 +246,7 @@ def configure(env):
env.ParseConfig('pkg-config zlib --cflags --libs')
env.Append(CPPPATH=['#platform/x11'])
- env.Append(CPPFLAGS=['-DX11_ENABLED', '-DUNIX_ENABLED', '-DOPENGL_ENABLED', '-DGLES2_ENABLED', '-DGLES_OVER_GL'])
+ env.Append(CPPFLAGS=['-DX11_ENABLED', '-DUNIX_ENABLED', '-DOPENGL_ENABLED', '-DGLES_ENABLED', '-DGLES_OVER_GL'])
env.Append(LIBS=['GL', 'pthread'])
if (platform.system() == "Linux"):
@@ -254,5 +264,10 @@ def configure(env):
env.Append(CPPFLAGS=['-m64'])
env.Append(LINKFLAGS=['-m64', '-L/usr/lib/i686-linux-gnu'])
+
+ if env["openmp"]:
+ env.Append(CPPFLAGS=['-fopenmp'])
+ env.Append(LINKFLAGS=['-fopenmp'])
+
if env['use_static_cpp']:
env.Append(LINKFLAGS=['-static-libstdc++'])
diff --git a/platform/x11/export/export.cpp b/platform/x11/export/export.cpp
index fdb43c9ae0..1baa3e127f 100644
--- a/platform/x11/export/export.cpp
+++ b/platform/x11/export/export.cpp
@@ -44,7 +44,8 @@ void register_x11_exporter() {
logo->create_from_image(img);
platform->set_logo(logo);
platform->set_name("Linux/X11");
- platform->set_extension("bin");
+ platform->set_extension("x86");
+ 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");
diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp
index f018145d82..0c0bc1a8a3 100644
--- a/platform/x11/os_x11.cpp
+++ b/platform/x11/os_x11.cpp
@@ -132,10 +132,9 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
// Try to support IME if detectable auto-repeat is supported
if (xkb_dar == True) {
-// Xutf8LookupString will be used later instead of XmbLookupString before
-// the multibyte sequences can be converted to unicode string.
-
#ifdef X_HAVE_UTF8_STRING
+ // Xutf8LookupString will be used later instead of XmbLookupString before
+ // the multibyte sequences can be converted to unicode string.
modifiers = XSetLocaleModifiers("");
#endif
}
@@ -178,6 +177,49 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
}
}
+#ifdef TOUCH_ENABLED
+ if (!XQueryExtension(x11_display, "XInputExtension", &touch.opcode, &event_base, &error_base)) {
+ fprintf(stderr, "XInput extension not available");
+ } else {
+ // 2.2 is the first release with multitouch
+ int xi_major = 2;
+ int xi_minor = 2;
+ if (XIQueryVersion(x11_display, &xi_major, &xi_minor) != Success) {
+ fprintf(stderr, "XInput 2.2 not available (server supports %d.%d)\n", xi_major, xi_minor);
+ touch.opcode = 0;
+ } else {
+ int dev_count;
+ XIDeviceInfo *info = XIQueryDevice(x11_display, XIAllDevices, &dev_count);
+
+ for (int i = 0; i < dev_count; i++) {
+ XIDeviceInfo *dev = &info[i];
+ if (!dev->enabled)
+ continue;
+ if (!(dev->use == XIMasterPointer || dev->use == XIFloatingSlave))
+ continue;
+
+ bool direct_touch = false;
+ for (int j = 0; j < dev->num_classes; j++) {
+ if (dev->classes[j]->type == XITouchClass && ((XITouchClassInfo *)dev->classes[j])->mode == XIDirectTouch) {
+ direct_touch = true;
+ break;
+ }
+ }
+ if (direct_touch) {
+ touch.devices.push_back(dev->deviceid);
+ fprintf(stderr, "Using touch device: %s\n", dev->name);
+ }
+ }
+
+ XIFreeDeviceInfo(info);
+
+ if (!touch.devices.size()) {
+ fprintf(stderr, "No touch devices found\n");
+ }
+ }
+ }
+#endif
+
xim = XOpenIM(x11_display, NULL, NULL, NULL);
if (xim == NULL) {
@@ -243,6 +285,8 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
RasterizerGLES3::make_current();
+ context_gl->set_use_vsync(current_videomode.use_vsync);
+
#endif
visual_server = memnew(VisualServerRaster);
@@ -250,41 +294,13 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
visual_server = memnew(VisualServerWrapMT(visual_server, get_render_thread_mode() == RENDER_SEPARATE_THREAD));
}
-
- // borderless fullscreen window mode
- if (current_videomode.fullscreen) {
- // set bypass compositor hint
- Atom bypass_compositor = XInternAtom(x11_display, "_NET_WM_BYPASS_COMPOSITOR", False);
- unsigned long compositing_disable_on = 1;
- XChangeProperty(x11_display, x11_window, bypass_compositor, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&compositing_disable_on, 1);
-
- // needed for lxde/openbox, possibly others
- Hints hints;
- Atom property;
- hints.flags = 2;
- hints.decorations = 0;
- property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True);
- XChangeProperty(x11_display, x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5);
- XMapRaised(x11_display, x11_window);
- XWindowAttributes xwa;
- XGetWindowAttributes(x11_display, DefaultRootWindow(x11_display), &xwa);
- XMoveResizeWindow(x11_display, x11_window, 0, 0, xwa.width, xwa.height);
-
- // code for netwm-compliants
- XEvent xev;
- Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
- Atom fullscreen = XInternAtom(x11_display, "_NET_WM_STATE_FULLSCREEN", False);
-
- memset(&xev, 0, sizeof(xev));
- xev.type = ClientMessage;
- xev.xclient.window = x11_window;
- xev.xclient.message_type = wm_state;
- xev.xclient.format = 32;
- xev.xclient.data.l[0] = 1;
- xev.xclient.data.l[1] = fullscreen;
- xev.xclient.data.l[2] = 0;
-
- XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureNotifyMask, &xev);
+ if (current_videomode.maximized) {
+ current_videomode.maximized = false;
+ set_window_maximized(true);
+ // borderless fullscreen window mode
+ } else if (current_videomode.fullscreen) {
+ current_videomode.fullscreen = false;
+ set_window_fullscreen(true);
} else if (current_videomode.borderless_window) {
Hints hints;
Atom property;
@@ -336,6 +352,34 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
XChangeWindowAttributes(x11_display, x11_window, CWEventMask, &new_attr);
+#ifdef TOUCH_ENABLED
+ if (touch.devices.size()) {
+
+ // Must be alive after this block
+ static unsigned char mask_data[XIMaskLen(XI_LASTEVENT)] = {};
+
+ touch.event_mask.deviceid = XIAllDevices;
+ touch.event_mask.mask_len = sizeof(mask_data);
+ touch.event_mask.mask = mask_data;
+
+ XISetMask(touch.event_mask.mask, XI_TouchBegin);
+ XISetMask(touch.event_mask.mask, XI_TouchUpdate);
+ XISetMask(touch.event_mask.mask, XI_TouchEnd);
+ XISetMask(touch.event_mask.mask, XI_TouchOwnership);
+
+ XISelectEvents(x11_display, x11_window, &touch.event_mask, 1);
+
+ // Disabled by now since grabbing also blocks mouse events
+ // (they are received as extended events instead of standard events)
+ /*XIClearMask(touch.event_mask.mask, XI_TouchOwnership);
+
+ // Grab touch devices to avoid OS gesture interference
+ for (int i = 0; i < touch.devices.size(); ++i) {
+ XIGrabDevice(x11_display, touch.devices[i], x11_window, CurrentTime, None, XIGrabModeAsync, XIGrabModeAsync, False, &touch.event_mask);
+ }*/
+ }
+#endif
+
/* set the titlebar name */
XStoreName(x11_display, x11_window, "Godot");
@@ -464,9 +508,17 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
#ifdef JOYDEV_ENABLED
joypad = memnew(JoypadLinux(input));
#endif
- _ensure_data_dir();
+ _ensure_user_data_dir();
power_manager = memnew(PowerX11);
+
+ XEvent xevent;
+ while (XPending(x11_display) > 0) {
+ XNextEvent(x11_display, &xevent);
+ if (xevent.type == ConfigureNotify) {
+ _window_changed(&xevent);
+ }
+ }
}
void OS_X11::xim_destroy_callback(::XIM im, ::XPointer client_data,
@@ -497,7 +549,7 @@ void OS_X11::finalize() {
memdelete(main_loop);
main_loop = NULL;
-/*
+ /*
if (debugger_connection_console) {
memdelete(debugger_connection_console);
}
@@ -506,6 +558,10 @@ void OS_X11::finalize() {
#ifdef JOYDEV_ENABLED
memdelete(joypad);
#endif
+#ifdef TOUCH_ENABLED
+ touch.devices.clear();
+ touch.state.clear();
+#endif
memdelete(input);
visual_server->finish();
@@ -648,6 +704,9 @@ void OS_X11::get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen) con
}
void OS_X11::set_wm_fullscreen(bool p_enabled) {
+ if (current_videomode.fullscreen == p_enabled)
+ return;
+
if (p_enabled && !is_window_resizable()) {
// Set the window as resizable to prevent window managers to ignore the fullscreen state flag.
XSizeHints *xsh;
@@ -971,6 +1030,9 @@ bool OS_X11::is_window_minimized() const {
}
void OS_X11::set_window_maximized(bool p_enabled) {
+ if (is_window_maximized() == p_enabled)
+ return;
+
// Using EWMH -- Extended Window Manager Hints
XEvent xev;
Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
@@ -1036,7 +1098,7 @@ bool OS_X11::is_window_maximized() const {
return false;
}
-void OS_X11::set_borderless_window(int p_borderless) {
+void OS_X11::set_borderless_window(bool p_borderless) {
if (current_videomode.borderless_window == p_borderless)
return;
@@ -1417,6 +1479,20 @@ static Atom pick_target_from_atoms(Display *p_disp, Atom p_t1, Atom p_t2, Atom p
return None;
}
+void OS_X11::_window_changed(XEvent *event) {
+
+ if (xic) {
+ // Not portable.
+ set_ime_position(Point2(0, 1));
+ }
+ if ((event->xconfigure.width == current_videomode.width) &&
+ (event->xconfigure.height == current_videomode.height))
+ return;
+
+ current_videomode.width = event->xconfigure.width;
+ current_videomode.height = event->xconfigure.height;
+}
+
void OS_X11::process_xevents() {
//printf("checking events %i\n", XPending(x11_display));
@@ -1434,6 +1510,69 @@ void OS_X11::process_xevents() {
continue;
}
+#ifdef TOUCH_ENABLED
+ if (XGetEventData(x11_display, &event.xcookie)) {
+
+ if (event.xcookie.type == GenericEvent && event.xcookie.extension == touch.opcode) {
+
+ XIDeviceEvent *event_data = (XIDeviceEvent *)event.xcookie.data;
+ int index = event_data->detail;
+ Vector2 pos = Vector2(event_data->event_x, event_data->event_y);
+
+ switch (event_data->evtype) {
+
+ case XI_TouchBegin: // Fall-through
+ // Disabled hand-in-hand with the grabbing
+ //XIAllowTouchEvents(x11_display, event_data->deviceid, event_data->detail, x11_window, XIAcceptTouch);
+
+ case XI_TouchEnd: {
+
+ bool is_begin = event_data->evtype == XI_TouchBegin;
+
+ Ref<InputEventScreenTouch> st;
+ st.instance();
+ st->set_index(index);
+ st->set_position(pos);
+ st->set_pressed(is_begin);
+
+ if (is_begin) {
+ if (touch.state.has(index)) // Defensive
+ break;
+ touch.state[index] = pos;
+ input->parse_input_event(st);
+ } else {
+ if (!touch.state.has(index)) // Defensive
+ break;
+ touch.state.erase(index);
+ input->parse_input_event(st);
+ }
+ } break;
+
+ case XI_TouchUpdate: {
+
+ Map<int, Vector2>::Element *curr_pos_elem = touch.state.find(index);
+ if (!curr_pos_elem) { // Defensive
+ break;
+ }
+
+ if (curr_pos_elem->value() != pos) {
+
+ Ref<InputEventScreenDrag> sd;
+ sd.instance();
+ sd->set_index(index);
+ sd->set_position(pos);
+ sd->set_relative(pos - curr_pos_elem->value());
+ input->parse_input_event(sd);
+
+ curr_pos_elem->value() = pos;
+ }
+ } break;
+ }
+ }
+ }
+ XFreeEventData(x11_display, &event.xcookie);
+#endif
+
switch (event.type) {
case Expose:
Main::force_redraw();
@@ -1476,6 +1615,12 @@ void OS_X11::process_xevents() {
ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
GrabModeAsync, GrabModeAsync, x11_window, None, CurrentTime);
}
+#ifdef TOUCH_ENABLED
+ // Grab touch devices to avoid OS gesture interference
+ /*for (int i = 0; i < touch.devices.size(); ++i) {
+ XIGrabDevice(x11_display, touch.devices[i], x11_window, CurrentTime, None, XIGrabModeAsync, XIGrabModeAsync, False, &touch.event_mask);
+ }*/
+#endif
if (xic) {
XSetICFocus(xic);
}
@@ -1492,24 +1637,30 @@ void OS_X11::process_xevents() {
}
XUngrabPointer(x11_display, CurrentTime);
}
+#ifdef TOUCH_ENABLED
+ // Ungrab touch devices so input works as usual while we are unfocused
+ /*for (int i = 0; i < touch.devices.size(); ++i) {
+ XIUngrabDevice(x11_display, touch.devices[i], CurrentTime);
+ }*/
+
+ // Release every pointer to avoid sticky points
+ for (Map<int, Vector2>::Element *E = touch.state.front(); E; E = E->next()) {
+
+ Ref<InputEventScreenTouch> st;
+ st.instance();
+ st->set_index(E->key());
+ st->set_position(E->get());
+ input->parse_input_event(st);
+ }
+ touch.state.clear();
+#endif
if (xic) {
XUnsetICFocus(xic);
}
break;
case ConfigureNotify:
- if (xic) {
- // Not portable.
- set_ime_position(Point2(0, 1));
- }
- /* call resizeGLScene only if our window-size changed */
-
- if ((event.xconfigure.width == current_videomode.width) &&
- (event.xconfigure.height == current_videomode.height))
- break;
-
- current_videomode.width = event.xconfigure.width;
- current_videomode.height = event.xconfigure.height;
+ _window_changed(&event);
break;
case ButtonPress:
case ButtonRelease: {
@@ -1941,6 +2092,39 @@ bool OS_X11::_check_internal_feature_support(const String &p_feature) {
return p_feature == "pc" || p_feature == "s3tc";
}
+String OS_X11::get_config_path() const {
+
+ if (has_environment("XDG_CONFIG_HOME")) {
+ return get_environment("XDG_CONFIG_HOME");
+ } else if (has_environment("HOME")) {
+ return get_environment("HOME").plus_file(".config");
+ } else {
+ return ".";
+ }
+}
+
+String OS_X11::get_data_path() const {
+
+ if (has_environment("XDG_DATA_HOME")) {
+ return get_environment("XDG_DATA_HOME");
+ } else if (has_environment("HOME")) {
+ return get_environment("HOME").plus_file(".local/share");
+ } else {
+ return get_config_path();
+ }
+}
+
+String OS_X11::get_cache_path() const {
+
+ if (has_environment("XDG_CACHE_HOME")) {
+ return get_environment("XDG_CACHE_HOME");
+ } else if (has_environment("HOME")) {
+ return get_environment("HOME").plus_file(".cache");
+ } else {
+ return get_config_path();
+ }
+}
+
String OS_X11::get_system_dir(SystemDir p_dir) const {
String xdgparam;
@@ -2080,6 +2264,13 @@ void OS_X11::set_icon(const Ref<Image> &p_icon) {
XFlush(x11_display);
}
+void OS_X11::force_process_input() {
+ process_xevents(); // get rid of pending events
+#ifdef JOYDEV_ENABLED
+ joypad->process_joypads();
+#endif
+}
+
void OS_X11::run() {
force_quit = false;
diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h
index 0ea5bbfdb6..c8cea1e30c 100644
--- a/platform/x11/os_x11.h
+++ b/platform/x11/os_x11.h
@@ -48,6 +48,9 @@
#include <X11/Xlib.h>
#include <X11/extensions/Xrandr.h>
#include <X11/keysym.h>
+#ifdef TOUCH_ENABLED
+#include <X11/extensions/XInput2.h>
+#endif
// Hints for X11 fullscreen
typedef struct {
@@ -117,6 +120,14 @@ class OS_X11 : public OS_Unix {
Point2i last_click_pos;
uint64_t last_click_ms;
uint32_t last_button_state;
+#ifdef TOUCH_ENABLED
+ struct {
+ int opcode;
+ Vector<int> devices;
+ XIEventMask event_mask;
+ Map<int, Vector2> state;
+ } touch;
+#endif
unsigned int get_mouse_button_state(unsigned int p_x11_state);
void get_key_modifier_state(unsigned int p_x11_state, Ref<InputEventWithModifiers> state);
@@ -187,6 +198,8 @@ protected:
virtual void set_main_loop(MainLoop *p_main_loop);
+ void _window_changed(XEvent *xevent);
+
public:
virtual String get_name();
@@ -213,6 +226,10 @@ public:
virtual void make_rendering_thread();
virtual void swap_buffers();
+ virtual String get_config_path() const;
+ virtual String get_data_path() const;
+ virtual String get_cache_path() const;
+
virtual String get_system_dir(SystemDir p_dir) const;
virtual Error shell_open(String p_uri);
@@ -241,7 +258,7 @@ public:
virtual bool is_window_maximized() const;
virtual void request_attention();
- virtual void set_borderless_window(int p_borderless);
+ virtual void set_borderless_window(bool p_borderless);
virtual bool get_borderless_window();
virtual void set_ime_position(const Point2 &p_pos);
@@ -262,6 +279,7 @@ public:
virtual bool _check_internal_feature_support(const String &p_feature);
+ virtual void force_process_input();
void run();
void disable_crash_handler();
diff --git a/platform/x11/power_x11.cpp b/platform/x11/power_x11.cpp
index 76ff7f91fb..0ef2629cb0 100644
--- a/platform/x11/power_x11.cpp
+++ b/platform/x11/power_x11.cpp
@@ -542,8 +542,10 @@ bool PowerX11::UpdatePowerInfo() {
return false;
}
-PowerX11::PowerX11()
- : nsecs_left(-1), percent_left(-1), power_state(OS::POWERSTATE_UNKNOWN) {
+PowerX11::PowerX11() :
+ nsecs_left(-1),
+ percent_left(-1),
+ power_state(OS::POWERSTATE_UNKNOWN) {
}
PowerX11::~PowerX11() {