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