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