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