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);