diff options
Diffstat (limited to 'platform/x11')
-rw-r--r-- | platform/x11/detect.py | 151 | ||||
-rw-r--r-- | platform/x11/export/export.cpp | 2 | ||||
-rw-r--r-- | platform/x11/godot_x11.cpp | 3 | ||||
-rw-r--r-- | platform/x11/os_x11.cpp | 202 | ||||
-rw-r--r-- | platform/x11/os_x11.h | 7 |
5 files changed, 267 insertions, 98 deletions
diff --git a/platform/x11/detect.py b/platform/x11/detect.py index 0ba0f68393..79778136ad 100644 --- a/platform/x11/detect.py +++ b/platform/x11/detect.py @@ -1,7 +1,6 @@ - import os -import sys import platform +import sys def is_active(): @@ -14,15 +13,12 @@ def get_name(): def can_build(): - if (os.name != "posix"): + if (os.name != "posix" or sys.platform == "darwin"): return False - if sys.platform == "darwin": - return False # no x11 on mac for now - - errorval = os.system("pkg-config --version > /dev/null") - - if (errorval): + # Check the minimal dependencies + x11_error = os.system("pkg-config --version > /dev/null") + if (x11_error): print("pkg-config not found.. x11 disabled.") return False @@ -31,11 +27,6 @@ def can_build(): print("X11 not found.. x11 disabled.") return False - ssl_error = os.system("pkg-config openssl --modversion > /dev/null ") - if (ssl_error): - print("OpenSSL not found.. x11 disabled.") - return False - x11_error = os.system("pkg-config xcursor --modversion > /dev/null ") if (x11_error): print("xcursor not found.. x11 disabled.") @@ -51,18 +42,18 @@ def can_build(): print("xrandr not found.. x11 disabled.") return False - return True # X11 enabled + return True def get_opts(): return [ - ('use_llvm', 'Use llvm compiler', 'no'), - ('use_static_cpp', 'link stdc++ statically', 'no'), - ('use_sanitizer', 'Use llvm compiler sanitize address', 'no'), - ('use_leak_sanitizer', 'Use llvm compiler sanitize memory leaks', 'no'), + ('use_llvm', 'Use the LLVM compiler', 'no'), + ('use_static_cpp', 'Link stdc++ statically', 'no'), + ('use_sanitizer', 'Use LLVM compiler address sanitizer', 'no'), + ('use_leak_sanitizer', 'Use LLVM compiler memory leaks sanitizer (implies use_sanitizer)', 'no'), ('use_lto', 'Use link time optimization', 'no'), - ('pulseaudio', 'Detect & Use pulseaudio', 'yes'), + ('pulseaudio', 'Detect & use pulseaudio', 'yes'), ('udev', 'Use udev for gamepad connection callbacks', 'no'), ('debug_release', 'Add debug symbols to release version', 'no'), ] @@ -80,66 +71,62 @@ def get_flags(): def configure(env): - is64 = sys.maxsize > 2**32 + ## Build type + + if (env["target"] == "release"): + env.Prepend(CCFLAGS=['-Ofast']) + if (env["debug_release"] == "yes"): + env.Prepend(CCFLAGS=['-g2']) + + elif (env["target"] == "release_debug"): + env.Prepend(CCFLAGS=['-O2', '-ffast-math', '-DDEBUG_ENABLED']) + if (env["debug_release"] == "yes"): + env.Prepend(CCFLAGS=['-g2']) + + elif (env["target"] == "debug"): + env.Prepend(CCFLAGS=['-g2', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED']) + + ## Architecture + is64 = sys.maxsize > 2**32 if (env["bits"] == "default"): - if (is64): - env["bits"] = "64" - else: - env["bits"] = "32" + env["bits"] = "64" if is64 else "32" + + ## Compiler configuration - env.Append(CPPPATH=['#platform/x11']) if (env["use_llvm"] == "yes"): - if 'clang++' not in env['CXX']: + if ('clang++' not in env['CXX']): env["CC"] = "clang" env["CXX"] = "clang++" env["LD"] = "clang++" env.Append(CPPFLAGS=['-DTYPED_METHOD_BIND']) - env.extra_suffix = ".llvm" - - if (env["use_sanitizer"] == "yes"): - env.Append(CCFLAGS=['-fsanitize=address', '-fno-omit-frame-pointer']) - env.Append(LINKFLAGS=['-fsanitize=address']) - env.extra_suffix += "s" + env.extra_suffix = ".llvm" + env.extra_suffix - if (env["use_leak_sanitizer"] == "yes"): + # leak sanitizer requires (address) sanitizer + if (env["use_sanitizer"] == "yes" or env["use_leak_sanitizer"] == "yes"): env.Append(CCFLAGS=['-fsanitize=address', '-fno-omit-frame-pointer']) env.Append(LINKFLAGS=['-fsanitize=address']) env.extra_suffix += "s" - - # if (env["tools"]=="no"): - # #no tools suffix - # env['OBJSUFFIX'] = ".nt"+env['OBJSUFFIX'] - # env['LIBSUFFIX'] = ".nt"+env['LIBSUFFIX'] + if (env["use_leak_sanitizer"] == "yes"): + env.Append(CCFLAGS=['-fsanitize=leak']) + env.Append(LINKFLAGS=['-fsanitize=leak']) if (env["use_lto"] == "yes"): env.Append(CCFLAGS=['-flto']) env.Append(LINKFLAGS=['-flto']) - env.Append(CCFLAGS=['-pipe']) env.Append(LINKFLAGS=['-pipe']) - if (env["target"] == "release"): - env.Prepend(CCFLAGS=['-Ofast']) - if (env["debug_release"] == "yes"): - env.Prepend(CCFLAGS=['-g2']) - - elif (env["target"] == "release_debug"): - - env.Prepend(CCFLAGS=['-O2', '-ffast-math', '-DDEBUG_ENABLED']) - if (env["debug_release"] == "yes"): - env.Prepend(CCFLAGS=['-g2']) - - elif (env["target"] == "debug"): - - env.Prepend(CCFLAGS=['-g2', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED']) + ## Dependencies env.ParseConfig('pkg-config x11 --cflags --libs') - env.ParseConfig('pkg-config xinerama --cflags --libs') env.ParseConfig('pkg-config xcursor --cflags --libs') + env.ParseConfig('pkg-config xinerama --cflags --libs') env.ParseConfig('pkg-config xrandr --cflags --libs') + # FIXME: Check for existence of the libs before parsing their flags with pkg-config + if (env['builtin_openssl'] == 'no'): # Currently not compatible with OpenSSL 1.1.0+ # https://github.com/godotengine/godot/issues/8624 @@ -196,47 +183,51 @@ def configure(env): if (env['builtin_libogg'] == 'no'): env.ParseConfig('pkg-config ogg --cflags --libs') - env.Append(CPPFLAGS=['-DOPENGL_ENABLED']) + if (env['builtin_libtheora'] != 'no'): + list_of_x86 = ['x86_64', 'x86', 'i386', 'i586'] + if any(platform.machine() in s for s in list_of_x86): + env["x86_libtheora_opt_gcc"] = True + + ## Flags - if os.system("pkg-config --exists alsa") == 0: + if (os.system("pkg-config --exists alsa") == 0): # 0 means found print("Enabling ALSA") env.Append(CPPFLAGS=["-DALSA_ENABLED"]) env.ParseConfig('pkg-config alsa --cflags --libs') else: print("ALSA libraries not found, disabling driver") - if (platform.system() == "Linux"): - env.Append(CPPFLAGS=["-DJOYDEV_ENABLED"]) - if (env["udev"] == "yes"): - # pkg-config returns 0 when the lib exists... - found_udev = not os.system("pkg-config --exists libudev") - - if (found_udev): - print("Enabling udev support") - env.Append(CPPFLAGS=["-DUDEV_ENABLED"]) - env.ParseConfig('pkg-config libudev --cflags --libs') - else: - print("libudev development libraries not found, disabling udev support") - if (env["pulseaudio"] == "yes"): - if not os.system("pkg-config --exists libpulse-simple"): + if (os.system("pkg-config --exists libpulse-simple") == 0): # 0 means found print("Enabling PulseAudio") env.Append(CPPFLAGS=["-DPULSEAUDIO_ENABLED"]) env.ParseConfig('pkg-config --cflags --libs libpulse-simple') else: print("PulseAudio development libraries not found, disabling driver") + if (platform.system() == "Linux"): + env.Append(CPPFLAGS=["-DJOYDEV_ENABLED"]) + + if (env["udev"] == "yes"): + if (os.system("pkg-config --exists libudev") == 0): # 0 means found + print("Enabling udev support") + env.Append(CPPFLAGS=["-DUDEV_ENABLED"]) + env.ParseConfig('pkg-config libudev --cflags --libs') + else: + print("libudev development libraries not found, disabling udev support") + + # Linkflags below this line should typically stay the last ones if (env['builtin_zlib'] == 'no'): env.ParseConfig('pkg-config zlib --cflags --libs') - env.Append(CPPFLAGS=['-DX11_ENABLED', '-DUNIX_ENABLED', '-DGLES2_ENABLED', '-DGLES_OVER_GL']) + env.Append(CPPPATH=['#platform/x11']) + env.Append(CPPFLAGS=['-DX11_ENABLED', '-DUNIX_ENABLED', '-DOPENGL_ENABLED', '-DGLES2_ENABLED', '-DGLES_OVER_GL']) env.Append(LIBS=['GL', 'pthread']) if (platform.system() == "Linux"): env.Append(LIBS=['dl']) - # env.Append(CPPFLAGS=['-DMPC_FIXED_POINT']) - # host compiler is default.. + ## Cross-compilation if (is64 and env["bits"] == "32"): env.Append(CPPFLAGS=['-m32']) @@ -245,17 +236,5 @@ def configure(env): env.Append(CPPFLAGS=['-m64']) env.Append(LINKFLAGS=['-m64', '-L/usr/lib/i686-linux-gnu']) - import methods - - # FIXME: Commented out when moving to gles3 - #env.Append(BUILDERS={'GLSL120': env.Builder(action=methods.build_legacygl_headers, suffix='glsl.h', src_suffix='.glsl')}) - #env.Append(BUILDERS={'GLSL': env.Builder(action=methods.build_glsl_headers, suffix='glsl.h', src_suffix='.glsl')}) - #env.Append(BUILDERS={'GLSL120GLES': env.Builder(action=methods.build_gles2_headers, suffix='glsl.h', src_suffix='.glsl')}) - #env.Append( BUILDERS = { 'HLSL9' : env.Builder(action = methods.build_hlsl_dx9_headers, suffix = 'hlsl.h',src_suffix = '.hlsl') } ) - if (env["use_static_cpp"] == "yes"): env.Append(LINKFLAGS=['-static-libstdc++']) - - list_of_x86 = ['x86_64', 'x86', 'i386', 'i586'] - if any(platform.machine() in s for s in list_of_x86): - env["x86_libtheora_opt_gcc"] = True diff --git a/platform/x11/export/export.cpp b/platform/x11/export/export.cpp index d6bad95e5b..69784a473d 100644 --- a/platform/x11/export/export.cpp +++ b/platform/x11/export/export.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "export.h" #include "editor/editor_export.h" -#include "platform/x11/logo.h" +#include "platform/x11/logo.gen.h" #include "scene/resources/texture.h" void register_x11_exporter() { diff --git a/platform/x11/godot_x11.cpp b/platform/x11/godot_x11.cpp index b293b1bebb..6f418b213f 100644 --- a/platform/x11/godot_x11.cpp +++ b/platform/x11/godot_x11.cpp @@ -28,6 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include <limits.h> +#include <locale.h> #include <stdlib.h> #include <unistd.h> @@ -38,6 +39,8 @@ int main(int argc, char *argv[]) { OS_X11 os; + setlocale(LC_CTYPE, ""); + char *cwd = (char *)malloc(PATH_MAX); getcwd(cwd, PATH_MAX); diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index 2eebc96d2c..790182794e 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -68,6 +68,8 @@ #undef CursorShape +#include <X11/XKBlib.h> + int OS_X11::get_video_driver_count() const { return 1; } @@ -93,6 +95,7 @@ const char *OS_X11::get_audio_driver_name(int p_driver) const { void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { + long im_event_mask = 0; last_button_state = 0; xmbstring = NULL; @@ -113,7 +116,32 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au /** XLIB INITIALIZATION **/ x11_display = XOpenDisplay(NULL); - char *modifiers = XSetLocaleModifiers("@im=none"); + Bool xkb_dar = False; + if (x11_display) { + XAutoRepeatOn(x11_display); + xkb_dar = XkbSetDetectableAutoRepeat(x11_display, True, NULL); + } + + char *modifiers = NULL; + + // 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 + modifiers = XSetLocaleModifiers(""); +#endif + } + + if (modifiers == NULL) { + if (is_stdout_verbose()) { + WARN_PRINT("IME is disabled"); + } + modifiers = XSetLocaleModifiers("@im=none"); + } if (modifiers == NULL) { WARN_PRINT("Error setting locale modifiers"); } @@ -153,6 +181,14 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au WARN_PRINT("XOpenIM failed"); xim_style = 0L; } else { + ::XIMCallback im_destroy_callback; + im_destroy_callback.client_data = (::XPointer)(this); + im_destroy_callback.callback = (::XIMProc)(xim_destroy_callback); + if (XSetIMValues(xim, XNDestroyCallback, &im_destroy_callback, + NULL) != NULL) { + WARN_PRINT("Error setting XIM destroy callback"); + } + ::XIMStyles *xim_styles = NULL; xim_style = 0L; char *imvalret = NULL; @@ -242,6 +278,13 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au xev.xclient.data.l[2] = 0; XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureNotifyMask, &xev); + } else if (current_videomode.borderless_window) { + 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); } // disable resizable window @@ -303,7 +346,8 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au StructureNotifyMask | SubstructureNotifyMask | SubstructureRedirectMask | FocusChangeMask | PropertyChangeMask | - ColormapChangeMask | OwnerGrabButtonMask; + ColormapChangeMask | OwnerGrabButtonMask | + im_event_mask; XChangeWindowAttributes(x11_display, x11_window, CWEventMask, &new_attr); @@ -327,6 +371,16 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au if (xim && xim_style) { xic = XCreateIC(xim, XNInputStyle, xim_style, XNClientWindow, x11_window, XNFocusWindow, x11_window, (char *)NULL); + if (XGetICValues(xic, XNFilterEvents, &im_event_mask, NULL) != NULL) { + WARN_PRINT("XGetICValues couldn't obtain XNFilterEvents value"); + XDestroyIC(xic); + xic = NULL; + } + if (xic) { + XSetICFocus(xic); + } else { + WARN_PRINT("XCreateIC couldn't create xic"); + } } else { xic = NULL; @@ -445,6 +499,33 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au _ensure_data_dir(); } +void OS_X11::xim_destroy_callback(::XIM im, ::XPointer client_data, + ::XPointer call_data) { + + WARN_PRINT("Input method stopped"); + OS_X11 *os = reinterpret_cast<OS_X11 *>(client_data); + os->xim = NULL; + os->xic = NULL; +} + +void OS_X11::set_ime_position(short x, short y) { + + if (!xic) { + return; + } + ::XPoint spot; + spot.x = x; + spot.y = y; + XVaNestedList preedit_attr = XVaCreateNestedList(0, + XNSpotLocation, &spot, + NULL); + XSetICValues(xic, + XNPreeditAttributes, preedit_attr, + NULL); + XFree(preedit_attr); + return; +} + void OS_X11::finalize() { if (main_loop) @@ -492,8 +573,12 @@ void OS_X11::finalize() { XcursorImageDestroy(img[i]); }; - XDestroyIC(xic); - XCloseIM(xim); + if (xic) { + XDestroyIC(xic); + } + if (xim) { + XCloseIM(xim); + } XCloseDisplay(x11_display); if (xmbstring) @@ -940,6 +1025,25 @@ bool OS_X11::is_window_maximized() const { return false; } +void OS_X11::set_borderless_window(int p_borderless) { + + if (current_videomode.borderless_window == p_borderless) + return; + + current_videomode.borderless_window = p_borderless; + + Hints hints; + Atom property; + hints.flags = 2; + hints.decorations = current_videomode.borderless_window ? 0 : 1; + property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True); + XChangeProperty(x11_display, x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5); +} + +bool OS_X11::get_borderless_window() { + return current_videomode.borderless_window; +} + void OS_X11::request_attention() { // Using EWMH -- Extended Window Manager Hints // @@ -1041,9 +1145,61 @@ void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) { xmblen = 8; } + keysym_unicode = keysym_keycode; + if (xkeyevent->type == KeyPress && xic) { Status status; +#ifdef X_HAVE_UTF8_STRING + int utf8len = 8; + char *utf8string = (char *)memalloc(sizeof(char) * utf8len); + int utf8bytes = Xutf8LookupString(xic, xkeyevent, utf8string, + utf8len - 1, &keysym_unicode, &status); + if (status == XBufferOverflow) { + utf8len = utf8bytes + 1; + utf8string = (char *)memrealloc(utf8string, utf8len); + utf8bytes = Xutf8LookupString(xic, xkeyevent, utf8string, + utf8len - 1, &keysym_unicode, &status); + } + utf8string[utf8bytes] = '\0'; + + if (status == XLookupChars) { + bool keypress = xkeyevent->type == KeyPress; + unsigned int keycode = KeyMappingX11::get_keycode(keysym_keycode); + if (keycode >= 'a' && keycode <= 'z') + keycode -= 'a' - 'A'; + + String tmp; + tmp.parse_utf8(utf8string, utf8bytes); + for (int i = 0; i < tmp.length(); i++) { + Ref<InputEventKey> k; + k.instance(); + if (keycode == 0 && tmp[i] == 0) { + continue; + } + + get_key_modifier_state(xkeyevent->state, k); + + k->set_unicode(tmp[i]); + + k->set_pressed(keypress); + + k->set_scancode(keycode); + + k->set_echo(false); + + if (k->get_scancode() == KEY_BACKTAB) { + //make it consistent across platforms. + k->set_scancode(KEY_TAB); + k->set_shift(true); + } + + input->parse_input_event(k); + } + return; + } + memfree(utf8string); +#else do { int mnbytes = XmbLookupString(xic, xkeyevent, xmbstring, xmblen - 1, &keysym_unicode, &status); @@ -1054,6 +1210,7 @@ void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) { xmbstring = (char *)memrealloc(xmbstring, xmblen); } } while (status == XBufferOverflow); +#endif } /* Phase 2, obtain a pigui keycode from the keysym */ @@ -1082,11 +1239,6 @@ void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) { bool keypress = xkeyevent->type == KeyPress; - if (xkeyevent->type == KeyPress && xic) { - if (XFilterEvent((XEvent *)xkeyevent, x11_window)) - return; - } - if (keycode == 0 && unicode == 0) return; @@ -1108,17 +1260,19 @@ void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) { // 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 treshold. + // 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); - // I'm using a treshold of 5 msecs, + // I'm using a threshold of 5 msecs, // since sometimes there seems to be a little // jitter. I'm still not convinced that all this approach // is correct, but the xorg developers are @@ -1172,6 +1326,18 @@ void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) { k->set_metakey(false); } + bool last_is_pressed = Input::get_singleton()->is_key_pressed(k->get_scancode()); + if (k->is_pressed()) { + if (last_is_pressed) { + k->set_echo(true); + } + } else { + //ignore + if (last_is_pressed == false) { + return; + } + } + //printf("key: %x\n",k->get_scancode()); input->parse_input_event(k); } @@ -1253,6 +1419,10 @@ void OS_X11::process_xevents() { XEvent event; XNextEvent(x11_display, &event); + if (XFilterEvent(&event, None)) { + continue; + } + switch (event.type) { case Expose: Main::force_redraw(); @@ -1295,6 +1465,9 @@ void OS_X11::process_xevents() { ButtonPressMask | ButtonReleaseMask | PointerMotionMask, GrabModeAsync, GrabModeAsync, x11_window, None, CurrentTime); } + if (xic) { + XSetICFocus(xic); + } break; case FocusOut: @@ -1308,9 +1481,16 @@ void OS_X11::process_xevents() { } XUngrabPointer(x11_display, CurrentTime); } + if (xic) { + XUnsetICFocus(xic); + } break; case ConfigureNotify: + if (xic) { + // Not portable. + set_ime_position(0, 1); + } /* call resizeGLScene only if our window-size changed */ if ((event.xconfigure.width == current_videomode.width) && diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h index d62186e5bd..39c512b6bd 100644 --- a/platform/x11/os_x11.h +++ b/platform/x11/os_x11.h @@ -113,6 +113,10 @@ class OS_X11 : public OS_Unix { ::XIC xic; ::XIM xim; ::XIMStyle xim_style; + static void xim_destroy_callback(::XIM im, ::XPointer client_data, + ::XPointer call_data); + void set_ime_position(short x, short y); + Point2i last_mouse_pos; bool last_mouse_pos_valid; Point2i last_click_pos; @@ -247,6 +251,9 @@ public: virtual bool is_window_maximized() const; virtual void request_attention(); + virtual void set_borderless_window(int p_borderless); + virtual bool get_borderless_window(); + virtual void move_window_to_foreground(); virtual void alert(const String &p_alert, const String &p_title = "ALERT!"); |