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