Mercurial > sdl-ios-xcode
comparison src/video/x11/SDL_x11video.c @ 3978:b966761fef6c SDL-1.2
Significantly improved XIM support.
Fixes Bugzilla #429.
Selected notes from the patch's README:
= FIXES =
This patch fixes the above issues as follows.
== X11 events ==
Moved XFilterEvent just after XNextEvent so that all events are passed
to it. Also, XFilterEvent will receive masks indicated by IM through
XNFilterEvents IC value as well as masks surpplied by SDL.
X11_KeyRepeat is called between XNextEvent and XFilterEvent, after
testing an event is a KeyRelease. I'm not 100% comfortable to do so,
but I couldn't find a better timing to call it, and use of the
function is inevitable.
== Xutf8LookupString ==
Used a longer buffer to receive UTF-8 string. If it is insufficient,
a dynamic storage of the requested size will be allocated. The
initial size of the buffer is set to 32, because the Japanese text
converted from the most widely used benchmark key sequence for
Japanese IM, "WATASHINONAMAEHANAKANODESU." has ten Japanese characters
in it, that occupies 30 bytes when encoded in UTF-8.
== SDL_keysym.unicode ==
On Windows version of SDL implementation, SDL_keysym.unicode stores
UTF-16 encoded unicode characters, one UTF-16 encoding unit per an SDL
event. A Unicode supplementary characters are sent to an application
as two events. (One with a high surrogate and another with a low
surrogate.) The behavior seems reasonable since it is upward
compatible with existing handling of BMP characters.
I wrote a UTF-8 to UTF-16 conversion function for the purpose. It is
designed with the execution speed in mind, having a minimum set of
features that my patch requires.
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Mon, 25 Jun 2007 19:58:32 +0000 |
parents | 3dc92ff218dd |
children | 1683d807c4fa |
comparison
equal
deleted
inserted
replaced
3977:722db1bd733c | 3978:b966761fef6c |
---|---|
52 #include "SDL_x11yuv_c.h" | 52 #include "SDL_x11yuv_c.h" |
53 #include "SDL_x11gl_c.h" | 53 #include "SDL_x11gl_c.h" |
54 #include "SDL_x11gamma_c.h" | 54 #include "SDL_x11gamma_c.h" |
55 #include "../blank_cursor.h" | 55 #include "../blank_cursor.h" |
56 | 56 |
57 #ifdef X_HAVE_UTF8_STRING | |
58 #include <locale.h> | |
59 #endif | |
60 | |
57 /* Initialization/Query functions */ | 61 /* Initialization/Query functions */ |
58 static int X11_VideoInit(_THIS, SDL_PixelFormat *vformat); | 62 static int X11_VideoInit(_THIS, SDL_PixelFormat *vformat); |
59 static SDL_Surface *X11_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags); | 63 static SDL_Surface *X11_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags); |
60 static int X11_ToggleFullScreen(_THIS, int on); | 64 static int X11_ToggleFullScreen(_THIS, int on); |
61 static void X11_UpdateMouse(_THIS); | 65 static void X11_UpdateMouse(_THIS); |
103 device = (SDL_VideoDevice *)SDL_malloc(sizeof(SDL_VideoDevice)); | 107 device = (SDL_VideoDevice *)SDL_malloc(sizeof(SDL_VideoDevice)); |
104 if ( device ) { | 108 if ( device ) { |
105 SDL_memset(device, 0, (sizeof *device)); | 109 SDL_memset(device, 0, (sizeof *device)); |
106 device->hidden = (struct SDL_PrivateVideoData *) | 110 device->hidden = (struct SDL_PrivateVideoData *) |
107 SDL_malloc((sizeof *device->hidden)); | 111 SDL_malloc((sizeof *device->hidden)); |
112 SDL_memset(device->hidden, 0, (sizeof *device->hidden)); | |
108 device->gl_data = (struct SDL_PrivateGLData *) | 113 device->gl_data = (struct SDL_PrivateGLData *) |
109 SDL_malloc((sizeof *device->gl_data)); | 114 SDL_malloc((sizeof *device->gl_data)); |
115 SDL_memset(device->gl_data, 0, (sizeof *device->gl_data)); | |
110 } | 116 } |
111 if ( (device == NULL) || (device->hidden == NULL) || | 117 if ( (device == NULL) || (device->hidden == NULL) || |
112 (device->gl_data == NULL) ) { | 118 (device->gl_data == NULL) ) { |
113 SDL_OutOfMemory(); | 119 SDL_OutOfMemory(); |
114 X11_DeleteDevice(device); /* calls SDL_X11_UnloadSymbols(). */ | 120 X11_DeleteDevice(device); /* calls SDL_X11_UnloadSymbols(). */ |
312 { | 318 { |
313 int x = 0, y = 0; | 319 int x = 0, y = 0; |
314 char classname[1024]; | 320 char classname[1024]; |
315 XSetWindowAttributes xattr; | 321 XSetWindowAttributes xattr; |
316 XWMHints *hints; | 322 XWMHints *hints; |
323 unsigned long app_event_mask; | |
317 int def_vis = (SDL_Visual == DefaultVisual(SDL_Display, SDL_Screen)); | 324 int def_vis = (SDL_Visual == DefaultVisual(SDL_Display, SDL_Screen)); |
318 | 325 |
319 /* Look up some useful Atoms */ | 326 /* Look up some useful Atoms */ |
320 WM_DELETE_WINDOW = XInternAtom(SDL_Display, "WM_DELETE_WINDOW", False); | 327 WM_DELETE_WINDOW = XInternAtom(SDL_Display, "WM_DELETE_WINDOW", False); |
321 | 328 |
389 } | 396 } |
390 XSetWMHints(SDL_Display, WMwindow, hints); | 397 XSetWMHints(SDL_Display, WMwindow, hints); |
391 XFree(hints); | 398 XFree(hints); |
392 X11_SetCaptionNoLock(this, this->wm_title, this->wm_icon); | 399 X11_SetCaptionNoLock(this, this->wm_title, this->wm_icon); |
393 | 400 |
394 XSelectInput(SDL_Display, WMwindow, | 401 app_event_mask = FocusChangeMask | KeyPressMask | KeyReleaseMask |
395 FocusChangeMask | KeyPressMask | KeyReleaseMask | 402 | PropertyChangeMask | StructureNotifyMask | KeymapStateMask; |
396 | PropertyChangeMask | StructureNotifyMask | KeymapStateMask); | 403 XSelectInput(SDL_Display, WMwindow, app_event_mask); |
397 | 404 |
398 /* Set the class hints so we can get an icon (AfterStep) */ | 405 /* Set the class hints so we can get an icon (AfterStep) */ |
399 get_classname(classname, sizeof(classname)); | 406 get_classname(classname, sizeof(classname)); |
400 { | 407 { |
401 XClassHint *classhints; | 408 XClassHint *classhints; |
407 XFree(classhints); | 414 XFree(classhints); |
408 } | 415 } |
409 } | 416 } |
410 | 417 |
411 /* Setup the communication with the IM server */ | 418 /* Setup the communication with the IM server */ |
412 SDL_IM = NULL; | 419 /* create_aux_windows may be called several times against the same |
413 SDL_IC = NULL; | 420 Display. We should reuse the SDL_IM if one has been opened for |
421 the Display, so we should not simply reset SDL_IM here. */ | |
414 | 422 |
415 #ifdef X_HAVE_UTF8_STRING | 423 #ifdef X_HAVE_UTF8_STRING |
416 if (SDL_X11_HAVE_UTF8) { | 424 if (SDL_X11_HAVE_UTF8) { |
425 /* Discard obsolete resources if any. */ | |
426 if (SDL_IM != NULL && SDL_Display != XDisplayOfIM(SDL_IM)) { | |
427 /* Just a double check. I don't think this | |
428 code is ever executed. */ | |
429 SDL_SetError("display has changed while an IM is kept"); | |
430 if (SDL_IC) { | |
431 XUnsetICFocus(SDL_IC); | |
432 XDestroyIC(SDL_IC); | |
433 SDL_IC = NULL; | |
434 } | |
435 XCloseIM(SDL_IM); | |
436 SDL_IM = NULL; | |
437 } | |
438 | |
439 /* Open an input method. */ | |
440 if (SDL_IM == NULL) { | |
441 char *old_locale, *old_modifiers; | |
442 /* I'm not comfortable to do locale setup | |
443 here. However, we need C library locale | |
444 (and xlib modifiers) to be set based on the | |
445 user's preference to use XIM, and many | |
446 existing game programs doesn't take care of | |
447 users' locale preferences, so someone other | |
448 than the game program should do it. | |
449 Moreover, ones say that some game programs | |
450 heavily rely on the C locale behaviour, | |
451 e.g., strcol()'s, and we can't change the C | |
452 library locale. Given the situation, I | |
453 couldn't find better place to do the | |
454 job... */ | |
455 | |
456 /* Save the current (application program's) | |
457 locale settings. */ | |
458 old_locale = setlocale(LC_ALL, NULL); | |
459 old_modifiers = XSetLocaleModifiers(NULL); | |
460 if (old_locale == NULL || old_modifiers == NULL) { | |
461 /* The specs guarantee that the query | |
462 calls to above functions never | |
463 fail, so we should never come | |
464 here. */ | |
465 SDL_SetError("failed to retreive current locale settings"); | |
466 old_locale = NULL; | |
467 old_modifiers = NULL; | |
468 } else { | |
469 /* Save retreived values in our own | |
470 storage, since they may be | |
471 overwritten by the successive calls | |
472 to | |
473 setlocale/XSetLocaleModifiers. */ | |
474 char const *p; | |
475 p = old_locale; | |
476 old_locale = SDL_malloc(strlen(p) + 1); | |
477 strcpy(old_locale, p); | |
478 p = old_modifiers; | |
479 old_modifiers = SDL_malloc(strlen(p) + 1); | |
480 strcpy(old_modifiers, p); | |
481 } | |
482 | |
483 /* Fetch the user's preferences and open the | |
484 input method with them. */ | |
485 setlocale(LC_ALL, ""); | |
486 XSetLocaleModifiers(""); | |
487 SDL_IM = XOpenIM(SDL_Display, NULL, classname, classname); | |
488 | |
489 /* Restore the application's locale settings | |
490 so that we don't break the application's | |
491 expected behaviour. */ | |
492 if (old_locale != NULL && old_modifiers != NULL) { | |
493 /* We need to restore the C library | |
494 locale first, since the | |
495 interpretation of the X modifier | |
496 may depend on it. */ | |
497 setlocale(LC_ALL, old_locale); | |
498 SDL_free(old_locale); | |
499 XSetLocaleModifiers(old_modifiers); | |
500 SDL_free(old_modifiers); | |
501 } | |
502 } | |
503 | |
504 /* Create a new input context for the new window just created. */ | |
417 SDL_IM = XOpenIM(SDL_Display, NULL, classname, classname); | 505 SDL_IM = XOpenIM(SDL_Display, NULL, classname, classname); |
418 if (SDL_IM == NULL) { | 506 if (SDL_IM == NULL) { |
419 SDL_SetError("no input method could be opened"); | 507 SDL_SetError("no input method could be opened"); |
420 } else { | 508 } else { |
509 if (SDL_IC != NULL) { | |
510 /* Discard the old IC before creating new one. */ | |
511 XUnsetICFocus(SDL_IC); | |
512 XDestroyIC(SDL_IC); | |
513 } | |
514 /* Theoretically we should check the current IM supports | |
515 PreeditNothing+StatusNothing style (i.e., root window method) | |
516 before creating the IC. However, it is the bottom line method, | |
517 and we supports any other options. If the IM didn't support | |
518 root window method, the following call fails, and SDL falls | |
519 back to pre-XIM keyboard handling. */ | |
421 SDL_IC = pXCreateIC(SDL_IM, | 520 SDL_IC = pXCreateIC(SDL_IM, |
422 XNClientWindow, WMwindow, | 521 XNClientWindow, WMwindow, |
423 XNFocusWindow, WMwindow, | 522 XNFocusWindow, WMwindow, |
424 XNInputStyle, XIMPreeditNothing | XIMStatusNothing, | 523 XNInputStyle, XIMPreeditNothing | XIMStatusNothing, |
425 XNResourceName, classname, | 524 XNResourceName, classname, |
426 XNResourceClass, classname, | 525 XNResourceClass, classname, |
427 NULL); | 526 NULL); |
428 | 527 |
429 if (SDL_IC == NULL) { | 528 if (SDL_IC == NULL) { |
430 SDL_SetError("no input context could be created"); | 529 SDL_SetError("no input context could be created"); |
431 XCloseIM(SDL_IM); | 530 XCloseIM(SDL_IM); |
432 SDL_IM = NULL; | 531 SDL_IM = NULL; |
532 } else { | |
533 /* We need to receive X events that an IM wants and to pass | |
534 them to the IM through XFilterEvent. The set of events may | |
535 vary depending on the IM implementation and the options | |
536 specified through various routes. Although unlikely, the | |
537 xlib specification allows IM to change the event requirement | |
538 with its own circumstances, it is safe to call SelectInput | |
539 whenever we re-create an IC. */ | |
540 unsigned long mask = 0; | |
541 char *ret = pXGetICValues(SDL_IC, XNFilterEvents, &mask, NULL); | |
542 &ic_event_mask, NULL); | |
543 XSelectInput(SDL_Display, WMwindow, app_event_mask | mask); | |
544 XSetICFocus(SDL_IC); | |
433 } | 545 } |
434 } | 546 } |
435 } | 547 } |
436 #endif | 548 #endif |
437 | 549 |
1348 XSync(GFX_Display, False); | 1460 XSync(GFX_Display, False); |
1349 | 1461 |
1350 /* Close the connection with the IM server */ | 1462 /* Close the connection with the IM server */ |
1351 #ifdef X_HAVE_UTF8_STRING | 1463 #ifdef X_HAVE_UTF8_STRING |
1352 if (SDL_IC != NULL) { | 1464 if (SDL_IC != NULL) { |
1465 XUnsetICFocus(SDL_IC); | |
1353 XDestroyIC(SDL_IC); | 1466 XDestroyIC(SDL_IC); |
1354 SDL_IC = NULL; | 1467 SDL_IC = NULL; |
1355 } | 1468 } |
1356 if (SDL_IM != NULL) { | 1469 if (SDL_IM != NULL) { |
1357 XCloseIM(SDL_IM); | 1470 XCloseIM(SDL_IM); |