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 get_server_startup();
269 /* setup TSX11 locking */
270 #ifdef NO_REENTRANT_X11
271 old_errno_location = (void *)InterlockedExchange( (PLONG)&wine_errno_location,
272 (LONG)x11_errno_location );
273 old_h_errno_location = (void *)InterlockedExchange( (PLONG)&wine_h_errno_location,
274 (LONG)x11_h_errno_location );
275 #endif /* NO_REENTRANT_X11 */
276 old_tsx11_lock = wine_tsx11_lock;
277 old_tsx11_unlock = wine_tsx11_unlock;
278 wine_tsx11_lock = lock_tsx11;
279 wine_tsx11_unlock = unlock_tsx11;
283 if (!(display = TSXOpenDisplay( NULL )))
285 MESSAGE( "x11drv: Can't open display: %s\n", XDisplayName(NULL) );
288 fcntl( ConnectionNumber(display), F_SETFD, 1 ); /* set close on exec flag */
289 screen = DefaultScreenOfDisplay( display );
290 visual = DefaultVisual( display, DefaultScreen(display) );
291 root_window = DefaultRootWindow( display );
293 /* Initialize screen depth */
295 if (screen_depth) /* depth specified */
298 int *depth_list = TSXListDepths(display, DefaultScreen(display), &depth_count);
299 for (i = 0; i < depth_count; i++)
300 if (depth_list[i] == screen_depth) break;
301 TSXFree( depth_list );
302 if (i >= depth_count)
304 MESSAGE( "x11drv: Depth %d not supported on this screen.\n", screen_depth );
308 else screen_depth = DefaultDepthOfScreen( screen );
310 /* If OpenGL is available, change the default visual, etc as necessary */
312 setup_opengl_visual( display );
313 #endif /* HAVE_OPENGL */
315 /* tell the libX11 that we will do input method handling ourselves
316 * that keep libX11 from doing anything whith dead keys, allowing Wine
317 * to have total control over dead keys, that is this line allows
318 * them to work in Wine, even whith a libX11 including the dead key
319 * patches from Th.Quinot (http://Web.FdN.FR/~tquinot/dead-keys.en.html)
321 TSXOpenIM( display, NULL, NULL, NULL);
325 XSetErrorHandler( error_handler );
326 XSynchronize( display, True );
329 screen_width = WidthOfScreen( screen );
330 screen_height = HeightOfScreen( screen );
332 if (desktop_geometry)
334 Options.managed = FALSE;
335 root_window = X11DRV_create_desktop( desktop_vi, desktop_geometry );
339 if(!X11DRV_GDI_Initialize( display ))
341 ERR( "Couldn't Initialize GDI.\n" );
345 #ifdef HAVE_LIBXXF86VM
346 /* initialize XVidMode */
347 X11DRV_XF86VM_Init();
349 #ifdef HAVE_LIBXXF86DGA2
350 /* initialize DGA2 */
351 X11DRV_XF86DGA2_Init();
355 /*X11DRV_GLX_Init();*/
358 /* load display.dll */
359 LoadLibrary16( "display" );
363 /***********************************************************************
364 * X11DRV thread termination routine
366 static void thread_detach(void)
368 struct x11drv_thread_data *data = NtCurrentTeb()->driver_data;
372 CloseHandle( data->display_fd );
374 XCloseDisplay( data->display );
376 HeapFree( GetProcessHeap(), 0, data );
381 /***********************************************************************
382 * X11DRV process termination routine
384 static void process_detach(void)
388 /*X11DRV_GLX_Cleanup();*/
390 #ifdef HAVE_LIBXXF86DGA2
392 X11DRV_XF86DGA2_Cleanup();
394 #ifdef HAVE_LIBXXF86VM
395 /* cleanup XVidMode */
396 X11DRV_XF86VM_Cleanup();
399 /* FIXME: should detach all threads */
403 X11DRV_GDI_Finalize();
405 /* restore TSX11 locking */
406 wine_tsx11_lock = old_tsx11_lock;
407 wine_tsx11_unlock = old_tsx11_unlock;
408 #ifdef NO_REENTRANT_X11
409 wine_errno_location = old_errno_location;
410 wine_h_errno_location = old_h_errno_location;
411 #endif /* NO_REENTRANT_X11 */
412 RtlDeleteCriticalSection( &X11DRV_CritSection );
416 /***********************************************************************
417 * X11DRV thread initialisation routine
419 struct x11drv_thread_data *x11drv_init_thread_data(void)
421 struct x11drv_thread_data *data;
423 if (!(data = HeapAlloc( GetProcessHeap(), 0, sizeof(*data) )))
425 ERR( "could not create data\n" );
429 if (!(data->display = XOpenDisplay(NULL)))
432 MESSAGE( "x11drv: Can't open display: %s\n", XDisplayName(NULL) );
435 fcntl( ConnectionNumber(data->display), F_SETFD, 1 ); /* set close on exec flag */
436 if (synchronous) XSynchronize( data->display, True );
438 data->display_fd = FILE_DupUnixHandle( ConnectionNumber(data->display),
439 GENERIC_READ | SYNCHRONIZE );
440 data->process_event_count = 0;
441 NtCurrentTeb()->driver_data = data;
446 /***********************************************************************
447 * X11DRV initialisation routine
449 BOOL WINAPI X11DRV_Init( HINSTANCE hinst, DWORD reason, LPVOID reserved )
453 case DLL_PROCESS_ATTACH:
456 case DLL_THREAD_DETACH:
459 case DLL_PROCESS_DETACH:
466 /***********************************************************************
467 * GetScreenSaveActive (X11DRV.@)
469 * Returns the active status of the screen saver
471 BOOL X11DRV_GetScreenSaveActive(void)
474 TSXGetScreenSaver(gdi_display, &timeout, &temp, &temp, &temp);
478 /***********************************************************************
479 * SetScreenSaveActive (X11DRV.@)
481 * Activate/Deactivate the screen saver
483 void X11DRV_SetScreenSaveActive(BOOL bActivate)
486 TSXActivateScreenSaver(gdi_display);
488 TSXResetScreenSaver(gdi_display);
491 /***********************************************************************
492 * GetScreenSaveTimeout (X11DRV.@)
494 * Return the screen saver timeout
496 int X11DRV_GetScreenSaveTimeout(void)
499 TSXGetScreenSaver(gdi_display, &timeout, &temp, &temp, &temp);
503 /***********************************************************************
504 * SetScreenSaveTimeout (X11DRV.@)
506 * Set the screen saver timeout
508 void X11DRV_SetScreenSaveTimeout(int nTimeout)
510 /* timeout is a 16bit entity (CARD16) in the protocol, so it should
511 * not get over 32767 or it will get negative. */
512 if (nTimeout>32767) nTimeout = 32767;
513 TSXSetScreenSaver(gdi_display, nTimeout, 60, DefaultBlanking, DefaultExposures);