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