mirror of
https://github.com/libsdl-org/SDL.git
synced 2026-09-17 10:34:48 +00:00
x11: Register IM destruction/instantiation callbacks
Register callbacks to listen for IM destruction and instantiation to handle the IME shutting down and restarting during runtime.
(cherry picked from commit 7e8a850246)
This commit is contained in:
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -472,12 +472,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);
|
||||
|
||||
Reference in New Issue
Block a user