winex11.drv: Give XCloseIM another chance.
[wine] / dlls / winex11.drv / x11drv_main.c
1 /*
2  * X11DRV initialization code
3  *
4  * Copyright 1998 Patrik Stridvall
5  * Copyright 2000 Alexandre Julliard
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23
24 #include <fcntl.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #ifdef HAVE_SYS_TIME_H
30 # include <sys/time.h>
31 #endif
32 #ifdef HAVE_UNISTD_H
33 # include <unistd.h>
34 #endif
35 #include <X11/cursorfont.h>
36 #include <X11/Xlib.h>
37 #ifdef HAVE_XKB
38 #include <X11/XKBlib.h>
39 #endif
40 #ifdef HAVE_X11_EXTENSIONS_XRENDER_H
41 #include <X11/extensions/Xrender.h>
42 #endif
43
44 #include "windef.h"
45 #include "winbase.h"
46 #include "wine/winbase16.h"
47 #include "winreg.h"
48
49 #include "x11drv.h"
50 #include "xvidmode.h"
51 #include "xrandr.h"
52 #include "wine/server.h"
53 #include "wine/debug.h"
54
55 WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
56 WINE_DECLARE_DEBUG_CHANNEL(synchronous);
57
58 static CRITICAL_SECTION X11DRV_CritSection;
59 static CRITICAL_SECTION_DEBUG critsect_debug =
60 {
61     0, 0, &X11DRV_CritSection,
62     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
63       0, 0, { (DWORD_PTR)(__FILE__ ": X11DRV_CritSection") }
64 };
65 static CRITICAL_SECTION X11DRV_CritSection = { &critsect_debug, -1, 0, 0, 0, 0 };
66
67 Screen *screen;
68 Visual *visual;
69 unsigned int screen_width;
70 unsigned int screen_height;
71 unsigned int screen_depth;
72 RECT virtual_screen_rect;
73 Window root_window;
74 int dxgrab = 0;
75 int usexvidmode = 1;
76 int usexrandr = 1;
77 int use_xkb = 1;
78 int use_take_focus = 1;
79 int use_primary_selection = 0;
80 int managed_mode = 1;
81 int private_color_map = 0;
82 int primary_monitor = 0;
83 int client_side_with_core = 1;
84 int client_side_with_render = 1;
85 int client_side_antialias_with_core = 1;
86 int client_side_antialias_with_render = 1;
87 int copy_default_colors = 128;
88 int alloc_system_colors = 256;
89 DWORD thread_data_tls_index = TLS_OUT_OF_INDEXES;
90 int xrender_error_base = 0;
91
92 static BOOL desktop_dbl_buf = TRUE;
93
94 static x11drv_error_callback err_callback;   /* current callback for error */
95 static Display *err_callback_display;        /* display callback is set for */
96 static void *err_callback_arg;               /* error callback argument */
97 static int err_callback_result;              /* error callback result */
98 static unsigned long err_serial;             /* serial number of first request */
99 static int (*old_error_handler)( Display *, XErrorEvent * );
100 static int use_xim = 1;
101 static char input_style[20];
102
103 #define IS_OPTION_TRUE(ch) \
104     ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1')
105 #define IS_OPTION_FALSE(ch) \
106     ((ch) == 'n' || (ch) == 'N' || (ch) == 'f' || (ch) == 'F' || (ch) == '0')
107
108 Atom X11DRV_Atoms[NB_XATOMS - FIRST_XATOM];
109
110 static const char * const atom_names[NB_XATOMS - FIRST_XATOM] =
111 {
112     "CLIPBOARD",
113     "COMPOUND_TEXT",
114     "MULTIPLE",
115     "SELECTION_DATA",
116     "TARGETS",
117     "TEXT",
118     "UTF8_STRING",
119     "RAW_ASCENT",
120     "RAW_DESCENT",
121     "RAW_CAP_HEIGHT",
122     "WM_PROTOCOLS",
123     "WM_DELETE_WINDOW",
124     "WM_TAKE_FOCUS",
125     "KWM_DOCKWINDOW",
126     "DndProtocol",
127     "DndSelection",
128     "_MOTIF_WM_HINTS",
129     "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR",
130     "_NET_SYSTEM_TRAY_OPCODE",
131     "_NET_SYSTEM_TRAY_S0",
132     "_NET_WM_MOVERESIZE",
133     "_NET_WM_NAME",
134     "_NET_WM_PID",
135     "_NET_WM_PING",
136     "_NET_WM_STATE",
137     "_NET_WM_STATE_FULLSCREEN",
138     "_NET_WM_WINDOW_TYPE",
139     "_NET_WM_WINDOW_TYPE_DIALOG",
140     "_NET_WM_WINDOW_TYPE_NORMAL",
141     "_NET_WM_WINDOW_TYPE_UTILITY",
142     "_XEMBED_INFO",
143     "XdndAware",
144     "XdndEnter",
145     "XdndPosition",
146     "XdndStatus",
147     "XdndLeave",
148     "XdndFinished",
149     "XdndDrop",
150     "XdndActionCopy",
151     "XdndActionMove",
152     "XdndActionLink",
153     "XdndActionAsk",
154     "XdndActionPrivate",
155     "XdndSelection",
156     "XdndTarget",
157     "XdndTypeList",
158     "WCF_DIB",
159     "image/gif",
160     "text/html",
161     "text/plain",
162     "text/rtf",
163     "text/richtext"
164 };
165
166 /***********************************************************************
167  *              ignore_error
168  *
169  * Check if the X error is one we can ignore.
170  */
171 static inline BOOL ignore_error( Display *display, XErrorEvent *event )
172 {
173     if (event->request_code == X_SetInputFocus && event->error_code == BadMatch) return TRUE;
174
175     /* ignore a number of errors on gdi display caused by creating/destroying windows */
176     if (display == gdi_display)
177     {
178         if (event->error_code == BadDrawable || event->error_code == BadGC) return TRUE;
179 #ifdef HAVE_X11_EXTENSIONS_XRENDER_H
180         if (xrender_error_base)  /* check for XRender errors */
181         {
182             if (event->error_code == xrender_error_base + BadPicture) return TRUE;
183         }
184 #endif
185     }
186     return FALSE;
187 }
188
189
190 /***********************************************************************
191  *              X11DRV_expect_error
192  *
193  * Setup a callback function that will be called on an X error.  The
194  * callback must return non-zero if the error is the one it expected.
195  * This function acquires the x11 lock; X11DRV_check_error must be
196  * called in all cases to release it.
197  */
198 void X11DRV_expect_error( Display *display, x11drv_error_callback callback, void *arg )
199 {
200     wine_tsx11_lock();
201     err_callback         = callback;
202     err_callback_display = display;
203     err_callback_arg     = arg;
204     err_callback_result  = 0;
205     err_serial           = NextRequest(display);
206 }
207
208
209 /***********************************************************************
210  *              X11DRV_check_error
211  *
212  * Check if an expected X11 error occurred; return non-zero if yes.
213  * Also release the x11 lock obtained in X11DRV_expect_error.
214  * The caller is responsible for calling XSync first if necessary.
215  */
216 int X11DRV_check_error(void)
217 {
218     int ret;
219     err_callback = NULL;
220     ret = err_callback_result;
221     wine_tsx11_unlock();
222     return ret;
223 }
224
225
226 /***********************************************************************
227  *              error_handler
228  */
229 static int error_handler( Display *display, XErrorEvent *error_evt )
230 {
231     if (err_callback && display == err_callback_display &&
232         (long)(error_evt->serial - err_serial) >= 0)
233     {
234         if ((err_callback_result = err_callback( display, error_evt, err_callback_arg )))
235         {
236             TRACE( "got expected error %d req %d\n",
237                    error_evt->error_code, error_evt->request_code );
238             return 0;
239         }
240     }
241     if (ignore_error( display, error_evt ))
242     {
243         TRACE( "got ignored error %d req %d\n",
244                error_evt->error_code, error_evt->request_code );
245         return 0;
246     }
247     if (TRACE_ON(synchronous))
248     {
249         ERR( "X protocol error: serial=%ld, request_code=%d - breaking into debugger\n",
250              error_evt->serial, error_evt->request_code );
251         DebugBreak();  /* force an entry in the debugger */
252     }
253     old_error_handler( display, error_evt );
254     return 0;
255 }
256
257 /***********************************************************************
258  *              wine_tsx11_lock   (X11DRV.@)
259  */
260 void wine_tsx11_lock(void)
261 {
262     EnterCriticalSection( &X11DRV_CritSection );
263 }
264
265 /***********************************************************************
266  *              wine_tsx11_unlock   (X11DRV.@)
267  */
268 void wine_tsx11_unlock(void)
269 {
270     LeaveCriticalSection( &X11DRV_CritSection );
271 }
272
273
274 /***********************************************************************
275  *              get_config_key
276  *
277  * Get a config key from either the app-specific or the default config
278  */
279 inline static DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name,
280                                     char *buffer, DWORD size )
281 {
282     if (appkey && !RegQueryValueExA( appkey, name, 0, NULL, (LPBYTE)buffer, &size )) return 0;
283     if (defkey && !RegQueryValueExA( defkey, name, 0, NULL, (LPBYTE)buffer, &size )) return 0;
284     return ERROR_FILE_NOT_FOUND;
285 }
286
287
288 /***********************************************************************
289  *              setup_options
290  *
291  * Setup the x11drv options.
292  */
293 static void setup_options(void)
294 {
295     char buffer[MAX_PATH+16];
296     HKEY hkey, appkey = 0;
297     DWORD len;
298
299     /* @@ Wine registry key: HKCU\Software\Wine\X11 Driver */
300     if (RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\X11 Driver", &hkey )) hkey = 0;
301
302     /* open the app-specific key */
303
304     len = (GetModuleFileNameA( 0, buffer, MAX_PATH ));
305     if (len && len < MAX_PATH)
306     {
307         HKEY tmpkey;
308         char *p, *appname = buffer;
309         if ((p = strrchr( appname, '/' ))) appname = p + 1;
310         if ((p = strrchr( appname, '\\' ))) appname = p + 1;
311         strcat( appname, "\\X11 Driver" );
312         /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\X11 Driver */
313         if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\AppDefaults", &tmpkey ))
314         {
315             if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0;
316             RegCloseKey( tmpkey );
317         }
318     }
319
320     if (!get_config_key( hkey, appkey, "Managed", buffer, sizeof(buffer) ))
321         managed_mode = IS_OPTION_TRUE( buffer[0] );
322
323     if (!get_config_key( hkey, appkey, "DXGrab", buffer, sizeof(buffer) ))
324         dxgrab = IS_OPTION_TRUE( buffer[0] );
325
326     if (!get_config_key( hkey, appkey, "UseXVidMode", buffer, sizeof(buffer) ))
327         usexvidmode = IS_OPTION_TRUE( buffer[0] );
328
329     if (!get_config_key( hkey, appkey, "UseXRandR", buffer, sizeof(buffer) ))
330         usexrandr = IS_OPTION_TRUE( buffer[0] );
331
332     if (!get_config_key( hkey, appkey, "UseTakeFocus", buffer, sizeof(buffer) ))
333         use_take_focus = IS_OPTION_TRUE( buffer[0] );
334
335     if (!get_config_key( hkey, appkey, "UsePrimarySelection", buffer, sizeof(buffer) ))
336         use_primary_selection = IS_OPTION_TRUE( buffer[0] );
337
338     screen_depth = 0;
339     if (!get_config_key( hkey, appkey, "ScreenDepth", buffer, sizeof(buffer) ))
340         screen_depth = atoi(buffer);
341
342     if (!get_config_key( hkey, appkey, "ClientSideWithCore", buffer, sizeof(buffer) ))
343         client_side_with_core = IS_OPTION_TRUE( buffer[0] );
344
345     if (!get_config_key( hkey, appkey, "ClientSideWithRender", buffer, sizeof(buffer) ))
346         client_side_with_render = IS_OPTION_TRUE( buffer[0] );
347
348     if (!get_config_key( hkey, appkey, "ClientSideAntiAliasWithCore", buffer, sizeof(buffer) ))
349         client_side_antialias_with_core = IS_OPTION_TRUE( buffer[0] );
350
351     if (!get_config_key( hkey, appkey, "ClientSideAntiAliasWithRender", buffer, sizeof(buffer) ))
352         client_side_antialias_with_render = IS_OPTION_TRUE( buffer[0] );
353
354     if (!get_config_key( hkey, appkey, "DesktopDoubleBuffered", buffer, sizeof(buffer) ))
355         desktop_dbl_buf = IS_OPTION_TRUE( buffer[0] );
356
357     if (!get_config_key( hkey, appkey, "UseXIM", buffer, sizeof(buffer) ))
358         use_xim = IS_OPTION_TRUE( buffer[0] );
359
360     if (!get_config_key( hkey, appkey, "PrivateColorMap", buffer, sizeof(buffer) ))
361         private_color_map = IS_OPTION_TRUE( buffer[0] );
362
363     if (!get_config_key( hkey, appkey, "PrimaryMonitor", buffer, sizeof(buffer) ))
364         primary_monitor = atoi( buffer );
365
366     if (!get_config_key( hkey, appkey, "CopyDefaultColors", buffer, sizeof(buffer) ))
367         copy_default_colors = atoi(buffer);
368
369     if (!get_config_key( hkey, appkey, "AllocSystemColors", buffer, sizeof(buffer) ))
370         alloc_system_colors = atoi(buffer);
371
372     get_config_key( hkey, appkey, "InputStyle", input_style, sizeof(input_style) );
373
374     if (appkey) RegCloseKey( appkey );
375     if (hkey) RegCloseKey( hkey );
376 }
377
378
379 /***********************************************************************
380  *           X11DRV process initialisation routine
381  */
382 static BOOL process_attach(void)
383 {
384     Display *display;
385     XVisualInfo *desktop_vi = NULL;
386
387     setup_options();
388
389     if ((thread_data_tls_index = TlsAlloc()) == TLS_OUT_OF_INDEXES) return FALSE;
390
391     /* Open display */
392
393     if (!XInitThreads()) ERR( "XInitThreads failed, trouble ahead\n" );
394
395     if (!(display = XOpenDisplay( NULL ))) return FALSE;
396
397     fcntl( ConnectionNumber(display), F_SETFD, 1 ); /* set close on exec flag */
398     screen = DefaultScreenOfDisplay( display );
399     visual = DefaultVisual( display, DefaultScreen(display) );
400     root_window = DefaultRootWindow( display );
401     gdi_display = display;
402     old_error_handler = XSetErrorHandler( error_handler );
403
404     /* Initialize screen depth */
405
406     if (screen_depth)  /* depth specified */
407     {
408         int depth_count, i;
409         int *depth_list = XListDepths(display, DefaultScreen(display), &depth_count);
410         for (i = 0; i < depth_count; i++)
411             if (depth_list[i] == screen_depth) break;
412         XFree( depth_list );
413         if (i >= depth_count)
414         {
415             WARN( "invalid depth %d, using default\n", screen_depth );
416             screen_depth = 0;
417         }
418     }
419     if (!screen_depth) screen_depth = DefaultDepthOfScreen( screen );
420
421     /* If OpenGL is available, change the default visual, etc as necessary */
422     if (desktop_dbl_buf && (desktop_vi = X11DRV_setup_opengl_visual( display )))
423     {
424         visual       = desktop_vi->visual;
425         screen       = ScreenOfDisplay(display, desktop_vi->screen);
426         screen_depth = desktop_vi->depth;
427         XFree(desktop_vi);
428     }
429
430     XInternAtoms( display, (char **)atom_names, NB_XATOMS - FIRST_XATOM, False, X11DRV_Atoms );
431
432     if (TRACE_ON(synchronous)) XSynchronize( display, True );
433
434     screen_width  = WidthOfScreen( screen );
435     screen_height = HeightOfScreen( screen );
436
437     xinerama_init();
438     X11DRV_Settings_Init();
439
440 #ifdef HAVE_LIBXXF86VM
441     /* initialize XVidMode */
442     X11DRV_XF86VM_Init();
443 #endif
444 #ifdef HAVE_LIBXRANDR
445     /* initialize XRandR */
446     X11DRV_XRandR_Init();
447 #endif
448
449     X11DRV_InitKeyboard();
450     X11DRV_InitClipboard();
451
452     return TRUE;
453 }
454
455
456 /***********************************************************************
457  *           X11DRV thread termination routine
458  */
459 static void thread_detach(void)
460 {
461     struct x11drv_thread_data *data = TlsGetValue( thread_data_tls_index );
462
463     if (data)
464     {
465         X11DRV_ResetSelectionOwner();
466         CloseHandle( data->display_fd );
467         wine_tsx11_lock();
468         if (data->xim) XCloseIM( data->xim );
469         XCloseDisplay( data->display );
470         wine_tsx11_unlock();
471         HeapFree( GetProcessHeap(), 0, data );
472     }
473 }
474
475
476 /***********************************************************************
477  *           X11DRV process termination routine
478  */
479 static void process_detach(void)
480 {
481 #ifdef HAVE_LIBXXF86VM
482     /* cleanup XVidMode */
483     X11DRV_XF86VM_Cleanup();
484 #endif
485     if(using_client_side_fonts)
486         X11DRV_XRender_Finalize();
487
488     /* cleanup GDI */
489     X11DRV_GDI_Finalize();
490
491     DeleteCriticalSection( &X11DRV_CritSection );
492     TlsFree( thread_data_tls_index );
493 }
494
495
496 /***********************************************************************
497  *           X11DRV thread initialisation routine
498  */
499 struct x11drv_thread_data *x11drv_init_thread_data(void)
500 {
501     struct x11drv_thread_data *data;
502
503     if (!(data = HeapAlloc( GetProcessHeap(), 0, sizeof(*data) )))
504     {
505         ERR( "could not create data\n" );
506         ExitProcess(1);
507     }
508     wine_tsx11_lock();
509     if (!(data->display = XOpenDisplay(NULL)))
510     {
511         wine_tsx11_unlock();
512         MESSAGE( "x11drv: Can't open display: %s\n", XDisplayName(NULL) );
513         MESSAGE( "Please ensure that your X server is running and that $DISPLAY is set correctly.\n" );
514         ExitProcess(1);
515     }
516
517     fcntl( ConnectionNumber(data->display), F_SETFD, 1 ); /* set close on exec flag */
518
519 #ifdef HAVE_XKB
520     if (use_xkb)
521     {
522         use_xkb = XkbUseExtension( data->display, NULL, NULL );
523         if (use_xkb)
524         {
525             /* Hack: dummy call to XkbKeysymToModifiers to force initialisation of Xkb internals */
526             /* This works around an Xlib bug where it tries to get the display lock */
527             /* twice during XFilterEvents if Xkb hasn't been initialised yet. */
528             XkbKeysymToModifiers( data->display, 'A' );
529             XkbSetDetectableAutoRepeat( data->display, True, NULL );
530         }
531     }
532 #endif
533
534     if (TRACE_ON(synchronous)) XSynchronize( data->display, True );
535     wine_tsx11_unlock();
536
537     if (!use_xim)
538         data->xim = NULL;
539     else if (!(data->xim = X11DRV_SetupXIM( data->display, input_style )))
540         WARN("Input Method is not available\n");
541
542     if (wine_server_fd_to_handle( ConnectionNumber(data->display), GENERIC_READ | SYNCHRONIZE,
543                                   0, &data->display_fd ))
544     {
545         MESSAGE( "x11drv: Can't allocate handle for display fd\n" );
546         ExitProcess(1);
547     }
548     data->process_event_count = 0;
549     data->cursor = None;
550     data->cursor_window = None;
551     data->grab_window = None;
552     data->last_focus = 0;
553     data->selection_wnd = 0;
554     TlsSetValue( thread_data_tls_index, data );
555     return data;
556 }
557
558
559 /***********************************************************************
560  *           X11DRV initialisation routine
561  */
562 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
563 {
564     BOOL ret = TRUE;
565
566     switch(reason)
567     {
568     case DLL_PROCESS_ATTACH:
569         ret = process_attach();
570         break;
571     case DLL_THREAD_DETACH:
572         thread_detach();
573         break;
574     case DLL_PROCESS_DETACH:
575         process_detach();
576         break;
577     }
578     return ret;
579 }
580
581 /***********************************************************************
582  *              GetScreenSaveActive (X11DRV.@)
583  *
584  * Returns the active status of the screen saver
585  */
586 BOOL X11DRV_GetScreenSaveActive(void)
587 {
588     int timeout, temp;
589     wine_tsx11_lock();
590     XGetScreenSaver(gdi_display, &timeout, &temp, &temp, &temp);
591     wine_tsx11_unlock();
592     return timeout != 0;
593 }
594
595 /***********************************************************************
596  *              SetScreenSaveActive (X11DRV.@)
597  *
598  * Activate/Deactivate the screen saver
599  */
600 void X11DRV_SetScreenSaveActive(BOOL bActivate)
601 {
602     int timeout, interval, prefer_blanking, allow_exposures;
603     static int last_timeout = 15 * 60;
604
605     wine_tsx11_lock();
606     XGetScreenSaver(gdi_display, &timeout, &interval, &prefer_blanking,
607                     &allow_exposures);
608     if (timeout) last_timeout = timeout;
609
610     timeout = bActivate ? last_timeout : 0;
611     XSetScreenSaver(gdi_display, timeout, interval, prefer_blanking,
612                     allow_exposures);
613     wine_tsx11_unlock();
614 }