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