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