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