Fix cannot input Chinese after restarting the input method on X11
Register a callback via `XRegisterIMInstantiateCallback()` to detect whether the input method is available again.
This commit is contained in:
@ -4143,7 +4143,6 @@ void DisplayServerX11::_xim_preedit_caret_callback(::XIM xim, ::XPointer client_
|
|||||||
|
|
||||||
void DisplayServerX11::_xim_destroy_callback(::XIM im, ::XPointer client_data,
|
void DisplayServerX11::_xim_destroy_callback(::XIM im, ::XPointer client_data,
|
||||||
::XPointer call_data) {
|
::XPointer call_data) {
|
||||||
WARN_PRINT("Input method stopped");
|
|
||||||
DisplayServerX11 *ds = reinterpret_cast<DisplayServerX11 *>(client_data);
|
DisplayServerX11 *ds = reinterpret_cast<DisplayServerX11 *>(client_data);
|
||||||
ds->xim = nullptr;
|
ds->xim = nullptr;
|
||||||
|
|
||||||
@ -6047,6 +6046,73 @@ DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, W
|
|||||||
return ds;
|
return ds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DisplayServerX11::_create_xic(WindowData &wd) {
|
||||||
|
if (xim && xim_style) {
|
||||||
|
// Block events polling while changing input focus
|
||||||
|
// because it triggers some event polling internally.
|
||||||
|
MutexLock mutex_lock(events_mutex);
|
||||||
|
|
||||||
|
// Force on-the-spot for the over-the-spot style.
|
||||||
|
if ((xim_style & XIMPreeditPosition) != 0) {
|
||||||
|
xim_style &= ~XIMPreeditPosition;
|
||||||
|
xim_style |= XIMPreeditCallbacks;
|
||||||
|
}
|
||||||
|
if ((xim_style & XIMPreeditCallbacks) != 0) {
|
||||||
|
::XIMCallback preedit_start_callback;
|
||||||
|
preedit_start_callback.client_data = (::XPointer)(this);
|
||||||
|
preedit_start_callback.callback = (::XIMProc)(void *)(_xim_preedit_start_callback);
|
||||||
|
|
||||||
|
::XIMCallback preedit_done_callback;
|
||||||
|
preedit_done_callback.client_data = (::XPointer)(this);
|
||||||
|
preedit_done_callback.callback = (::XIMProc)(_xim_preedit_done_callback);
|
||||||
|
|
||||||
|
::XIMCallback preedit_draw_callback;
|
||||||
|
preedit_draw_callback.client_data = (::XPointer)(this);
|
||||||
|
preedit_draw_callback.callback = (::XIMProc)(_xim_preedit_draw_callback);
|
||||||
|
|
||||||
|
::XIMCallback preedit_caret_callback;
|
||||||
|
preedit_caret_callback.client_data = (::XPointer)(this);
|
||||||
|
preedit_caret_callback.callback = (::XIMProc)(_xim_preedit_caret_callback);
|
||||||
|
|
||||||
|
::XVaNestedList preedit_attributes = XVaCreateNestedList(0,
|
||||||
|
XNPreeditStartCallback, &preedit_start_callback,
|
||||||
|
XNPreeditDoneCallback, &preedit_done_callback,
|
||||||
|
XNPreeditDrawCallback, &preedit_draw_callback,
|
||||||
|
XNPreeditCaretCallback, &preedit_caret_callback,
|
||||||
|
(char *)nullptr);
|
||||||
|
|
||||||
|
wd.xic = XCreateIC(xim,
|
||||||
|
XNInputStyle, xim_style,
|
||||||
|
XNClientWindow, wd.x11_xim_window,
|
||||||
|
XNFocusWindow, wd.x11_xim_window,
|
||||||
|
XNPreeditAttributes, preedit_attributes,
|
||||||
|
(char *)nullptr);
|
||||||
|
XFree(preedit_attributes);
|
||||||
|
} else {
|
||||||
|
wd.xic = XCreateIC(xim,
|
||||||
|
XNInputStyle, xim_style,
|
||||||
|
XNClientWindow, wd.x11_xim_window,
|
||||||
|
XNFocusWindow, wd.x11_xim_window,
|
||||||
|
(char *)nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
long im_event_mask = 0;
|
||||||
|
if (XGetICValues(wd.xic, XNFilterEvents, &im_event_mask, nullptr) != nullptr) {
|
||||||
|
WARN_PRINT("XGetICValues couldn't obtain XNFilterEvents value.");
|
||||||
|
XDestroyIC(wd.xic);
|
||||||
|
wd.xic = nullptr;
|
||||||
|
}
|
||||||
|
if (wd.xic) {
|
||||||
|
XUnsetICFocus(wd.xic);
|
||||||
|
} else {
|
||||||
|
WARN_PRINT("XCreateIC couldn't create wd.xic.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
wd.xic = nullptr;
|
||||||
|
WARN_PRINT("XCreateIC couldn't create wd.xic.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, Window p_parent_window) {
|
DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, Window p_parent_window) {
|
||||||
//Create window
|
//Create window
|
||||||
|
|
||||||
@ -6252,70 +6318,7 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V
|
|||||||
XChangeProperty(x11_display, wd.x11_window, xdnd_aware, XA_ATOM, 32, PropModeReplace, (unsigned char *)&xdnd_version, 1);
|
XChangeProperty(x11_display, wd.x11_window, xdnd_aware, XA_ATOM, 32, PropModeReplace, (unsigned char *)&xdnd_version, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xim && xim_style) {
|
_create_xic(wd);
|
||||||
// Block events polling while changing input focus
|
|
||||||
// because it triggers some event polling internally.
|
|
||||||
MutexLock mutex_lock(events_mutex);
|
|
||||||
|
|
||||||
// Force on-the-spot for the over-the-spot style.
|
|
||||||
if ((xim_style & XIMPreeditPosition) != 0) {
|
|
||||||
xim_style &= ~XIMPreeditPosition;
|
|
||||||
xim_style |= XIMPreeditCallbacks;
|
|
||||||
}
|
|
||||||
if ((xim_style & XIMPreeditCallbacks) != 0) {
|
|
||||||
::XIMCallback preedit_start_callback;
|
|
||||||
preedit_start_callback.client_data = (::XPointer)(this);
|
|
||||||
preedit_start_callback.callback = (::XIMProc)(void *)(_xim_preedit_start_callback);
|
|
||||||
|
|
||||||
::XIMCallback preedit_done_callback;
|
|
||||||
preedit_done_callback.client_data = (::XPointer)(this);
|
|
||||||
preedit_done_callback.callback = (::XIMProc)(_xim_preedit_done_callback);
|
|
||||||
|
|
||||||
::XIMCallback preedit_draw_callback;
|
|
||||||
preedit_draw_callback.client_data = (::XPointer)(this);
|
|
||||||
preedit_draw_callback.callback = (::XIMProc)(_xim_preedit_draw_callback);
|
|
||||||
|
|
||||||
::XIMCallback preedit_caret_callback;
|
|
||||||
preedit_caret_callback.client_data = (::XPointer)(this);
|
|
||||||
preedit_caret_callback.callback = (::XIMProc)(_xim_preedit_caret_callback);
|
|
||||||
|
|
||||||
::XVaNestedList preedit_attributes = XVaCreateNestedList(0,
|
|
||||||
XNPreeditStartCallback, &preedit_start_callback,
|
|
||||||
XNPreeditDoneCallback, &preedit_done_callback,
|
|
||||||
XNPreeditDrawCallback, &preedit_draw_callback,
|
|
||||||
XNPreeditCaretCallback, &preedit_caret_callback,
|
|
||||||
(char *)nullptr);
|
|
||||||
|
|
||||||
wd.xic = XCreateIC(xim,
|
|
||||||
XNInputStyle, xim_style,
|
|
||||||
XNClientWindow, wd.x11_xim_window,
|
|
||||||
XNFocusWindow, wd.x11_xim_window,
|
|
||||||
XNPreeditAttributes, preedit_attributes,
|
|
||||||
(char *)nullptr);
|
|
||||||
XFree(preedit_attributes);
|
|
||||||
} else {
|
|
||||||
wd.xic = XCreateIC(xim,
|
|
||||||
XNInputStyle, xim_style,
|
|
||||||
XNClientWindow, wd.x11_xim_window,
|
|
||||||
XNFocusWindow, wd.x11_xim_window,
|
|
||||||
(char *)nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (XGetICValues(wd.xic, XNFilterEvents, &im_event_mask, nullptr) != nullptr) {
|
|
||||||
WARN_PRINT("XGetICValues couldn't obtain XNFilterEvents value");
|
|
||||||
XDestroyIC(wd.xic);
|
|
||||||
wd.xic = nullptr;
|
|
||||||
}
|
|
||||||
if (wd.xic) {
|
|
||||||
XUnsetICFocus(wd.xic);
|
|
||||||
} else {
|
|
||||||
WARN_PRINT("XCreateIC couldn't create wd.xic");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
wd.xic = nullptr;
|
|
||||||
WARN_PRINT("XCreateIC couldn't create wd.xic");
|
|
||||||
}
|
|
||||||
|
|
||||||
_update_context(wd);
|
_update_context(wd);
|
||||||
|
|
||||||
if (p_flags & WINDOW_FLAG_BORDERLESS_BIT) {
|
if (p_flags & WINDOW_FLAG_BORDERLESS_BIT) {
|
||||||
@ -6471,6 +6474,54 @@ static ::XIMStyle _get_best_xim_style(const ::XIMStyle &p_style_a, const ::XIMSt
|
|||||||
return p_style_a;
|
return p_style_a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DisplayServerX11::_xim_instantiate_callback(::Display *display, ::XPointer client_data,
|
||||||
|
::XPointer call_data) {
|
||||||
|
DisplayServerX11 *ds = reinterpret_cast<DisplayServerX11 *>(client_data);
|
||||||
|
|
||||||
|
ds->xim = XOpenIM(display, nullptr, nullptr, nullptr);
|
||||||
|
|
||||||
|
if (ds->xim == nullptr) {
|
||||||
|
WARN_PRINT("XOpenIM failed.");
|
||||||
|
ds->xim_style = 0L;
|
||||||
|
} else {
|
||||||
|
::XIMCallback im_destroy_callback;
|
||||||
|
im_destroy_callback.client_data = client_data;
|
||||||
|
im_destroy_callback.callback = (::XIMProc)(_xim_destroy_callback);
|
||||||
|
if (XSetIMValues(ds->xim, XNDestroyCallback, &im_destroy_callback,
|
||||||
|
nullptr) != nullptr) {
|
||||||
|
WARN_PRINT("Error setting XIM destroy callback.");
|
||||||
|
}
|
||||||
|
|
||||||
|
::XIMStyles *xim_styles = nullptr;
|
||||||
|
ds->xim_style = 0L;
|
||||||
|
char *imvalret = XGetIMValues(ds->xim, XNQueryInputStyle, &xim_styles, nullptr);
|
||||||
|
if (imvalret != nullptr || xim_styles == nullptr) {
|
||||||
|
fprintf(stderr, "Input method doesn't support any styles\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xim_styles) {
|
||||||
|
ds->xim_style = 0L;
|
||||||
|
for (int i = 0; i < xim_styles->count_styles; i++) {
|
||||||
|
const ::XIMStyle &style = xim_styles->supported_styles[i];
|
||||||
|
|
||||||
|
if (!_is_xim_style_supported(style)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ds->xim_style = _get_best_xim_style(ds->xim_style, style);
|
||||||
|
}
|
||||||
|
|
||||||
|
XFree(xim_styles);
|
||||||
|
}
|
||||||
|
XFree(imvalret);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The input method has been (re)started.
|
||||||
|
for (KeyValue<WindowID, WindowData> &E : ds->windows) {
|
||||||
|
ds->_create_xic(E.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, int64_t p_parent_window, Error &r_error) {
|
DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, int64_t p_parent_window, Error &r_error) {
|
||||||
KeyMappingX11::initialize();
|
KeyMappingX11::initialize();
|
||||||
|
|
||||||
@ -6663,10 +6714,10 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
|
|||||||
|
|
||||||
if (modifiers == nullptr) {
|
if (modifiers == nullptr) {
|
||||||
if (OS::get_singleton()->is_stdout_verbose()) {
|
if (OS::get_singleton()->is_stdout_verbose()) {
|
||||||
WARN_PRINT("IME is disabled");
|
WARN_PRINT("IME is disabled.");
|
||||||
}
|
}
|
||||||
XSetLocaleModifiers("@im=none");
|
XSetLocaleModifiers("@im=none");
|
||||||
WARN_PRINT("Error setting locale modifiers");
|
WARN_PRINT("Error setting locale modifiers.");
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *err;
|
const char *err;
|
||||||
@ -6711,42 +6762,9 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
xim = XOpenIM(x11_display, nullptr, nullptr, nullptr);
|
if (!XRegisterIMInstantiateCallback(x11_display, nullptr, nullptr, nullptr, (::XIDProc)(_xim_instantiate_callback), (::XPointer)this)) {
|
||||||
|
WARN_PRINT("Error registering XIM instantiate callback.");
|
||||||
if (xim == nullptr) {
|
_xim_instantiate_callback(x11_display, (::XPointer)this, nullptr);
|
||||||
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,
|
|
||||||
nullptr) != nullptr) {
|
|
||||||
WARN_PRINT("Error setting XIM destroy callback");
|
|
||||||
}
|
|
||||||
|
|
||||||
::XIMStyles *xim_styles = nullptr;
|
|
||||||
xim_style = 0L;
|
|
||||||
char *imvalret = XGetIMValues(xim, XNQueryInputStyle, &xim_styles, nullptr);
|
|
||||||
if (imvalret != nullptr || xim_styles == nullptr) {
|
|
||||||
fprintf(stderr, "Input method doesn't support any styles\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xim_styles) {
|
|
||||||
xim_style = 0L;
|
|
||||||
for (int i = 0; i < xim_styles->count_styles; i++) {
|
|
||||||
const ::XIMStyle &style = xim_styles->supported_styles[i];
|
|
||||||
|
|
||||||
if (!_is_xim_style_supported(style)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
xim_style = _get_best_xim_style(xim_style, style);
|
|
||||||
}
|
|
||||||
|
|
||||||
XFree(xim_styles);
|
|
||||||
}
|
|
||||||
XFree(imvalret);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Atom internment */
|
/* Atom internment */
|
||||||
|
|||||||
@ -236,6 +236,7 @@ class DisplayServerX11 : public DisplayServer {
|
|||||||
WindowID last_focused_window = INVALID_WINDOW_ID;
|
WindowID last_focused_window = INVALID_WINDOW_ID;
|
||||||
|
|
||||||
WindowID window_id_counter = MAIN_WINDOW_ID;
|
WindowID window_id_counter = MAIN_WINDOW_ID;
|
||||||
|
void _create_xic(WindowData &wd);
|
||||||
WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, Window p_parent_window);
|
WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect, Window p_parent_window);
|
||||||
|
|
||||||
String internal_clipboard;
|
String internal_clipboard;
|
||||||
@ -246,7 +247,7 @@ class DisplayServerX11 : public DisplayServer {
|
|||||||
int xmblen = 0;
|
int xmblen = 0;
|
||||||
unsigned long last_timestamp = 0;
|
unsigned long last_timestamp = 0;
|
||||||
::Time last_keyrelease_time = 0;
|
::Time last_keyrelease_time = 0;
|
||||||
::XIM xim;
|
::XIM xim = nullptr;
|
||||||
::XIMStyle xim_style;
|
::XIMStyle xim_style;
|
||||||
|
|
||||||
static int _xim_preedit_start_callback(::XIM xim, ::XPointer client_data,
|
static int _xim_preedit_start_callback(::XIM xim, ::XPointer client_data,
|
||||||
@ -259,6 +260,8 @@ class DisplayServerX11 : public DisplayServer {
|
|||||||
::XIMPreeditCaretCallbackStruct *call_data);
|
::XIMPreeditCaretCallbackStruct *call_data);
|
||||||
static void _xim_destroy_callback(::XIM im, ::XPointer client_data,
|
static void _xim_destroy_callback(::XIM im, ::XPointer client_data,
|
||||||
::XPointer call_data);
|
::XPointer call_data);
|
||||||
|
static void _xim_instantiate_callback(::Display *display, ::XPointer client_data,
|
||||||
|
::XPointer call_data);
|
||||||
|
|
||||||
Point2i last_mouse_pos;
|
Point2i last_mouse_pos;
|
||||||
bool last_mouse_pos_valid = false;
|
bool last_mouse_pos_valid = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user