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