Merge branch 'master' into blender2.8
authorCampbell Barton <ideasman42@gmail.com>
Sat, 9 Jun 2018 09:27:22 +0000 (11:27 +0200)
committerCampbell Barton <ideasman42@gmail.com>
Sat, 9 Jun 2018 09:27:22 +0000 (11:27 +0200)
1  2 
intern/ghost/intern/GHOST_SystemX11.cpp
intern/ghost/intern/GHOST_SystemX11.h

  
  #include "GHOST_Debug.h"
  
 +#if defined(WITH_GL_EGL)
 +#  include "GHOST_ContextEGL.h"
 +#else
 +#  include "GHOST_ContextGLX.h"
 +#endif
 +
  #ifdef WITH_XF86KEYSYM
  #include <X11/XF86keysym.h>
  #endif
   * See T47228 and D1746 */
  #define USE_NON_LATIN_KB_WORKAROUND
  
- static GHOST_TKey convertXKey(KeySym key);
+ static GHOST_TKey ghost_key_from_keysym(
+         const KeySym key);
+ static GHOST_TKey ghost_key_from_keycode(
+         const XkbDescPtr xkb_descr, const KeyCode keycode);
+ static GHOST_TKey ghost_key_from_keysym_or_keycode(
+         const KeySym key, const XkbDescPtr xkb_descr, const KeyCode keycode);
  
  /* these are for copy and select copy */
  static char *txt_cut_buffer = NULL;
@@@ -117,9 -116,9 +122,10 @@@ GHOST_SystemX11:
  GHOST_SystemX11(
          )
      : GHOST_System(),
+       m_xkb_descr(NULL),
        m_start_time(0)
  {
 +      XInitThreads();
        m_display = XOpenDisplay(NULL);
  
        if (!m_display) {
        use_xkb = XkbQueryExtension(m_display, &xkb_opcode, &xkb_event, &xkb_error, &xkb_major, &xkb_minor);
        if (use_xkb) {
                XkbSetDetectableAutoRepeat(m_display, true, NULL);
+               m_xkb_descr = XkbGetMap(m_display, 0, XkbUseCoreKbd);
+               if (m_xkb_descr) {
+                       XkbGetNames(m_display, XkbKeyNamesMask, m_xkb_descr);
+               }
        }
  
  #ifdef WITH_XWAYLAND_HACK
@@@ -249,6 -253,10 +260,10 @@@ GHOST_SystemX11:
                XCloseDevice(m_display, m_xtablet.EraserDevice);
  #endif /* WITH_X11_XINPUT */
  
+       if (m_xkb_descr) {
+               XkbFreeNames(m_xkb_descr, XkbKeyNamesMask, false);
+       }
        XCloseDisplay(m_display);
  }
  
@@@ -391,97 -399,6 +406,97 @@@ bool GHOST_SystemX11::supportsNativeDia
        return false;
  }
  
 +/**
 + * Create a new offscreen context.
 + * Never explicitly delete the context, use disposeContext() instead.
 + * \return  The new context (or 0 if creation failed).
 + */
 +GHOST_IContext *
 +GHOST_SystemX11::
 +createOffscreenContext()
 +{
 +      // During development:
 +      //   try 4.x compatibility profile
 +      //   try 3.3 compatibility profile
 +      //   fall back to 3.0 if needed
 +      //
 +      // Final Blender 2.8:
 +      //   try 4.x core profile
 +      //   try 3.3 core profile
 +      //   no fallbacks
 +
 +#if defined(WITH_GL_PROFILE_CORE)
 +      {
 +              const char *version_major = (char*)glewGetString(GLEW_VERSION_MAJOR);
 +              if (version_major != NULL && version_major[0] == '1') {
 +                      fprintf(stderr, "Error: GLEW version 2.0 and above is required.\n");
 +                      abort();
 +              }
 +      }
 +#endif
 +
 +      const int profile_mask =
 +#if defined(WITH_GL_PROFILE_CORE)
 +              GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
 +#elif defined(WITH_GL_PROFILE_COMPAT)
 +              GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
 +#else
 +#  error // must specify either core or compat at build time
 +#endif
 +
 +      GHOST_Context *context;
 +
 +      for (int minor = 5; minor >= 0; --minor) {
 +              context = new GHOST_ContextGLX(
 +                      false,
 +                      0,
 +                      (Window)NULL,
 +                      m_display,
 +                      (GLXFBConfig)NULL,
 +                      profile_mask,
 +                      4, minor,
 +                      GHOST_OPENGL_GLX_CONTEXT_FLAGS | (false ? GLX_CONTEXT_DEBUG_BIT_ARB : 0),
 +                      GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY);
 +
 +              if (context->initializeDrawingContext())
 +                      return context;
 +              else
 +                      delete context;
 +      }
 +
 +      context = new GHOST_ContextGLX(
 +              false,
 +              0,
 +              (Window)NULL,
 +              m_display,
 +              (GLXFBConfig)NULL,
 +              profile_mask,
 +              3, 3,
 +              GHOST_OPENGL_GLX_CONTEXT_FLAGS | (false ? GLX_CONTEXT_DEBUG_BIT_ARB : 0),
 +              GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY);
 +
 +      if (context->initializeDrawingContext())
 +              return context;
 +      else
 +              delete context;
 +
 +      return NULL;
 +}
 +
 +/**
 + * Dispose of a context.
 + * \param   context Pointer to the context to be disposed.
 + * \return  Indication of success.
 + */
 +GHOST_TSuccess
 +GHOST_SystemX11::
 +disposeContext(GHOST_IContext *context)
 +{
 +      delete context;
 +
 +      return GHOST_kSuccess;
 +}
 +
  #if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
  static void destroyIMCallback(XIM /*xim*/, XPointer ptr, XPointer /*data*/)
  {
@@@ -724,7 -641,7 +739,7 @@@ processEvents
                                                                                      getMilliSeconds(),
                                                                                      GHOST_kEventKeyDown,
                                                                                      window,
-                                                                                     convertXKey(modifiers[i]),
+                                                                                     ghost_key_from_keysym(modifiers[i]),
                                                                                      '\0',
                                                                                      NULL));
                                                                }
