Dmitry Timoshkov wrote:
"Anthony Fok" anthony@thizlinux.com wrote:
I have made some tests and found that actually very little work is required: create Input context using XOpenIM/XCreateIC. In order to not create context for each window and therefore save some memory do attach windows to only one global Input context in FocusIn event handler: XUnsetICFocus()/XSetICValues/ XSetICFocus(). Use XFilterEvent() to pass all work to an X server.
And don't forget to remove ugly dead keys emulating code from windows/message.c.
Hello,
I am sorry that I am newbie to Xlib, wine and xcin. I would like to ask if I should modify dlls/x11drv/x11drv_main.c, in process_attach(), continue the call of TSXOpenIM(display, NULL, NULL, NULL);
XRegisterIMInstantiateCallback(...,im_callback,...);
and in my callback function:
im_callback() { XOpenIM(); ... XCreateIC(); }
as I know, we need to wrap X functions with wine_tsx11_lock() and wine_tsx11_unlock(); Unfortunately I cannot find the IM API function prototypes
e.g. XGetIMValues()
when I type "man XGetIMValues" it showed
~~~~~~~~~~~~~~~ XOpenIM(3X11) XLIB FUNCTIONS XOpenIM(3X11)
NAME XOpenIM, XCloseIM, XSetIMValues, XGetIMValues, XDisplay- OfIM, XLocaleOfIM, XRegisterIMInstantiateCallback, XUnreg- isterIMInstantiateCallback - open, close, and otain input method information
SYNTAX XIM XOpenIM(display, db, res_name, res_class) Display *display; XrmDatabase db; char *res_name; char *res_class;
Status XCloseIM(im) XIM im;
char * XSetIMValues(im, ...) XIM im;
char * XGetIMValues(im, ...) XIM im; ... ~~~~~~~~~~~~~~
how can I know the details of the arguments? (sorry, maybe it's a Xlib question)
TSXGetIMValues(XIM im, ?????) { wine_tsx11_lock(); XGetIMValues(...); wine_tsx11_unlock(); }
and After my modifications, it does not work. Could anybody help? Thanks very much! (I attached x11drv_main.c that I modified)
/* * X11DRV initialization code * * Copyright 1998 Patrik Stridvall * Copyright 2000 Alexandre Julliard */
#include "config.h"
#ifdef NO_REENTRANT_X11 /* Get pointers to the static errno and h_errno variables used by Xlib. This must be done before including <errno.h> makes the variables invisible. */ extern int errno; static int *perrno = &errno; extern int h_errno; static int *ph_errno = &h_errno; #endif /* NO_REENTRANT_X11 */
#include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/time.h> #include <unistd.h> #include <X11/cursorfont.h> #include "ts_xlib.h" #include "ts_xutil.h" #include "ts_shape.h"
#include "winbase.h" #include "wine/winbase16.h" #include "winreg.h"
#include "debugtools.h" #include "gdi.h" #include "file.h" #include "options.h" #include "user.h" #include "win.h" #include "wine_gl.h" #include "x11drv.h" #include "xvidmode.h" #include "dga2.h"
DEFAULT_DEBUG_CHANNEL(x11drv);
static void (*old_tsx11_lock)(void); static void (*old_tsx11_unlock)(void);
static CRITICAL_SECTION X11DRV_CritSection = CRITICAL_SECTION_INIT("X11DRV_CritSection");
Screen *screen; Visual *visual; unsigned int screen_width; unsigned int screen_height; unsigned int screen_depth; Window root_window; int dxgrab, usedga, usexvidmode;
unsigned int X11DRV_server_startticks;
static BOOL synchronous; /* run in synchronous mode? */ static char *desktop_geometry; static XVisualInfo *desktop_vi;
#define IS_OPTION_TRUE(ch) \ ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1') #define IS_OPTION_FALSE(ch) \ ((ch) == 'n' || (ch) == 'N' || (ch) == 'f' || (ch) == 'F' || (ch) == '0')
#ifdef NO_REENTRANT_X11 static int* (*old_errno_location)(void); static int* (*old_h_errno_location)(void);
/*********************************************************************** * x11_errno_location * * Get the per-thread errno location. */ static int *x11_errno_location(void) { /* Use static libc errno while running in Xlib. */ if (X11DRV_CritSection.OwningThread == GetCurrentThreadId()) return perrno; return old_errno_location(); }
/*********************************************************************** * x11_h_errno_location * * Get the per-thread h_errno location. */ static int *x11_h_errno_location(void) { /* Use static libc h_errno while running in Xlib. */ if (X11DRV_CritSection.OwningThread == GetCurrentThreadId()) return ph_errno; return old_h_errno_location(); } #endif /* NO_REENTRANT_X11 */
//MEW
#include <X11/Xlocale.h>
typedef struct { XIMStyle style; char *description; } im_style_t;
char *fontset_name; XFontSet fontset; int ef_height, ef_width, ef_ascent; XRectangle win_rect;
XIM im; XIC ic; char *im_name; char *im_style; char *lc_ctype; char *encoding; XIMStyle style; wchar_t input_buf[1024]; int idx; char ic_focus; im_style_t im_styles[] = { { XIMPreeditNothing | XIMStatusNothing, "Root" }, { XIMPreeditPosition | XIMStatusNothing, "OverTheSpot" }, { XIMPreeditArea | XIMStatusArea, "OffTheSpot" }, { XIMPreeditCallbacks| XIMStatusCallbacks, "OnTheSpot" }, { (XIMStyle)0, NULL }};
//MEW
/*********************************************************************** * error_handler */ static int error_handler(Display *display, XErrorEvent *error_evt) { DebugBreak(); /* force an entry in the debugger */ return 0; }
/*********************************************************************** * lock_tsx11 */ static void lock_tsx11(void) { RtlEnterCriticalSection( &X11DRV_CritSection ); }
/*********************************************************************** * unlock_tsx11 */ static void unlock_tsx11(void) { RtlLeaveCriticalSection( &X11DRV_CritSection ); }
/*********************************************************************** * get_server_startup * * Get the server startup time * Won't be exact, but should be sufficient */ static void get_server_startup(void) { struct timeval t; gettimeofday( &t, NULL ); X11DRV_server_startticks = ((t.tv_sec * 1000) + (t.tv_usec / 1000)) - GetTickCount(); }
/*********************************************************************** * get_config_key * * Get a config key from either the app-specific or the default config */ inline static DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name, char *buffer, DWORD size ) { if (appkey && !RegQueryValueExA( appkey, name, 0, NULL, buffer, &size )) return 0; return RegQueryValueExA( defkey, name, 0, NULL, buffer, &size ); }
/*********************************************************************** * setup_options * * Setup the x11drv options. */ static void setup_options(void) { char buffer[MAX_PATH+16]; HKEY hkey, appkey = 0; DWORD count;
if (RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\Wine\Wine\Config\x11drv", 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL )) { ERR("Cannot create config registry key\n" ); ExitProcess(1); }
/* open the app-specific key */
if (GetModuleFileName16( GetCurrentTask(), buffer, MAX_PATH ) || GetModuleFileNameA( 0, buffer, MAX_PATH )) { HKEY tmpkey; char *p, *appname = buffer; if ((p = strrchr( appname, '/' ))) appname = p + 1; if ((p = strrchr( appname, '\' ))) appname = p + 1; strcat( appname, "\x11drv" ); if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\Wine\Wine\Config\AppDefaults", &tmpkey )) { if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0; RegCloseKey( tmpkey ); } }
/* get the display name */
strcpy( buffer, "DISPLAY=" ); count = sizeof(buffer) - 8; if (!RegQueryValueExA( hkey, "display", 0, NULL, buffer + 8, &count )) { const char *display_name = getenv( "DISPLAY" ); if (display_name && strcmp( buffer, display_name )) MESSAGE( "x11drv: Warning: $DISPLAY variable ignored, using '%s' specified in config file\n", buffer + 8 ); putenv( strdup(buffer) ); }
/* check --managed option in wine config file if it was not set on command line */
if (!Options.managed) { if (!get_config_key( hkey, appkey, "Managed", buffer, sizeof(buffer) )) Options.managed = IS_OPTION_TRUE( buffer[0] ); }
if (!get_config_key( hkey, appkey, "Desktop", buffer, sizeof(buffer) )) { /* Imperfect validation: If Desktop=N, then we don't turn on ** the --desktop option. We should really validate for a correct ** sizing entry */ if (!IS_OPTION_FALSE(buffer[0])) desktop_geometry = strdup(buffer); }
if (!get_config_key( hkey, appkey, "DXGrab", buffer, sizeof(buffer) )) dxgrab = IS_OPTION_TRUE( buffer[0] );
if (!get_config_key( hkey, appkey, "UseDGA", buffer, sizeof(buffer) )) usedga = IS_OPTION_TRUE( buffer[0] );
if (!get_config_key( hkey, appkey, "UseXVidMode", buffer, sizeof(buffer) )) usexvidmode = IS_OPTION_TRUE( buffer[0] );
screen_depth = 0; if (!get_config_key( hkey, appkey, "ScreenDepth", buffer, sizeof(buffer) )) screen_depth = atoi(buffer);
if (!get_config_key( hkey, appkey, "Synchronous", buffer, sizeof(buffer) )) synchronous = IS_OPTION_TRUE( buffer[0] );
if (appkey) RegCloseKey( appkey ); RegCloseKey( hkey ); }
/*********************************************************************** * setup_opengl_visual * * Setup the default visual used for OpenGL and Direct3D, and the desktop * window (if it exists). If OpenGL isn't available, the visual is simply * set to the default visual for the display */ #ifdef HAVE_OPENGL static void setup_opengl_visual( Display *display ) { int err_base, evt_base;
/* In order to support OpenGL or D3D, we require a double-buffered * visual */ if (glXQueryExtension(display, &err_base, &evt_base) == True) { int dblBuf[]={GLX_RGBA,GLX_DEPTH_SIZE,16,GLX_DOUBLEBUFFER,None}; ENTER_GL(); desktop_vi = glXChooseVisual(display, DefaultScreen(display), dblBuf); LEAVE_GL(); }
if (desktop_vi != NULL) { visual = desktop_vi->visual; screen = ScreenOfDisplay(display, desktop_vi->screen); screen_depth = desktop_vi->depth; } } #endif /* HAVE_OPENGL */
////////////////////////////////////////////////////////////////////////// //MEW static void locale_init(void) { char *s;
if ((s = setlocale(LC_CTYPE, "")) == NULL) { //printf("setlocale LC_CTYPE false.\n"); printf("setlocale LC_CTYPE false.\n"); exit(0); } lc_ctype = (char *)strdup(s); if ((s = strchr(lc_ctype, '.')) != NULL) { *s = '\0'; s++; } else s = "";
printf("LC_CTYPE = %s\n", lc_ctype);
while (*s) { *s = (char)tolower(*s); s++; }
printf("ENCODING = %s\n", s);
if (XSupportsLocale() != True) { printf("XSupportsLocale false.\n"); exit(0); } }
static void destroy_callback_func(XIM current_ic, XPointer client_data, XPointer call_data) { ic = NULL; im = NULL; ic_focus = 0;
printf("destroy_callback_func\n"); }
static void im_callback(Display *display, XPointer client_data, XPointer call_data) { XIMStyles *xim_styles = NULL; /* XIMValuesList im_values_list; */ XIMCallback destroy; int i, j;
XVaNestedList preedit_attr = NULL; XPoint spot; XRectangle local_win_rect;
/* * Open connection to IM server. */ if (! (im = XOpenIM(display, NULL, NULL, NULL))) { printf("Cannot open the connection to XIM server.\n"); exit(1); }
/* * Get IM values. */ /* if (XGetIMValues(im, XNQueryIMValuesList, &im_values_list, NULL) || ! im_values_list.count_values) { printf("no IM values list available.\n"); XCloseIM(im); exit(1); } else { for (i=0; i<im_values_list.count_values; i++) printf("supported: %s\n", im_values_list.supported_values[i]); } destroy.callback = (XIMProc)destroy_callback_func; destroy.client_data = NULL; XSetIMValues(im, XNDestroyCallback, &destroy, NULL);
*/
/* * Detect the input style supported by XIM server. */ if (XGetIMValues(im, XNQueryInputStyle, &xim_styles, NULL) || ! xim_styles) { printf("input method doesn't support any style\n"); XCloseIM(im); exit(1); } else { for (i=0; i<xim_styles->count_styles; i++) { for (j=0; im_styles[j].description!=NULL; j++) { if (im_styles[j].style == xim_styles->supported_styles[i]) { printf("XIM server support input_style = %s\n", im_styles[j].description); break; } } if (im_styles[j].description==NULL) printf("XIM server support unknown input_style = %x\n", (unsigned)(xim_styles->supported_styles[i])); } } /* * Setting the XIM style used by me. */ if (im_style) { for (j=0; im_styles[j].description!=NULL; j++) { if (! strcmp(im_styles[j].description, im_style)) { style = im_styles[j].style; printf("Use input style: %s\n", im_style); break; } } if (im_styles[j].description==NULL) { printf("The input style %s is not supported.\n", im_style); exit(1); }
} else { /* Root input_style as the default */ for (j=0; im_styles[j].description!=NULL; j++) { if (! strcmp(im_styles[j].description, "Root")) { style = im_styles[j].style; printf("Use input style: %s\n", "Root"); break; } } } /* OverTheSpot */ /* if (style == (XIMPreeditPosition | XIMStatusNothing)) { spot.x = 5; spot.y = 2*ef_height + 3*(ef_ascent+5); local_win_rect.x = 1; local_win_rect.y = 1; local_win_rect.width = win_rect.width; local_win_rect.height = win_rect.height; preedit_attr = XVaCreateNestedList(0, XNArea, &local_win_rect, XNSpotLocation, &spot, XNFontSet, fontset, XNForeground, WhitePixel(display, screen), XNBackground, BlackPixel(display, screen), NULL); } */
/* * Create IC. */ ic = XCreateIC(im, XNInputStyle, style, XNClientWindow, root_window, XNFocusWindow, root_window, (preedit_attr) ? XNPreeditAttributes : NULL, preedit_attr, NULL); if(ic == NULL) { printf("Cannot create XIC.\n"); exit(1); } }
static void xim_init(Display *display) { char buf[1024];
memset(buf, 0, 1024); if (XSetLocaleModifiers(buf) == NULL) { printf("XSetLocaleModifiers false.\n"); exit(0); } if (XRegisterIMInstantiateCallback( display, NULL, NULL, NULL, im_callback, NULL) != True) { printf("XRegisterIMInstantiateCallback false.\n"); exit(0); } }
//MEW
/*********************************************************************** * X11DRV process initialisation routine */ static void process_attach(void) { Display *display;
get_server_startup(); setup_options();
/* setup TSX11 locking */ #ifdef NO_REENTRANT_X11 old_errno_location = InterlockedExchangePointer( &wine_errno_location, x11_errno_location ); old_h_errno_location = InterlockedExchangePointer( &wine_h_errno_location, x11_h_errno_location ); #endif /* NO_REENTRANT_X11 */ old_tsx11_lock = wine_tsx11_lock; old_tsx11_unlock = wine_tsx11_unlock; wine_tsx11_lock = lock_tsx11; wine_tsx11_unlock = unlock_tsx11;
/* Open display */
if (!(display = TSXOpenDisplay( NULL ))) { MESSAGE( "x11drv: Can't open display: %s\n", XDisplayName(NULL) ); ExitProcess(1); } fcntl( ConnectionNumber(display), F_SETFD, 1 ); /* set close on exec flag */ screen = DefaultScreenOfDisplay( display ); visual = DefaultVisual( display, DefaultScreen(display) ); root_window = DefaultRootWindow( display );
/* Initialize screen depth */
if (screen_depth) /* depth specified */ { int depth_count, i; int *depth_list = TSXListDepths(display, DefaultScreen(display), &depth_count); for (i = 0; i < depth_count; i++) if (depth_list[i] == screen_depth) break; TSXFree( depth_list ); if (i >= depth_count) { MESSAGE( "x11drv: Depth %d not supported on this screen.\n", screen_depth ); ExitProcess(1); } } else screen_depth = DefaultDepthOfScreen( screen );
/* If OpenGL is available, change the default visual, etc as necessary */ #ifdef HAVE_OPENGL setup_opengl_visual( display ); #endif /* HAVE_OPENGL */
/* tell the libX11 that we will do input method handling ourselves * that keep libX11 from doing anything whith dead keys, allowing Wine * to have total control over dead keys, that is this line allows * them to work in Wine, even whith a libX11 including the dead key * patches from Th.Quinot (http://Web.FdN.FR/~tquinot/dead-keys.en.html) */
//MEW //TSXOpenIM( display, NULL, NULL, NULL);
///////////////// //wine_tsx11_lock();
locale_init();
xim_init(display);
//////////////////// //wine_tsx11_unlock(); //MEW
if (synchronous) { XSetErrorHandler( error_handler ); XSynchronize( display, True ); }
screen_width = WidthOfScreen( screen ); screen_height = HeightOfScreen( screen );
if (desktop_geometry) { Options.managed = FALSE; root_window = X11DRV_create_desktop( desktop_vi, desktop_geometry ); }
/* initialize GDI */ if(!X11DRV_GDI_Initialize( display )) { ERR( "Couldn't Initialize GDI.\n" ); ExitProcess(1); }
#ifdef HAVE_LIBXXF86VM /* initialize XVidMode */ X11DRV_XF86VM_Init(); #endif #ifdef HAVE_LIBXXF86DGA2 /* initialize DGA2 */ X11DRV_XF86DGA2_Init(); #endif #ifdef HAVE_OPENGL /* initialize GLX */ /*X11DRV_GLX_Init();*/ #endif
/* load display.dll */ LoadLibrary16( "display" ); }
/*********************************************************************** * X11DRV thread termination routine */ static void thread_detach(void) { struct x11drv_thread_data *data = NtCurrentTeb()->driver_data;
if (data) { CloseHandle( data->display_fd ); wine_tsx11_lock(); XCloseDisplay( data->display ); wine_tsx11_unlock(); HeapFree( GetProcessHeap(), 0, data ); } }
/*********************************************************************** * X11DRV process termination routine */ static void process_detach(void) { #ifdef HAVE_OPENGL /* cleanup GLX */ /*X11DRV_GLX_Cleanup();*/ #endif #ifdef HAVE_LIBXXF86DGA2 /* cleanup DGA2 */ X11DRV_XF86DGA2_Cleanup(); #endif #ifdef HAVE_LIBXXF86VM /* cleanup XVidMode */ X11DRV_XF86VM_Cleanup(); #endif
/* FIXME: should detach all threads */ thread_detach();
/* cleanup GDI */ X11DRV_GDI_Finalize();
/* restore TSX11 locking */ wine_tsx11_lock = old_tsx11_lock; wine_tsx11_unlock = old_tsx11_unlock; #ifdef NO_REENTRANT_X11 wine_errno_location = old_errno_location; wine_h_errno_location = old_h_errno_location; #endif /* NO_REENTRANT_X11 */ RtlDeleteCriticalSection( &X11DRV_CritSection ); }
/*********************************************************************** * X11DRV thread initialisation routine */ struct x11drv_thread_data *x11drv_init_thread_data(void) { struct x11drv_thread_data *data;
if (!(data = HeapAlloc( GetProcessHeap(), 0, sizeof(*data) ))) { ERR( "could not create data\n" ); ExitProcess(1); } wine_tsx11_lock(); if (!(data->display = XOpenDisplay(NULL))) { wine_tsx11_unlock(); MESSAGE( "x11drv: Can't open display: %s\n", XDisplayName(NULL) ); ExitProcess(1); } fcntl( ConnectionNumber(data->display), F_SETFD, 1 ); /* set close on exec flag */ if (synchronous) XSynchronize( data->display, True ); wine_tsx11_unlock(); data->display_fd = FILE_DupUnixHandle( ConnectionNumber(data->display), GENERIC_READ | SYNCHRONIZE, FALSE ); data->process_event_count = 0; NtCurrentTeb()->driver_data = data; return data; }
/*********************************************************************** * X11DRV initialisation routine */ BOOL WINAPI X11DRV_Init( HINSTANCE hinst, DWORD reason, LPVOID reserved ) { switch(reason) { case DLL_PROCESS_ATTACH: process_attach(); break; case DLL_THREAD_DETACH: thread_detach(); break; case DLL_PROCESS_DETACH: process_detach(); break; } return TRUE; }
/*********************************************************************** * GetScreenSaveActive (X11DRV.@) * * Returns the active status of the screen saver */ BOOL X11DRV_GetScreenSaveActive(void) { int timeout, temp; TSXGetScreenSaver(gdi_display, &timeout, &temp, &temp, &temp); return timeout != 0; }
/*********************************************************************** * SetScreenSaveActive (X11DRV.@) * * Activate/Deactivate the screen saver */ void X11DRV_SetScreenSaveActive(BOOL bActivate) { int timeout, interval, prefer_blanking, allow_exposures; static int last_timeout = 15 * 60;
TSXGetScreenSaver(gdi_display, &timeout, &interval, &prefer_blanking, &allow_exposures); if (timeout) last_timeout = timeout;
timeout = bActivate ? last_timeout : 0; TSXSetScreenSaver(gdi_display, timeout, interval, prefer_blanking, allow_exposures); }