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