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