winex11: Moved the X11DRV_resize_desktop function to desktop.c.
[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 #include "wine/port.h"
24
25 #include <fcntl.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #ifdef HAVE_SYS_TIME_H
31 # include <sys/time.h>
32 #endif
33 #ifdef HAVE_UNISTD_H
34 # include <unistd.h>
35 #endif
36 #include <X11/cursorfont.h>
37 #include <X11/Xlib.h>
38 #ifdef HAVE_XKB
39 #include <X11/XKBlib.h>
40 #endif
41 #ifdef HAVE_X11_EXTENSIONS_XRENDER_H
42 #include <X11/extensions/Xrender.h>
43 #endif
44
45 #include "windef.h"
46 #include "winbase.h"
47 #include "winreg.h"
48
49 #include "x11drv.h"
50 #include "xvidmode.h"
51 #include "xrandr.h"
52 #include "xcomposite.h"
53 #include "wine/server.h"
54 #include "wine/debug.h"
55 #include "wine/library.h"
56
57 WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
58 WINE_DECLARE_DEBUG_CHANNEL(synchronous);
59
60 static CRITICAL_SECTION X11DRV_CritSection;
61 static CRITICAL_SECTION_DEBUG critsect_debug =
62 {
63     0, 0, &X11DRV_CritSection,
64     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
65       0, 0, { (DWORD_PTR)(__FILE__ ": X11DRV_CritSection") }
66 };
67 static CRITICAL_SECTION X11DRV_CritSection = { &critsect_debug, -1, 0, 0, 0, 0 };
68
69 Screen *screen;
70 Visual *visual;
71 unsigned int screen_width;
72 unsigned int screen_height;
73 unsigned int screen_bpp;
74 unsigned int screen_depth;
75 RECT virtual_screen_rect;
76 Window root_window;
77 int dxgrab = 0;
78 int usexvidmode = 1;
79 int usexrandr = 1;
80 int usexcomposite = 1;
81 int use_xkb = 1;
82 int use_take_focus = 1;
83 int use_primary_selection = 0;
84 int managed_mode = 1;
85 int decorated_mode = 1;
86 int private_color_map = 0;
87 int primary_monitor = 0;
88 int client_side_with_core = 1;
89 int client_side_with_render = 1;
90 int client_side_antialias_with_core = 1;
91 int client_side_antialias_with_render = 1;
92 int copy_default_colors = 128;
93 int alloc_system_colors = 256;
94 DWORD thread_data_tls_index = TLS_OUT_OF_INDEXES;
95 int xrender_error_base = 0;
96
97 static x11drv_error_callback err_callback;   /* current callback for error */
98 static Display *err_callback_display;        /* display callback is set for */
99 static void *err_callback_arg;               /* error callback argument */
100 static int err_callback_result;              /* error callback result */
101 static unsigned long err_serial;             /* serial number of first request */
102 static int (*old_error_handler)( Display *, XErrorEvent * );
103 static int use_xim = 1;
104 static char input_style[20];
105
106 #define IS_OPTION_TRUE(ch) \
107     ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1')
108 #define IS_OPTION_FALSE(ch) \
109     ((ch) == 'n' || (ch) == 'N' || (ch) == 'f' || (ch) == 'F' || (ch) == '0')
110
111 Atom X11DRV_Atoms[NB_XATOMS - FIRST_XATOM];
112
113 static const char * const atom_names[NB_XATOMS - FIRST_XATOM] =
114 {
115     "CLIPBOARD",
116     "COMPOUND_TEXT",
117     "MULTIPLE",
118     "SELECTION_DATA",
119     "TARGETS",
120     "TEXT",
121     "UTF8_STRING",
122     "RAW_ASCENT",
123     "RAW_DESCENT",
124     "RAW_CAP_HEIGHT",
125     "WM_PROTOCOLS",
126     "WM_DELETE_WINDOW",
127     "WM_STATE",
128     "WM_TAKE_FOCUS",
129     "DndProtocol",
130     "DndSelection",
131     "_ICC_PROFILE",
132     "_MOTIF_WM_HINTS",
133     "_NET_SUPPORTED",
134     "_NET_SYSTEM_TRAY_OPCODE",
135     "_NET_SYSTEM_TRAY_S0",
136     "_NET_WM_MOVERESIZE",
137     "_NET_WM_NAME",
138     "_NET_WM_PID",
139     "_NET_WM_PING",
140     "_NET_WM_STATE",
141     "_NET_WM_STATE_ABOVE",
142     "_NET_WM_STATE_FULLSCREEN",
143     "_NET_WM_STATE_MAXIMIZED_HORZ",
144     "_NET_WM_STATE_MAXIMIZED_VERT",
145     "_NET_WM_STATE_SKIP_PAGER",
146     "_NET_WM_STATE_SKIP_TASKBAR",
147     "_NET_WM_WINDOW_TYPE",
148     "_NET_WM_WINDOW_TYPE_DIALOG",
149     "_NET_WM_WINDOW_TYPE_NORMAL",
150     "_NET_WM_WINDOW_TYPE_UTILITY",
151     "_XEMBED_INFO",
152     "XdndAware",
153     "XdndEnter",
154     "XdndPosition",
155     "XdndStatus",
156     "XdndLeave",
157     "XdndFinished",
158     "XdndDrop",
159     "XdndActionCopy",
160     "XdndActionMove",
161     "XdndActionLink",
162     "XdndActionAsk",
163     "XdndActionPrivate",
164     "XdndSelection",
165     "XdndTarget",
166     "XdndTypeList",
167     "WCF_DIB",
168     "image/gif",
169     "text/html",
170     "text/plain",
171     "text/rtf",
172     "text/richtext",
173     "text/uri-list"
174 };
175
176 /***********************************************************************
177  *              ignore_error
178  *
179  * Check if the X error is one we can ignore.
180  */
181 static inline BOOL ignore_error( Display *display, XErrorEvent *event )
182 {
183     if (event->request_code == X_SetInputFocus && event->error_code == BadMatch) return TRUE;
184
185     /* ignore a number of errors on gdi display caused by creating/destroying windows */
186     if (display == gdi_display)
187     {
188         if (event->error_code == BadDrawable || event->error_code == BadGC) return TRUE;
189 #ifdef HAVE_X11_EXTENSIONS_XRENDER_H
190         if (xrender_error_base)  /* check for XRender errors */
191         {
192             if (event->error_code == xrender_error_base + BadPicture) return TRUE;
193         }
194 #endif
195     }
196     return FALSE;
197 }
198
199
200 /***********************************************************************
201  *              X11DRV_expect_error
202  *
203  * Setup a callback function that will be called on an X error.  The
204  * callback must return non-zero if the error is the one it expected.
205  * This function acquires the x11 lock; X11DRV_check_error must be
206  * called in all cases to release it.
207  */
208 void X11DRV_expect_error( Display *display, x11drv_error_callback callback, void *arg )
209 {
210     wine_tsx11_lock();
211     err_callback         = callback;
212     err_callback_display = display;
213     err_callback_arg     = arg;
214     err_callback_result  = 0;
215     err_serial           = NextRequest(display);
216 }
217
218
219 /***********************************************************************
220  *              X11DRV_check_error
221  *
222  * Check if an expected X11 error occurred; return non-zero if yes.
223  * Also release the x11 lock obtained in X11DRV_expect_error.
224  * The caller is responsible for calling XSync first if necessary.
225  */
226 int X11DRV_check_error(void)
227 {
228     int ret;
229     err_callback = NULL;
230     ret = err_callback_result;
231     wine_tsx11_unlock();
232     return ret;
233 }
234
235
236 /***********************************************************************
237  *              error_handler
238  */
239 static int error_handler( Display *display, XErrorEvent *error_evt )
240 {
241     if (err_callback && display == err_callback_display &&
242         (long)(error_evt->serial - err_serial) >= 0)
243     {
244         if ((err_callback_result = err_callback( display, error_evt, err_callback_arg )))
245         {
246             TRACE( "got expected error %d req %d\n",
247                    error_evt->error_code, error_evt->request_code );
248             return 0;
249         }
250     }
251     if (ignore_error( display, error_evt ))
252     {
253         TRACE( "got ignored error %d req %d\n",
254                error_evt->error_code, error_evt->request_code );
255         return 0;
256     }
257     if (TRACE_ON(synchronous))
258     {
259         ERR( "X protocol error: serial=%ld, request_code=%d - breaking into debugger\n",
260              error_evt->serial, error_evt->request_code );
261         DebugBreak();  /* force an entry in the debugger */
262     }
263     old_error_handler( display, error_evt );
264     return 0;
265 }
266
267 /***********************************************************************
268  *              wine_tsx11_lock   (X11DRV.@)
269  */
270 void wine_tsx11_lock(void)
271 {
272     EnterCriticalSection( &X11DRV_CritSection );
273 }
274
275 /***********************************************************************
276  *              wine_tsx11_unlock   (X11DRV.@)
277  */
278 void wine_tsx11_unlock(void)
279 {
280     LeaveCriticalSection( &X11DRV_CritSection );
281 }
282
283
284 /***********************************************************************
285  *              depth_to_bpp
286  *
287  * Convert X11-reported depth to the BPP value that Windows apps expect to see.
288  */
289 unsigned int depth_to_bpp( unsigned int depth )
290 {
291     switch (depth)
292     {
293     case 1:
294     case 8:
295         return depth;
296     case 15:
297     case 16:
298         return 16;
299     case 24:
300         /* This is not necessarily right. X11 always has 24 bits per pixel, but it can run
301          * with 24 bit framebuffers and 32 bit framebuffers. It doesn't make any difference
302          * for windowing, but gl applications can get visuals with alpha channels. So we
303          * should check the framebuffer and/or opengl formats available to find out what the
304          * framebuffer actually does
305          */
306     case 32:
307         return 32;
308     default:
309         FIXME( "Unexpected X11 depth %d bpp, what to report to app?\n", depth );
310         return depth;
311     }
312 }
313
314
315 /***********************************************************************
316  *              get_config_key
317  *
318  * Get a config key from either the app-specific or the default config
319  */
320 static inline DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name,
321                                     char *buffer, DWORD size )
322 {
323     if (appkey && !RegQueryValueExA( appkey, name, 0, NULL, (LPBYTE)buffer, &size )) return 0;
324     if (defkey && !RegQueryValueExA( defkey, name, 0, NULL, (LPBYTE)buffer, &size )) return 0;
325     return ERROR_FILE_NOT_FOUND;
326 }
327
328
329 /***********************************************************************
330  *              setup_options
331  *
332  * Setup the x11drv options.
333  */
334 static void setup_options(void)
335 {
336     char buffer[MAX_PATH+16];
337     HKEY hkey, appkey = 0;
338     DWORD len;
339
340     /* @@ Wine registry key: HKCU\Software\Wine\X11 Driver */
341     if (RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\X11 Driver", &hkey )) hkey = 0;
342
343     /* open the app-specific key */
344
345     len = (GetModuleFileNameA( 0, buffer, MAX_PATH ));
346     if (len && len < MAX_PATH)
347     {
348         HKEY tmpkey;
349         char *p, *appname = buffer;
350         if ((p = strrchr( appname, '/' ))) appname = p + 1;
351         if ((p = strrchr( appname, '\\' ))) appname = p + 1;
352         strcat( appname, "\\X11 Driver" );
353         /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\X11 Driver */
354         if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\AppDefaults", &tmpkey ))
355         {
356             if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0;
357             RegCloseKey( tmpkey );
358         }
359     }
360
361     if (!get_config_key( hkey, appkey, "Managed", buffer, sizeof(buffer) ))
362         managed_mode = IS_OPTION_TRUE( buffer[0] );
363
364     if (!get_config_key( hkey, appkey, "Decorated", buffer, sizeof(buffer) ))
365         decorated_mode = IS_OPTION_TRUE( buffer[0] );
366
367     if (!get_config_key( hkey, appkey, "DXGrab", buffer, sizeof(buffer) ))
368         dxgrab = IS_OPTION_TRUE( buffer[0] );
369
370     if (!get_config_key( hkey, appkey, "UseXVidMode", buffer, sizeof(buffer) ))
371         usexvidmode = IS_OPTION_TRUE( buffer[0] );
372
373     if (!get_config_key( hkey, appkey, "UseXRandR", buffer, sizeof(buffer) ))
374         usexrandr = IS_OPTION_TRUE( buffer[0] );
375
376     if (!get_config_key( hkey, appkey, "UseTakeFocus", buffer, sizeof(buffer) ))
377         use_take_focus = IS_OPTION_TRUE( buffer[0] );
378
379     if (!get_config_key( hkey, appkey, "UsePrimarySelection", buffer, sizeof(buffer) ))
380         use_primary_selection = IS_OPTION_TRUE( buffer[0] );
381
382     screen_depth = 0;
383     if (!get_config_key( hkey, appkey, "ScreenDepth", buffer, sizeof(buffer) ))
384         screen_depth = atoi(buffer);
385
386     if (!get_config_key( hkey, appkey, "ClientSideWithCore", buffer, sizeof(buffer) ))
387         client_side_with_core = IS_OPTION_TRUE( buffer[0] );
388
389     if (!get_config_key( hkey, appkey, "ClientSideWithRender", buffer, sizeof(buffer) ))
390         client_side_with_render = IS_OPTION_TRUE( buffer[0] );
391
392     if (!get_config_key( hkey, appkey, "ClientSideAntiAliasWithCore", buffer, sizeof(buffer) ))
393         client_side_antialias_with_core = IS_OPTION_TRUE( buffer[0] );
394
395     if (!get_config_key( hkey, appkey, "ClientSideAntiAliasWithRender", buffer, sizeof(buffer) ))
396         client_side_antialias_with_render = IS_OPTION_TRUE( buffer[0] );
397
398     if (!get_config_key( hkey, appkey, "UseXIM", buffer, sizeof(buffer) ))
399         use_xim = IS_OPTION_TRUE( buffer[0] );
400
401     if (!get_config_key( hkey, appkey, "PrivateColorMap", buffer, sizeof(buffer) ))
402         private_color_map = IS_OPTION_TRUE( buffer[0] );
403
404     if (!get_config_key( hkey, appkey, "PrimaryMonitor", buffer, sizeof(buffer) ))
405         primary_monitor = atoi( buffer );
406
407     if (!get_config_key( hkey, appkey, "CopyDefaultColors", buffer, sizeof(buffer) ))
408         copy_default_colors = atoi(buffer);
409
410     if (!get_config_key( hkey, appkey, "AllocSystemColors", buffer, sizeof(buffer) ))
411         alloc_system_colors = atoi(buffer);
412
413     get_config_key( hkey, appkey, "InputStyle", input_style, sizeof(input_style) );
414
415     if (appkey) RegCloseKey( appkey );
416     if (hkey) RegCloseKey( hkey );
417 }
418
419 #ifdef SONAME_LIBXCOMPOSITE
420
421 #define MAKE_FUNCPTR(f) typeof(f) * p##f;
422 MAKE_FUNCPTR(XCompositeQueryExtension)
423 MAKE_FUNCPTR(XCompositeQueryVersion)
424 MAKE_FUNCPTR(XCompositeVersion)
425 MAKE_FUNCPTR(XCompositeRedirectWindow)
426 MAKE_FUNCPTR(XCompositeRedirectSubwindows)
427 MAKE_FUNCPTR(XCompositeUnredirectWindow)
428 MAKE_FUNCPTR(XCompositeUnredirectSubwindows)
429 MAKE_FUNCPTR(XCompositeCreateRegionFromBorderClip)
430 MAKE_FUNCPTR(XCompositeNameWindowPixmap)
431 #undef MAKE_FUNCPTR
432
433 static int xcomp_event_base;
434 static int xcomp_error_base;
435
436 static void X11DRV_XComposite_Init(void)
437 {
438     void *xcomposite_handle = wine_dlopen(SONAME_LIBXCOMPOSITE, RTLD_NOW, NULL, 0);
439     if (!xcomposite_handle)
440     {
441         TRACE("Unable to open %s, XComposite disabled\n", SONAME_LIBXCOMPOSITE);
442         usexcomposite = 0;
443         return;
444     }
445
446 #define LOAD_FUNCPTR(f) \
447     if((p##f = wine_dlsym(xcomposite_handle, #f, NULL, 0)) == NULL) \
448         goto sym_not_found;
449     LOAD_FUNCPTR(XCompositeQueryExtension)
450     LOAD_FUNCPTR(XCompositeQueryVersion)
451     LOAD_FUNCPTR(XCompositeVersion)
452     LOAD_FUNCPTR(XCompositeRedirectWindow)
453     LOAD_FUNCPTR(XCompositeRedirectSubwindows)
454     LOAD_FUNCPTR(XCompositeUnredirectWindow)
455     LOAD_FUNCPTR(XCompositeUnredirectSubwindows)
456     LOAD_FUNCPTR(XCompositeCreateRegionFromBorderClip)
457     LOAD_FUNCPTR(XCompositeNameWindowPixmap)
458 #undef LOAD_FUNCPTR
459
460     if(!pXCompositeQueryExtension(gdi_display, &xcomp_event_base,
461                                   &xcomp_error_base)) {
462         TRACE("XComposite extension could not be queried; disabled\n");
463         wine_dlclose(xcomposite_handle, NULL, 0);
464         xcomposite_handle = NULL;
465         usexcomposite = 0;
466         return;
467     }
468     TRACE("XComposite is up and running error_base = %d\n", xcomp_error_base);
469     return;
470
471 sym_not_found:
472     TRACE("Unable to load function pointers from %s, XComposite disabled\n", SONAME_LIBXCOMPOSITE);
473     wine_dlclose(xcomposite_handle, NULL, 0);
474     xcomposite_handle = NULL;
475     usexcomposite = 0;
476 }
477 #endif /* defined(SONAME_LIBXCOMPOSITE) */
478
479
480 /***********************************************************************
481  *           X11DRV process initialisation routine
482  */
483 static BOOL process_attach(void)
484 {
485     Display *display;
486     const char *env;
487
488     setup_options();
489
490     if ((thread_data_tls_index = TlsAlloc()) == TLS_OUT_OF_INDEXES) return FALSE;
491
492     /* Open display */
493
494     if (!(env = getenv("XMODIFIERS")) || !*env)  /* try to avoid the Xlib XIM locking bug */
495         if (!XInitThreads()) ERR( "XInitThreads failed, trouble ahead\n" );
496
497     if (!(display = XOpenDisplay( NULL ))) return FALSE;
498
499     fcntl( ConnectionNumber(display), F_SETFD, 1 ); /* set close on exec flag */
500     screen = DefaultScreenOfDisplay( display );
501     visual = DefaultVisual( display, DefaultScreen(display) );
502     root_window = DefaultRootWindow( display );
503     gdi_display = display;
504     old_error_handler = XSetErrorHandler( error_handler );
505
506     /* Initialize screen depth */
507
508     if (screen_depth)  /* depth specified */
509     {
510         int depth_count, i;
511         int *depth_list = XListDepths(display, DefaultScreen(display), &depth_count);
512         for (i = 0; i < depth_count; i++)
513             if (depth_list[i] == screen_depth) break;
514         XFree( depth_list );
515         if (i >= depth_count)
516         {
517             WARN( "invalid depth %d, using default\n", screen_depth );
518             screen_depth = 0;
519         }
520     }
521     if (!screen_depth) screen_depth = DefaultDepthOfScreen( screen );
522     screen_bpp = depth_to_bpp( screen_depth );
523
524     XInternAtoms( display, (char **)atom_names, NB_XATOMS - FIRST_XATOM, False, X11DRV_Atoms );
525
526     if (TRACE_ON(synchronous)) XSynchronize( display, True );
527
528     xinerama_init( WidthOfScreen(screen), HeightOfScreen(screen) );
529     X11DRV_Settings_Init();
530
531 #ifdef HAVE_LIBXXF86VM
532     /* initialize XVidMode */
533     X11DRV_XF86VM_Init();
534 #endif
535 #ifdef SONAME_LIBXRANDR
536     /* initialize XRandR */
537     X11DRV_XRandR_Init();
538 #endif
539 #ifdef SONAME_LIBXCOMPOSITE
540     X11DRV_XComposite_Init();
541 #endif
542
543     X11DRV_InitKeyboard( gdi_display );
544     X11DRV_InitClipboard();
545     if (use_xim) use_xim = X11DRV_InitXIM( input_style );
546
547     return TRUE;
548 }
549
550
551 /***********************************************************************
552  *           X11DRV thread termination routine
553  */
554 static void thread_detach(void)
555 {
556     struct x11drv_thread_data *data = TlsGetValue( thread_data_tls_index );
557
558     if (data)
559     {
560         X11DRV_ResetSelectionOwner();
561         wine_tsx11_lock();
562         if (data->xim) XCloseIM( data->xim );
563         XCloseDisplay( data->display );
564         wine_tsx11_unlock();
565         HeapFree( GetProcessHeap(), 0, data );
566     }
567 }
568
569
570 /***********************************************************************
571  *           X11DRV process termination routine
572  */
573 static void process_detach(void)
574 {
575 #ifdef HAVE_LIBXXF86VM
576     /* cleanup XVidMode */
577     X11DRV_XF86VM_Cleanup();
578 #endif
579     if(using_client_side_fonts)
580         X11DRV_XRender_Finalize();
581
582     /* cleanup GDI */
583     X11DRV_GDI_Finalize();
584
585     DeleteCriticalSection( &X11DRV_CritSection );
586     TlsFree( thread_data_tls_index );
587 }
588
589
590 /* store the display fd into the message queue */
591 static void set_queue_display_fd( Display *display )
592 {
593     HANDLE handle;
594     int ret;
595
596     if (wine_server_fd_to_handle( ConnectionNumber(display), GENERIC_READ | SYNCHRONIZE, 0, &handle ))
597     {
598         MESSAGE( "x11drv: Can't allocate handle for display fd\n" );
599         ExitProcess(1);
600     }
601     SERVER_START_REQ( set_queue_fd )
602     {
603         req->handle = handle;
604         ret = wine_server_call( req );
605     }
606     SERVER_END_REQ;
607     if (ret)
608     {
609         MESSAGE( "x11drv: Can't store handle for display fd\n" );
610         ExitProcess(1);
611     }
612     CloseHandle( handle );
613 }
614
615
616 /***********************************************************************
617  *           X11DRV thread initialisation routine
618  */
619 struct x11drv_thread_data *x11drv_init_thread_data(void)
620 {
621     struct x11drv_thread_data *data;
622
623     if (!(data = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data) )))
624     {
625         ERR( "could not create data\n" );
626         ExitProcess(1);
627     }
628     wine_tsx11_lock();
629     if (!(data->display = XOpenDisplay(NULL)))
630     {
631         wine_tsx11_unlock();
632         MESSAGE( "x11drv: Can't open display: %s\n", XDisplayName(NULL) );
633         MESSAGE( "Please ensure that your X server is running and that $DISPLAY is set correctly.\n" );
634         ExitProcess(1);
635     }
636
637     fcntl( ConnectionNumber(data->display), F_SETFD, 1 ); /* set close on exec flag */
638
639 #ifdef HAVE_XKB
640     if (use_xkb)
641     {
642         use_xkb = XkbUseExtension( data->display, NULL, NULL );
643         if (use_xkb)
644         {
645             /* Hack: dummy call to XkbKeysymToModifiers to force initialisation of Xkb internals */
646             /* This works around an Xlib bug where it tries to get the display lock */
647             /* twice during XFilterEvents if Xkb hasn't been initialised yet. */
648             XkbKeysymToModifiers( data->display, 'A' );
649             XkbSetDetectableAutoRepeat( data->display, True, NULL );
650         }
651     }
652 #endif
653
654     if (TRACE_ON(synchronous)) XSynchronize( data->display, True );
655     wine_tsx11_unlock();
656
657     set_queue_display_fd( data->display );
658     TlsSetValue( thread_data_tls_index, data );
659
660     if (use_xim) X11DRV_SetupXIM();
661     X11DRV_SetCursor( NULL );
662
663     return data;
664 }
665
666
667 /***********************************************************************
668  *           X11DRV initialisation routine
669  */
670 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
671 {
672     BOOL ret = TRUE;
673
674     switch(reason)
675     {
676     case DLL_PROCESS_ATTACH:
677         ret = process_attach();
678         IME_RegisterClasses(hinst);
679         break;
680     case DLL_THREAD_DETACH:
681         thread_detach();
682         break;
683     case DLL_PROCESS_DETACH:
684         process_detach();
685         IME_UnregisterClasses(hinst);
686         break;
687     }
688     return ret;
689 }
690
691 /***********************************************************************
692  *              GetScreenSaveActive (X11DRV.@)
693  *
694  * Returns the active status of the screen saver
695  */
696 BOOL X11DRV_GetScreenSaveActive(void)
697 {
698     int timeout, temp;
699     wine_tsx11_lock();
700     XGetScreenSaver(gdi_display, &timeout, &temp, &temp, &temp);
701     wine_tsx11_unlock();
702     return timeout != 0;
703 }
704
705 /***********************************************************************
706  *              SetScreenSaveActive (X11DRV.@)
707  *
708  * Activate/Deactivate the screen saver
709  */
710 void X11DRV_SetScreenSaveActive(BOOL bActivate)
711 {
712     int timeout, interval, prefer_blanking, allow_exposures;
713     static int last_timeout = 15 * 60;
714
715     wine_tsx11_lock();
716     XGetScreenSaver(gdi_display, &timeout, &interval, &prefer_blanking,
717                     &allow_exposures);
718     if (timeout) last_timeout = timeout;
719
720     timeout = bActivate ? last_timeout : 0;
721     XSetScreenSaver(gdi_display, timeout, interval, prefer_blanking,
722                     allow_exposures);
723     wine_tsx11_unlock();
724 }