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