uxtheme: Mark internal symbols with hidden visibility.
[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 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 grab_fullscreen = 0;
88 int managed_mode = 1;
89 int decorated_mode = 1;
90 int private_color_map = 0;
91 int primary_monitor = 0;
92 int client_side_with_core = 1;
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  *              depth_to_bpp
328  *
329  * Convert X11-reported depth to the BPP value that Windows apps expect to see.
330  */
331 unsigned int depth_to_bpp( unsigned int depth )
332 {
333     switch (depth)
334     {
335     case 1:
336     case 8:
337         return depth;
338     case 15:
339     case 16:
340         return 16;
341     case 24:
342         /* This is not necessarily right. X11 always has 24 bits per pixel, but it can run
343          * with 24 bit framebuffers and 32 bit framebuffers. It doesn't make any difference
344          * for windowing, but gl applications can get visuals with alpha channels. So we
345          * should check the framebuffer and/or opengl formats available to find out what the
346          * framebuffer actually does
347          */
348     case 32:
349         return 32;
350     default:
351         FIXME( "Unexpected X11 depth %d bpp, what to report to app?\n", depth );
352         return depth;
353     }
354 }
355
356
357 /***********************************************************************
358  *              get_config_key
359  *
360  * Get a config key from either the app-specific or the default config
361  */
362 static inline DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name,
363                                     char *buffer, DWORD size )
364 {
365     if (appkey && !RegQueryValueExA( appkey, name, 0, NULL, (LPBYTE)buffer, &size )) return 0;
366     if (defkey && !RegQueryValueExA( defkey, name, 0, NULL, (LPBYTE)buffer, &size )) return 0;
367     return ERROR_FILE_NOT_FOUND;
368 }
369
370
371 /***********************************************************************
372  *              setup_options
373  *
374  * Setup the x11drv options.
375  */
376 static void setup_options(void)
377 {
378     char buffer[MAX_PATH+16];
379     HKEY hkey, appkey = 0;
380     DWORD len;
381
382     /* @@ Wine registry key: HKCU\Software\Wine\X11 Driver */
383     if (RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\X11 Driver", &hkey )) hkey = 0;
384
385     /* open the app-specific key */
386
387     len = (GetModuleFileNameA( 0, buffer, MAX_PATH ));
388     if (len && len < MAX_PATH)
389     {
390         HKEY tmpkey;
391         char *p, *appname = buffer;
392         if ((p = strrchr( appname, '/' ))) appname = p + 1;
393         if ((p = strrchr( appname, '\\' ))) appname = p + 1;
394         strcat( appname, "\\X11 Driver" );
395         /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\X11 Driver */
396         if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\AppDefaults", &tmpkey ))
397         {
398             if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0;
399             RegCloseKey( tmpkey );
400         }
401     }
402
403     if (!get_config_key( hkey, appkey, "Managed", buffer, sizeof(buffer) ))
404         managed_mode = IS_OPTION_TRUE( buffer[0] );
405
406     if (!get_config_key( hkey, appkey, "Decorated", buffer, sizeof(buffer) ))
407         decorated_mode = IS_OPTION_TRUE( buffer[0] );
408
409     if (!get_config_key( hkey, appkey, "UseXVidMode", buffer, sizeof(buffer) ))
410         usexvidmode = IS_OPTION_TRUE( buffer[0] );
411
412     if (!get_config_key( hkey, appkey, "UseXRandR", buffer, sizeof(buffer) ))
413         usexrandr = IS_OPTION_TRUE( buffer[0] );
414
415     if (!get_config_key( hkey, appkey, "UseTakeFocus", buffer, sizeof(buffer) ))
416         use_take_focus = IS_OPTION_TRUE( buffer[0] );
417
418     if (!get_config_key( hkey, appkey, "UsePrimarySelection", buffer, sizeof(buffer) ))
419         use_primary_selection = IS_OPTION_TRUE( buffer[0] );
420
421     if (!get_config_key( hkey, appkey, "UseSystemCursors", buffer, sizeof(buffer) ))
422         use_system_cursors = IS_OPTION_TRUE( buffer[0] );
423
424     if (!get_config_key( hkey, appkey, "ShowSystray", buffer, sizeof(buffer) ))
425         show_systray = IS_OPTION_TRUE( buffer[0] );
426
427     if (!get_config_key( hkey, appkey, "GrabPointer", buffer, sizeof(buffer) ))
428         grab_pointer = IS_OPTION_TRUE( buffer[0] );
429
430     if (!get_config_key( hkey, appkey, "GrabFullscreen", buffer, sizeof(buffer) ))
431         grab_fullscreen = IS_OPTION_TRUE( buffer[0] );
432
433     screen_depth = 0;
434     if (!get_config_key( hkey, appkey, "ScreenDepth", buffer, sizeof(buffer) ))
435         screen_depth = atoi(buffer);
436
437     if (!get_config_key( hkey, appkey, "ClientSideWithCore", buffer, sizeof(buffer) ))
438         client_side_with_core = IS_OPTION_TRUE( buffer[0] );
439
440     if (!get_config_key( hkey, appkey, "ClientSideWithRender", buffer, sizeof(buffer) ))
441         client_side_with_render = IS_OPTION_TRUE( buffer[0] );
442
443     if (!get_config_key( hkey, appkey, "ClientSideAntiAliasWithCore", buffer, sizeof(buffer) ))
444         client_side_antialias_with_core = IS_OPTION_TRUE( buffer[0] );
445
446     if (!get_config_key( hkey, appkey, "ClientSideAntiAliasWithRender", buffer, sizeof(buffer) ))
447         client_side_antialias_with_render = IS_OPTION_TRUE( buffer[0] );
448
449     if (!get_config_key( hkey, appkey, "UseXIM", buffer, sizeof(buffer) ))
450         use_xim = IS_OPTION_TRUE( buffer[0] );
451
452     if (!get_config_key( hkey, appkey, "PrivateColorMap", buffer, sizeof(buffer) ))
453         private_color_map = IS_OPTION_TRUE( buffer[0] );
454
455     if (!get_config_key( hkey, appkey, "PrimaryMonitor", buffer, sizeof(buffer) ))
456         primary_monitor = atoi( buffer );
457
458     if (!get_config_key( hkey, appkey, "CopyDefaultColors", buffer, sizeof(buffer) ))
459         copy_default_colors = atoi(buffer);
460
461     if (!get_config_key( hkey, appkey, "AllocSystemColors", buffer, sizeof(buffer) ))
462         alloc_system_colors = atoi(buffer);
463
464     get_config_key( hkey, appkey, "InputStyle", input_style, sizeof(input_style) );
465
466     if (appkey) RegCloseKey( appkey );
467     if (hkey) RegCloseKey( hkey );
468 }
469
470 #ifdef SONAME_LIBXCOMPOSITE
471
472 #define MAKE_FUNCPTR(f) typeof(f) * p##f;
473 MAKE_FUNCPTR(XCompositeQueryExtension)
474 MAKE_FUNCPTR(XCompositeQueryVersion)
475 MAKE_FUNCPTR(XCompositeVersion)
476 MAKE_FUNCPTR(XCompositeRedirectWindow)
477 MAKE_FUNCPTR(XCompositeRedirectSubwindows)
478 MAKE_FUNCPTR(XCompositeUnredirectWindow)
479 MAKE_FUNCPTR(XCompositeUnredirectSubwindows)
480 MAKE_FUNCPTR(XCompositeCreateRegionFromBorderClip)
481 MAKE_FUNCPTR(XCompositeNameWindowPixmap)
482 #undef MAKE_FUNCPTR
483
484 static int xcomp_event_base;
485 static int xcomp_error_base;
486
487 static void X11DRV_XComposite_Init(void)
488 {
489     void *xcomposite_handle = wine_dlopen(SONAME_LIBXCOMPOSITE, RTLD_NOW, NULL, 0);
490     if (!xcomposite_handle)
491     {
492         TRACE("Unable to open %s, XComposite disabled\n", SONAME_LIBXCOMPOSITE);
493         usexcomposite = 0;
494         return;
495     }
496
497 #define LOAD_FUNCPTR(f) \
498     if((p##f = wine_dlsym(xcomposite_handle, #f, NULL, 0)) == NULL) \
499         goto sym_not_found;
500     LOAD_FUNCPTR(XCompositeQueryExtension)
501     LOAD_FUNCPTR(XCompositeQueryVersion)
502     LOAD_FUNCPTR(XCompositeVersion)
503     LOAD_FUNCPTR(XCompositeRedirectWindow)
504     LOAD_FUNCPTR(XCompositeRedirectSubwindows)
505     LOAD_FUNCPTR(XCompositeUnredirectWindow)
506     LOAD_FUNCPTR(XCompositeUnredirectSubwindows)
507     LOAD_FUNCPTR(XCompositeCreateRegionFromBorderClip)
508     LOAD_FUNCPTR(XCompositeNameWindowPixmap)
509 #undef LOAD_FUNCPTR
510
511     if(!pXCompositeQueryExtension(gdi_display, &xcomp_event_base,
512                                   &xcomp_error_base)) {
513         TRACE("XComposite extension could not be queried; disabled\n");
514         wine_dlclose(xcomposite_handle, NULL, 0);
515         xcomposite_handle = NULL;
516         usexcomposite = 0;
517         return;
518     }
519     TRACE("XComposite is up and running error_base = %d\n", xcomp_error_base);
520     return;
521
522 sym_not_found:
523     TRACE("Unable to load function pointers from %s, XComposite disabled\n", SONAME_LIBXCOMPOSITE);
524     wine_dlclose(xcomposite_handle, NULL, 0);
525     xcomposite_handle = NULL;
526     usexcomposite = 0;
527 }
528 #endif /* defined(SONAME_LIBXCOMPOSITE) */
529
530
531 /***********************************************************************
532  *           X11DRV process initialisation routine
533  */
534 static BOOL process_attach(void)
535 {
536     char error[1024];
537     Display *display;
538     void *libx11 = wine_dlopen( SONAME_LIBX11, RTLD_NOW|RTLD_GLOBAL, error, sizeof(error) );
539
540     if (!libx11)
541     {
542         ERR( "failed to load %s: %s\n", SONAME_LIBX11, error );
543         return FALSE;
544     }
545     pXGetEventData = wine_dlsym( libx11, "XGetEventData", NULL, 0 );
546     pXFreeEventData = wine_dlsym( libx11, "XFreeEventData", NULL, 0 );
547 #ifdef SONAME_LIBXEXT
548     wine_dlopen( SONAME_LIBXEXT, RTLD_NOW|RTLD_GLOBAL, NULL, 0 );
549 #endif
550
551     setup_options();
552
553     if ((thread_data_tls_index = TlsAlloc()) == TLS_OUT_OF_INDEXES) return FALSE;
554
555     /* Open display */
556
557     if (!(display = XOpenDisplay( NULL ))) return FALSE;
558
559     fcntl( ConnectionNumber(display), F_SETFD, 1 ); /* set close on exec flag */
560     screen = DefaultScreenOfDisplay( display );
561     visual = DefaultVisual( display, DefaultScreen(display) );
562     root_window = DefaultRootWindow( display );
563     gdi_display = display;
564     old_error_handler = XSetErrorHandler( error_handler );
565
566     /* Initialize screen depth */
567
568     if (screen_depth)  /* depth specified */
569     {
570         int depth_count, i;
571         int *depth_list = XListDepths(display, DefaultScreen(display), &depth_count);
572         for (i = 0; i < depth_count; i++)
573             if (depth_list[i] == screen_depth) break;
574         XFree( depth_list );
575         if (i >= depth_count)
576         {
577             WARN( "invalid depth %d, using default\n", screen_depth );
578             screen_depth = 0;
579         }
580     }
581     if (!screen_depth) screen_depth = DefaultDepthOfScreen( screen );
582     screen_bpp = depth_to_bpp( screen_depth );
583
584     XInternAtoms( display, (char **)atom_names, NB_XATOMS - FIRST_XATOM, False, X11DRV_Atoms );
585
586     if (TRACE_ON(synchronous)) XSynchronize( display, True );
587
588     xinerama_init( WidthOfScreen(screen), HeightOfScreen(screen) );
589     X11DRV_Settings_Init();
590
591 #ifdef SONAME_LIBXXF86VM
592     /* initialize XVidMode */
593     X11DRV_XF86VM_Init();
594 #endif
595 #ifdef SONAME_LIBXRANDR
596     /* initialize XRandR */
597     X11DRV_XRandR_Init();
598 #endif
599 #ifdef SONAME_LIBXCOMPOSITE
600     X11DRV_XComposite_Init();
601 #endif
602     X11DRV_XInput2_Init();
603
604 #ifdef HAVE_XKB
605     if (use_xkb) use_xkb = XkbUseExtension( gdi_display, NULL, NULL );
606 #endif
607     X11DRV_InitKeyboard( gdi_display );
608     X11DRV_InitClipboard();
609     if (use_xim) use_xim = X11DRV_InitXIM( input_style );
610
611     return TRUE;
612 }
613
614
615 /***********************************************************************
616  *           X11DRV thread termination routine
617  */
618 static void thread_detach(void)
619 {
620     struct x11drv_thread_data *data = TlsGetValue( thread_data_tls_index );
621
622     if (data)
623     {
624         X11DRV_ResetSelectionOwner();
625         wine_tsx11_lock();
626         if (data->xim) XCloseIM( data->xim );
627         if (data->font_set) XFreeFontSet( data->display, data->font_set );
628         XCloseDisplay( data->display );
629         wine_tsx11_unlock();
630         HeapFree( GetProcessHeap(), 0, data );
631     }
632 }
633
634
635 /***********************************************************************
636  *           X11DRV process termination routine
637  */
638 static void process_detach(void)
639 {
640     X11DRV_Clipboard_Cleanup();
641 #ifdef SONAME_LIBXXF86VM
642     /* cleanup XVidMode */
643     X11DRV_XF86VM_Cleanup();
644 #endif
645     if(using_client_side_fonts)
646         X11DRV_XRender_Finalize();
647
648     /* cleanup GDI */
649     X11DRV_GDI_Finalize();
650     X11DRV_OpenGL_Cleanup();
651
652     IME_UnregisterClasses();
653     DeleteCriticalSection( &X11DRV_CritSection );
654     TlsFree( thread_data_tls_index );
655 }
656
657
658 /* store the display fd into the message queue */
659 static void set_queue_display_fd( Display *display )
660 {
661     HANDLE handle;
662     int ret;
663
664     if (wine_server_fd_to_handle( ConnectionNumber(display), GENERIC_READ | SYNCHRONIZE, 0, &handle ))
665     {
666         MESSAGE( "x11drv: Can't allocate handle for display fd\n" );
667         ExitProcess(1);
668     }
669     SERVER_START_REQ( set_queue_fd )
670     {
671         req->handle = wine_server_obj_handle( handle );
672         ret = wine_server_call( req );
673     }
674     SERVER_END_REQ;
675     if (ret)
676     {
677         MESSAGE( "x11drv: Can't store handle for display fd\n" );
678         ExitProcess(1);
679     }
680     CloseHandle( handle );
681 }
682
683
684 /***********************************************************************
685  *           X11DRV thread initialisation routine
686  */
687 struct x11drv_thread_data *x11drv_init_thread_data(void)
688 {
689     struct x11drv_thread_data *data = x11drv_thread_data();
690
691     if (data) return data;
692
693     if (!(data = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data) )))
694     {
695         ERR( "could not create data\n" );
696         ExitProcess(1);
697     }
698     wine_tsx11_lock();
699     if (!(data->display = XOpenDisplay(NULL)))
700     {
701         wine_tsx11_unlock();
702         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));
703         ExitProcess(1);
704     }
705
706     fcntl( ConnectionNumber(data->display), F_SETFD, 1 ); /* set close on exec flag */
707
708 #ifdef HAVE_XKB
709     if (use_xkb && XkbUseExtension( data->display, NULL, NULL ))
710         XkbSetDetectableAutoRepeat( data->display, True, NULL );
711 #endif
712
713     if (TRACE_ON(synchronous)) XSynchronize( data->display, True );
714     wine_tsx11_unlock();
715
716     set_queue_display_fd( data->display );
717     TlsSetValue( thread_data_tls_index, data );
718
719     if (use_xim) X11DRV_SetupXIM();
720
721     return data;
722 }
723
724
725 /***********************************************************************
726  *           X11DRV initialisation routine
727  */
728 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
729 {
730     BOOL ret = TRUE;
731
732     switch(reason)
733     {
734     case DLL_PROCESS_ATTACH:
735         x11drv_module = hinst;
736         ret = process_attach();
737         break;
738     case DLL_THREAD_DETACH:
739         thread_detach();
740         break;
741     case DLL_PROCESS_DETACH:
742         process_detach();
743         break;
744     }
745     return ret;
746 }
747
748 /***********************************************************************
749  *              GetScreenSaveActive (X11DRV.@)
750  *
751  * Returns the active status of the screen saver
752  */
753 BOOL CDECL X11DRV_GetScreenSaveActive(void)
754 {
755     int timeout, temp;
756     wine_tsx11_lock();
757     XGetScreenSaver(gdi_display, &timeout, &temp, &temp, &temp);
758     wine_tsx11_unlock();
759     return timeout != 0;
760 }
761
762 /***********************************************************************
763  *              SetScreenSaveActive (X11DRV.@)
764  *
765  * Activate/Deactivate the screen saver
766  */
767 void CDECL X11DRV_SetScreenSaveActive(BOOL bActivate)
768 {
769     int timeout, interval, prefer_blanking, allow_exposures;
770     static int last_timeout = 15 * 60;
771
772     wine_tsx11_lock();
773     XGetScreenSaver(gdi_display, &timeout, &interval, &prefer_blanking,
774                     &allow_exposures);
775     if (timeout) last_timeout = timeout;
776
777     timeout = bActivate ? last_timeout : 0;
778     XSetScreenSaver(gdi_display, timeout, interval, prefer_blanking,
779                     allow_exposures);
780     wine_tsx11_unlock();
781 }