@@@ -981,7 -898,7 +996,7 @@@ GHOST_SystemX11::processEvent(XEvent *x
                         *       is unmodified (or anyone swapping the keys with xmodmap).
                         *
                         *     - XLookupKeysym seems to always use first defined keymap (see T47228), which generates
-                        *       keycodes unusable by convertXKey for non-latin-compatible keymaps.
+                        *       keycodes unusable by ghost_key_from_keysym for non-latin-compatible keymaps.
                         *
                         * To address this, we:
                         *
  
                        /* Only allow a limited set of keys from XLookupKeysym, all others we take from XLookupString,
                         * unless it gives unknown key... */
-                       gkey = convertXKey(key_sym);
+                       gkey = ghost_key_from_keysym_or_keycode(key_sym, m_xkb_descr, xke->keycode);
                        switch (gkey) {
                                case GHOST_kKeyRightAlt:
                                case GHOST_kKeyLeftAlt:
                                case GHOST_kKeyNumpadSlash:
                                        break;
                                default:
-                                       GHOST_TKey gkey_str = convertXKey(key_sym_str);
+                               {
+                                       GHOST_TKey gkey_str = ghost_key_from_keysym(key_sym_str);
                                        if (gkey_str != GHOST_kKeyUnknown) {
                                                gkey = gkey_str;
                                        }
+                               }
                        }
  #else
                        /* In keyboards like latin ones,
                                key_sym = XLookupKeysym(xke, 0);
                        }
  
-                       gkey = convertXKey(key_sym);
+                       gkey = ghost_key_from_keysym(key_sym);
  
                        if (!XLookupString(xke, &ascii, 1, NULL, NULL)) {
                                ascii = '\0';
@@@ -1730,10 -1649,22 +1747,22 @@@ generateWindowExposeEvents(
        return anyProcessed;
  }
  
+ static GHOST_TKey
+ ghost_key_from_keysym_or_keycode(const KeySym keysym, XkbDescPtr xkb_descr, const KeyCode keycode)
+ {
+       GHOST_TKey type = ghost_key_from_keysym(keysym);
+       if (type == GHOST_kKeyUnknown) {
+               if (xkb_descr) {
+                       type = ghost_key_from_keycode(xkb_descr, keycode);
+               }
+       }
+       return type;
+ }
  #define GXMAP(k, x, y) case x: k = y; break
  
  static GHOST_TKey
convertXKey(KeySym key)
ghost_key_from_keysym(const KeySym key)
  {
        GHOST_TKey type;
  
                        GXMAP(type, XF86XK_AudioForward, GHOST_kKeyMediaLast);
  #endif
  #endif
-                       /* Non US keyboard layouts: avoid 'UnknownKey' - TODO(campbell): lookup scan-codes. */
-                       GXMAP(type, XK_dead_circumflex, GHOST_kKeyAccentGrave);         /* 'de' */
-                       GXMAP(type, XK_dead_grave, GHOST_kKeyAccentGrave);              /* 'us' (intl) */
-                       GXMAP(type, XK_masculine, GHOST_kKeyAccentGrave);               /* 'es' */
-                       GXMAP(type, XK_onehalf, GHOST_kKeyAccentGrave);                 /* 'dk' */
-                       GXMAP(type, XK_twosuperior, GHOST_kKeyAccentGrave);             /* 'fr' */
                        default:
  #ifdef GHOST_DEBUG
                                printf("%s: unknown key: %lu / 0x%lx\n", __func__, key, key);
  
  #undef GXMAP
  
+ #define MAKE_ID(a, b, c, d) ((int)(d) << 24 | (int)(c) << 16 | (b) << 8 | (a))
+ static GHOST_TKey
+ ghost_key_from_keycode(const XkbDescPtr xkb_descr, const KeyCode keycode)
+ {
+       GHOST_ASSERT(XkbKeyNameLength == 4, "Name length is invalid!");
+       if (keycode >= xkb_descr->min_key_code && keycode <= xkb_descr->max_key_code) {
+               const char *id_str = xkb_descr->names->keys[keycode].name;
+               const uint32_t id = MAKE_ID(id_str[0], id_str[1], id_str[2], id_str[3]);
+               // printf("scancode is: %.*s\n", XkbKeyNameLength, id_str);
+               switch (id) {
+                       case MAKE_ID('T', 'L', 'D', 'E'):
+                               return GHOST_kKeyAccentGrave;
+               }
+       }
+       else {
+               GHOST_ASSERT(false, "KeyCode out of range!");
+       }
+       return GHOST_kKeyUnknown;
+ }
+ #undef MAKE_ID
  /* from xclip.c xcout() v0.11 */
  
  #define XCLIB_XCOUT_NONE            0 /* no context */
@@@ -34,6 -34,7 +34,7 @@@
  #define __GHOST_SYSTEMX11_H__
  
  #include <X11/Xlib.h>
+ #include <X11/XKBlib.h> /* allow detectable autorepeate */
  
  #include "GHOST_System.h"
  #include "../GHOST_Types.h"
@@@ -175,26 -176,6 +176,26 @@@ public
            const GHOST_TEmbedderWindowID parentWindow = 0
            );
  
 +
 +      /**
 +       * Create a new offscreen context.
 +       * Never explicitly delete the context, use disposeContext() instead.
 +       * \return  The new context (or 0 if creation failed).
 +       */
 +      GHOST_IContext *
 +      createOffscreenContext(
 +          );
 +
 +      /**
 +       * Dispose of a context.
 +       * \param   context Pointer to the context to be disposed.
 +       * \return  Indication of success.
 +       */
 +      GHOST_TSuccess
 +      disposeContext(
 +          GHOST_IContext *context
 +          );
 +
        /**
         * Retrieves events from the system and stores them in the queue.
         * \param waitForEvent Flag to wait for an event (or return immediately).
  private:
  
        Display *m_display;
+       /* Use for scancode lookups. */
+       XkbDescRec *m_xkb_descr;
  #if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
        XIM m_xim;
  #endif