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