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