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