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