diff --git a/src/video/x11/SDL_x11keyboard.c b/src/video/x11/SDL_x11keyboard.c index f89d98ada6..b1fb94c078 100644 --- a/src/video/x11/SDL_x11keyboard.c +++ b/src/video/x11/SDL_x11keyboard.c @@ -107,6 +107,84 @@ static SDL_Scancode X11_KeyCodeToSDLScancode(SDL_VideoDevice *_this, KeyCode key return SDL_GetScancodeFromKeySym(keysym, keycode); } +#ifdef X_HAVE_UTF8_STRING +static bool X11_InitIM(SDL_VideoData *videodata); + +static void im_instantiate_handler(Display *display, XPointer clientData, XPointer callData) +{ + SDL_VideoData *videodata = (SDL_VideoData *)clientData; + + if (X11_InitIM(videodata)) { + X11_XUnregisterIMInstantiateCallback(videodata->display, NULL, NULL, NULL, im_instantiate_handler, clientData); + } +} + +static void im_destroyed_handler(XIM im, XPointer clientData, XPointer callData) +{ + SDL_VideoData *videodata = (SDL_VideoData *)clientData; + + videodata->im = NULL; + X11_XRegisterIMInstantiateCallback(videodata->display, NULL, NULL, NULL, im_instantiate_handler, clientData); +} + +static bool X11_InitIM(SDL_VideoData *videodata) +{ + /* Set the locale, and call XSetLocaleModifiers before XOpenIM so that + * Compose keys will work correctly. + */ + char *prev_locale = setlocale(LC_ALL, NULL); + char *prev_xmods = X11_XSetLocaleModifiers(NULL); + + if (prev_locale) { + prev_locale = SDL_strdup(prev_locale); + } + + if (prev_xmods) { + prev_xmods = SDL_strdup(prev_xmods); + } + + (void)setlocale(LC_ALL, ""); + X11_XSetLocaleModifiers(""); + + XIM im = X11_XOpenIM(videodata->display, NULL, NULL, NULL); + + /* Reset the locale + X locale modifiers back to how they were, + * locale first because the X locale modifiers depend on it. + */ + (void)setlocale(LC_ALL, prev_locale); + X11_XSetLocaleModifiers(prev_xmods); + + SDL_free(prev_locale); + SDL_free(prev_xmods); + + if (im) { + videodata->im = im; + + XIMCallback destroyed_callback; + destroyed_callback.client_data = (XPointer)videodata; + destroyed_callback.callback = (XIMProc)im_destroyed_handler; + + X11_XSetIMValues(im, XNDestroyCallback, &destroyed_callback, NULL); + + /* Attach the new IC to any existing windows. + * + * If we wound up here before any old input contexts were destroyed, + * they will be recreated in the IC destroyed callback. + */ + for (int i = 0; i < videodata->numwindows; ++i) { + SDL_WindowData *w = videodata->windowlist[i]; + if (!w->ic) { + X11_CreateInputContext(w); + } + } + + return true; + } + + return false; +} +#endif // X_HAVE_UTF8_STRING + bool X11_InitKeyboard(SDL_VideoDevice *_this) { SDL_VideoData *data = _this->internal; @@ -160,32 +238,9 @@ bool X11_InitKeyboard(SDL_VideoDevice *_this) // Open a connection to the X input manager #ifdef X_HAVE_UTF8_STRING if (SDL_X11_HAVE_UTF8) { - /* Set the locale, and call XSetLocaleModifiers before XOpenIM so that - Compose keys will work correctly. */ - char *prev_locale = setlocale(LC_ALL, NULL); - char *prev_xmods = X11_XSetLocaleModifiers(NULL); - - if (prev_locale) { - prev_locale = SDL_strdup(prev_locale); + if (!X11_InitIM(data)) { + X11_XRegisterIMInstantiateCallback(data->display, NULL, NULL, NULL, im_instantiate_handler, (XPointer)data); } - - if (prev_xmods) { - prev_xmods = SDL_strdup(prev_xmods); - } - - (void)setlocale(LC_ALL, ""); - X11_XSetLocaleModifiers(""); - - data->im = X11_XOpenIM(data->display, NULL, NULL, NULL); - - /* Reset the locale + X locale modifiers back to how they were, - locale first because the X locale modifiers depend on it. */ - (void)setlocale(LC_ALL, prev_locale); - X11_XSetLocaleModifiers(prev_xmods); - - SDL_free(prev_locale); - - SDL_free(prev_xmods); } #endif // Try to determine which scancodes are being used based on fingerprint @@ -522,6 +577,15 @@ void X11_QuitKeyboard(SDL_VideoDevice *_this) { SDL_VideoData *data = _this->internal; +#ifdef X_HAVE_UTF8_STRING + if (data->im) { + X11_XCloseIM(data->im); + data->im = NULL; + } else { + X11_XUnregisterIMInstantiateCallback(data->display, NULL, NULL, NULL, im_instantiate_handler, (XPointer)data); + } +#endif // X_HAVE_UTF8_STRING + #ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLIB if (data->keyboard.xkb_enabled) { for (int i = 0; i < XkbNumKbdGroups; ++i) { @@ -584,6 +648,7 @@ static void X11_SendEditingEvent(SDL_WindowData *data) data->ime_needs_clear_composition = true; } +#ifdef X_HAVE_UTF8_STRING static int preedit_start_callback(XIC xic, XPointer client_data, XPointer call_data) { // No limit on preedit text length @@ -716,7 +781,14 @@ static void ic_destroyed_handler(XIC ic, XPointer clientData, XPointer callData) { SDL_WindowData *data = (SDL_WindowData *)clientData; data->ic = NULL; + X11_DestroyInputContext(data); + + // If the IM was already recreated, create a new IC. + if (data->videodata->im) { + X11_CreateInputContext(data); + } } +#endif // X_HAVE_UTF8_STRING void X11_CreateInputContext(SDL_WindowData *data) { diff --git a/src/video/x11/SDL_x11sym.h b/src/video/x11/SDL_x11sym.h index 1f1335373f..e195346a6f 100644 --- a/src/video/x11/SDL_x11sym.h +++ b/src/video/x11/SDL_x11sym.h @@ -231,6 +231,9 @@ SDL_X11_SYM(void,XSetICFocus,(XIC a)) SDL_X11_SYM(void,XUnsetICFocus,(XIC a)) SDL_X11_SYM(XIM,XOpenIM,(Display* a,struct _XrmHashBucketRec* b,char* c,char* d)) SDL_X11_SYM(Status,XCloseIM,(XIM a)) +SDL_X11_SYM(char*, XSetIMValues,(XIM,...)) +SDL_X11_SYM(Bool,XRegisterIMInstantiateCallback,(Display*,struct _XrmHashBucketRec*,char*,char*,XIDProc,XPointer)) +SDL_X11_SYM(Bool,XUnregisterIMInstantiateCallback,(Display*,struct _XrmHashBucketRec*,char*,char*,XIDProc,XPointer)) SDL_X11_SYM(void,Xutf8DrawString,(Display *a, Drawable b, XFontSet c, GC d, int e, int f, _Xconst char *g, int h)) SDL_X11_SYM(int,Xutf8TextExtents,(XFontSet a, _Xconst char* b, int c, XRectangle* d, XRectangle* e)) SDL_X11_SYM(char*,XSetLocaleModifiers,(const char *a)) diff --git a/src/video/x11/SDL_x11video.c b/src/video/x11/SDL_x11video.c index 80e86ff9af..4ed9e0a3d3 100644 --- a/src/video/x11/SDL_x11video.c +++ b/src/video/x11/SDL_x11video.c @@ -489,12 +489,6 @@ void X11_VideoQuit(SDL_VideoDevice *_this) X11_XDestroyWindow(data->display, data->xsettings_window); } -#ifdef X_HAVE_UTF8_STRING - if (data->im) { - X11_XCloseIM(data->im); - } -#endif - X11_QuitXinput2(_this); X11_QuitModes(_this); X11_QuitKeyboard(_this);