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