Merge pull request #103749 from Rindbee/fix-cannot-input-after-restarting-the-input-method-on-x11
Fix cannot input Chinese after restarting the input method on X11
This commit is contained in:
@ -4361,7 +4361,6 @@ void DisplayServerX11::_xim_preedit_caret_callback(::XIM xim, ::XPointer client_
|
||||
|
||||
void DisplayServerX11::_xim_destroy_callback(::XIM im, ::XPointer client_data,
|
||||
::XPointer call_data) {
|
||||
WARN_PRINT("Input method stopped");
|
||||
DisplayServerX11 *ds = reinterpret_cast<DisplayServerX11 *>(client_data);
|
||||
ds->xim = nullptr;
|
||||
|
||||
@ -6249,6 +6248,73 @@ DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, W
|
||||
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) {
|
||||
//Create window
|
||||
|
||||
@ -6461,70 +6527,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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
_create_xic(wd);
|
||||
_update_context(wd);
|
||||
|
||||
if (wd.is_popup || wd.no_focus || (wd.embed_parent && !kde5_embed_workaround)) {
|
||||
@ -6669,6 +6672,54 @@ static ::XIMStyle _get_best_xim_style(const ::XIMStyle &p_style_a, const ::XIMSt
|
||||
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) {
|
||||
KeyMappingX11::initialize();
|
||||
|
||||
@ -6865,10 +6916,10 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
|
||||
|
||||
if (modifiers == nullptr) {
|
||||
if (OS::get_singleton()->is_stdout_verbose()) {
|
||||
WARN_PRINT("IME is disabled");
|
||||
WARN_PRINT("IME is disabled.");
|
||||
}
|
||||
XSetLocaleModifiers("@im=none");
|
||||
WARN_PRINT("Error setting locale modifiers");
|
||||
WARN_PRINT("Error setting locale modifiers.");
|
||||
}
|
||||
|
||||
const char *err;
|
||||
@ -6913,42 +6964,9 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
|
||||
return;
|
||||
}
|
||||
|
||||
xim = XOpenIM(x11_display, nullptr, nullptr, nullptr);
|
||||
|
||||
if (xim == 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);
|
||||
if (!XRegisterIMInstantiateCallback(x11_display, nullptr, nullptr, nullptr, (::XIDProc)(_xim_instantiate_callback), (::XPointer)this)) {
|
||||
WARN_PRINT("Error registering XIM instantiate callback.");
|
||||
_xim_instantiate_callback(x11_display, (::XPointer)this, nullptr);
|
||||
}
|
||||
|
||||
/* Atom internment */
|
||||
|
||||
@ -235,6 +235,7 @@ class DisplayServerX11 : public DisplayServer {
|
||||
WindowID last_focused_window = INVALID_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);
|
||||
|
||||
String internal_clipboard;
|
||||
@ -245,7 +246,7 @@ class DisplayServerX11 : public DisplayServer {
|
||||
int xmblen = 0;
|
||||
unsigned long last_timestamp = 0;
|
||||
::Time last_keyrelease_time = 0;
|
||||
::XIM xim;
|
||||
::XIM xim = nullptr;
|
||||
::XIMStyle xim_style;
|
||||
|
||||
static int _xim_preedit_start_callback(::XIM xim, ::XPointer client_data,
|
||||
@ -258,6 +259,8 @@ class DisplayServerX11 : public DisplayServer {
|
||||
::XIMPreeditCaretCallbackStruct *call_data);
|
||||
static void _xim_destroy_callback(::XIM im, ::XPointer client_data,
|
||||
::XPointer call_data);
|
||||
static void _xim_instantiate_callback(::Display *display, ::XPointer client_data,
|
||||
::XPointer call_data);
|
||||
|
||||
Point2i last_mouse_pos;
|
||||
bool last_mouse_pos_valid = false;
|
||||
|
||||
Reference in New Issue
Block a user