summaryrefslogtreecommitdiff
path: root/platform/x11/os_x11.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'platform/x11/os_x11.cpp')
-rw-r--r--platform/x11/os_x11.cpp132
1 files changed, 122 insertions, 10 deletions
diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp
index 2eebc96d2c..aa20030606 100644
--- a/platform/x11/os_x11.cpp
+++ b/platform/x11/os_x11.cpp
@@ -93,6 +93,7 @@ const char *OS_X11::get_audio_driver_name(int p_driver) const {
void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) {
+ long im_event_mask = 0;
last_button_state = 0;
xmbstring = NULL;
@@ -113,7 +114,10 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
/** XLIB INITIALIZATION **/
x11_display = XOpenDisplay(NULL);
- char *modifiers = XSetLocaleModifiers("@im=none");
+ char *modifiers = XSetLocaleModifiers("");
+ if (modifiers == NULL) {
+ modifiers = XSetLocaleModifiers("@im=none");
+ }
if (modifiers == NULL) {
WARN_PRINT("Error setting locale modifiers");
}
@@ -153,6 +157,14 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
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,
+ NULL) != NULL) {
+ WARN_PRINT("Error setting XIM destroy callback");
+ }
+
::XIMStyles *xim_styles = NULL;
xim_style = 0L;
char *imvalret = NULL;
@@ -303,7 +315,8 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
StructureNotifyMask |
SubstructureNotifyMask | SubstructureRedirectMask |
FocusChangeMask | PropertyChangeMask |
- ColormapChangeMask | OwnerGrabButtonMask;
+ ColormapChangeMask | OwnerGrabButtonMask |
+ im_event_mask;
XChangeWindowAttributes(x11_display, x11_window, CWEventMask, &new_attr);
@@ -327,6 +340,16 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
if (xim && xim_style) {
xic = XCreateIC(xim, XNInputStyle, xim_style, XNClientWindow, x11_window, XNFocusWindow, x11_window, (char *)NULL);
+ if (XGetICValues(xic, XNFilterEvents, &im_event_mask, NULL) != NULL) {
+ WARN_PRINT("XGetICValues couldn't obtain XNFilterEvents value");
+ XDestroyIC(xic);
+ xic = NULL;
+ }
+ if (xic) {
+ XSetICFocus(xic);
+ } else {
+ WARN_PRINT("XCreateIC couldn't create xic");
+ }
} else {
xic = NULL;
@@ -445,6 +468,30 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
_ensure_data_dir();
}
+void OS_X11::xim_destroy_callback(::XIM im, ::XPointer client_data,
+ ::XPointer call_data) {
+ WARN_PRINT("Input method stopped");
+ OS_X11 *os = reinterpret_cast<OS_X11 *>(client_data);
+ os->xim = NULL;
+ os->xic = NULL;
+}
+
+void OS_X11::set_ime_position(short x, short y) {
+ if (xic) {
+ ::XPoint spot;
+ spot.x = x;
+ spot.y = y;
+ XVaNestedList preedit_attr = XVaCreateNestedList(0,
+ XNSpotLocation, &spot,
+ NULL);
+ XSetICValues(xic,
+ XNPreeditAttributes, preedit_attr,
+ NULL);
+ XFree(preedit_attr);
+ }
+ return;
+}
+
void OS_X11::finalize() {
if (main_loop)
@@ -492,8 +539,12 @@ void OS_X11::finalize() {
XcursorImageDestroy(img[i]);
};
- XDestroyIC(xic);
- XCloseIM(xim);
+ if (xic) {
+ XDestroyIC(xic);
+ }
+ if (xim) {
+ XCloseIM(xim);
+ }
XCloseDisplay(x11_display);
if (xmbstring)
@@ -1041,11 +1092,61 @@ void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) {
xmblen = 8;
}
+ keysym_unicode = keysym_keycode;
+
if (xkeyevent->type == KeyPress && xic) {
Status status;
- do {
+#ifdef X_HAVE_UTF8_STRING
+ int utf8len = 8;
+ char *utf8string = (char *)memalloc(sizeof(char) * utf8len);
+ int utf8bytes = Xutf8LookupString(xic, xkeyevent, utf8string,
+ utf8len - 1, &keysym_unicode, &status);
+ if (status == XBufferOverflow) {
+ utf8len = utf8bytes + 1;
+ utf8string = (char *)memrealloc(utf8string, utf8len);
+ utf8bytes = Xutf8LookupString(xic, xkeyevent, utf8string,
+ utf8len - 1, &keysym_unicode, &status);
+ }
+ utf8string[utf8bytes] = '\0';
+
+ if (status == XLookupChars) {
+ bool keypress = xkeyevent->type == KeyPress;
+ unsigned int keycode = KeyMappingX11::get_keycode(keysym_keycode);
+ String tmp;
+ tmp.parse_utf8(utf8string, utf8bytes);
+ for (int i = 0; i < tmp.length(); i++) {
+ Ref<InputEventKey> k;
+ k.instance();
+ if (keycode == 0 && tmp[i] == 0) {
+ continue;
+ }
+
+ get_key_modifier_state(xkeyevent->state, k);
+
+ k->set_unicode(tmp[i]);
+
+ k->set_pressed(keypress);
+
+ if (keycode >= 'a' && keycode <= 'z')
+ keycode -= 'a' - 'A';
+ k->set_scancode(keycode);
+ k->set_echo(p_echo);
+
+ if (k->get_scancode() == KEY_BACKTAB) {
+ //make it consistent across platforms.
+ k->set_scancode(KEY_TAB);
+ k->set_shift(true);
+ }
+
+ input->parse_input_event(k);
+ }
+ return;
+ }
+ memfree(utf8string);
+#else
+ do {
int mnbytes = XmbLookupString(xic, xkeyevent, xmbstring, xmblen - 1, &keysym_unicode, &status);
xmbstring[mnbytes] = '\0';
@@ -1054,6 +1155,7 @@ void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) {
xmbstring = (char *)memrealloc(xmbstring, xmblen);
}
} while (status == XBufferOverflow);
+#endif
}
/* Phase 2, obtain a pigui keycode from the keysym */
@@ -1082,11 +1184,6 @@ void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) {
bool keypress = xkeyevent->type == KeyPress;
- if (xkeyevent->type == KeyPress && xic) {
- if (XFilterEvent((XEvent *)xkeyevent, x11_window))
- return;
- }
-
if (keycode == 0 && unicode == 0)
return;
@@ -1253,6 +1350,10 @@ void OS_X11::process_xevents() {
XEvent event;
XNextEvent(x11_display, &event);
+ if (XFilterEvent(&event, None)) {
+ continue;
+ }
+
switch (event.type) {
case Expose:
Main::force_redraw();
@@ -1295,6 +1396,9 @@ void OS_X11::process_xevents() {
ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
GrabModeAsync, GrabModeAsync, x11_window, None, CurrentTime);
}
+ if (xic) {
+ XSetICFocus(xic);
+ }
break;
case FocusOut:
@@ -1308,9 +1412,17 @@ void OS_X11::process_xevents() {
}
XUngrabPointer(x11_display, CurrentTime);
}
+ if (xic) {
+ XUnsetICFocus(xic);
+ }
break;
case ConfigureNotify:
+ if (xic) {
+ // Not portable.
+ set_ime_position(0, 1);
+ }
+
/* call resizeGLScene only if our window-size changed */
if ((event.xconfigure.width == current_videomode.width) &&