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