2 * X11DRV initialization code
4 * Copyright 1998 Patrik Stridvall
5 * Copyright 2000 Alexandre Julliard
10 #ifdef NO_REENTRANT_X11
11 /* Get pointers to the static errno and h_errno variables used by Xlib. This
12 must be done before including <errno.h> makes the variables invisible. */
14 static int *perrno = &errno;
16 static int *ph_errno = &h_errno;
17 #endif /* NO_REENTRANT_X11 */
25 #include <X11/cursorfont.h>
31 #include "wine/winbase16.h"
34 #include "debugtools.h"
45 DEFAULT_DEBUG_CHANNEL(x11drv);
47 static void (*old_tsx11_lock)(void);
48 static void (*old_tsx11_unlock)(void);
50 static CRITICAL_SECTION X11DRV_CritSection = CRITICAL_SECTION_INIT;
54 unsigned int screen_width;
55 unsigned int screen_height;
56 unsigned int screen_depth;
60 unsigned int X11DRV_server_startticks;
62 static BOOL synchronous; /* run in synchronous mode? */
63 static char *desktop_geometry;
64 static XVisualInfo *desktop_vi;
66 #ifdef NO_REENTRANT_X11
67 static int* (*old_errno_location)(void);
68 static int* (*old_h_errno_location)(void);
70 /***********************************************************************
73 * Get the per-thread errno location.
75 static int *x11_errno_location(void)
77 /* Use static libc errno while running in Xlib. */
78 if (X11DRV_CritSection.OwningThread == GetCurrentThreadId()) return perrno;
79 return old_errno_location();
82 /***********************************************************************
83 * x11_h_errno_location
85 * Get the per-thread h_errno location.
87 static int *x11_h_errno_location(void)
89 /* Use static libc h_errno while running in Xlib. */
90 if (X11DRV_CritSection.OwningThread == GetCurrentThreadId()) return ph_errno;
91 return old_h_errno_location();
93 #endif /* NO_REENTRANT_X11 */
95 /***********************************************************************
98 static int error_handler(Display *display, XErrorEvent *error_evt)
100 DebugBreak(); /* force an entry in the debugger */
104 /***********************************************************************
107 static void lock_tsx11(void)
109 RtlEnterCriticalSection( &X11DRV_CritSection );
112 /***********************************************************************
115 static void unlock_tsx11(void)
117 RtlLeaveCriticalSection( &X11DRV_CritSection );
120 /***********************************************************************
123 * Get the server startup time
124 * Won't be exact, but should be sufficient
126 static void get_server_startup(void)
129 gettimeofday( &t, NULL );
130 X11DRV_server_startticks = ((t.tv_sec * 1000) + (t.tv_usec / 1000)) - GetTickCount();
134 /***********************************************************************
137 * Get a config key from either the app-specific or the default config
139 inline static DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name,
140 char *buffer, DWORD size )
142 if (appkey && !RegQueryValueExA( appkey, name, 0, NULL, buffer, &size )) return 0;
143 return RegQueryValueExA( defkey, name, 0, NULL, buffer, &size );
147 /***********************************************************************
150 * Setup the x11drv options.
152 static void setup_options(void)
154 char buffer[MAX_PATH+16];
155 HKEY hkey, appkey = 0;
158 if (RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\x11drv", 0, NULL,
159 REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ))
161 ERR("Cannot create config registry key\n" );
165 /* open the app-specific key */
167 if (GetModuleFileName16( GetCurrentTask(), buffer, MAX_PATH ) ||
168 GetModuleFileNameA( 0, buffer, MAX_PATH ))
171 char *p, *appname = buffer;
172 if ((p = strrchr( appname, '/' ))) appname = p + 1;
173 if ((p = strrchr( appname, '\\' ))) appname = p + 1;
174 strcat( appname, "\\x11drv" );
175 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\AppDefaults", &tmpkey ))
177 if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0;
178 RegCloseKey( tmpkey );
182 /* get the display name */
184 strcpy( buffer, "DISPLAY=" );
185 count = sizeof(buffer) - 8;
186 if (!RegQueryValueExA( hkey, "display", 0, NULL, buffer + 8, &count ))
188 const char *display_name = getenv( "DISPLAY" );
189 if (display_name && strcmp( buffer, display_name ))
190 MESSAGE( "x11drv: Warning: $DISPLAY variable ignored, using '%s' specified in config file\n",
192 putenv( strdup(buffer) );
195 /* check --managed option in wine config file if it was not set on command line */
197 if (!Options.managed)
199 if (!get_config_key( hkey, appkey, "Managed", buffer, sizeof(buffer) ))
200 Options.managed = IS_OPTION_TRUE( buffer[0] );
203 if (!get_config_key( hkey, appkey, "Desktop", buffer, sizeof(buffer) ))
205 /* Imperfect validation: If Desktop=N, then we don't turn on
206 ** the --desktop option. We should really validate for a correct
208 if (!IS_OPTION_FALSE(buffer[0])) desktop_geometry = strdup(buffer);
211 if (!get_config_key( hkey, appkey, "DXGrab", buffer, sizeof(buffer) ))
212 dxgrab = IS_OPTION_TRUE( buffer[0] );
214 if (!get_config_key( hkey, appkey, "UseDGA", buffer, sizeof(buffer) ))
215 usedga = IS_OPTION_TRUE( buffer[0] );
218 if (!get_config_key( hkey, appkey, "ScreenDepth", buffer, sizeof(buffer) ))
219 screen_depth = atoi(buffer);
221 if (!get_config_key( hkey, appkey, "Synchronous", buffer, sizeof(buffer) ))
222 synchronous = IS_OPTION_TRUE( buffer[0] );
224 if (appkey) RegCloseKey( appkey );
229 /***********************************************************************
230 * setup_opengl_visual
232 * Setup the default visual used for OpenGL and Direct3D, and the desktop
233 * window (if it exists). If OpenGL isn't available, the visual is simply
234 * set to the default visual for the display
237 static void setup_opengl_visual( Display *display )
239 int err_base, evt_base;
241 /* In order to support OpenGL or D3D, we require a double-buffered
243 if (glXQueryExtension(display, &err_base, &evt_base) == True) {
244 int dblBuf[]={GLX_RGBA,GLX_DEPTH_SIZE,16,GLX_DOUBLEBUFFER,None};
247 desktop_vi = glXChooseVisual(display, DefaultScreen(display), dblBuf);
251 if (desktop_vi != NULL) {
252 visual = desktop_vi->visual;
253 screen = ScreenOfDisplay(display, desktop_vi->screen);
254 screen_depth = desktop_vi->depth;
257 #endif /* HAVE_OPENGL */
259 /***********************************************************************
260 * X11DRV process initialisation routine
262 static void process_attach(void)
266 WND_Driver = &X11DRV_WND_Driver;
268 get_server_startup();
271 /* setup TSX11 locking */
272 #ifdef NO_REENTRANT_X11
273 old_errno_location = (void *)InterlockedExchange( (PLONG)&wine_errno_location,
274 (LONG)x11_errno_location );
275 old_h_errno_location = (void *)InterlockedExchange( (PLONG)&wine_h_errno_location,
276 (LONG)x11_h_errno_location );
277 #endif /* NO_REENTRANT_X11 */
278 old_tsx11_lock = wine_tsx11_lock;
279 old_tsx11_unlock = wine_tsx11_unlock;
280 wine_tsx11_lock = lock_tsx11;
281 wine_tsx11_unlock = unlock_tsx11;
285 if (!(display = TSXOpenDisplay( NULL )))
287 MESSAGE( "x11drv: Can't open display: %s\n", XDisplayName(NULL) );
290 fcntl( ConnectionNumber(display), F_SETFD, 1 ); /* set close on exec flag */
291 screen = DefaultScreenOfDisplay( display );
292 visual = DefaultVisual( display, DefaultScreen(display) );
293 root_window = DefaultRootWindow( display );
295 /* Initialize screen depth */
297 if (screen_depth) /* depth specified */
300 int *depth_list = TSXListDepths(display, DefaultScreen(display), &depth_count);
301 for (i = 0; i < depth_count; i++)
302 if (depth_list[i] == screen_depth) break;
303 TSXFree( depth_list );
304 if (i >= depth_count)
306 MESSAGE( "x11drv: Depth %d not supported on this screen.\n", screen_depth );
310 else screen_depth = DefaultDepthOfScreen( screen );
312 /* If OpenGL is available, change the default visual, etc as necessary */
314 setup_opengl_visual( display );
315 #endif /* HAVE_OPENGL */
317 /* tell the libX11 that we will do input method handling ourselves
318 * that keep libX11 from doing anything whith dead keys, allowing Wine
319 * to have total control over dead keys, that is this line allows
320 * them to work in Wine, even whith a libX11 including the dead key
321 * patches from Th.Quinot (http://Web.FdN.FR/~tquinot/dead-keys.en.html)
323 TSXOpenIM( display, NULL, NULL, NULL);
327 XSetErrorHandler( error_handler );
328 XSynchronize( display, True );
331 screen_width = WidthOfScreen( screen );
332 screen_height = HeightOfScreen( screen );
334 if (desktop_geometry)
336 Options.managed = FALSE;
337 root_window = X11DRV_create_desktop( desktop_vi, desktop_geometry );
341 if(!X11DRV_GDI_Initialize( display ))
343 ERR( "Couldn't Initialize GDI.\n" );
347 #ifdef HAVE_LIBXXF86VM
348 /* initialize XVidMode */
349 X11DRV_XF86VM_Init();
351 #ifdef HAVE_LIBXXF86DGA2
352 /* initialize DGA2 */
353 X11DRV_XF86DGA2_Init();
357 /*X11DRV_GLX_Init();*/
360 /* load display.dll */
361 LoadLibrary16( "display" );
365 /***********************************************************************
366 * X11DRV thread termination routine
368 static void thread_detach(void)
370 struct x11drv_thread_data *data = NtCurrentTeb()->driver_data;
374 CloseHandle( data->display_fd );
376 XCloseDisplay( data->display );
378 HeapFree( GetProcessHeap(), 0, data );
383 /***********************************************************************
384 * X11DRV process termination routine
386 static void process_detach(void)
390 /*X11DRV_GLX_Cleanup();*/
392 #ifdef HAVE_LIBXXF86DGA2
394 X11DRV_XF86DGA2_Cleanup();
396 #ifdef HAVE_LIBXXF86VM
397 /* cleanup XVidMode */
398 X11DRV_XF86VM_Cleanup();
401 /* FIXME: should detach all threads */
405 X11DRV_GDI_Finalize();
407 /* restore TSX11 locking */
408 wine_tsx11_lock = old_tsx11_lock;
409 wine_tsx11_unlock = old_tsx11_unlock;
410 #ifdef NO_REENTRANT_X11
411 wine_errno_location = old_errno_location;
412 wine_h_errno_location = old_h_errno_location;
413 #endif /* NO_REENTRANT_X11 */
414 RtlDeleteCriticalSection( &X11DRV_CritSection );
418 /***********************************************************************
419 * X11DRV thread initialisation routine
421 struct x11drv_thread_data *x11drv_init_thread_data(void)
423 struct x11drv_thread_data *data;
425 if (!(data = HeapAlloc( GetProcessHeap(), 0, sizeof(*data) )))
427 ERR( "could not create data\n" );
431 if (!(data->display = XOpenDisplay(NULL)))
434 MESSAGE( "x11drv: Can't open display: %s\n", XDisplayName(NULL) );
437 fcntl( ConnectionNumber(data->display), F_SETFD, 1 ); /* set close on exec flag */
438 if (synchronous) XSynchronize( data->display, True );
440 data->display_fd = FILE_DupUnixHandle( ConnectionNumber(data->display),
441 GENERIC_READ | SYNCHRONIZE );
442 data->process_event_count = 0;
443 NtCurrentTeb()->driver_data = data;
448 /***********************************************************************
449 * X11DRV initialisation routine
451 BOOL WINAPI X11DRV_Init( HINSTANCE hinst, DWORD reason, LPVOID reserved )
455 case DLL_PROCESS_ATTACH:
458 case DLL_THREAD_DETACH:
461 case DLL_PROCESS_DETACH:
468 /***********************************************************************
469 * X11DRV_GetScreenSaveActive
471 * Returns the active status of the screen saver
473 BOOL X11DRV_GetScreenSaveActive(void)
476 TSXGetScreenSaver(gdi_display, &timeout, &temp, &temp, &temp);
480 /***********************************************************************
481 * X11DRV_SetScreenSaveActive
483 * Activate/Deactivate the screen saver
485 void X11DRV_SetScreenSaveActive(BOOL bActivate)
488 TSXActivateScreenSaver(gdi_display);
490 TSXResetScreenSaver(gdi_display);
493 /***********************************************************************
494 * X11DRV_GetScreenSaveTimeout
496 * Return the screen saver timeout
498 int X11DRV_GetScreenSaveTimeout(void)
501 TSXGetScreenSaver(gdi_display, &timeout, &temp, &temp, &temp);
505 /***********************************************************************
506 * X11DRV_SetScreenSaveTimeout
508 * Set the screen saver timeout
510 void X11DRV_SetScreenSaveTimeout(int nTimeout)
512 /* timeout is a 16bit entity (CARD16) in the protocol, so it should
513 * not get over 32767 or it will get negative. */
514 if (nTimeout>32767) nTimeout = 32767;
515 TSXSetScreenSaver(gdi_display, nTimeout, 60, DefaultBlanking, DefaultExposures);