diff options
Diffstat (limited to 'platform/x11')
-rw-r--r-- | platform/x11/SCsub | 5 | ||||
-rw-r--r-- | platform/x11/context_gl_x11.cpp | 4 | ||||
-rw-r--r-- | platform/x11/detect.py | 9 | ||||
-rw-r--r-- | platform/x11/os_x11.cpp | 169 | ||||
-rw-r--r-- | platform/x11/os_x11.h | 11 | ||||
-rw-r--r-- | platform/x11/power_x11.cpp | 6 |
6 files changed, 194 insertions, 10 deletions
diff --git a/platform/x11/SCsub b/platform/x11/SCsub index aabc49149f..6378553638 100644 --- a/platform/x11/SCsub +++ b/platform/x11/SCsub @@ -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 3d07851c4f..d7dbe71da4 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']: diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index d1aa129e77..263ff012d4 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,50 @@ 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) + 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; + printf("%d) %d %s\n", i, dev->attachment, dev->name); + 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 suitable touch device found\n"); + } + } + } +#endif + xim = XOpenIM(x11_display, NULL, NULL, NULL); if (xim == NULL) { @@ -243,6 +286,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); @@ -308,6 +353,32 @@ 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 = XIAllMasterDevices; + 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); + + 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"); @@ -478,7 +549,7 @@ void OS_X11::finalize() { memdelete(main_loop); main_loop = NULL; -/* + /* if (debugger_connection_console) { memdelete(debugger_connection_console); } @@ -487,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(); @@ -1435,6 +1510,69 @@ void OS_X11::process_xevents() { continue; } +#ifdef TOUCH_ENABLED + if (XGetEventData(x11_display, &event.xcookie)) { + + if (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 + 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(); @@ -1477,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); } @@ -1493,6 +1637,23 @@ 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); } diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h index a74e6ee5f3..84dff2e089 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); 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() { |